Added vcs_nonideal, another equilibrium solver that can handle

nonideal thermo multiphase systems.
This commit is contained in:
Harry Moffat 2007-12-19 21:19:28 +00:00
parent daa7cbfe95
commit d0e99aec18
47 changed files with 21542 additions and 8 deletions

View file

@ -15,6 +15,10 @@ INCDIR = ../../../build/include/cantera/kernel
INSTALL_TSC = ../../../bin/install_tsc
do_ranlib = @DO_RANLIB@
# do_VCSnonideal = @DO_VCSNONIDEAL@
do_VCSnonideal = 1
# do_VCSnonideal = 0
debug_mode = @CANTERA_DEBUG_MODE@
ifeq ($(debug_mode), 1)
DEBUG_FLAG=-DDEBUG_MODE
@ -32,7 +36,7 @@ endif
#
#LOCAL_DEFS=-DDEBUG_BASISOPTIMIZE
#
#LOCAL_DEFS=-DDEBUG_BASISOPTIMIZE -DDEBUG_CHEMEQUIL
LOCAL_DEFS=-DDEBUG_BASISOPTIMIZE -DDEBUG_CHEMEQUIL -DCANTERA_SRC_TREE -DALTLINPROG -DDEBUG
#
PIC_FLAG=@PIC@
@ -43,28 +47,56 @@ EQUIL_OBJ = BasisOptimize.o ChemEquil.o MultiPhase.o MultiPhaseEquil.o equilibra
EQUIL_H = ChemEquil.h MultiPhase.h MultiPhaseEquil.h equil.h PropertyCalculator.h
ifeq ($(do_VCSnonideal), 1)
VCSNONIDEAL_OBJ = vcs_solve_TP.o vcs_VolPhase.o vcs_solve.o vcs_prob.o \
vcs_TP.o vcs_TV.o vcs_report.o vcs_util.o \
vcs_IntStarStar.o vcs_DoubleStarStar.o vcs_elem.o \
vcs_elem_rearrange.o vcs_MultiPhaseEquil.o \
vcs_nasa_poly.o vcs_nondim.o vcs_Exception.o \
vcs_funcVtot.o vcs_inest.o vcs_rearrange.o \
vcs_root1d.o vcs_rxnadj.o vcs_timer_generic.o \
vcs_SpeciesProperties.o vcs_setMolesLinProg.o \
vcs_prep.o vcs_species_thermo.o vcs_Gibbs.o
VCSNONIDEAL_H = vcs_internal.h vcs_VolPhase.h vcs_solve.h vcs_prob.h \
vcs_IntStarStar.h vcs_DoubleStarStar.h vcs_defs.h \
vcs_MultiPhaseEquil.h vcs_nasa_poly.h vcs_Exception.h \
vcs_SpeciesProperties.h vcs_species_thermo.h
endif
CXX_INCLUDES = -I../base -I../thermo -I../numerics @CXX_INCLUDES@
LIB = @buildlib@/libequil.a
DEPENDS = $(EQUIL_OBJ:.o=.d)
ifeq ($(do_VCSnonideal), 1)
VLIB=@buildlib@/libVCSnonideal.a
endif
all: $(LIB) .depends
DEPENDS = $(EQUIL_OBJ:.o=.d) $(VCSNONIDEAL_OBJ:.o=.d)
all: $(LIB) $(VLIB)
@(@INSTALL@ -d $(INCDIR))
@(for lh in $(EQUIL_H) ; do \
@(for lh in $(EQUIL_H) $(VCSNONIDEAL_H); do \
$(INSTALL_TSC) "$${lh}" $(INCDIR) ; \
done)
%.d:
@CXX_DEPENDS@ $(CXX_INCLUDES) $*.cpp > $*.d
@CXX_DEPENDS@ $(CXX_FLAGS) $(CXX_INCLUDES) $*.cpp > $*.d
.cpp.o:
@CXX@ -c $< $(CXX_FLAGS) $(CXX_INCLUDES)
$(LIB): $(EQUIL_OBJ) $(EQUIL_H)
@ARCHIVE@ $(LIB) $(EQUIL_OBJ) > /dev/null
$(LIB): $(EQUIL_OBJ) $(EQUIL_H) $(VCSNONIDEAL_OBJ) $(VCSNONIDEAL_H)
@ARCHIVE@ $(LIB) $(EQUIL_OBJ) $(VCSNONIDEAL_OBJ) > /dev/null
ifeq ($(do_ranlib),1)
@RANLIB@ $(LIB)
endif
$(VLIB): $(VCSNONIDEAL_OBJ) $(VCS_NONIDEAL_H)
@ARCHIVE@ $(VLIB) $(VCSNONIDEAL_OBJ) > /dev/null
ifeq ($(do_ranlib),1)
@RANLIB@ $(VLIB)
endif
clean:
@(for lh in dummy.h $(EQUIL_H) ; do \
th=$(INCDIR)/"$${lh}" ; \

View file

@ -1,5 +1,6 @@
#include "MultiPhaseEquil.h"
#include "MultiPhase.h"
#include "MolalityVPSSTP.h"
#include "sort.h"
#include "global.h"
@ -851,4 +852,172 @@ namespace Cantera {
}
return maxerr;
}
double MultiPhaseEquil::phaseMoles(index_t iph) {
return m_mix->phaseMoles(iph);
}
#include <stdio.h>
/*
*
*/
void MultiPhaseEquil::reportCSV(const std::string &reportFile) {
int k;
int istart;
int nSpecies;
double vol = 0.0;
string sName;
int nphase = m_np;
FILE * FP = fopen(reportFile.c_str(), "w");
if (!FP) {
printf("Failure to open file\n");
exit(-1);
}
double Temp = m_mix->temperature();
double pres = m_mix->pressure();
vector<double> mf( m_nsp_mix, 1.0);
vector<double> fe(m_nsp_mix, 0.0);
std::vector<double> VolPM;
std::vector<double> activity;
std::vector<double> ac;
std::vector<double> mu;
std::vector<double> mu0;
std::vector<double> molalities;
vol = 0.0;
for (int iphase = 0; iphase < nphase; iphase++) {
istart = m_mix->speciesIndex(0, iphase);
ThermoPhase &tref = m_mix->phase(iphase);
nSpecies = tref.nSpecies();
VolPM.resize(nSpecies, 0.0);
tref.getMoleFractions(&mf[istart]);
tref.getPartialMolarVolumes(DATA_PTR(VolPM));
//vcs_VolPhase *volP = m_vprob->VPhaseList[iphase];
double TMolesPhase = phaseMoles(iphase);
double VolPhaseVolumes = 0.0;
for (k = 0; k < nSpecies; k++) {
VolPhaseVolumes += VolPM[k] * mf[istart + k];
}
VolPhaseVolumes *= TMolesPhase;
vol += VolPhaseVolumes;
}
fprintf(FP,"--------------------- VCS_MULTIPHASE_EQUIL FINAL REPORT"
" -----------------------------\n");
fprintf(FP,"Temperature = %11.5g kelvin\n", Temp);
fprintf(FP,"Pressure = %11.5g Pascal\n", pres);
fprintf(FP,"Total Volume = %11.5g m**3\n", vol);
// fprintf(FP,"Number Basis optimizations = %d\n", m_vprob->m_NumBasisOptimizations);
// fprintf(FP,"Number VCS iterations = %d\n", m_vprob->m_Iterations);
for (int iphase = 0; iphase < nphase; iphase++) {
istart = m_mix->speciesIndex(0, iphase);
ThermoPhase &tref = m_mix->phase(iphase);
ThermoPhase *tp = &tref;
tp->getMoleFractions(&mf[istart]);
string phaseName = tref.name();
// vcs_VolPhase *volP = m_vprob->VPhaseList[iphase];
double TMolesPhase = phaseMoles(iphase);
//AssertTrace(TMolesPhase == m_mix->phaseMoles(iphase));
nSpecies = tref.nSpecies();
activity.resize(nSpecies, 0.0);
ac.resize(nSpecies, 0.0);
mu0.resize(nSpecies, 0.0);
mu.resize(nSpecies, 0.0);
VolPM.resize(nSpecies, 0.0);
molalities.resize(nSpecies, 0.0);
int actConvention = tp->activityConvention();
tp->getActivities(DATA_PTR(activity));
tp->getActivityCoefficients(DATA_PTR(ac));
tp->getStandardChemPotentials(DATA_PTR(mu0));
tp->getPartialMolarVolumes(DATA_PTR(VolPM));
tp->getChemPotentials(DATA_PTR(mu));
double VolPhaseVolumes = 0.0;
for (k = 0; k < nSpecies; k++) {
VolPhaseVolumes += VolPM[k] * mf[istart + k];
}
VolPhaseVolumes *= TMolesPhase;
vol += VolPhaseVolumes;
if (actConvention == 1) {
MolalityVPSSTP *mTP = static_cast<MolalityVPSSTP *>(tp);
tp->getChemPotentials(DATA_PTR(mu));
mTP->getMolalities(DATA_PTR(molalities));
tp->getChemPotentials(DATA_PTR(mu));
if (iphase == 0) {
fprintf(FP," Name, Phase, PhaseMoles, Mole_Fract, "
"Molalities, ActCoeff, Activity,"
"ChemPot_SS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
fprintf(FP," , , (kmol), , "
", , ,"
" (kJ/gmol), (kJ/gmol), (kmol), (m**3/kmol), (m**3)\n");
}
for (k = 0; k < nSpecies; k++) {
sName = tp->speciesName(k);
fprintf(FP,"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e,"
"%11.3e, %11.3e, %11.3e, %11.3e, %11.3e\n",
sName.c_str(),
phaseName.c_str(), TMolesPhase,
mf[istart + k], molalities[k], ac[k], activity[k],
mu0[k]*1.0E-6, mu[k]*1.0E-6,
mf[istart + k] * TMolesPhase,
VolPM[k], VolPhaseVolumes );
}
} else {
if (iphase == 0) {
fprintf(FP," Name, Phase, PhaseMoles, Mole_Fract, "
"Molalities, ActCoeff, Activity,"
" ChemPotSS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
fprintf(FP," , , (kmol), , "
", , ,"
" (kJ/gmol), (kJ/gmol), (kmol), (m**3/kmol), (m**3)\n");
}
for (k = 0; k < nSpecies; k++) {
molalities[k] = 0.0;
}
for (k = 0; k < nSpecies; k++) {
sName = tp->speciesName(k);
fprintf(FP,"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e, "
"%11.3e, %11.3e,% 11.3e, %11.3e, %11.3e\n",
sName.c_str(),
phaseName.c_str(), TMolesPhase,
mf[istart + k], molalities[k], ac[k],
activity[k], mu0[k]*1.0E-6, mu[k]*1.0E-6,
mf[istart + k] * TMolesPhase,
VolPM[k], VolPhaseVolumes );
}
}
#ifdef DEBUG
/*
* Check consistency: These should be equal
*/
tp->getChemPotentials(&(fe[istart]));
for (k = 0; k < nSpecies; k++) {
//if (!vcs_doubleEqual(fe[istart+k], mu[k])) {
// fprintf(FP,"ERROR: incompatibility!\n");
// fclose(FP);
// printf("ERROR: incompatibility!\n");
// exit(-1);
// }
}
#endif
}
fclose(FP);
}
}

View file

@ -75,6 +75,10 @@ namespace Cantera {
index_t componentIndex(index_t n) { return m_species[m_order[n]]; }
void reportCSV(const std::string &reportFile);
double phaseMoles(index_t iph);
protected:
void getComponents(const vector_int& order);

View file

@ -7,6 +7,7 @@
#include "equil.h"
#include "ChemEquil.h"
#include "MultiPhaseEquil.h"
#include "vcs_MultiPhaseEquil.h"
namespace Cantera {
@ -23,6 +24,7 @@ namespace Cantera {
doublereal equilibrate(MultiPhase& s, const char* XY,
doublereal tol, int maxsteps, int maxiter,
int loglevel) {
if (loglevel > 0) {
beginLogGroup("equilibrate",loglevel);
addLogEntry("multiphase equilibrate function");
@ -62,6 +64,7 @@ namespace Cantera {
throw CanteraError("equilibrate","unsupported option");
return -1.0;
}
}
/*
@ -103,6 +106,8 @@ namespace Cantera {
int retn = -1;
int nAttempts = 0;
int retnSub = 0;
bool estimateEquil = false;
int printLvlSub = 0;
if (loglevel > 0) {
beginLogGroup("equilibrate", loglevel);
@ -120,7 +125,37 @@ namespace Cantera {
}
}
while (redo) {
if (solver > 0) {
if (solver >= 2) {
m = new MultiPhase;
try {
m->addPhase(&s, 1.0);
m->init();
nAttempts++;
(void) vcs_equilibrate(*m, XY, estimateEquil, printLvlSub,
rtol, maxsteps, maxiter, loglevel-1);
redo = false;
if (loglevel > 0)
addLogEntry("VCSnonideal solver succeeded.");
delete m;
retn = nAttempts;
}
catch (CanteraError err) {
if (loglevel > 0)
addLogEntry("VCSnonideal solver failed.");
delete m;
if (nAttempts < 2) {
if (loglevel > 0)
addLogEntry("Trying single phase ChemEquil solver.");
solver = -1;
}
else {
if (loglevel > 0)
endLogGroup("equilibrate");
throw err;
}
}
} else if (solver == 1) {
m = new MultiPhase;
try {
m->addPhase(&s, 1.0);

View file

@ -0,0 +1,140 @@
/**
* @file DoubleStarStar.cpp
*
* Header file for class DoubleStarStar
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#include "vcs_DoubleStarStar.h"
namespace VCSnonideal {
//!Default constructor. Create an empty array.
DoubleStarStar::DoubleStarStar() :
m_nrows(0),
m_ncols(0)
{
m_data.clear();
m_colAddr.clear();
}
/*
* Constructor. Create an \c m by \c n array, and initialize
* all elements to \c v.
*/
DoubleStarStar::DoubleStarStar(int m, int n, double v) :
m_nrows(n),
m_ncols(m)
{
m_data.resize(n*m);
std::fill(m_data.begin(), m_data.end(), v);
m_colAddr.resize(m);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
}
// copy constructor
DoubleStarStar::DoubleStarStar(const DoubleStarStar& y) {
m_nrows = y.m_nrows;
m_ncols = y.m_ncols;
m_data.resize(m_nrows*m_ncols);
m_data = y.m_data;
m_colAddr.resize(m_ncols);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
}
// assignment operator
DoubleStarStar& DoubleStarStar::operator=(const DoubleStarStar& y) {
if (&y == this) return *this;
m_nrows = y.m_nrows;
m_ncols = y.m_ncols;
m_data.resize(m_nrows*m_ncols);
m_data = y.m_data;
m_colAddr.resize(m_ncols);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
return *this;
}
// resize the array, and fill the new entries with 'v'
/*
* @param n This is the number of rows
* @param m This is the number of columns in the new matrix
* @param v Default fill value -> defaults to zero.
*/
void DoubleStarStar::resize(int m, int n, double v) {
std::vector<double> old_data;
bool doCopy = false;
if (m_nrows > 0 && m_ncols > 0) {
if (m_nrows != n) {
doCopy = true;
old_data = m_data;
}
}
m_data.resize(n*m, v);
if (doCopy) {
if (n >= m_nrows && m >= m_ncols) {
for (int jcol = 0; jcol < m_ncols; jcol++) {
for (int irow = 0; irow < m_nrows; irow++) {
m_data[jcol*n + irow] = old_data[jcol*m_nrows + irow];
}
for (int irow = m_nrows; irow < n; irow++) {
m_data[jcol*n + irow] = v;
}
}
for (int jcol = m_ncols; jcol < m; jcol++) {
for (int irow = 0; irow < n; irow++) {
m_data[jcol*n + irow] = v;
}
}
} else {
std::fill(m_data.begin(), m_data.end(), v);
for (int jcol = 0; jcol < m_ncols; jcol++) {
for (int irow = 0; irow < m_nrows; irow++) {
m_data[jcol*n + irow] = old_data[jcol*m_nrows + irow];
}
}
}
}
m_nrows = n;
m_ncols = m;
m_colAddr.resize(m_ncols);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
}
double * const DoubleStarStar::operator[](int jcol) {
return m_colAddr[jcol];
}
const double * const DoubleStarStar::operator[](int jcol) const {
return (const double * const) m_colAddr[jcol];
}
double * const * const DoubleStarStar::baseDataAddr() {
return (double * const * const) &(m_colAddr[0]);
}
// Number of rows
int DoubleStarStar::nRows() const {
return m_nrows;
}
// Number of columns
int DoubleStarStar::nColumns() const {
return m_ncols;
}
}

View file

@ -0,0 +1,124 @@
/**
* @file DoubleStarStar.h
*
* Header file for class DoubleStarStar
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#ifndef VCS_DOUBLESTARSTAR_H
#define VCS_DOUBLESTARSTAR_H
#include <vector>
namespace VCSnonideal {
//! A class for 2D double arrays storred in column-major
//! (Fortran-compatible) form.
/*!
* In this form, the data entry for an n row, m col
* matrix is
* index = i + (n-1) * j
* where
* Matrix[j][i]
* i = row
* j = column
* The way this is instantiated is via the constructor:
* DoubleStarStar Dmatrix(mcol, mrow);
*
* The way this is referenced is via the notation:
* Dmatrix[icol][irow]
*/
class DoubleStarStar {
public:
//! Default constructor. Create an empty array.
DoubleStarStar();
//! Constructor.
/*!
* Create an \c nrow by \c mcol double array, and initialize
* all elements to \c v.
*
* @param mcol Number of columns
* @param nrow Number of rows
*/
DoubleStarStar(int mcol, int nrow, double v = 0.0);
//! copy constructor
/*!
* @param y object to be copied
*/
DoubleStarStar(const DoubleStarStar& y);
/// assignment operator
/*!
* @param y object to be copied
*/
DoubleStarStar& operator=(const DoubleStarStar& y);
//! Resize the array, and fill the new entries with 'v'
/*!
* @param mrow This is the number of columns in the new matrix
* @param ncol This is the number of rows
* @param v Default fill value -> defaults to zero.
*/
void resize(int mcol, int nrow, double v = 0.0);
//! Pointer to the top of the column
/*!
* @param jcol This is the jth column
*
* @return returns the pointer to the top of the jth column
*/
double * const operator[](int jcol);
//! Returns a const Pointer to the top of the jth column
/*!
* @param jcol This is the jth column
*
* @return returns the pointer to the top of the jth column
*/
const double * const operator[](int jcol) const;
//! Returns a double ** pointer to the base address
/*!
* This is the second way to get to the data
* This returns a double ** which can later be used in
* Dmatrix[icol][irow] notation to get to the data
*/
double * const * const baseDataAddr();
//! Number of rows
int nRows() const;
//! Number of columns
int nColumns() const;
private:
//! Storage area
std::vector<double> m_data;
//! Vector of addresses for the top of the columns
/*!
* Length = mcol
*/
std::vector<double *> m_colAddr;
//! number of rows
int m_nrows;
//! number of columns
int m_ncols;
};
}
#endif

View file

@ -0,0 +1,14 @@
#include "vcs_Exception.h"
namespace VCSnonideal {
vcsError::vcsError(std::string proc, std::string msg, int errorCode) :
m_proc(proc),
m_msg(msg),
m_errorCode(errorCode)
{
}
}

View file

@ -0,0 +1,45 @@
/**
* @file vcs_Exception.h
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef VCS_EXCEPTION_H
#define VCS_EXCEPTION_H
#include <string>
namespace VCSnonideal {
class vcsError {
public:
vcsError(std::string proc, std::string msg, int errorCode=-1);
virtual ~vcsError(){}
protected:
std::string m_proc;
std::string m_msg;
int m_errorCode;
};
//! Assertion must be true or an error is thrown
/*!
* Assertion must be true or else a vcsError is thrown. A diagnostic
* string indicating where the error
* occured is added to the thrown object.
*
* @param expr Boolean expression that must be true
* @param proc Character string or std:string expression indicating the procedure
* where the assertion failed
* @ingroup errorhandling
*/
#define AssertThrowVCS(expr, proc) ((expr) ? (void) 0 : throw vcsError(proc, std::string("failed assert: ") + #expr,-1))
}
#endif

View file

@ -0,0 +1,101 @@
/**
* @file vcs_Gibbs.cpp
* Functions which calculate the extrinsic Gibbs Free energies
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
#include "math.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::vcs_Total_Gibbs(double *w, double *fe, double *tPhMoles)
/*************************************************************************
*
* vcs_Total_Gibbs:
*
* Calculate the total dimensionless Gibbs free energy
* -> Inert species are handled as if they had a standard free
* energy of zero.
* Note, for this algorithm this function should be MONOTONICALLY
* DECREASING.
*************************************************************************/
{
double g = 0.0;
int kspec;
int iph;
for (iph = 0; iph < NPhase; iph++) {
vcs_VolPhase *Vphase = VPhaseList[iph];
if ((TPhInertMoles[iph] > 0.0) && (tPhMoles[iph] > 0.0)) {
g += TPhInertMoles[iph] *
log(TPhInertMoles[iph] / tPhMoles[iph]);
if (Vphase->GasPhase) {
g += TPhInertMoles[iph] * log(Pres);
}
}
}
for (kspec = 0; kspec < m_numSpeciesRdc; ++kspec) {
g += w[kspec] * fe[kspec];
}
return g;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::vcs_GibbsPhase(int iphase, double *w, double *fe)
/*************************************************************************
*
* vcs_Total_Gibbs:
*
* Calculate the total dimensionless Gibbs free energy
* -> Inert species are handled as if they had a standard free
* energy of zero.
* Note, for this algorithm this function should be MONOTONICALLY
* DECREASING.
*************************************************************************/
{
double g = 0.0;
vcs_VolPhase *Vphase = VPhaseList[iphase];
if ((TPhInertMoles[iphase] > 0.0) && (TPhMoles[iphase] > 0.0)) {
g += TPhInertMoles[iphase] *
log(TPhInertMoles[iphase] / TPhMoles[iphase]);
if (Vphase->GasPhase == iphase) {
g += TPhInertMoles[iphase] * log(Pres);
}
}
for (int kspec = 0; kspec < m_numSpeciesRdc; ++kspec) {
if (PhaseID[kspec] == iphase) {
g += w[kspec] * fe[kspec];
}
}
return g;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
}

View file

@ -0,0 +1,141 @@
/**
* @file IntStarStar.cpp
*
* Header file for class IntStarStar
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#include "vcs_IntStarStar.h"
namespace VCSnonideal {
//!Default constructor. Create an empty array.
IntStarStar::IntStarStar() :
m_nrows(0),
m_ncols(0)
{
m_data.clear();
m_colAddr.clear();
}
/*
* Constructor. Create an \c m by \c n array, and initialize
* all elements to \c v.
*/
IntStarStar::IntStarStar(int m, int n, int v) :
m_nrows(n),
m_ncols(m)
{
m_data.resize(n*m);
std::fill(m_data.begin(), m_data.end(), v);
m_colAddr.resize(m);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
}
// copy constructor
IntStarStar::IntStarStar(const IntStarStar& y) {
m_nrows = y.m_nrows;
m_ncols = y.m_ncols;
m_data.resize(m_nrows*m_ncols);
m_data = y.m_data;
m_colAddr.resize(m_ncols);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
}
// assignment operator
IntStarStar& IntStarStar::operator=(const IntStarStar& y) {
if (&y == this) return *this;
m_nrows = y.m_nrows;
m_ncols = y.m_ncols;
m_data.resize(m_nrows*m_ncols);
m_data = y.m_data;
m_colAddr.resize(m_ncols);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
return *this;
}
//! resize the array, and fill the new entries with 'v'
/*!
* @param n This is the number of rows
* @param m This is the number of columns in the new matrix
* @param v Default fill value -> defaults to zero.
*/
void IntStarStar::resize(int m, int n, int v) {
std::vector<int> old_data;
bool doCopy = false;
if (m_nrows > 0 && m_ncols > 0) {
if (m_ncols != m) {
doCopy = true;
old_data = m_data;
}
}
m_data.resize(n*m, v);
if (doCopy) {
if (n >= m_nrows && m >= m_ncols) {
for (int jcol = 0; jcol < m_ncols; jcol++) {
for (int irow = 0; irow < m_nrows; irow++) {
m_data[jcol*m + irow] = old_data[jcol*m_ncols + irow];
}
for (int irow = m_nrows; irow < n; irow++) {
m_data[jcol*m + irow] = v;
}
}
for (int jcol = m_ncols; jcol < m; jcol++) {
for (int irow = 0; irow < n; irow++) {
m_data[jcol*m + irow] = v;
}
}
} else {
std::fill(m_data.begin(), m_data.end(), v);
for (int jcol = 0; jcol < m_ncols; jcol++) {
for (int irow = 0; irow < m_nrows; irow++) {
m_data[jcol*m + irow] = old_data[jcol*m_ncols + irow];
}
}
}
}
m_nrows = n;
m_ncols = m;
m_colAddr.resize(m_ncols);
for (int jcol = 0; jcol < m_ncols; jcol++) {
m_colAddr[jcol] = &(m_data[jcol*m_nrows]);
}
}
int * const IntStarStar::operator[](int jcol) {
return m_colAddr[jcol];
}
const int * const IntStarStar::operator[](int jcol) const {
return (const int * const) m_colAddr[jcol];
}
int * const * const IntStarStar::baseDataAddr() {
return (int * const * const) &(m_colAddr[0]);
}
/// Number of rows
int IntStarStar::nRows() const {
return m_nrows;
}
/// Number of columns
int IntStarStar::nColumns() const {
return m_ncols;
}
}

View file

@ -0,0 +1,106 @@
/**
* @file IntStarStar.h
*
* Header file for class IntStarStar
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#ifndef VCS_INTSTARSTAR_H
#define VCS_INTSTARSTAR_H
#include <vector>
namespace VCSnonideal {
//! A class for 2D int arrays storred in column-major
//! (Fortran-compatible) form.
/*!
* In this form, the data entry for an n row, m col
* matrix is
* index = i + (n-1) * j
* where
* Matrix[j][i]
* i = row
* j = column
*/
class IntStarStar {
public:
//! Default constructor. Create an empty array.
IntStarStar();
//! Constructor.
/*!
* Create an \c nrow by \c mcol int array, and initialize
* all elements to \c v.
*
* @param mcol Number of columns
* @param nrow Number of rows
*/
IntStarStar(int mcol, int nrow, int v = 0);
//! copy constructor
IntStarStar(const IntStarStar& y);
/// assignment operator
IntStarStar& operator=(const IntStarStar& y);
//! Resize the array, and fill the new entries with 'v'
/*!
* @param mcol This is the number of columns in the new matrix
* @param nrow This is the number of rows
* @param v Default fill value -> defaults to zero.
*/
void resize(int mcol, int nrow, int v = 0);
//! Pointer to the top of the column
/*!
* @param jcol Pointer to the top of the jth column
*/
int * const operator[](int jcol);
//! Pointer to the top of the column
/*!
* @param j Pointer to the top of the jth column
*/
const int * const operator[](int jcol) const;
//! Returns a int ** pointer to the base address
/*!
* This is the second way to get to the data
* This returns a int ** which can later be used in
* Imatrix[icol][irow] notation to get to the data
*/
int * const * const baseDataAddr();
//! Number of rows
int nRows() const;
//! Number of columns
int nColumns() const;
private:
//! Storage area
std::vector<int> m_data;
std::vector<int *> m_colAddr;
//! number of rows
int m_nrows;
//! number of columns
int m_ncols;
};
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,362 @@
/**
* @file vcs_MultiPhase.h
* Interface class for the vcsnonlinear solver
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#ifndef VCS_MULTIPHASEEQUIL_H
#define VCS_MULTIPHASEEQUIL_H
#ifdef CANTERA_NOTIN_SRC_TREE
#include "cantera/kernel/ct_defs.h"
#include "cantera/kernel/MultiPhase.h"
#else
#include "ct_defs.h"
#include "MultiPhase.h"
#endif
/*
* VCS_PROB is outside of Cantera namespace
*/
namespace VCSnonideal {
class VCS_PROB;
class VCS_SOLVE;
}
namespace Cantera {
int vcs_Cantera_to_vprob(MultiPhase *mphase, VCSnonideal::VCS_PROB *vprob);
int vcs_Cantera_update_vprob(MultiPhase *mphase,
VCSnonideal::VCS_PROB *vprob);
//! Set a single-phase chemical solution to chemical equilibrium.
/*!
* The function uses the element abundance vector that is
* currently consistent with the composition within the phase
* itself. Two other thermodynamic quantities, determined by the
* XY string, are held constant during the equilibration.
* This is a convenience function that uses one or the other of
* the two chemical equilibrium solvers.
*
* @param s The object to set to an equilibrium state
*
* @param XY An integer specifying the two properties to be held
* constant.
*
* @param estimateEquil Boolean indicating whether the solver
* should estimate its own initial condition.
* If false, the initial mole fraction vector
* in the %ThermoPhase object is used as the
* initial condition.
*
* @param printLvl Determines the amount of printing that
* gets sent to stdout from the vcs package
* (Note, you may have to compile with debug
* flags to get some printing).
*
* @param solver The equilibrium solver to use. If solver = 0,
* the ChemEquil solver will be used, and if
* solver = 1, the vcs_MultiPhaseEquil solver will
* be used (slower than ChemEquil,
* but more stable). If solver < 0 (default, then
* ChemEquil will be tried first, and if it fails
* vcs_MultiPhaseEquil will be tried.
*
* @param maxsteps The maximum number of steps to take to find
* the solution.
*
* @param maxiter For the MultiPhaseEquil solver only, this is
* the maximum number of outer temperature or
* pressure iterations to take when T and/or P is
* not held fixed.
*
* @param loglevel Controls amount of diagnostic output. loglevel
* = 0 suppresses diagnostics, and increasingly-verbose
* messages are written as loglevel increases. The
* messages are written to a file in HTML format for viewing
* in a web browser. @see HTML_logs
*
* @ingroup equilfunctions
*/
int vcs_equilibrate(thermo_t& s, const char* XY,
bool estimateEquil = false, int printLvl = 0,
int solver = -1, doublereal rtol = 1.0e-9,
int maxsteps = 1000,
int maxiter = 100, int loglevel = -99);
//! Set a multi-phase chemical solution to chemical equilibrium.
/*!
* This function uses the vcs_MultiPhaseEquil interface to the
* vcs solver.
* The function uses the element abundance vector that is
* currently consistent with the composition within the phases
* themselves. Two other thermodynamic quantities, determined by the
* XY string, are held constant during the equilibration.
*
* @param s The object to set to an equilibrium state
*
* @param XY A character string representing the unknowns
* to be held constant
*
* @param estimateEquil Boolean indicating whether the solver
* should estimate its own initial condition.
* If false, the initial mole fraction vector
* in the %ThermoPhase object is used as the
* initial condition.
*
* @param printLvl Determines the amount of printing that
* gets sent to stdout from the vcs package
* (Note, you may have to compile with debug
* flags to get some printing).
*
* @param maxsteps The maximum number of steps to take to find
* the solution.
*
* @param maxiter For the MultiPhaseEquil solver only, this is
* the maximum number of outer temperature or
* pressure iterations to take when T and/or P is
* not held fixed.
*
* @param loglevel Controls amount of diagnostic output. loglevel
* = 0 suppresses diagnostics, and increasingly-verbose
* messages are written as loglevel increases. The
* messages are written to a file in HTML format for viewing
* in a web browser. @see HTML_logs
*
* @ingroup equilfunctions
*/
int vcs_equilibrate(MultiPhase& s, const char* XY,
bool estimateEquil = false, int printLvl = 0,
doublereal rtol = 1.0e-9, int maxsteps = 1000,
int maxiter = 100, int loglevel = -99);
//! Set a multi-phase chemical solution to chemical equilibrium.
/*!
* This function uses the vcs_MultiPhaseEquil interface to the
* vcs solver.
* The function uses the element abundance vector that is
* currently consistent with the composition within the phases
* themselves. Two other thermodynamic quantities, determined by the
* XY string, are held constant during the equilibration.
*
* @param s The object to set to an equilibrium state
*
* @param XY An integer specifying the two properties to be held
* constant.
*
* @param estimateEquil Boolean indicating whether the solver
* should estimate its own initial condition.
* If false, the initial mole fraction vector
* in the %ThermoPhase object is used as the
* initial condition.
*
* @param printLvl Determines the amount of printing that
* gets sent to stdout from the vcs package
* (Note, you may have to compile with debug
* flags to get some printing).
*
* @param maxsteps The maximum number of steps to take to find
* the solution.
*
* @param maxiter For the MultiPhaseEquil solver only, this is
* the maximum number of outer temperature or
* pressure iterations to take when T and/or P is
* not held fixed.
*
* @param loglevel Controls amount of diagnostic output. loglevel
* = 0 suppresses diagnostics, and increasingly-verbose
* messages are written as loglevel increases. The
* messages are written to a file in HTML format for viewing
* in a web browser. @see HTML_logs
*
* @ingroup equilfunctions
*/
int vcs_equilibrate_1(MultiPhase& s, int ixy,
bool estimateEquil = false, int printLvl = 0,
doublereal rtol = 1.0e-9, int maxsteps = 1000,
int maxiter = 100, int loglevel = -99);
//! Cantera's Interface to the Multiphase chemical equilibrium solver.
/*!
* Class MultiPhaseEquil is designed to be used to set a mixture
* containing one or more phases to a state of chemical equilibrium.
*
* @ingroup equilfunctions
*/
class vcs_MultiPhaseEquil {
public:
//! Shorthand for the MultiPhase mixture object used by Cantera
//! to store information about multiple phases
typedef MultiPhase mix_t;
typedef size_t index_t;
typedef DenseMatrix matrix_t;
vcs_MultiPhaseEquil();
vcs_MultiPhaseEquil(mix_t* mix, int printLvl, bool start=true);
virtual ~vcs_MultiPhaseEquil();
int constituent(index_t m) {
if (m < m_nel) return m_order[m];
else return -1;
}
void getStoichVector(index_t rxn, vector_fp& nu) {
index_t k;
nu.resize(m_nsp, 0.0);
if (rxn > m_nsp - m_nel) return;
for (k = 0; k < m_nsp; k++) {
nu[m_order[k]] = m_N(k, rxn);
}
}
int iterations() { return m_iter; }
//! Equilibrate the solution using the current element abundances
//! storred in the MultiPhase object
/*!
* Use the vcs algorithm to equilibrate the current multiphase
* mixture.
*
* @param XY Integer representing what two thermo quantities
* are held constant during the equilibration
*
* @param estimateEquil Boolean indicating whether the solver
* should estimate its own initial condition.
* If false, the initial mole fraction vector
* in the %ThermoPhase object is used as the
* initial condition.
*
* @param printLvl Determines the amount of printing that
* gets sent to stdout from the vcs package
* (Note, you may have to compile with debug
* flags to get some printing).
* @param err Internal error level
* @param maxsteps max steps allowed.
* @param loglevel for
*/
int equilibrate(int XY, bool estimateEquil = false,
int printLvl= 0, doublereal err = 1.0e-6,
int maxsteps = 1000, int loglevel=-99);
//! Equilibrate the solution using the current element abundances
//! storred in the MultiPhase object using constant T and P
/*!
* Use the vcs algorithm to equilibrate the current multiphase
* mixture.
*
* @param estimateEquil Boolean indicating whether the solver
* should estimate its own initial condition.
* If false, the initial mole fraction vector
* in the %ThermoPhase object is used as the
* initial condition.
*
* @param printLvl Determines the amount of printing that
* gets sent to stdout from the vcs package
* (Note, you may have to compile with debug
* flags to get some printing).
* @param err Internal error level
* @param maxsteps max steps allowed.
* @param loglevel for
*/
int equilibrate_TP(bool estimateEquil = false,
int printLvl= 0, doublereal err = 1.0e-6,
int maxsteps = 1000, int loglevel=-99);
//! Equilibrate the solution using the current element abundances
//! storred in the MultiPhase object using constant H and P
/*!
* Use the vcs algorithm to equilibrate the current multiphase
* mixture.
*
* @param estimateEquil Boolean indicating whether the solver
* should estimate its own initial condition.
* If false, the initial mole fraction vector
* in the %ThermoPhase object is used as the
* initial condition.
*
* @param printLvl Determines the amount of printing that
* gets sent to stdout from the vcs package
* (Note, you may have to compile with debug
* flags to get some printing).
* @param err Internal error level
* @param maxsteps max steps allowed.
* @param loglevel for
*/
int equilibrate_HP(doublereal Htarget, int XY, double Tlow, double Thigh,
bool estimateEquil = false,
int printLvl = 0, doublereal err = 1.0E-6,
int maxsteps = 1000, int loglevel=-99);
int equilibrate_SP(doublereal Starget, double Tlow, double Thigh,
bool estimateEquil = false,
int printLvl = 0, doublereal err = 1.0E-6,
int maxsteps = 1000, int loglevel=-99);
int equilibrate_TV(int XY, doublereal xtarget,
bool estimateEquil,
int printLvl, doublereal err,
int maxsteps, int loglevel);
void reportCSV(const std::string &reportFile);
index_t componentIndex(index_t n) { return m_species[m_order[n]]; }
protected:
//! Number of elements in the combined element object describing all of the
//! phases.
index_t m_nel;
//! Number of species in the combined multiphase object
index_t m_nsp;
//! Vector that takes into account of the current sorting of the species
/*!
* The index of m_order is the original k value of the species in the
* multiphase. The value of m_order, k_sorted, is the current value of the
* species index.
*
* m_order[korig] = k_sorted
*/
vector_int m_order;
VCSnonideal::VCS_PROB *m_vprob;
//! Pointer to the MultiPhase mixture that will be equilibrated.
/*!
* Solutions will be returned in this variable.
*/
mix_t *m_mix;
int m_printLvl;
matrix_t m_N;
int m_iter;
// Vector of indices for species that are included in the
// calculation. This is used to exclude pure-phase species
// with invalid thermo data
vector_int m_species;
//! Pointer to the object that does all of the equilibration work.
/*!
* This object owns the pointer.
*/
VCSnonideal::VCS_SOLVE *m_vsolvePtr;
};
}
#endif

View file

@ -0,0 +1,93 @@
/**
* @file vcs_SpeciesProperties.cpp
*/
/*
* $Id $
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_defs.h"
#include "vcs_SpeciesProperties.h"
#include "vcs_VolPhase.h"
#include "vcs_species_thermo.h"
#include "vcs_internal.h"
using namespace std;
namespace VCSnonideal {
/*****************************************************************************
*
* constructor():
*/
vcs_SpeciesProperties::vcs_SpeciesProperties(int indexPhase,
int indexSpeciesPhase,
vcs_VolPhase *owning) :
IndexPhase(indexPhase),
IndexSpeciesPhase(indexSpeciesPhase),
OwningPhase(owning),
SpeciesThermo(0),
WtSpecies(0.0),
Charge(0.0),
SurfaceSpecies(0),
VolPM(0.0),
ReferenceMoleFraction(1.0E-6)
{
}
/******************************************************************************
*
* destructor
*/
vcs_SpeciesProperties::~vcs_SpeciesProperties()
{
}
/*****************************************************************************
*
* Copy Constructor vcs_SpeciesProperties
*/
vcs_SpeciesProperties::vcs_SpeciesProperties(const vcs_SpeciesProperties& b) :
IndexPhase(b.IndexPhase),
IndexSpeciesPhase(b.IndexSpeciesPhase),
OwningPhase(b.OwningPhase),
NumElements(b.NumElements),
SpeciesThermo(b.SpeciesThermo),
WtSpecies(b.WtSpecies),
Charge(b.Charge),
SurfaceSpecies(b.SurfaceSpecies),
VolPM(b.VolPM),
ReferenceMoleFraction(b.ReferenceMoleFraction)
{
SpName = b.SpName;
FormulaMatrixCol = b.FormulaMatrixCol;
}
/*****************************************************************************
*
* Assignment operator for vcs_SpeciesProperties
*/
vcs_SpeciesProperties&
vcs_SpeciesProperties::operator=(const vcs_SpeciesProperties& b)
{
if (&b != this) {
IndexPhase = b.IndexPhase;
IndexSpeciesPhase = b.IndexSpeciesPhase;
OwningPhase = b.OwningPhase;
NumElements = b.NumElements;
SpName = b.SpName;
WtSpecies = b.WtSpecies;
FormulaMatrixCol = b.FormulaMatrixCol;
Charge = b.Charge;
SurfaceSpecies = b.SurfaceSpecies;
VolPM = b.VolPM;
ReferenceMoleFraction = b.ReferenceMoleFraction;
}
return *this;
}
/*****************************************************************************/
}

View file

@ -0,0 +1,66 @@
/* $Id$ */
#ifndef VCS_SPECIES_PROPERTIES_H
#define VCS_SPECIES_PROPERTIES_H
#include <vector>
#include <string>
namespace VCSnonideal {
class VCS_SPECIES_THERMO;
class vcs_VolPhase;
class vcs_SpeciesProperties {
public:
int IndexPhase;
int IndexSpeciesPhase;
vcs_VolPhase *OwningPhase;
int NumElements;
//! Name of the species
std::string SpName;
VCS_SPECIES_THERMO *SpeciesThermo; /* Pointer to the thermo
structure for this species */
double WtSpecies; /* Molecular Weight of the species (gm/mol) */
//! Column of the formula matrix, comprising the
//! element composition of the species */
std::vector<double> FormulaMatrixCol;
double Charge; /* Charge state of the species -> This may
be duplication of what's in the
FormulaMatrixCol entries. However, it's prudent
to separate it out. */
int SurfaceSpecies; /* True if this species belongs to a surface phase
*/
/*
* Various Calculated Quantities that are appropriate to
* keep copies of at this level.
*/
double VolPM; /* Partial molar volume of the species */
double ReferenceMoleFraction; /* Representative value of the mole
fraction of this species in a phase.
This value is used for convergence issues
and for calculation of numerical derivs */
/*
* constructor and destructor
*/
vcs_SpeciesProperties(int indexPhase, int indexSpeciesPhase,
vcs_VolPhase *owning);
virtual ~vcs_SpeciesProperties();
/*
* Copy constructor and assignment operator
*/
vcs_SpeciesProperties(const vcs_SpeciesProperties& b);
vcs_SpeciesProperties& operator=(const vcs_SpeciesProperties& b);
};
}
#endif

View file

@ -0,0 +1,196 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_species_thermo.h"
#include "vcs_VolPhase.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_TP(int ipr, int ip1, int maxit, double T_arg, double pres_arg)
/**************************************************************************
*
* vcs_TP:
*
* Solve an equilibrium problem at a particular fixed temperature
* and pressure
*
* ipr = 1 -> Print results to standard output
* 0 -> don't report on anything
* ip1 = 1 -> Print intermediate results.
* maxit -> Maximum number of iterations for the algorithm
* T = Temperature (Kelvin)
* pres = Pressure (units given by if__ variable)
*
* 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 retn, iconv;
/*
* Store the temperature and pressure in the private global variables
*/
T = T_arg;
Pres = pres_arg;
/*
* Evaluate the standard state free energies
* at the current temperatures and pressures.
*/
iconv = vcs_evalSS_TP(ipr, ip1, T, pres_arg);
/*
* Prepare the problem data:
* ->nondimensionalize the free energies using
* the divisor, R * T
*/
vcs_nondim_TP();
/*
* Prep the fe field
*/
vcs_fePrep_TP();
/*
* Decide whether we need an initial estimate of the solution
* If so, go get one. If not, then
*/
if (iest) {
retn = vcs_inest_TP();
if (retn != VCS_SUCCESS) {
plogf("vcs_inest_TP returned a failure flag\n");
}
}
/*
* Solve the problem at a fixed Temperature and Pressure
* (all information concerning Temperature and Pressure has already
* been derived. The free energies are now in dimensionless form.)
*/
iconv = vcs_solve_TP(ipr, ip1, maxit);
/*
* Redimensionalize the free energies using
* the reverse of vcs_nondim to add back units.
*/
vcs_redim_TP();
/*
* Return the convergence success flag.
*/
return iconv;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*ARGSUSED*/
int VCS_SOLVE::vcs_evalSS_TP(int ipr, int ip1, double Temp, double pres)
/**************************************************************************
*
* vcs_evalSS_TP:
*
* IPR = 1 -> Print results to standard output
* 0 -> don't report on anything
* IP1 = 1 -> Print intermediate results.
* T = Temperature (Kelvin)
* Pres = Pressure (units of if__ variable)
*
* Evaluate the standard state free energies at the current temperature
* and pressure. Ideal gas pressure contribution is added in here.
*
***************************************************************************/
{
// int i;
//double R;
/*
* At this level of the program, we are still using values
* for the free energies that have units.
*/
// R = vcsUtil_gasConstant(m_VCS_UnitsFormat);
/*
* We need to special case VCS_UNITS_UNITLESS, here.
* cpc_ts_GStar_calc() returns units of Kelvin. Also, the temperature
* comes into play in calculating the ideal equation of state
* contributions, and other equations of state also. Therefore,
* we will emulate the VCS_UNITS_KELVIN case, here by chaning
* the initial gibbs free energy units to Kelvin before feeding
* them to the cpc_ts_GStar_calc() routine. Then, we will revert
* them back to unitless at the end of this routine.
*/
/*
* Loop over the species calculating the standard state Gibbs free
* energies. -> These are energies that only depend upon the Temperature
* and possibly on the pressure (i.e., ideal gas, etc).
*/
// HKM -> We can change this to looks over phases, calling the vcs_VolPhase
// object. Working to get rid of VCS_SPECIES_THERMO object
//for (i = 0; i < m_numSpeciesTot; ++i) {
// VCS_SPECIES_THERMO *spt = SpeciesThermo[i];
// ff[i] = R * spt->GStar_R_calc(i, Temp, pres);
//}
for (int iph = 0; iph < NPhase; iph++) {
vcs_VolPhase* vph = VPhaseList[iph];
vph->setState_TP(T, Pres);
vph->sendToVCSGStar(VCS_DATA_PTR(ff));
}
if (m_VCS_UnitsFormat == VCS_UNITS_UNITLESS) {
for (int i = 0; i < m_numSpeciesTot; ++i) {
ff[i] /= Temp;
}
}
return VCS_SUCCESS;
} /***************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::vcs_fePrep_TP(void)
/**************************************************************************
*
*
***************************************************************************/
{
int i;
for (i = 0; i < m_numSpeciesTot; ++i) {
/*
* For single species phases, initialize the chemical
* potential with the value of the standard state chemical
* potential. This value doesn't change during the calculation
*/
if (SSPhase[i]) {
m_gibbsSpecies[i] = ff[i];
}
}
} /* vcs_fePrep_TP() ********************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
}

View file

@ -0,0 +1,112 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
#include "vcs_species_thermo.h"
namespace VCSnonideal {
/**************************************************************************
*
* vcs_TV:
*
* Solve an equilibrium problem at a particular fixed temperature
* and volume.
* This is done as a root finder problem, solving repetative
* calls to solve_TP.
*
* ipr = 1 -> Print results to standard output
* 0 -> don't report on anything
* ip1 = 1 -> Print intermediate results.
* maxit -> Maximum number of iterations for the algorithm
* T = Temperature (Kelvin)
* Pres = Pressure (units specififed by if__ variable)
*/
int VCS_SOLVE::vcs_TV(int ipr, int ip1, int maxit, double T_arg, double VolRequest)
{
int iconv, varID;
double Pmin, Pmax, Preturn;
VCS_FUNC_PTR func;
/*
* Store the temperature in the private global variables
*/
T = T_arg;
/*
* Set the unknown variable to the pressure
*/
varID = 1;
/*
* Set the function to the volume function
*/
func = vcs_funcVtot;
/*
* Set max and min Pressures
*/
Pmin = 0.0;
Pmax = 1.0E30;
Preturn = 1.0;
iconv = vcsUtil_root1d(Pmin, Pmax, maxit, func, (void *) this,
VolRequest, varID, &Preturn);
/*
* Return the convergence success flag.
*/
return iconv;
}
/**************************************************************************
*
* vcs_VolTotal
*
* This function calculates the partial molar volume
* for all species, kspec, in the thermo problem
* at the temperature TKelvin and pressure, Pres, pres is in atm.
* And, it calculates the total volume of the combined system.
*
* Input
* iphase
* TKelvin
* pres
* w[] => vector containing the current mole numbers.
*
* Output
* VolPM[] => For species in all phase, the entries are the
* partial molar volumes
* return value = Total volume of the phase in L**3 / MOL_UNITS
*
* (L and MOL_UNITS determined from global units value if__)
*/
double VCS_SOLVE::vcs_VolTotal(double tkelvin, double pres, double w[],
double VolPM[])
{
double volTot = 0.0;
for (int iphase = 0; iphase < NPhase; iphase++) {
vcs_VolPhase *Vphase = VPhaseList[iphase];
Vphase->setState_TP(tkelvin, pres);
Vphase->setMolesFromVCS(w);
double volp = Vphase->VolPM_calc();
(void) Vphase->sendToVCSVolPM(VolPM);
volTot += volp;
}
return volTot;
}
/**************************************************************************/
}

View file

@ -0,0 +1,978 @@
/**
* @file vcs_VolPhase.cpp
*/
/* $Id$ */
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include "vcs_VolPhase.h"
#include "vcs_internal.h"
#include "vcs_SpeciesProperties.h"
#include "vcs_species_thermo.h"
#ifdef CANTERA_SRC_TREE
#include "ThermoPhase.h"
#else
#include "cantera/Cantera.h"
#include "cantera/kernel/ThermoPhase.h"
#endif
#include <cstdio>
#include <cstdlib>
namespace VCSnonideal {
/*****************************************************************************
*
* vcs_VolPhase():
*
* Constructor for the VolPhase object.
*/
vcs_VolPhase::vcs_VolPhase() :
VP_ID(-1),
Domain_ID(-1),
SingleSpecies(true),
GasPhase(false),
LiqPhase(false),
EqnState(VCS_EOS_CONSTANT),
nElemConstraints(0),
ChargeNeutralityElement(-1),
ElGlobalIndex(0),
NVolSpecies(0),
TMolesInert(0.0),
ActivityConvention(0),
Existence(0),
IndexSpecialSpecies(-1),
Activity_Coeff_Model(VCS_AC_CONSTANT),
Activity_Coeff_Params(0),
IndSpecies(0),
IndSpeciesContig(true),
UseCanteraCalls(false),
m_VCS_UnitsFormat(VCS_UNITS_MKS),
TP_ptr(0),
TMoles(0.0),
Vol(0.0),
m_phi(0.0),
m_UpToDate_AC(false),
m_UpToDate_VolStar(false),
m_UpToDate_VolPM(false),
m_UpToDate_GStar(false),
Temp(273.15),
Pres(1.01325E5),
RefPres(1.01325E5)
{
}
/*
*
* ~vcs_VolPhase():
*
* Destructor for the VolPhase object.
*/
vcs_VolPhase::~vcs_VolPhase() {
for (int k = 0; k < NVolSpecies; k++) {
vcs_SpeciesProperties *sp = ListSpeciesPtr[k];
delete sp;
sp = 0;
}
}
/*
*
* Copy Constructor():
*
* Objects that are owned by this object are deep copied here, except
* for the ThermoPhase object.
* The assignment operator does most of the work.
*/
vcs_VolPhase::vcs_VolPhase(const vcs_VolPhase& b) :
VP_ID(b.VP_ID),
Domain_ID(b.Domain_ID),
SingleSpecies(b.SingleSpecies),
GasPhase(b.GasPhase),
LiqPhase(b.LiqPhase),
EqnState(b.EqnState),
nElemConstraints(b.nElemConstraints),
ChargeNeutralityElement(b.ChargeNeutralityElement),
NVolSpecies(b.NVolSpecies),
TMolesInert(b.TMolesInert),
ActivityConvention(b.ActivityConvention),
Existence(b.Existence),
IndexSpecialSpecies(b.IndexSpecialSpecies),
Activity_Coeff_Model(b.Activity_Coeff_Model),
Activity_Coeff_Params(b.Activity_Coeff_Params),
IndSpeciesContig(b.IndSpeciesContig),
UseCanteraCalls(b.UseCanteraCalls),
m_VCS_UnitsFormat(b.m_VCS_UnitsFormat),
TP_ptr(b.TP_ptr),
TMoles(b.TMoles),
m_phiVarIndex(-1),
Vol(b.Vol),
m_phi(b.m_phi),
m_UpToDate_AC(false),
m_UpToDate_VolStar(false),
m_UpToDate_VolPM(false),
m_UpToDate_GStar(false),
Temp(b.Temp),
Pres(b.Pres)
{
/*
* Call the Assignment operator to do the heavy
* lifting.
*/
*this = b;
}
/*****************************************************************************
* Assignment operator()
*
* (note, this is used, so keep it current!)
*/
vcs_VolPhase& vcs_VolPhase::operator=(const vcs_VolPhase& b)
{
int k;
if (&b != this) {
int old_num = NVolSpecies;
VP_ID = b.VP_ID;
Domain_ID = b.Domain_ID;
SingleSpecies = b.SingleSpecies;
GasPhase = b.GasPhase;
LiqPhase = b.LiqPhase;
EqnState = b.EqnState;
NVolSpecies = b.NVolSpecies;
nElemConstraints = b.nElemConstraints;
ChargeNeutralityElement = b.ChargeNeutralityElement;
ElName.resize(b.nElemConstraints);
for (int e = 0; e < b.nElemConstraints; e++) {
ElName[e] = b.ElName[e];
}
ElActive = b.ElActive;
m_elType = b.m_elType;
FormulaMatrix.resize(nElemConstraints, NVolSpecies, 0.0);
for (int e = 0; e < nElemConstraints; e++) {
for (int k = 0; k < NVolSpecies; k++) {
FormulaMatrix[e][k] = b.FormulaMatrix[e][k];
}
}
SpeciesUnknownType = b.SpeciesUnknownType;
ElGlobalIndex = b.ElGlobalIndex;
NVolSpecies = b.NVolSpecies;
PhaseName = b.PhaseName;
TMolesInert = b.TMolesInert;
ActivityConvention = b.ActivityConvention;
Existence = b.Existence;
IndexSpecialSpecies = b.IndexSpecialSpecies;
Activity_Coeff_Model = b.Activity_Coeff_Model;
/*
* Do a shallow copy because we haven' figured this out.
*/
Activity_Coeff_Params = b.Activity_Coeff_Params;
IndSpecies = b.IndSpecies;
IndSpeciesContig = b.IndSpeciesContig;
for (k = 0; k < old_num; k++) {
if ( ListSpeciesPtr[k]) {
delete ListSpeciesPtr[k];
ListSpeciesPtr[k] = 0;
}
}
ListSpeciesPtr.resize(NVolSpecies, 0);
for (k = 0; k < NVolSpecies; k++) {
ListSpeciesPtr[k] =
new vcs_SpeciesProperties(*(b.ListSpeciesPtr[k]));
}
UseCanteraCalls = b.UseCanteraCalls;
m_VCS_UnitsFormat = b.m_VCS_UnitsFormat;
/*
* Do a shallow copy of the ThermoPhase object pointer.
* We don't duplicate the object.
* Um, there is no reason we couldn't do a
* duplicateMyselfAsThermoPhase() call here. This will
* have to be looked into.
*/
TP_ptr = b.TP_ptr;
TMoles = b.TMoles;
Xmol = b.Xmol;
m_phi = b.m_phi;
m_phiVarIndex = b.m_phiVarIndex;
SS0ChemicalPotential = b.SS0ChemicalPotential;
StarChemicalPotential = b.StarChemicalPotential;
StarMolarVol = b.StarMolarVol;
PartialMolarVol = b.PartialMolarVol;
ActCoeff = b.ActCoeff;
dLnActCoeffdMolNumber = b.dLnActCoeffdMolNumber;
m_UpToDate_AC = false;
m_UpToDate_VolStar = false;
m_UpToDate_VolPM = false;
m_UpToDate_GStar = false;
Temp = b.Temp;
Pres = b.Pres;
setState_TP(Temp, Pres);
_updateMoleFractionDependencies();
}
return *this;
}
void vcs_VolPhase::resize(int phaseNum, int nspecies, const char *phaseName,
double molesInert) {
if (nspecies <= 0) {
plogf("nspecies Error\n");
exit(-1);
}
if (phaseNum < 0) {
plogf("phaseNum should be greater than 0\n");
exit(-1);
}
TMolesInert = molesInert;
if (TMolesInert > 0.0) {
Existence = 2;
}
m_phi = 0.0;
m_phiVarIndex = -1;
if (phaseNum == VP_ID) {
if (strcmp(PhaseName.c_str(), phaseName)) {
plogf("Strings are different: %s %s :unknown situation\n",
PhaseName.c_str(), phaseName);
exit(-1);
}
} else {
VP_ID = phaseNum;
if (!phaseName) {
char itmp[40];
sprintf(itmp, "Phase_%d", VP_ID);
PhaseName = itmp;
} else {
PhaseName = phaseName;
}
}
if (nspecies > 1) {
SingleSpecies = false;
} else {
SingleSpecies = true;
}
if (NVolSpecies == nspecies) {
return;
}
NVolSpecies = nspecies;
if (nspecies > 1) {
SingleSpecies = false;
}
IndSpecies.resize(nspecies,-1);
if ((int) ListSpeciesPtr.size() >= NVolSpecies) {
for (int i = 0; i < NVolSpecies; i++) {
if (ListSpeciesPtr[i]) {
delete ListSpeciesPtr[i];
ListSpeciesPtr[i] = 0;
}
}
}
ListSpeciesPtr.resize(nspecies, 0);
for (int i = 0; i < nspecies; i++) {
ListSpeciesPtr[i] = new vcs_SpeciesProperties(phaseNum, i, this);
}
Xmol.resize(nspecies, 0.0);
for (int i = 0; i < nspecies; i++) {
Xmol[i] = 1.0/nspecies;
}
SS0ChemicalPotential.resize(nspecies, -1.0);
StarChemicalPotential.resize(nspecies, -1.0);
StarMolarVol.resize(nspecies, -1.0);
PartialMolarVol.resize(nspecies, -1.0);
ActCoeff.resize(nspecies, 1.0);
dLnActCoeffdMolNumber.resize(nspecies, nspecies, 0.0);
SpeciesUnknownType.resize(nspecies, VCS_SPECIES_TYPE_MOLNUM);
m_UpToDate_AC = false;
m_UpToDate_VolStar = false;
m_UpToDate_VolPM = false;
m_UpToDate_GStar = false;
}
//! Evaluate activity coefficients
/*!
* We carry out a calculation whenever UpTODate_AC is false. Specifically
* whenever a phase goes zero, we do not carry out calculations on it.
*/
void vcs_VolPhase::evaluateActCoeff() const {
char yo[] = "cpc_eval_ac ";
if (m_UpToDate_AC == true) return;
if (UseCanteraCalls) {
TP_ptr->getActivityCoefficients(VCS_DATA_PTR(ActCoeff));
} else {
switch (Activity_Coeff_Model) {
case VCS_AC_CONSTANT:
/*
* Don't need to do anything since ActCoeff[] is initialized to
* the value of one, and never changed for this model.
*/
break;
case VCS_AC_DEBYE_HUCKEL:
plogf("Not implemented Yet\n");
exit(-1);
break;
case VCS_AC_REGULAR_SOLN:
plogf("Not implemented Yet\n");
exit(-1);
break;
case VCS_AC_MARGULES:
plogf("Not implemented Yet\n");
exit(-1);
break;
default:
plogf("%sERROR: unknown model\n", yo);
exit(-1);
}
}
m_UpToDate_AC = true;
}
/******************************************************************************
*
* Evaluate one activity coefficients.
*
* return one activity coefficient. Have to recalculate them all to get
* one.
*/
double vcs_VolPhase::AC_calc_one(int kspec) const {
evaluateActCoeff();
return(ActCoeff[kspec]);
}
// Gibbs free energy calculation at a temperature for the reference state
// of each species
/*
* @param TKelvin temperature
*/
void vcs_VolPhase::G0_calc(double tkelvin) {
bool lsame = false;
if (Temp == tkelvin) {
lsame = true;
}
bool doit = !lsame;
setState_TP(tkelvin, Pres);
if (SS0ChemicalPotential[0] == -1) doit = true;
if (doit) {
if (UseCanteraCalls) {
TP_ptr->getGibbs_ref(VCS_DATA_PTR(SS0ChemicalPotential));
} else {
double R = vcsUtil_gasConstant(m_VCS_UnitsFormat);
for (int k = 0; k < NVolSpecies; k++) {
int kglob = IndSpecies[k];
vcs_SpeciesProperties *sProp = ListSpeciesPtr[k];
VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo;
SS0ChemicalPotential[k] =
R * (sTherm->G0_R_calc(kglob, tkelvin));
}
}
}
}
// Gibbs free energy calculation at a temperature for the reference state
// of a species, return a value for one species
/*
* @param kspec species index
* @param TKelvin temperature
*
* @return return value of the gibbs free energy
*/
double vcs_VolPhase::G0_calc_one(int kspec, double tkelvin) {
G0_calc(tkelvin);
return SS0ChemicalPotential[kspec];
}
// Gibbs free energy calculation for standard states
/*
* Calculate the Gibbs free energies for the standard states
* The results are held internally within the object.
*
* @param TKelvin Current temperature
* @param pres Current pressure
*/
void vcs_VolPhase::GStar_calc(double tkelvin, double pres) {
setState_TP(tkelvin, pres);
if (!m_UpToDate_GStar) {
if (UseCanteraCalls) {
TP_ptr->getStandardChemPotentials(VCS_DATA_PTR(StarChemicalPotential));
} else {
double R = vcsUtil_gasConstant(m_VCS_UnitsFormat);
for (int k = 0; k < NVolSpecies; k++) {
int kglob = IndSpecies[k];
vcs_SpeciesProperties *sProp = ListSpeciesPtr[k];
VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo;
StarChemicalPotential[k] =
R * (sTherm->GStar_R_calc(kglob, tkelvin, pres));
}
}
m_UpToDate_GStar = true;
}
}
// Gibbs free energy calculation for standard state of one species
/*
* Calculate the Gibbs free energies for the standard state
* of the kth species.
* The results are held internally within the object.
* The kth species standard state G is returned
*
* @param kspec Species number (within the phase)
* @param TKelvin Current temperature
* @param pres Current pressure
*
* @return Gstar[kspec] returns the gibbs free energy for the
* standard state of the kth species.
*/
double vcs_VolPhase::GStar_calc_one(int kspec, double tkelvin,
double pres) {
GStar_calc(tkelvin, pres);
return StarChemicalPotential[kspec];
}
// Set the moles within the phase
/*
* This function takes as input the mole numbers in vcs format, and
* then updates this object with their values. This is essentially
* a gather routine.
*
*
* @param molesSpeciesVCS array of mole numbers. Note, the indecises for species in
* this array may not be contiguous. IndSpecies[] is needed
* to gather the species into the local contiguous vector
* format.
*/
void vcs_VolPhase::setMolesFromVCS(const double * const molesSpeciesVCS) {
int kglob;
double tmp;
TMoles = TMolesInert;
for (int k = 0; k < NVolSpecies; k++) {
if (SpeciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
kglob = IndSpecies[k];
tmp = MAX(0.0, molesSpeciesVCS[kglob]);
Xmol[k] = tmp;
TMoles += tmp;
}
}
if (TMoles > 0.0) {
for (int k = 0; k < NVolSpecies; k++) {
Xmol[k] /= TMoles;
}
Existence = 1;
} else {
// This is where we will start to store a better approximation
// for the mole fractions, when the phase doesn't exist.
// This is currently unimplemented.
for (int k = 0; k < NVolSpecies; k++) {
Xmol[k] = 1.0 / NVolSpecies;
}
Existence = 0;
}
/*
* Update the electric potential if it is a solution variable
* in the equation system
*/
if (m_phiVarIndex >= 0) {
kglob = IndSpecies[m_phiVarIndex];
if (NVolSpecies == 1) {
Xmol[m_phiVarIndex] = 1.0;
} else {
Xmol[m_phiVarIndex] = 0.0;
}
double phi = molesSpeciesVCS[kglob];
setElectricPotential(phi);
if (NVolSpecies == 1) {
Existence = 1;
}
}
_updateMoleFractionDependencies();
if (TMolesInert > 0.0) {
Existence = 2;
}
}
// Set the mole fractions from a conventional mole fraction vector
/*
*
* @param xmol Value of the mole fractions for the species
* in the phase. These are contiguous.
*/
void vcs_VolPhase::setMoleFractions(const double * const xmol) {
double sum = -1.0;
for (int k = 0; k < NVolSpecies; k++) {
Xmol[k] = xmol[k];
sum+= xmol[k];
}
if (fabs(sum) > 1.0E-13) {
for (int k = 0; k < NVolSpecies; k++) {
Xmol[k] /= sum;
}
}
_updateMoleFractionDependencies();
}
// Updates the mole fractions in subobjects
/*
* Whenever the mole fractions change, this routine
* should be called.
*/
void vcs_VolPhase::_updateMoleFractionDependencies() {
if (UseCanteraCalls) {
if (TP_ptr) {
TP_ptr->setState_PX(Pres, VCS_DATA_PTR(Xmol));
}
}
m_UpToDate_AC = false;
m_UpToDate_VolPM = false;
}
// Return a const reference to the mole fraction vector in the phase
const std::vector<double> & vcs_VolPhase::moleFractions() const {
return Xmol;
}
//! Set the moles within the phase
/*!
* This function takes as input the mole numbers in vcs format, and
* then updates this object with their values. This is essentially
* a gather routine.
*
*
* @param molesSpeciesVCS array of mole numbers. Note, the indecises for species in
* this array may not be contiguous. IndSpecies[] is needed
* to gather the species into the local contiguous vector
* format.
*/
void vcs_VolPhase::setMolesFromVCSCheck(const double * const molesSpeciesVCS,
const double * const TPhMoles,
int iphase) {
setMolesFromVCS(molesSpeciesVCS);
/*
* Check for consistency with TPhMoles[]
*/
double Tcheck = TPhMoles[VP_ID];
if (Tcheck != TMoles) {
if (vcs_doubleEqual(Tcheck, TMoles)) {
Tcheck = TMoles;
} else {
plogf("We have a consistency problem: %21.16g %21.16g\n",
Tcheck, TMoles);
exit(-1);
}
}
}
// Fill in an activity coefficients vector for VCS
/*
* This routine will calculate the activity coefficients for the
* current phase, and fill in the corresponding entries in the
* VCS activity coefficients vector.
*
* @param AC vector of activity coefficients for all of the species
* in all of the phases in a VCS problem. Only the
* entries for the current phase are filled in.
*/
void vcs_VolPhase::sendToVCSActCoeff(double * const AC) const {
if (!m_UpToDate_AC) {
evaluateActCoeff();
}
int kglob;
for (int k = 0; k < NVolSpecies; k++) {
kglob = IndSpecies[k];
AC[kglob] = ActCoeff[k];
}
}
// Fill in the partial molar volume vector for VCS
/*
* This routine will calculate the partial molar volumes for the
* current phase (if needed), and fill in the corresponding entries in the
* VCS partial molar volumes vector.
*
* @param VolPM vector of partial molar volumes for all of the species
* in all of the phases in a VCS problem. Only the
* entries for the current phase are filled in.
*/
double vcs_VolPhase::sendToVCSVolPM(double * const VolPM) const {
if (!m_UpToDate_VolPM) {
(void) VolPM_calc();
}
int kglob;
for (int k = 0; k < NVolSpecies; k++) {
kglob = IndSpecies[k];
VolPM[kglob] = PartialMolarVol[k];
}
return Vol;
}
// Fill in the partial molar volume vector for VCS
/*
* This routine will calculate the partial molar volumes for the
* current phase (if needed), and fill in the corresponding entries in the
* VCS partial molar volumes vector.
*
* @param VolPM vector of partial molar volumes for all of the species
* in all of the phases in a VCS problem. Only the
* entries for the current phase are filled in.
*/
void vcs_VolPhase::sendToVCSGStar(double * const gstar){
if (!m_UpToDate_GStar) {
GStar_calc(Temp, Pres);
}
int kglob;
for (int k = 0; k < NVolSpecies; k++) {
kglob = IndSpecies[k];
gstar[kglob] = StarChemicalPotential[k];
}
}
void vcs_VolPhase::setElectricPotential(double phi) {
m_phi = phi;
if (UseCanteraCalls) {
TP_ptr->setElectricPotential(m_phi);
}
// We have changed the state variable. Set uptodate flags to false
m_UpToDate_AC = false;
m_UpToDate_VolStar = false;
m_UpToDate_VolPM = false;
m_UpToDate_GStar = false;
}
double vcs_VolPhase::electricPotential() const {
return m_phi;
}
// Sets the temperature and pressure in this object and
// underlying objects
/*
* Sets the temperature and pressure in this object and
* underlying objects. The underlying objects refers to the
* Cantera's ThermoPhase object for this phase.
*
* @param temperature_Kelvin (Kelvin)
* @param pressure_PA Pressure (MKS units - Pascal)
*/
void vcs_VolPhase::setState_TP(double temp, double pres)
{
if (Temp == temp) {
if (Pres == pres) {
return;
}
}
if (UseCanteraCalls) {
TP_ptr->setElectricPotential(m_phi);
TP_ptr->setState_TP(temp, pres);
}
Temp = temp;
Pres = pres;
m_UpToDate_AC = false;
m_UpToDate_VolStar = false;
m_UpToDate_VolPM = false;
m_UpToDate_GStar = false;
}
// Molar volume calculation for standard states
/*
* Calculate the molar volume for the standard states
* The results are held internally within the object.
*
* @param TKelvin Current temperature
* @param pres Current pressure
*/
void vcs_VolPhase::VolStar_calc(double tkelvin, double pres) {
setState_TP(tkelvin, pres);
if (!m_UpToDate_VolStar) {
if (UseCanteraCalls) {
TP_ptr->getStandardVolumes(VCS_DATA_PTR(StarMolarVol));
} else {
for (int k = 0; k < NVolSpecies; k++) {
int kglob = IndSpecies[k];
vcs_SpeciesProperties *sProp = ListSpeciesPtr[k];
VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo;
StarMolarVol[k] =
(sTherm->VolStar_calc(kglob, tkelvin, pres));
}
}
m_UpToDate_VolStar = true;
}
}
// Molar volume calculation for standard state of one species
/*
* Calculate the molar volume for the standard states
* The results are held internally within the object.
* Return the molar volume for one species
*
* @param kspec Species number (within the phase)
* @param TKelvin Current temperature
* @param pres Current pressure
*
* @return molar volume of the kspec species's standard
* state
*/
double vcs_VolPhase::VolStar_calc_one(int kspec, double tkelvin, double pres)
{
VolStar_calc(tkelvin, pres);
return StarMolarVol[kspec];
}
/******************************************************************************
*
* VolPM_calc
*/
double vcs_VolPhase::VolPM_calc() const {
int k, kglob;
if (!m_UpToDate_VolPM) {
if (UseCanteraCalls) {
TP_ptr->getPartialMolarVolumes(VCS_DATA_PTR(PartialMolarVol));
} else {
for (k = 0; k < NVolSpecies; k++) {
kglob = IndSpecies[k];
vcs_SpeciesProperties *sProp = ListSpeciesPtr[k];
VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo;
StarMolarVol[k] =
(sTherm->VolStar_calc(kglob, Temp, Pres));
}
for (k = 0; k < NVolSpecies; k++) {
PartialMolarVol[k] = StarMolarVol[k];
}
}
Vol = 0.0;
for (k = 0; k < NVolSpecies; k++) {
Vol += PartialMolarVol[k] * Xmol[k];
}
Vol *= TMoles;
}
m_UpToDate_VolPM = true;
return Vol;
}
/*
* updateLnActCoeffJac():
*
*/
void vcs_VolPhase::updateLnActCoeffJac(const double * const moleNumbersVCS) {
int k, j;
double deltaMoles_j = 0.0;
/*
* Make sure the base state of this object is fully up to date.
* with the current values of the mole numbers.
* -> This sets TMoles and Xmol[]
*/
setMolesFromVCS(moleNumbersVCS);
/*
* Evaluate the current base activity coefficients.
*/
evaluateActCoeff();
// Make copies of ActCoeff and Xmol for use in taking differences
std::vector<double> ActCoeff_Base(ActCoeff);
std::vector<double> Xmol_Base(Xmol);
double TMoles_base = TMoles;
/*
* Loop over the columns species to be deltad
*/
for (j = 0; j < NVolSpecies; j++) {
/*
* Calculate a value for the delta moles of species j
* -> NOte Xmol[] and Tmoles are always positive or zero
* quantities.
*/
double moles_j_base = TMoles * Xmol_Base[j];
deltaMoles_j = 1.0E-7 * moles_j_base + 1.0E-20 * TMoles + 1.0E-150;
/*
* Now, update the total moles in the phase and all of the
* mole fractions based on this.
*/
TMoles = TMoles_base + deltaMoles_j;
for (k = 0; k < NVolSpecies; k++) {
Xmol[k] = Xmol_Base[k] * TMoles_base / TMoles;
}
Xmol[j] = (moles_j_base + deltaMoles_j) / TMoles;
/*
* Go get new values for the activity coefficients.
* -> Note this calls setState_PX();
*/
_updateMoleFractionDependencies();
evaluateActCoeff();
/*
* Calculate the column of the matrix
*/
double * const lnActCoeffCol = dLnActCoeffdMolNumber[j];
for (k = 0; k < NVolSpecies; k++) {
lnActCoeffCol[k] = (ActCoeff[k] - ActCoeff_Base[k]) /
((ActCoeff[k] + ActCoeff_Base[k]) * 0.5 * deltaMoles_j);
}
/*
* Revert to the base case Xmol, TMoles
*/
TMoles = TMoles_base;
vcs_vdcopy(Xmol, Xmol_Base, NVolSpecies);
}
/*
* Go get base values for the activity coefficients.
* -> Note this calls setState_TPX() again;
* -> Just wanted to make sure that cantera is in sync
* with VolPhase after this call.
*/
setMoleFractions(VCS_DATA_PTR(Xmol_Base));
_updateMoleFractionDependencies();
evaluateActCoeff();
}
// Downloads the ln ActCoeff jacobian into the VCS version of the
// ln ActCoeff jacobian.
/*
*
* This is essentially a scatter operation.
*
* The Jacobians are actually d( lnActCoeff) / d (MolNumber);
* dLnActCoeffdMolNumber[j][k]
*
* j = id of the species mole number
* k = id of the species activity coefficient
*/
void vcs_VolPhase::sendToVCSLnActCoeffJac(double * const * const LnACJac_VCS) const {
int j, k, jglob, kglob;
for (j = 0; j < NVolSpecies; j++) {
jglob = IndSpecies[j];
double * const lnACJacVCS_col = LnACJac_VCS[jglob];
const double * const lnACJac_col = dLnActCoeffdMolNumber[j];
for (k = 0; k < NVolSpecies; k++) {
kglob = IndSpecies[k];
lnACJacVCS_col[kglob] = lnACJac_col[k];
}
}
}
// Set the pointer for Cantera's ThermoPhase parameter
/*
* When we first initialize the ThermoPhase object, we read the
* state of the ThermoPhase into vcs_VolPhase object.
*
* @param tp_ptr Pointer to the ThermoPhase object corresponding
* to this phase.
*/
void vcs_VolPhase::setPtrThermoPhase(Cantera::ThermoPhase *tp_ptr) {
TP_ptr = tp_ptr;
if (TP_ptr) {
UseCanteraCalls = true;
Temp = TP_ptr->temperature();
Pres = TP_ptr->pressure();
setState_TP(Temp, Pres);
m_VCS_UnitsFormat = VCS_UNITS_MKS;
m_phi = TP_ptr->electricPotential();
int nsp = TP_ptr->nSpecies();
if (nsp != NVolSpecies) {
if (NVolSpecies != 0) {
plogf("Warning Nsp != NVolSpeces: %d %d \n", nsp, NVolSpecies);
}
resize(VP_ID, nsp, PhaseName.c_str());
}
TP_ptr->getMoleFractions(VCS_DATA_PTR(Xmol));
_updateMoleFractionDependencies();
} else {
UseCanteraCalls = false;
}
}
// Return a const ThermoPhase pointer corresponding to this phase
/*
* @return pointer to the ThermoPhase.
*/
const Cantera::ThermoPhase *vcs_VolPhase::ptrThermoPhase() const {
return TP_ptr;
}
double vcs_VolPhase::TotalMoles() const {
return TMoles;
}
double vcs_VolPhase::molefraction(int k) const {
return Xmol[k];
}
void vcs_VolPhase::setTotalMoles(double tmols) {
TMoles = tmols;
}
// Return a string representing the equation of state
/*
* The string is no more than 16 characters.
* @param EOSType : integer value of the equation of state
*
* @return returns a string representing the EOS
*/
std::string string16_EOSType(int EOSType) {
char st[32];
st[16] = '\0';
switch (EOSType) {
case VCS_EOS_CONSTANT:
sprintf(st,"Constant ");
break;
case VCS_EOS_IDEAL_GAS:
sprintf(st,"Ideal Gas ");
break;
case VCS_EOS_STOICH_SUB:
sprintf(st,"Stoich Sub ");
break;
case VCS_EOS_IDEAL_SOLN:
sprintf(st,"Ideal Soln ");
break;
case VCS_EOS_DEBEYE_HUCKEL:
sprintf(st,"Debeye Huckel ");
break;
case VCS_EOS_REDLICK_KWONG:
sprintf(st,"Redlick_Kwong ");
break;
case VCS_EOS_REGULAR_SOLN:
sprintf(st,"Regular Soln ");
break;
default:
sprintf(st,"UnkType: %-7d", EOSType);
break;
}
st[16] = '\0';
std::string sss=st;
return sss;
}
}

View file

@ -0,0 +1,750 @@
/**
* @file vcs_VolPhase.h
* Header for the object representing each phase within vcs
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef VCS_VOLPHASE_H
#define VCS_VOLPHASE_H
#include "vcs_DoubleStarStar.h"
#include <vector>
#include <string>
/*
* Forward references
*/
// Forward reference for ThermoPhase object within the Cantera namespace
namespace Cantera {
class ThermoPhase;
}
namespace VCSnonideal {
/*
* Models for the species activity coefficients
*
*/
#define VCS_AC_CONSTANT 0
#define VCS_AC_DEBYE_HUCKEL 23
#define VCS_AC_REGULAR_SOLN 25
#define VCS_AC_MARGULES 300
#define VCS_AC_UNK_CANTERA -1
#define VCS_AC_UNK -2
/*
*
* Models for the standard state volume of each species
*/
#define VCS_SSVOL_IDEALGAS 0
#define VCS_SSVOL_CONSTANT 1
/*
* DEFINITIONS FOR THE vcs_VolPhase structure
*
*
* Equation of State Types
* - Permissible values for the EqnState variable in CPC_PHASE structure
*/
#define VCS_EOS_CONSTANT 0
#define VCS_EOS_IDEAL_GAS 1
#define VCS_EOS_STOICH_SUB 5
#define VCS_EOS_IDEAL_SOLN 22
#define VCS_EOS_DEBEYE_HUCKEL 23
#define VCS_EOS_REDLICK_KWONG 24
#define VCS_EOS_REGULAR_SOLN 25
#define VCS_EOS_UNK_CANTERA -1
struct VCS_SPECIES;
class vcs_SpeciesProperties;
//! Phase information and Phase calculations for vcs.
/*!
* Each phase in a vcs calculation has a vcs_VolPhase object associated
* with it. This object helps to coordinate property evaluations for
* species within the phase. Usually these evaluations must be carried
* out on a per phase basis. However, vcs frequently needs per species
* quantitites. Therefore, we need an interface layer between vcs
* and Cantera's ThermoPhase.
*
* The species stay in the same ordering within this structure.
* The vcs algorithm will change the ordering of species in
* the global species list. However, the indexing of species in this
* list stays the same. This structure contains structures that
* point to the species belonging to this phase in the global
* vcs species list.
*
* This object is considered not to own the underlying Cantera ThermoPhase
* object for the phase.
*
* This object contains an idea of the temperature and pressure.
* It checks to see if if the temperature and pressure has changed before calling
* underlying property evalulation routines.
*
* The object contains values for the electric potential of a phase.
* It coordinates the evalulation of properties wrt when the electric
* potential of a phase has changed.
*
* The object knows about the mole fractions of the phase. It controls
* the values of mole fractions, and coordinates the property evalulation
* wrt to changes in the mole fractions. It also will keep track of the
* likely values of mole fractions in multicomponent phases even when
* the phase doesn't actually exist within the thermo program.
*
* The object knows about the total moles of a phase. It checkes to
* see if the phase currently exists or not, and modifies its behavior
* accordingly.
*
*
* Activity coefficients and volume calculations are lagged. They are only
* called when they are needed (and when the state has changed so that they
* need to be recalculated).
*/
class vcs_VolPhase {
public:
//! Original ID of the phase in the problem.
/*!
* If a non-ideal phase splits into two due to a
* miscibility gap, these numbers will stay the
* same after the split.
*/
int VP_ID;
//! ID of the surface or volume domain in which the
//! this phase exists
/*!
* This ventures into the idea of installing a physical location
* into a thermodynamics program. This unknown is currently not
* being used.
*/
int Domain_ID;
//! If true, this phase consists of a single species
int SingleSpecies;
//! If true, this phase is a gas-phase like phase
/*!
* A RTlog(p/1atm) term is added onto the chemical potential
*/
int GasPhase;
//! If true, this phase is a liquid-phase like phase*/
int LiqPhase;
//! Type of the equation of state
/*!
* The known types are listed at the top of this file.
*/
int EqnState;
//! Number of element constraints within the problem
/*!
* This is usually equal to the number of elements.
*
*/
int nElemConstraints;
//! This is the element number for the charge neutrality condition of the phase
/*!
* If it has one. If it does not have a charge neutrality
* constraint, then this value is equal to -1
*/
int ChargeNeutralityElement;
//! vector of strings containing the element names
/*!
* Length = nElemConstraints
*/
std::vector<std::string> ElName;
//! boolean indicating whether element constraint is active
//! for the current problem
std::vector<int> ElActive;
//! Type of the element
/*!
* m_elType[j] = type of the element
* 0 VCS_ELEM_TYPE_ABSPOS Normal element that is positive
* or zero in all species.
* 1 VCS_ELEM_TPYE_ELECTRONCHARGE element dof that corresponds
* to the charge DOF.
* 2 VCS_ELEM_TYPE_OTHERCONSTRAINT Other constraint which may
* mean that a species has neg 0 or pos value
* of that constraint (other than charge)
*/
std::vector<int> m_elType;
//! Formula Matrix for the phase
/*!
* FormulaMatrix[j][kspec]
* = Formula Matrix for the species
* Number of elements, j,
* in the kspec species
*/
DoubleStarStar FormulaMatrix;
//! Type of the species unknown
/*!
* SpeciesUnknownType[k] = type of species
* Normal -> VCS_SPECIES_TYPE_MOLUNK
* ( unknown is the mole number in the phase)
* metal electron -> VCS_SPECIES_INTERFACIALVOLTAGE
* ( unknown is the interfacial voltage (volts)
*/
std::vector<int> SpeciesUnknownType;
//! Index of the element number in the global list of elements
//! storred in VCS_PROB or VCS_SOLVE
std::vector<int> ElGlobalIndex;
//! Number of species in the phase
int NVolSpecies;
//! String name for the phase
std::string PhaseName;
//! Total moles of inert in the phase
double TMolesInert;
//! Convention for the activity formulation
/*!
* 0 = molar based activities (default)
* 1 = Molality based activities
* mu = mu_0 + ln a_molality
* standard state is based on unity molality
*/
int ActivityConvention;
//! Current state of existence:
/*!
* 0 : Doesn't exist currently
* 1 : Does exist currently
* 2 : Always exists because it contains
* inerts which can't exist in any other
* phase
*/
int Existence;
//! Index of the species which is special in
//! with respect to the thermo treatment.
/*!
* For water models this index will point to
* the index for water.
* defaults to 0
*/
int IndexSpecialSpecies;
//! Integer representing the activity coefficient model
/*!
* The known models are listed at the top of this page
*/
int Activity_Coeff_Model;
//! General pointer for hanging stuff off of
/*!
* Currently, not implemented very well
*/
void *Activity_Coeff_Params;
//! Index into the species vectors
/*!
* Maps the phase species number into the global species number.
* Note, as part of the vcs algorithm, the order of the species
* vector is changed during the algorithm
*/
std::vector<int> IndSpecies;
//! Boolean indicating whether IndSpecies is contiguous
bool IndSpeciesContig;
//! Vector of Species structures for the species belonging to this phase
/*!
* The index into this vector is the species index within the phase.
*/
std::vector<vcs_SpeciesProperties *> ListSpeciesPtr;
//! If this is true, then calculations are actually performed within
//! Cantera
bool UseCanteraCalls;
//! Units for the chemical potential data, pressure data, volume,
//! and species amounts
/*!
* All internally storred quantities will have these units. Also, printed
* quantitities will display in these units. Input quantities are expected
* in these units.
*
* Chem_Pot Pres vol moles
* ----------------------------------------------------------------------
* -1 VCS_UNITS_KCALMOL = kcal/mol atm cm**3 gmol
* 0 VCS_UNITS_UNITLESS = MU / RT -> no units atm cm**3 gmol
* 1 VCS_UNITS_KJMOL = kJ / mol atm cm**3 gmol
* 2 VCS_UNITS_KELVIN = KELVIN -> MU / R atm cm**3 gmol
* 3 VCS_UNITS_MKS = Joules / Kmol (Cantera) Pa m**3 kmol
* ----------------------------------------------------------------------
*
* see vcs_defs.h for more information.
*
* Currently, this value should be the same as the owning VCS_PROB or
* VCS_SOLVE object. There is no code for handling anything else atm.
*/
int m_VCS_UnitsFormat;
private:
/**
* If we are using Cantera, this is the
* pointer to the ThermoPhase object. If not, this is null.
*/
Cantera::ThermoPhase * TP_ptr;
/**
* Variables Having to do with Calculated States
*/
//! Total mols in the phase
/*!
* units vary
*/
double TMoles;
//! Vector of the current mole fractions for species
//! in the phase
std::vector<double> Xmol;
public:
//! If the potential is a solution variable in VCS, it acts as a species.
//! This is the species index in the phase for the potential
int m_phiVarIndex;
//! Total Volume of the phase
/*!
* units are m**3
*/
mutable double Vol;
//! Vector of calculated SS0 chemical potentials for the
//! current Temperature.
/*!
* Note, This is the chemical potential derived strictly from the polynomial
* in temperature. Pressure effects have to be added in to
* get to the standard state.
*
* Units -> depends on VCS_UnitsFormat variable
* Cantera -> J/kmol
*/
mutable std::vector<double> SS0ChemicalPotential;
//! Vector of calculated Star chemical potentials for the
//! current Temperature and pressure.
/*!
* Note, This is the chemical potential at unit activity. Thus, we can call
* it the standard state chemical potential as well.
*
* Units -> depends on VCS_UnitsFormat variable
* Cantera -> J/kmol
*/
mutable std::vector<double> StarChemicalPotential;
//! Vector of the Star molar Volumes of the species.
/*!
* units depends on VCS_UnitsFormat variable
* Cantera -> m3 / kmol
*/
mutable std::vector<double> StarMolarVol;
//! Vector of the Partial molar Volumes of the species.
/*!
* units depends on VCS_UnitsFormat variable
* Cantera -> m3 / kmol
*/
mutable std::vector<double> PartialMolarVol;
/**
* Vector of calculated activity coefficients for the current
* state.
*/
mutable std::vector<double> ActCoeff;
//! Vector of the derivatives of the ln activity coefficient wrt to the
//! current mole number
/*!
* dLnActCoeffdMolNumber[j][k];
* j = id of the species mole number
* k = id of the species activity coefficient
*/
mutable DoubleStarStar dLnActCoeffdMolNumber;
private:
//! Value of the potential for the phase (Volts)
double m_phi;
//! Boolean indicating whether activity coefficients are uptodate.
/*!
* Activity coefficients and volume calculations are lagged. They are only
* called when they are needed (and when the state has changed so that they
* need to be recalculated).
*/
mutable bool m_UpToDate_AC;
//! Boolean indicating whether Star volumes are uptodate.
/*!
* Activity coefficients and volume calculations are lagged. They are only
* called when they are needed (and when the state has changed so that they
* need to be recalculated).
* Star volumes are sensitive to temperature and pressure
*/
mutable bool m_UpToDate_VolStar;
//! Boolean indicating whether partial molar volumes are uptodate.
/*!
* Activity coefficients and volume calculations are lagged. They are only
* called when they are needed (and when the state has changed so that they
* need to be recalculated).
* partial molar volumes are sensitive to everything
*/
mutable bool m_UpToDate_VolPM;
//! Boolean indicating whether GStar is uptodate.
/*!
* GStar is sensitive to the temperature and the pressure, only
*/
mutable bool m_UpToDate_GStar;
//! Current value of the temperature for this object, and underlying objects
double Temp;
//! Current value of the pressure for this object, and underlying objects
double Pres;
public:
//! Reference pressure for the phase
double RefPres;
/*************************************************************************
* FUNCTIONS *
************************************************************************/
//! Base constructor for the class
vcs_VolPhase();
//! Copy constructor
/*!
* @param b object to be copied
*/
vcs_VolPhase(const vcs_VolPhase& b);
//! Assignment operator
/*!
* @param b object to be copied
*/
vcs_VolPhase& operator=(const vcs_VolPhase& b);
//! Destructor
~vcs_VolPhase();
/**
* The resize() function fills in all of the initial information if it
* is not given in the constructor.
*/
void resize(int phaseNum, int numSpecies, const char *phaseName,
double molesInert = 0.0);
//! Evaluate activity coefficients
/*!
* We carry out a calculation whenever UpTODate_AC is false. Specifically
* whenever a phase goes zero, we do not carry out calculations on it.
*/
void evaluateActCoeff() const;
//! Evaluate activity coefficients and return the kspec coefficient
/*!
* We carry out a calculation whenever UpTODate_AC is false. Specifically
* whenever a phase goes zero, we do not carry out calculations on it.
*
* @param kspec species number
*/
double AC_calc_one(int kspec) const;
//! Set the moles within the phase
/*!
* This function takes as input the mole numbers in vcs format, and
* then updates this object with their values. This is essentially
* a gather routine.
*
* @param molesSpeciesVCS array of mole numbers. Note, the indecises for species in
* this array may not be contiguous. IndSpecies[] is needed
* to gather the species into the local contiguous vector
* format.
*/
void setMolesFromVCS(const double * const molesSpeciesVCS);
//! Set the moles within the phase
/*!
* This function takes as input the mole numbers in vcs format, and
* then updates this object with their values. This is essentially
* a gather routine.
* Additionally it checks to see that the total moles value in
* TPhMoles[iplace] is equal to the internally computed value.
* If this isn't the case, an error exit is carried out.
*
*
* @param molesSpeciesVCS array of mole numbers. Note, the indecises
* for species in
* this array may not be contiguous. IndSpecies[] is needed
* to gather the species into the local contiguous vector
* format.
* @param TPhMoles VCS's array containing the number of moles
* in each phase.
* @param iphase index of the current phase.
*
*/
void setMolesFromVCSCheck(const double * const molesSpeciesVCS,
const double * const TPhMoles,
int iphase = -1);
//! Fill in an activity coefficients vector for VCS
/*!
* This routine will calculate the activity coefficients for the
* current phase, and fill in the corresponding entries in the
* VCS activity coefficients vector.
*
* @param AC vector of activity coefficients for all of the species
* in all of the phases in a VCS problem. Only the
* entries for the current phase are filled in.
*/
void sendToVCSActCoeff(double * const AC) const;
//! set the electric potential of the phase
/*!
* @param phi electric potential (volts)
*/
void setElectricPotential(double phi);
//! Returns the electric field of the phase
/*!
* Units are potential
*/
double electricPotential() const;
//! Gibbs free energy calculation for standard states
/*!
* Calculate the Gibbs free energies for the standard states
* The results are held internally within the object.
*
* @param TKelvin Current temperature
* @param pres Current pressure
*/
void GStar_calc(double TKelvin, double pres);
//! Gibbs free energy calculation for standard state of one species
/*!
* Calculate the Gibbs free energies for the standard state
* of the kth species.
* The results are held internally within the object.
* The kth species standard state G is returned
*
* @param kspec Species number (within the phase)
* @param TKelvin Current temperature
* @param pres Current pressure
*
* @return Gstar[kspec] returns the gibbs free energy for the
* standard state of the kth species.
*/
double GStar_calc_one(int kspec, double TKelvin, double pres);
//! Gibbs free energy calculation at a temperature for the reference state
//! of each species
/*!
* @param TKelvin temperature
*/
void G0_calc(double TKelvin);
//! Gibbs free energy calculation at a temperature for the reference state
//! of a species, return a value for one species
/*!
* @param kspec species index
* @param TKelvin temperature
*
* @return return value of the gibbs free energy
*/
double G0_calc_one(int kspec, double TKelvin);
//! Molar volume calculation for standard states
/*!
* Calculate the molar volume for the standard states
* The results are held internally within the object.
*
* @param TKelvin Current temperature
* @param pres Current pressure
*/
void VolStar_calc(double TKelvin, double pres);
//! Molar volume calculation for standard state of one species
/*!
* Calculate the molar volume for the standard states
* The results are held internally within the object.
* Return the molar volume for one species
*
* @param kspec Species number (within the phase)
* @param TKelvin Current temperature
* @param pres Current pressure
*
* @return molar volume of the kspec species's standard
* state
*/
double VolStar_calc_one(int kglob, double TKelvin, double pres);
//! Calculate the partial molar volumes of all species and return the
//! total volume
/*!
* Calculates these quantitites internally
*
* @return total volume
*/
double VolPM_calc() const;
//! Fill in the partial molar volume vector for VCS
/*!
* This routine will calculate the partial molar volumes for the
* current phase (if needed), and fill in the corresponding entries in the
* VCS partial molar volumes vector.
*
* @param VolPM vector of partial molar volumes for all of the species
* in all of the phases in a VCS problem. Only the
* entries for the current phase are filled in.
*/
double sendToVCSVolPM(double * const VolPM) const;
//! Fill in the partial molar volume vector for VCS
/*!
* This routine will calculate the partial molar volumes for the
* current phase (if needed), and fill in the corresponding entries in the
* VCS partial molar volumes vector.
*
* @param VolPM vector of partial molar volumes for all of the species
* in all of the phases in a VCS problem. Only the
* entries for the current phase are filled in.
*/
void sendToVCSGStar(double * const gstar);
//! Sets the temperature and pressure in this object and
//! underlying objects
/*!
* Sets the temperature and pressure in this object and
* underlying objects. The underlying objects refers to the
* Cantera's ThermoPhase object for this phase.
*
* @param temperature_Kelvin (Kelvin)
* @param pressure_PA Pressure (MKS units - Pascal)
*/
void setState_TP(double temperature_Kelvin, double pressure_PA);
//! Evaluation of Activity Coefficient Jacobians
/*!
* This is the derivative of the ln of the activity coefficient
* with respect to mole number of jth species.
* (temp, pressure, and other mole numbers held constant
*
* @param moleNumbers Mole numbers are input.
*/
void updateLnActCoeffJac(const double * const moleNumbers);
// Downloads the ln ActCoeff jacobian into the VCS version of the
// ln ActCoeff jacobian.
/*
*
* This is essentially a scatter operation.
*
* @param LnAcJac_VCS jacobian parameter
* The Jacobians are actually d( lnActCoeff) / d (MolNumber);
* dLnActCoeffdMolNumber[j][k]
*
* j = id of the species mole number
* k = id of the species activity coefficient
*/
void sendToVCSLnActCoeffJac(double * const * const LnACJac_VCS) const;
//! Set the pointer for Cantera's ThermoPhase parameter
/*!
* When we first initialize the ThermoPhase object, we read the
* state of the ThermoPhase into vcs_VolPhase object.
*
* @param tp_ptr Pointer to the ThermoPhase object corresponding
* to this phase.
*/
void setPtrThermoPhase(Cantera::ThermoPhase *tp_ptr);
//! Return a const ThermoPhase pointer corresponding to this phase
/*!
* @return pointer to the ThermoPhase.
*/
const Cantera::ThermoPhase *ptrThermoPhase() const;
//! Return the total moles in the phase
/*!
*
* Units -> depends on VCS_UnitsFormat variable
* Cantera -> J/kmol
*/
double TotalMoles() const;
//! Returns the mole fraction of the kspec species
/*!
* Returns the mole fraction of the kspec species
*
*/
double molefraction(int kspec) const;
//! Sets the total moles in the phase
/*!
*
*/
void setTotalMoles(double tmols);
//! Set the mole fractions from a conventional mole fraction vector
/*!
*
* @param xmol Value of the mole fractions for the species
* in the phase. These are contiguous.
*/
void setMoleFractions (const double * const xmol);
//! Return a const reference to the mole fractions
const std::vector<double> & moleFractions() const;
private:
//! Updates the mole fractions in subobjects
/*!
* Whenever the mole fractions change, this routine
* should be called.
*/
void _updateMoleFractionDependencies();
};
//! Return a string representing the equation of state
/*!
* @param EOSType : integer value of the equation of state
*
* @return returns a string representing the EOS
*/
std::string string16_EOSType(int EOSType);
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,957 @@
/* dbols.f -- translated by f2c (version 20031025).
You must link the resulting object file with libf2c:
on Microsoft Windows system, link with libf2c.lib;
on Linux or Unix systems, link with .../path/to/libf2c.a -lm
or, if you install libf2c.a in a standard place, with -lf2c -lm
-- in that order, at the end of the command line, as in
cc *.o -lf2c -lm
Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
http://www.netlib.org/f2c/libf2c.zip
*/
#include "f2c.h"
/* Table of constant values */
static integer c__1 = 1;
static integer c__0 = 0;
static integer c__2 = 2;
/* DECK DBOLS */
/* Subroutine */ int dbols_(doublereal *w, integer *mdw, integer *mrows,
integer *ncols, doublereal *bl, doublereal *bu, integer *ind, integer
*iopt, doublereal *x, doublereal *rnorm, integer *mode, doublereal *
rw, integer *iw)
{
/* Initialized data */
static integer igo = 0;
/* System generated locals */
integer w_dim1, w_offset, i__1, i__2, i__3;
doublereal d__1;
/* Local variables */
static integer i__, j;
static doublereal sc;
static integer ip, jp, lp;
static doublereal ss;
static integer llb;
static doublereal one;
static integer lds, llx, ibig, idum, lmdw, lndw, nerr;
static real rdum;
static integer lenx, lliw, mnew;
extern /* Subroutine */ int drot_(integer *, doublereal *, integer *,
doublereal *, integer *, doublereal *, doublereal *);
static integer lopt;
static doublereal zero;
static integer llrw;
extern doublereal dnrm2_(integer *, doublereal *, integer *);
static real rdum2;
static integer nchar, level;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *), drotg_(doublereal *, doublereal *,
doublereal *, doublereal *);
static integer liopt, locacc;
static logical checkl;
static integer iscale;
extern integer idamax_(integer *, doublereal *, integer *);
static integer locdim;
extern /* Subroutine */ int dbolsm_(doublereal *, integer *, integer *,
integer *, doublereal *, doublereal *, integer *, integer *,
doublereal *, doublereal *, integer *, doublereal *, doublereal *,
doublereal *, integer *, integer *);
static integer inrows;
extern /* Subroutine */ int xerrwv_(char *, integer *, integer *, integer
*, integer *, integer *, integer *, integer *, real *, real *,
ftnlen);
/* ***BEGIN PROLOGUE DBOLS */
/* ***DATE WRITTEN 821220 (YYMMDD) */
/* ***REVISION DATE 861211 (YYMMDD) */
/* ***CATEGORY NO. K1A2A,G2E,G2H1,G2H2 */
/* ***KEYWORDS LIBRARY=SLATEC,TYPE=DOUBLE PRECISION(SBOLS-S DBOLS-D), */
/* BOUNDS,CONSTRAINTS,INEQUALITY,LEAST SQUARES,LINEAR */
/* ***AUTHOR HANSON, R. J., SNLA */
/* ***PURPOSE Solve the problem */
/* E*X = F (in the least squares sense) */
/* with bounds on selected X values. */
/* ***DESCRIPTION */
/* **** Double Precision Version of SBOLS **** */
/* **** All INPUT and OUTPUT real variables are DOUBLE PRECISION **** */
/* The user must have dimension statements of the form: */
/* DIMENSION W(MDW,NCOLS+1), BL(NCOLS), BU(NCOLS), */
/* * X(NCOLS+NX), RW(5*NCOLS) */
/* INTEGER IND(NCOLS), IOPT(1+NI), IW(2*NCOLS) */
/* (here NX=number of extra locations required for option 4; NX=0 */
/* for no options; NX=NCOLS if this option is in use. Here NI=number */
/* of extra locations required for options 1-6; NI=0 for no */
/* options.) */
/* INPUT */
/* ----- */
/* -------------------- */
/* W(MDW,*),MROWS,NCOLS */
/* -------------------- */
/* The array W(*,*) contains the matrix [E:F] on entry. The matrix */
/* [E:F] has MROWS rows and NCOLS+1 columns. This data is placed in */
/* the array W(*,*) with E occupying the first NCOLS columns and the */
/* right side vector F in column NCOLS+1. The row dimension, MDW, of */
/* the array W(*,*) must satisfy the inequality MDW .ge. MROWS. */
/* Other values of MDW are errrors. The values of MROWS and NCOLS */
/* must be positive. Other values are errors. There is an exception */
/* to this when using option 1 for accumulation of blocks of */
/* equations. In that case MROWS is an OUTPUT variable ONLY, and the */
/* matrix data for [E:F] is placed in W(*,*), one block of rows at a */
/* time. MROWS contains the number of rows in the matrix after */
/* triangularizing several blocks of equations. This is an OUTPUT */
/* parameter ONLY when option 1 is used. See IOPT(*) CONTENTS */
/* for details about option 1. */
/* ------------------ */
/* BL(*),BU(*),IND(*) */
/* ------------------ */
/* These arrays contain the information about the bounds that the */
/* solution values are to satisfy. The value of IND(J) tells the */
/* type of bound and BL(J) and BU(J) give the explicit values for */
/* the respective upper and lower bounds. */
/* 1. For IND(J)=1, require X(J) .ge. BL(J). */
/* (the value of BU(J) is not used.) */
/* 2. For IND(J)=2, require X(J) .le. BU(J). */
/* (the value of BL(J) is not used.) */
/* 3. For IND(J)=3, require X(J) .ge. BL(J) and */
/* X(J) .le. BU(J). */
/* 4. For IND(J)=4, no bounds on X(J) are required. */
/* (the values of BL(J) and BU(J) are not used.) */
/* Values other than 1,2,3 or 4 for IND(J) are errors. In the case */
/* IND(J)=3 (upper and lower bounds) the condition BL(J) .gt. BU(J) */
/* is an error. */
/* ------- */
/* IOPT(*) */
/* ------- */
/* This is the array where the user can specify nonstandard options */
/* for DBOLSM( ). Most of the time this feature can be ignored by */
/* setting the input value IOPT(1)=99. Occasionally users may have */
/* needs that require use of the following subprogram options. For */
/* details about how to use the options see below: IOPT(*) CONTENTS. */
/* Option Number Brief Statement of Purpose */
/* ------ ------ ----- --------- -- ------- */
/* 1 Return to user for accumulation of blocks */
/* of least squares equations. */
/* 2 Check lengths of all arrays used in the */
/* subprogram. */
/* 3 Standard scaling of the data matrix, E. */
/* 4 User provides column scaling for matrix E. */
/* 5 Provide option array to the low-level */
/* subprogram DBOLSM( ). */
/* 6 Move the IOPT(*) processing pointer. */
/* 99 No more options to change. */
/* ---- */
/* X(*) */
/* ---- */
/* This array is used to pass data associated with option 4. Ignore */
/* this parameter if this option is not used. Otherwise see below: */
/* IOPT(*) CONTENTS. */
/* OUTPUT */
/* ------ */
/* ---------- */
/* X(*),RNORM */
/* ---------- */
/* The array X(*) contains a solution (if MODE .ge.0 or .eq.-22) for */
/* the constrained least squares problem. The value RNORM is the */
/* minimum residual vector length. */
/* ---- */
/* MODE */
/* ---- */
/* The sign of MODE determines whether the subprogram has completed */
/* normally, or encountered an error condition or abnormal status. A */
/* value of MODE .ge. 0 signifies that the subprogram has completed */
/* normally. The value of MODE (.GE. 0) is the number of variables */
/* in an active status: not at a bound nor at the value ZERO, for */
/* the case of free variables. A negative value of MODE will be one */
/* of the cases -37,-36,...,-22, or -17,...,-2. Values .lt. -1 */
/* correspond to an abnormal completion of the subprogram. To */
/* understand the abnormal completion codes see below: ERROR */
/* MESSAGES for DBOLS( ). AN approximate solution will be returned */
/* to the user only when max. iterations is reached, MODE=-22. */
/* Values for MODE=-37,...,-22 come from the low-level subprogram */
/* DBOLSM(). See the section ERROR MESSAGES for DBOLSM() in the */
/* documentation for DBOLSM(). */
/* ----------- */
/* RW(*),IW(*) */
/* ----------- */
/* These are working arrays with 5*NCOLS and 2*NCOLS entries. */
/* (normally the user can ignore the contents of these arrays, */
/* but they must be dimensioned properly.) */
/* IOPT(*) CONTENTS */
/* ------- -------- */
/* The option array allows a user to modify internal variables in */
/* the subprogram without recompiling the source code. A central */
/* goal of the initial software design was to do a good job for most */
/* people. Thus the use of options will be restricted to a select */
/* group of users. The processing of the option array proceeds as */
/* follows: a pointer, here called LP, is initially set to the value */
/* 1. This value is updated as each option is processed. At the */
/* pointer position the option number is extracted and used for */
/* locating other information that allows for options to be changed. */
/* The portion of the array IOPT(*) that is used for each option is */
/* fixed; the user and the subprogram both know how many locations */
/* are needed for each option. A great deal of error checking is */
/* done by the subprogram on the contents of the option array. */
/* Nevertheless it is still possible to give the subprogram optional */
/* input that is meaningless. For example option 4 uses the */
/* locations X(NCOLS+IOFF),...,X(NCOLS+IOFF+NCOLS-1) for passing */
/* scaling data. The user must manage the allocation of these */
/* locations. */
/* 1 */
/* - */
/* This option allows the user to solve problems with a large number */
/* of rows compared to the number of variables. The idea is that the */
/* subprogram returns to the user (perhaps many times) and receives */
/* new least squares equations from the calling program unit. */
/* Eventually the user signals "that's all" and then computes the */
/* solution with one final call to subprogram DBOLS( ). The value of */
/* MROWS is an OUTPUT variable when this option is used. Its value */
/* is always in the range 0 .le. MROWS .le. NCOLS+1. It is equal to */
/* the number of rows after the triangularization of the entire set */
/* of equations. If LP is the processing pointer for IOPT(*), the */
/* usage for the sequential processing of blocks of equations is */
/* IOPT(LP)=1 */
/* Move block of equations to W(*,*) starting at */
/* the first row of W(*,*). */
/* IOPT(LP+3)=# of rows in the block; user defined */
/* The user now calls DBOLS( ) in a loop. The value of IOPT(LP+1) */
/* directs the user's action. The value of IOPT(LP+2) points to */
/* where the subsequent rows are to be placed in W(*,*). */
/* .<LOOP */
/* . CALL DBOLS() */
/* . IF(IOPT(LP+1) .EQ. 1) THEN */
/* . IOPT(LP+3)=# OF ROWS IN THE NEW BLOCK; USER DEFINED */
/* . PLACE NEW BLOCK OF IOPT(LP+3) ROWS IN */
/* . W(*,*) STARTING AT ROW IOPT(LP+2). */
/* . */
/* . IF( THIS IS THE LAST BLOCK OF EQUATIONS ) THEN */
/* . IOPT(LP+1)=2 */
/* .<------CYCLE LOOP */
/* . ELSE IF (IOPT(LP+1) .EQ. 2) THEN */
/* <-------EXIT LOOP SOLUTION COMPUTED IF MODE .GE. 0 */
/* . ELSE */
/* . ERROR CONDITION; SHOULD NOT HAPPEN. */
/* .<END LOOP */
/* Use of this option adds 4 to the required length of IOPT(*). */
/* 2 */
/* - */
/* This option is useful for checking the lengths of all arrays used */
/* by DBOLS() against their actual requirements for this problem. */
/* The idea is simple: the user's program unit passes the declared */
/* dimension information of the arrays. These values are compared */
/* against the problem-dependent needs within the subprogram. If any */
/* of the dimensions are too small an error message is printed and a */
/* negative value of MODE is returned, -11 to -17. The printed error */
/* message tells how long the dimension should be. If LP is the */
/* processing pointer for IOPT(*), */
/* IOPT(LP)=2 */
/* IOPT(LP+1)=Row dimension of W(*,*) */
/* IOPT(LP+2)=Col. dimension of W(*,*) */
/* IOPT(LP+3)=Dimensions of BL(*),BU(*),IND(*) */
/* IOPT(LP+4)=Dimension of X(*) */
/* IOPT(LP+5)=Dimension of RW(*) */
/* IOPT(LP+6)=Dimension of IW(*) */
/* IOPT(LP+7)=Dimension of IOPT(*) */
/* . */
/* CALL DBOLS() */
/* Use of this option adds 8 to the required length of IOPT(*). */
/* 3 */
/* - */
/* This option changes the type of scaling for the data matrix E. */
/* Nominally each nonzero column of E is scaled so that the */
/* magnitude of its largest entry is equal to the value ONE. If LP */
/* is the processing pointer for IOPT(*), */
/* IOPT(LP)=3 */
/* IOPT(LP+1)=1,2 or 3 */
/* 1= Nominal scaling as noted; */
/* 2= Each nonzero column scaled to have length ONE; */
/* 3= Identity scaling; scaling effectively suppressed. */
/* . */
/* CALL DBOLS() */
/* Use of this option adds 2 to the required length of IOPT(*). */
/* 4 */
/* - */
/* This option allows the user to provide arbitrary (positive) */
/* column scaling for the matrix E. If LP is the processing pointer */
/* for IOPT(*), */
/* IOPT(LP)=4 */
/* IOPT(LP+1)=IOFF */
/* X(NCOLS+IOFF),...,X(NCOLS+IOFF+NCOLS-1) */
/* = Positive scale factors for cols. of E. */
/* . */
/* CALL DBOLS() */
/* Use of this option adds 2 to the required length of IOPT(*) and */
/* NCOLS to the required length of X(*). */
/* 5 */
/* - */
/* This option allows the user to provide an option array to the */
/* low-level subprogram DBOLSM(). If LP is the processing pointer */
/* for IOPT(*), */
/* IOPT(LP)=5 */
/* IOPT(LP+1)= Position in IOPT(*) where option array */
/* data for DBOLSM() begins. */
/* . */
/* CALL DBOLS() */
/* Use of this option adds 2 to the required length of IOPT(*). */
/* 6 */
/* - */
/* Move the processing pointer (either forward or backward) to the */
/* location IOPT(LP+1). The processing point is moved to entry */
/* LP+2 of IOPT(*) if the option is left with -6 in IOPT(LP). For */
/* example to skip over locations 3,...,NCOLS+2 of IOPT(*), */
/* IOPT(1)=6 */
/* IOPT(2)=NCOLS+3 */
/* (IOPT(I), I=3,...,NCOLS+2 are not defined here.) */
/* IOPT(NCOLS+3)=99 */
/* CALL DBOLS() */
/* CAUTION: Misuse of this option can yield some very hard */
/* -to-find bugs. Use it with care. */
/* 99 */
/* -- */
/* There are no more options to change. */
/* Only option numbers -99, -6,-5,...,-1, 1,2,...,6, and 99 are */
/* permitted. Other values are errors. Options -99,-1,...,-6 mean */
/* that the repective options 99,1,...,6 are left at their default */
/* values. An example is the option to modify the (rank) tolerance: */
/* IOPT(1)=-3 Option is recognized but not changed */
/* IOPT(2)=2 Scale nonzero cols. to have length ONE */
/* IOPT(3)=99 */
/* ERROR MESSAGES for DBOLS() */
/* ----- -------- --- ------- */
/* WARNING IN... */
/* DBOLS(). MDW=(I1) MUST BE POSITIVE. */
/* IN ABOVE MESSAGE, I1= 0 */
/* ERROR NUMBER = 2 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). NCOLS=(I1) THE NO. OF VARIABLES MUST BE POSITIVE. */
/* IN ABOVE MESSAGE, I1= 0 */
/* ERROR NUMBER = 3 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). FOR J=(I1), IND(J)=(I2) MUST BE 1-4. */
/* IN ABOVE MESSAGE, I1= 1 */
/* IN ABOVE MESSAGE, I2= 0 */
/* ERROR NUMBER = 4 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). FOR J=(I1), BOUND BL(J)=(R1) IS .GT. BU(J)=(R2). */
/* IN ABOVE MESSAGE, I1= 1 */
/* IN ABOVE MESSAGE, R1= 0. */
/* IN ABOVE MESSAGE, R2= ABOVE MESSAGE, I1= 0 */
/* ERROR NUMBER = 6 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). ISCALE OPTION=(I1) MUST BE 1-3. */
/* IN ABOVE MESSAGE, I1= 0 */
/* ERROR NUMBER = 7 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). OFFSET PAST X(NCOLS) (I1) FOR USER-PROVIDED COLUMN SCALING */
/* MUST BE POSITIVE. */
/* IN ABOVE MESSAGE, I1= 0 */
/* ERROR NUMBER = 8 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). EACH PROVIDED COL. SCALE FACTOR MUST BE POSITIVE. */
/* COMPONENT (I1) NOW = (R1). */
/* IN ABOVE MESSAGE, I1= ND. .LE. MDW=(I2). */
/* IN ABOVE MESSAGE, I1= 1 */
/* IN ABOVE MESSAGE, I2= 0 */
/* ERROR NUMBER = 10 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS().THE ROW DIMENSION OF W(,)=(I1) MUST BE .GE.THE NUMBER OF ROWS= */
/* (I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 1 */
/* ERROR NUMBER = 11 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). THE COLUMN DIMENSION OF W(,)=(I1) MUST BE .GE. NCOLS+1=(I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 2 */
/* ERROR NUMBER = 12 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS().THE DIMENSIONS OF THE ARRAYS BL(),BU(), AND IND()=(I1) MUST BE */
/* .GE. NCOLS=(I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 1 */
/* ERROR NUMBER = 13 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). THE DIMENSION OF X()=(I1) MUST BE .GE. THE REQD. LENGTH=(I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 2 */
/* ERROR NUMBER = 14 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS(). THE DIMENSION OF RW()=(I1) MUST BE .GE. 5*NCOLS=(I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 3 */
/* ERROR NUMBER = 15 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS() THE DIMENSION OF IW()=(I1) MUST BE .GE. 2*NCOLS=(I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 2 */
/* ERROR NUMBER = 16 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* WARNING IN... */
/* DBOLS() THE DIMENSION OF IOPT()=(I1) MUST BE .GE. THE REQD. LEN.=(I2). */
/* IN ABOVE MESSAGE, I1= 0 */
/* IN ABOVE MESSAGE, I2= 1 */
/* ERROR NUMBER = 17 */
/* (NORMALLY A RETURN TO THE USER TAKES PLACE FOLLOWING THIS MESSAGE.) */
/* ***REFERENCES HANSON, R. J. LINEAR LEAST SQUARES WITH BOUNDS AND */
/* LINEAR CONSTRAINTS, SNLA REPT. SAND82-1517, AUG.,1982 */
/* ***ROUTINES CALLED DBOLSM,DCOPY,DNRM2,DROT,DROTG,IDAMAX,XERRWV */
/* ***END PROLOGUE DBOLS */
/* SOLVE LINEAR LEAST SQUARES SYSTEM WITH BOUNDS ON */
/* SELECTED VARIABLES. */
/* REVISED 850329-1400 */
/* REVISED YYMMDD-HHMM */
/* TO CHANGE THIS SUBPROGRAM FROM SINGLE TO DOUBLE PRECISION BEGIN */
/* EDITING AT THE CARD 'C++'. */
/* CHANGE THIS SUBPROGRAM NAME TO DBOLS AND THE STRINGS */
/* /SCOPY/ TO /DCOPY/, /SBOL/ TO /DBOL/, */
/* /SNRM2/ TO /DNRM2/, /ISAMAX/ TO /IDAMAX/, */
/* /SROTG/ TO /DROTG/, /SROT/ TO /DROT/, /E0/ TO /D0/, */
/* /REAL / TO /DOUBLE PRECISION/. */
/* ++ */
/* THIS VARIABLE SHOULD REMAIN TYPE REAL. */
/* Parameter adjustments */
w_dim1 = *mdw;
w_offset = 1 + w_dim1;
w -= w_offset;
--bl;
--bu;
--ind;
--iopt;
--x;
--rw;
--iw;
/* Function Body */
/* ***FIRST EXECUTABLE STATEMENT DBOLS */
level = 1;
nerr = 0;
*mode = 0;
if (igo == 0) {
/* DO(CHECK VALIDITY OF INPUT DATA) */
/* PROCEDURE(CHECK VALIDITY OF INPUT DATA) */
/* SEE THAT MDW IS .GT.0. GROSS CHECK ONLY. */
if (*mdw <= 0) {
nerr = 2;
nchar = 35;
xerrwv_("DBOLS(). MDW=(I1) MUST BE POSITIVE.", &nchar, &nerr, &
level, &c__1, mdw, &idum, &c__0, &rdum, &rdum, (ftnlen)35)
;
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
/* SEE THAT NUMBER OF UNKNOWNS IS POSITIVE. */
if (*ncols <= 0) {
nerr = 3;
nchar = 58;
xerrwv_("DBOLS(). NCOLS=(I1) THE NO. OF VARIABLES MUST BE POSITI"
"VE.", &nchar, &nerr, &level, &c__1, ncols, &idum, &c__0, &
rdum, &rdum, (ftnlen)58);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
/* SEE THAT CONSTRAINT INDICATORS ARE ALL WELL-DEFINED. */
i__1 = *ncols;
for (j = 1; j <= i__1; ++j) {
if (ind[j] < 1 || ind[j] > 4) {
nerr = 4;
nchar = 45;
xerrwv_("DBOLS(). FOR J=(I1), IND(J)=(I2) MUST BE 1-4.", &
nchar, &nerr, &level, &c__2, &j, &ind[j], &c__0, &
rdum, &rdum, (ftnlen)45);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
/* L10: */
}
/* SEE THAT BOUNDS ARE CONSISTENT. */
i__1 = *ncols;
for (j = 1; j <= i__1; ++j) {
if (ind[j] == 3) {
if (bl[j] > bu[j]) {
nerr = 5;
nchar = 57;
rdum2 = bl[j];
rdum = bu[j];
xerrwv_("DBOLS(). FOR J=(I1), BOUND BL(J)=(R1) IS .GT. B"
"U(J)=(R2).", &nchar, &nerr, &level, &c__1, &j, &
idum, &c__2, &rdum2, &rdum, (ftnlen)57);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
}
/* L20: */
}
/* END PROCEDURE */
/* DO(PROCESS OPTION ARRAY) */
/* PROCEDURE(PROCESS OPTION ARRAY) */
zero = 0.;
one = 1.;
checkl = FALSE_;
lenx = *ncols;
iscale = 1;
igo = 2;
lopt = 0;
lp = 0;
lds = 0;
L30:
lp += lds;
ip = iopt[lp + 1];
jp = abs(ip);
/* TEST FOR NO MORE OPTIONS. */
if (ip == 99) {
if (lopt == 0) {
lopt = lp + 1;
}
goto L50;
} else if (jp == 99) {
lds = 1;
goto L30;
} else if (jp == 1) {
if (ip > 0) {
/* SET UP DIRECTION FLAG, ROW STACKING POINTER */
/* LOCATION, AND LOCATION FOR NUMBER OF NEW ROWS. */
locacc = lp + 2;
/* IOPT(LOCACC-1)=OPTION NUMBER FOR SEQ. ACCUMULATION. */
/* CONTENTS.. IOPT(LOCACC )=USER DIRECTION FLAG, 1 OR 2. */
/* IOPT(LOCACC+1)=ROW STACKING POINTER. */
/* IOPT(LOCACC+2)=NUMBER OF NEW ROWS TO PROCESS. */
/* USER ACTION WITH THIS OPTION.. */
/* (SET UP OPTION DATA FOR SEQ. ACCUMULATION IN IOPT(*). */
/* MUST ALSO START PROCESS WITH IOPT(LOCACC)=1.) */
/* (MOVE BLOCK OF EQUATIONS INTO W(*,*) STARTING AT FIRST */
/* ROW OF W(*,*). SET IOPT(LOCACC+2)=NO. OF ROWS IN BLOCK.) */
/* LOOP */
/* CALL DBOLS() */
/* IF(IOPT(LOCACC) .EQ. 1) THEN */
/* STACK EQUAS., STARTING AT ROW IOPT(LOCACC+1), */
/* INTO W(*,*). */
/* SET IOPT(LOCACC+2)=NO. OF EQUAS. */
/* IF LAST BLOCK OF EQUAS., SET IOPT(LOCACC)=2. */
/* ELSE IF IOPT(LOCACC) .EQ. 2) THEN */
/* (PROCESS IS OVER. EXIT LOOP.) */
/* ELSE */
/* (ERROR CONDITION. SHOULD NOT HAPPEN.) */
/* END IF */
/* END LOOP */
/* SET IOPT(LOCACC-1)=-OPTION NUMBER FOR SEQ. ACCUMULATION. */
/* CALL DBOLS( ) */
iopt[locacc + 1] = 1;
igo = 1;
}
lds = 4;
goto L30;
} else if (jp == 2) {
if (ip > 0) {
/* GET ACTUAL LENGTHS OF ARRAYS FOR CHECKING AGAINST NEEDS. */
locdim = lp + 2;
/* LMDW.GE.MROWS */
/* LNDW.GE.NCOLS+1 */
/* LLB .GE.NCOLS */
/* LLX .GE.NCOLS+EXTRA REQD. IN OPTIONS. */
/* LLRW.GE.5*NCOLS */
/* LLIW.GE.2*NCOLS */
/* LIOP.GE. AMOUNT REQD. FOR IOPTION ARRAY. */
lmdw = iopt[locdim];
lndw = iopt[locdim + 1];
llb = iopt[locdim + 2];
llx = iopt[locdim + 3];
llrw = iopt[locdim + 4];
lliw = iopt[locdim + 5];
liopt = iopt[locdim + 6];
checkl = TRUE_;
}
lds = 8;
goto L30;
/* OPTION TO MODIFY THE COLUMN SCALING. */
} else if (jp == 3) {
if (ip > 0) {
iscale = iopt[lp + 2];
/* SEE THAT ISCALE IS 1 THRU 3. */
if (iscale < 1 || iscale > 3) {
nerr = 7;
nchar = 40;
xerrwv_("DBOLS(). ISCALE OPTION=(I1) MUST BE 1-3.", &
nchar, &nerr, &level, &c__1, &iscale, &idum, &
c__0, &rdum, &rdum, (ftnlen)40);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
}
lds = 2;
/* CYCLE FOREVER */
goto L30;
/* IN THIS OPTION THE USER HAS PROVIDED SCALING. THE */
/* SCALE FACTORS FOR THE COLUMNS BEGIN IN X(NCOLS+IOPT(LP+2)). */
} else if (jp == 4) {
if (ip > 0) {
iscale = 4;
if (iopt[lp + 2] <= 0) {
nerr = 8;
nchar = 85;
xerrwv_("DBOLS(). OFFSET PAST X(NCOLS) (I1) FOR USER-PRO"
"VIDED COLUMN SCALING MUST BE POSITIVE.", &nchar, &
nerr, &level, &c__1, &iopt[lp + 2], &idum, &c__0,
&rdum, &rdum, (ftnlen)85);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
dcopy_(ncols, &x[*ncols + iopt[lp + 2]], &c__1, &rw[1], &c__1)
;
lenx += *ncols;
i__1 = *ncols;
for (j = 1; j <= i__1; ++j) {
if (rw[j] <= zero) {
nerr = 9;
nchar = 85;
rdum2 = rw[j];
xerrwv_("DBOLS(). EACH PROVIDED COL. SCALE FACTOR MU"
"ST BE POSITIVE. COMPONENT (I1) NOW = (R1).", &
nchar, &nerr, &level, &c__1, &j, &idum, &c__1,
&rdum2, &rdum, (ftnlen)85);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
/* L40: */
}
}
lds = 2;
/* CYCLE FOREVER */
goto L30;
/* IN THIS OPTION AN OPTION ARRAY IS PROVIDED TO DBOLSM(). */
} else if (jp == 5) {
if (ip > 0) {
lopt = iopt[lp + 2];
}
lds = 2;
/* CYCLE FOREVER */
goto L30;
/* THIS OPTION USES THE NEXT LOC OF IOPT(*) AS AN */
/* INCREMENT TO SKIP. */
} else if (jp == 6) {
if (ip > 0) {
lp = iopt[lp + 2] - 1;
lds = 0;
} else {
lds = 2;
}
/* CYCLE FOREVER */
goto L30;
/* NO VALID OPTION NUMBER WAS NOTED. THIS IS AN ERROR CONDITION. */
} else {
nerr = 6;
nchar = 47;
rdum2 = (real) idum;
xerrwv_("DBOLS(). THE OPTION NUMBER=(I1) IS NOT DEFINED.", &nchar,
&nerr, &level, &c__1, &jp, &idum, &c__0, &rdum2, &rdum2,
(ftnlen)47);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
L50:
/* END PROCEDURE */
if (checkl) {
/* DO(CHECK LENGTHS OF ARRAYS) */
/* PROCEDURE(CHECK LENGTHS OF ARRAYS) */
/* THIS FEATURE ALLOWS THE USER TO MAKE SURE THAT THE */
/* ARRAYS ARE LONG ENOUGH FOR THE INTENDED PROBLEM SIZE AND USE. */
if (lmdw < *mrows) {
nerr = 11;
nchar = 76;
xerrwv_("DBOLS(). THE ROW DIMENSION OF W(,)=(I1) MUST BE .GE"
".THE NUMBER OF ROWS=(I2).", &nchar, &nerr, &level, &
c__2, &lmdw, mrows, &c__0, &rdum, &rdum, (ftnlen)76);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
if (lndw < *ncols + 1) {
nerr = 12;
nchar = 69;
i__1 = *ncols + 1;
xerrwv_("DBOLS(). THE COLUMN DIMENSION OF W(,)=(I1) MUST BE "
".GE. NCOLS+1=(I2).", &nchar, &nerr, &level, &c__2, &
lndw, &i__1, &c__0, &rdum, &rdum, (ftnlen)69);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
if (llb < *ncols) {
nerr = 13;
nchar = 88;
xerrwv_("DBOLS(). THE DIMENSIONS OF THE ARRAYS BL(),BU(), AN"
"D IND()=(I1) MUST BE .GE. NCOLS=(I2).", &nchar, &nerr,
&level, &c__2, &llb, ncols, &c__0, &rdum, &rdum, (
ftnlen)88);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
if (llx < lenx) {
nerr = 14;
nchar = 70;
xerrwv_("DBOLS(). THE DIMENSION OF X()=(I1) MUST BE .GE. THE"
" REQD. LENGTH=(I2).", &nchar, &nerr, &level, &c__2, &
llx, &lenx, &c__0, &rdum, &rdum, (ftnlen)70);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
if (llrw < *ncols * 5) {
nerr = 15;
nchar = 62;
i__1 = *ncols * 5;
xerrwv_("DBOLS(). THE DIMENSION OF RW()=(I1) MUST BE .GE. 5*"
"NCOLS=(I2).", &nchar, &nerr, &level, &c__2, &llrw, &
i__1, &c__0, &rdum, &rdum, (ftnlen)62);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
if (lliw < *ncols << 1) {
nerr = 16;
nchar = 61;
i__1 = *ncols << 1;
xerrwv_("DBOLS() THE DIMENSION OF IW()=(I1) MUST BE .GE. 2*N"
"COLS=(I2).", &nchar, &nerr, &level, &c__2, &lliw, &
i__1, &c__0, &rdum, &rdum, (ftnlen)61);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
if (liopt < lp + 1) {
nerr = 17;
nchar = 71;
i__1 = lp + 1;
xerrwv_("DBOLS(). THE DIMENSION OF IOPT()=(I1) MUST BE .GE. "
"THE REQD. LEN.=(I2).", &nchar, &nerr, &level, &c__2, &
liopt, &i__1, &c__0, &rdum, &rdum, (ftnlen)71);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
/* END PROCEDURE */
}
}
switch (igo) {
case 1: goto L60;
case 2: goto L90;
}
goto L180;
/* GO BACK TO THE USER FOR ACCUMULATION OF LEAST SQUARES */
/* EQUATIONS AND DIRECTIONS TO QUIT PROCESSING. */
/* CASE 1 */
L60:
/* DO(ACCUMULATE LEAST SQUARES EQUATIONS) */
/* PROCEDURE(ACCUMULATE LEAST SQUARES EQUATIONS) */
*mrows = iopt[locacc + 1] - 1;
inrows = iopt[locacc + 2];
mnew = *mrows + inrows;
if (mnew < 0 || mnew > *mdw) {
nerr = 10;
nchar = 61;
xerrwv_("DBOLS(). NO. OF ROWS=(I1) MUST BE .GE. 0 .AND. .LE. MDW=(I2"
").", &nchar, &nerr, &level, &c__2, &mnew, mdw, &c__0, &rdum, &
rdum, (ftnlen)61);
/* DO(RETURN TO USER PROGRAM UNIT) */
goto L190;
}
/* Computing MIN */
i__2 = *ncols + 1;
i__1 = min(i__2,mnew);
for (j = 1; j <= i__1; ++j) {
i__2 = max(*mrows,j) + 1;
for (i__ = mnew; i__ >= i__2; --i__) {
i__3 = i__ - j;
ibig = idamax_(&i__3, &w[j + j * w_dim1], &c__1) + j - 1;
/* PIVOT FOR INCREASED STABILITY. */
drotg_(&w[ibig + j * w_dim1], &w[i__ + j * w_dim1], &sc, &ss);
i__3 = *ncols + 1 - j;
drot_(&i__3, &w[ibig + (j + 1) * w_dim1], mdw, &w[i__ + (j + 1) *
w_dim1], mdw, &sc, &ss);
w[i__ + j * w_dim1] = zero;
/* L70: */
}
/* L80: */
}
/* Computing MIN */
i__1 = *ncols + 1;
*mrows = min(i__1,mnew);
iopt[locacc + 1] = *mrows + 1;
igo = iopt[locacc];
/* END PROCEDURE */
if (igo == 2) {
igo = 0;
}
goto L180;
/* CASE 2 */
L90:
/* DO(INITIALIZE VARIABLES AND DATA VALUES) */
/* PROCEDURE(INITIALIZE VARIABLES AND DATA VALUES) */
i__1 = *ncols;
for (j = 1; j <= i__1; ++j) {
switch (iscale) {
case 1: goto L100;
case 2: goto L110;
case 3: goto L120;
case 4: goto L130;
}
goto L140;
L100:
/* CASE 1 */
/* THIS IS THE NOMINAL SCALING. EACH NONZERO */
/* COL. HAS MAX. NORM EQUAL TO ONE. */
ibig = idamax_(mrows, &w[j * w_dim1 + 1], &c__1);
rw[j] = (d__1 = w[ibig + j * w_dim1], abs(d__1));
if (rw[j] == zero) {
rw[j] = one;
} else {
rw[j] = one / rw[j];
}
goto L140;
L110:
/* CASE 2 */
/* THIS CHOICE OF SCALING MAKES EACH NONZERO COLUMN */
/* HAVE EUCLIDEAN LENGTH EQUAL TO ONE. */
rw[j] = dnrm2_(mrows, &w[j * w_dim1 + 1], &c__1);
if (rw[j] == zero) {
rw[j] = one;
} else {
rw[j] = one / rw[j];
}
goto L140;
L120:
/* CASE 3 */
/* THIS CASE EFFECTIVELY SUPPRESSES SCALING BY SETTING */
/* THE SCALING MATRIX TO THE IDENTITY MATRIX. */
rw[1] = one;
dcopy_(ncols, &rw[1], &c__0, &rw[1], &c__1);
goto L160;
L130:
/* CASE 4 */
goto L160;
L140:
/* L150: */
;
}
L160:
/* END PROCEDURE */
/* DO(SOLVE BOUNDED LEAST SQUARES PROBLEM) */
/* PROCEDURE(SOLVE BOUNDED LEAST SQUARES PROBLEM) */
/* INITIALIZE IBASIS(*), J=1,NCOLS, AND IBB(*), J=1,NCOLS, */
/* TO =J,AND =1, FOR USE IN DBOLSM( ). */
i__1 = *ncols;
for (j = 1; j <= i__1; ++j) {
iw[j] = j;
iw[j + *ncols] = 1;
rw[*ncols * 3 + j] = bl[j];
rw[(*ncols << 2) + j] = bu[j];
/* L170: */
}
dbolsm_(&w[w_offset], mdw, mrows, ncols, &rw[*ncols * 3 + 1], &rw[(*ncols
<< 2) + 1], &ind[1], &iopt[lopt], &x[1], rnorm, mode, &rw[*ncols
+ 1], &rw[(*ncols << 1) + 1], &rw[1], &iw[1], &iw[*ncols + 1]);
/* END PROCEDURE */
igo = 0;
L180:
return 0;
/* PROCEDURE(RETURN TO USER PROGRAM UNIT) */
L190:
if (*mode >= 0) {
*mode = -nerr;
}
igo = 0;
return 0;
/* END PROCEDURE */
} /* dbols_ */

View file

@ -0,0 +1,262 @@
/**
* @file vcs_defs.h
* Defines and definitions within the vcs package
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef VCS_DEFS_H
#define VCS_DEFS_H
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
*
* COMMON DEFINITIONS -> Protect them against redefinitions
*/
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#ifndef BOOLEAN
# define BOOLEAN int
#endif
#ifndef MAX
# define MAX(x,y) (( (x) > (y) ) ? (x) : (y))
#endif
#ifndef MIN
# define MIN(x,y) (( (x) < (y) ) ? (x) : (y))
#endif
#ifndef SWAP
# define SWAP(x1, x2, temp) ((temp) = (x1), (x1) = (x2), (x2) = (temp))
#endif
#ifndef SQUARE
# define SQUARE(x) ((x) * (x))
#endif
#ifndef DSIGN
# define DSIGN(x) (( (x) == (0.0) ) ? (0.0) : ( ((x) > 0.0) ? 1.0 : -1.0 ))
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* ERROR CODES
*
*/
#define VCS_SUCCESS 0
#define VCS_NOMEMORY 1
#define VCS_FAILED_CONVERGENCE -1
#define VCS_SHOULDNT_BE_HERE -2
#define VCS_PUB_BAD -3
#define VCS_THERMO_OUTOFRANGE -4
#define VCS_FAILED_LOOKUP -5
#define VCS_MP_FAIL -6
#define VCS_ERR_NOVALUE -1.1234E15
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* Problem Types
*/
#define VCS_PROBTYPE_TP 0
#define VCS_PROBTYPE_TV 1
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* Maximum Length of any name in this package
*/
#define VCS_MAX_NAME_LEN 31
#define VCS_MAX_NAME_LEN_P1 32
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* SIZES OF PHASES AND MOLE NUMBER CUTOFFS
*
* VCS_DELETE_SPECIES_CUTOFF: Cutoff relative mole number value,
* below which species are deleted
* from the equilibrium problem.
*/
#ifndef VCS_DELETE_SPECIES_CUTOFF
#define VCS_DELETE_SPECIES_CUTOFF 1.0e-32
#endif
#ifndef VCS_DELETE_MINORSPECIES_CUTOFF
#define VCS_DELETE_MINORSPECIES_CUTOFF 1.0e-140
#endif
/*
* VCS_SMALL_MULTIPHASE_SPECIES:
* Relative value of multiphase
* species mole number for a multiphase
* species which is small.
*/
#define VCS_SMALL_MULTIPHASE_SPECIES 1.0e-25
/*
* VCS_DELETE_PHASE_CUTOFF: Cutoff relative moles below
* which a phase is deleted
* from the equilibrium problem.
*/
#ifndef VCS_DELETE_PHASE_CUTOFF
#define VCS_DELETE_PHASE_CUTOFF 1.0e-11
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* State of Dimensional Units for Gibbs free energies
*/
#define VCS_NONDIMENSIONAL_G 1
#define VCS_DIMENSIONAL_G 0
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* SPECIES CATEGORIES USED IN VCS_SOLVE_TP
*/
//! @name Species Types during the iteration
//! valid values for spStatus()
//@{
//! Species is a component
#define VCS_SPECIES_COMPONENT 2
//! Species is a major species
/*!
* A major species is either a species in a multicomponent phase with
* significant concentration or its a Stoich Phase
*/
#define VCS_SPECIES_MAJOR 1
//! Species is a major species
/*!
* A major species is either a species in a multicomponent phase with
* significant concentration or its a Stoich Phase
*/
#define VCS_SPECIES_MINOR 0
//! Species lies in a multicomponent phase that is zeroed atm
/*!
* The species lies in a multicomponent phase that is currently
* deleted.
*/
#define VCS_SPECIES_ZEROEDPHASE -1
//! Species lies in a multicomponent phase, with concentration zero
/*!
* The species lies in a multicomponent phase that exists.
* It concentration is currently zero, even though it may
* or may not actually have a low mole fraction in the phase
* this situation occurs when phases pop back into life.
*/
#define VCS_SPECIES_ZEROEDMS -2
//! Species is a SS phase, that is currently zeroed out.
/*!
* The species lies in a single-species phase which
* is currently zereod out.
*/
#define VCS_SPECIES_ZEROEDSS -3
//! Species has such a small mole fraction it is deleted.
/*!
* The species is believed to have such a small mole fraction
* that it best to throw the calculation of it out.
* It will be aded back in at the end of the calculation.
*/
#define VCS_SPECIES_DELETED -4
//! Species refers to an electron in the metal
/*!
* The unknown is equal to the interfacial voltage
* drop across the interface on the SHE (standard
* hyrdogen electrode) scale (volts).
*/
#define VCS_SPECIES_INTERFACIALVOLTAGE -5
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* Units for the chemical potential data and pressure variables:
*
* Chem_Pot Pres vol moles
* -------------------------------------------------
* VCS_UNITS_KCALMOL = kcal/mol atm cm**3 gmol
* VCS_UNITS_UNITLESS = MU / RT -> no units atm cm**3 gmol
* VCS_UNITS_KJMOL = kJ / mol atm cm**3 gmol
* VCS_UNITS_KELVIN = KELVIN -> MU / R atm cm**3 gmol
* VCS_UNITS_MKS = Joules / Kmol (Cantera) Pa m**3 kmol
*
* Energy:
* VCS_UNITS_KCALMOL = kcal/mol
* VCS_UNITS_UNITLESS = MU / RT -> no units
* VCS_UNITS_KJMOL = kJ / mol
* VCS_UNITS_KELVIN = KELVIN -> MU / R
* VCS_UNITS_MKS = J / kmol
*
* Pressure: (Pref and Pres)
* VCS_UNITS_KCALMOL = atm
* VCS_UNITS_UNITLESS = no units
* VCS_UNITS_KJMOL = atm
* VCS_UNITS_KELVIN = atm
* VCS_UNITS_MKS = Pa = kg / m s2
*/
#define VCS_UNITS_KCALMOL -1
#define VCS_UNITS_UNITLESS 0
#define VCS_UNITS_KJMOL 1
#define VCS_UNITS_KELVIN 2
#define VCS_UNITS_MKS 3
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* Element type Defines
*/
#define VCS_ELEM_TYPE_ABSPOS 0
#define VCS_ELEM_TYPE_ELECTRONCHARGE 1
#define VCS_ELEM_TYPE_CHARGENEUTRALITY 2
#define VCS_ELEM_TYPE_OTHERCONSTRAINT 3
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* Species type Defines
*/
#define VCS_SPECIES_TYPE_MOLNUM 0
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE -5
/****************************************************************************/
}
#endif

View file

@ -0,0 +1,294 @@
/* dvout.f -- translated by f2c (version 20031025).
You must link the resulting object file with libf2c:
on Microsoft Windows system, link with libf2c.lib;
on Linux or Unix systems, link with .../path/to/libf2c.a -lm
or, if you install libf2c.a in a standard place, with -lf2c -lm
-- in that order, at the end of the command line, as in
cc *.o -lf2c -lm
Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
http://www.netlib.org/f2c/libf2c.zip
*/
#include "f2c.h"
/* Table of constant values */
static integer c__2 = 2;
static integer c__1 = 1;
/* DECK DVOUT */
/* Subroutine */ int dvout_(integer *n, doublereal *dx, char *ifmt, integer *
idigit, ftnlen ifmt_len)
{
/* Format strings */
static char fmt_1000[] = "(1x,i4,\002 - \002,i4,1x,1p8d14.5)";
static char fmt_1001[] = "(1x,i4,\002 - \002,i4,1x,1p5d22.13)";
static char fmt_1002[] = "(1x,i4,\002 - \002,i4,1x,1p4d28.19)";
static char fmt_1003[] = "(1x,i4,\002 - \002,i4,1x,1p3d36.27)";
/* System generated locals */
integer i__1, i__2, i__3;
cilist ci__1;
/* Builtin functions */
integer s_wsfe(cilist *), e_wsfe(void), do_fio(integer *, char *, ftnlen);
/* Local variables */
static integer i__, k1, k2, lout;
extern integer i1mach_(integer *);
static integer ndigit;
/* Fortran I/O blocks */
static cilist io___5 = { 0, 0, 0, fmt_1000, 0 };
static cilist io___7 = { 0, 0, 0, fmt_1001, 0 };
static cilist io___8 = { 0, 0, 0, fmt_1002, 0 };
static cilist io___9 = { 0, 0, 0, fmt_1003, 0 };
static cilist io___10 = { 0, 0, 0, fmt_1000, 0 };
static cilist io___11 = { 0, 0, 0, fmt_1001, 0 };
static cilist io___12 = { 0, 0, 0, fmt_1002, 0 };
static cilist io___13 = { 0, 0, 0, fmt_1003, 0 };
/* ***BEGIN PROLOGUE DVOUT */
/* ***REFER TO DSPLP */
/* ***ROUTINES CALLED I1MACH */
/* ***DESCRIPTION */
/* REVISED FEB. 27, 1981. */
/* DOUBLE PRECISION VECTOR OUTPUT ROUTINE. */
/* INPUT.. */
/* N,DX(*) PRINT THE DOUBLE PRECISION ARRAY DX(I),I=1,...,N, ON */
/* OUTPUT UNIT LOUT. THE HEADING IN THE FORTRAN FORMAT */
/* STATEMENT IFMT(*), DESCRIBED BELOW, IS PRINTED AS A FIRST */
/* STEP. THE COMPONENTS DX(I) ARE INDEXED, ON OUTPUT, */
/* IN A PLEASANT FORMAT. */
/* IFMT(*) A FORTRAN FORMAT STATEMENT. THIS IS PRINTED ON OUTPUT */
/* UNIT LOUT WITH THE VARIABLE FORMAT FORTRAN STATEMENT */
/* WRITE(LOUT,IFMT) */
/* IDIGIT PRINT AT LEAST IABS(IDIGIT) DECIMAL DIGITS PER NUMBER. */
/* THE SUBPROGRAM WILL CHOOSE THAT INTEGER 4,6,10 OR 14 */
/* WHICH WILL PRINT AT LEAST IABS(IDIGIT) NUMBER OF */
/* PLACES. IF IDIGIT.LT.0, 72 PRINTING COLUMNS ARE UTILIZED */
/* TO WRITE EACH LINE OF OUTPUT OF THE ARRAY DX(*). (THIS */
/* CAN BE USED ON MOST TIME-SHARING TERMINALS). IF */
/* IDIGIT.GE.0, 133 PRINTING COLUMNS ARE UTILIZED. (THIS CAN */
/* BE USED ON MOST LINE PRINTERS). */
/* EXAMPLE.. */
/* PRINT AN ARRAY CALLED (COSTS OF PURCHASES) OF LENGTH 100 SHOWING */
/* 6 DECIMAL DIGITS PER NUMBER. THE USER IS RUNNING ON A TIME-SHARING */
/* SYSTEM WITH A 72 COLUMN OUTPUT DEVICE. */
/* DOUBLE PRECISION COSTS(100) */
/* N = 100 */
/* IDIGIT = -6 */
/* CALL DVOUT(N,COSTS,'(''1COSTS OF PURCHASES'')',IDIGIT) */
/* AUTHORS JOHN A. WISNIEWSKI SANDIA LABS ALBUQUERQUE. */
/* RICHARD J. HANSON SANDIA LABS ALBUQUERQUE. */
/* DATE JULY 27,1978. */
/* ***END PROLOGUE DVOUT */
/* ***FIRST EXECUTABLE STATEMENT DVOUT */
/* Parameter adjustments */
--dx;
/* Function Body */
lout = i1mach_(&c__2);
ci__1.cierr = 0;
ci__1.ciunit = lout;
ci__1.cifmt = ifmt;
s_wsfe(&ci__1);
e_wsfe();
if (*n <= 0) {
return 0;
}
ndigit = *idigit;
if (*idigit == 0) {
ndigit = 6;
}
if (*idigit >= 0) {
goto L80;
}
ndigit = -(*idigit);
if (ndigit > 6) {
goto L20;
}
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 4) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 3;
k2 = min(i__2,i__3);
io___5.ciunit = lout;
s_wsfe(&io___5);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L10: */
}
return 0;
L20:
if (ndigit > 14) {
goto L40;
}
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 2) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 1;
k2 = min(i__2,i__3);
io___7.ciunit = lout;
s_wsfe(&io___7);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L30: */
}
return 0;
L40:
if (ndigit > 20) {
goto L60;
}
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 2) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 1;
k2 = min(i__2,i__3);
io___8.ciunit = lout;
s_wsfe(&io___8);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L50: */
}
return 0;
L60:
i__1 = *n;
for (k1 = 1; k1 <= i__1; ++k1) {
k2 = k1;
io___9.ciunit = lout;
s_wsfe(&io___9);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L70: */
}
return 0;
L80:
if (ndigit > 6) {
goto L100;
}
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 8) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 7;
k2 = min(i__2,i__3);
io___10.ciunit = lout;
s_wsfe(&io___10);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L90: */
}
return 0;
L100:
if (ndigit > 14) {
goto L120;
}
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 5) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 4;
k2 = min(i__2,i__3);
io___11.ciunit = lout;
s_wsfe(&io___11);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L110: */
}
return 0;
L120:
if (ndigit > 20) {
goto L140;
}
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 4) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 3;
k2 = min(i__2,i__3);
io___12.ciunit = lout;
s_wsfe(&io___12);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L130: */
}
return 0;
L140:
i__1 = *n;
for (k1 = 1; k1 <= i__1; k1 += 3) {
/* Computing MIN */
i__2 = *n, i__3 = k1 + 2;
k2 = min(i__2,i__3);
io___13.ciunit = lout;
s_wsfe(&io___13);
do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
i__2 = k2;
for (i__ = k1; i__ <= i__2; ++i__) {
do_fio(&c__1, (char *)&dx[i__], (ftnlen)sizeof(doublereal));
}
e_wsfe();
/* L150: */
}
return 0;
} /* dvout_ */

View file

@ -0,0 +1,602 @@
/**
* @file vcs_elem.cpp
*/
/*
* $Id$
*/
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "math.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::vcs_elab(void)
/*************************************************************************
*
* vcs_elab:
*
* Computes the elemental abundances vector, ga[], and stores it
* back into the global structure
*************************************************************************/
{
for (int j = 0; j < m_numElemConstraints; ++j) {
ga[j] = 0.0;
for (int i = 0; i < m_numSpeciesTot; ++i) {
if (SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
ga[j] += FormulaMatrix[j][i] * soln[i];
}
}
}
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
*
* vcs_elabcheck:
*
* This function checks to see if the element abundances are in
* compliance. If they are, then TRUE is returned. If not,
* FALSE is returned. Note the number of constraints checked is
* usually equal to the number of components in the problem. This
* routine can check satisfaction of all of the constraints in the
* problem, which is equal to ne. However, the solver can't fix
* breakage of constraints above nc, because that nc is the
* range space by definition. Satisfaction of extra constraints would
* have had to occur in the problem specification.
*
* The constraints should be broken up into 2 sections. If
* a constraint involves a formula matrix with positive and
* negative signs, and eaSet = 0.0, then you can't expect that the
* sum will be zero. There may be roundoff that inhibits this.
* However, if the formula matrix is all of one sign, then
* this requires that all species with nonzero entries in the
* formula matrix be identically zero. We put this into
* the logic below.
*
* Input
* -------
* ibound = 1 : Checks constraints up to the number of elements
* 0 : Checks constraints up to the number of components.
*
*/
int VCS_SOLVE::vcs_elabcheck(int ibound) {
int i;
int top = m_numComponents;
double eval, scale;
int numNonZero;
bool multisign = false;
if (ibound) {
top = m_numElemConstraints;
}
/*
* Require 12 digits of accuracy on non-zero constraints.
*/
for (i = 0; i < top; ++i) {
if (fabs(ga[i] - gai[i]) > (fabs(gai[i]) * 1.0e-12)) {
/*
* This logic is for charge neutrality condition
*/
if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY) {
AssertThrowVCS(gai[i] == 0.0, "vcs_elabcheck");
}
if (gai[i] == 0.0 || (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE)) {
scale = VCS_DELETE_MINORSPECIES_CUTOFF;
/*
* Find out if the constraint is a multisign constraint.
* If it is, then we have to worry about roundoff error
* in the addition of terms. We are limited to 13
* digits of finite arithmetic accuracy.
*/
numNonZero = 0;
multisign = false;
for (int kspec = 0; kspec < m_numSpeciesTot; kspec++) {
eval = FormulaMatrix[i][kspec];
if (eval < 0.0) {
multisign = true;
}
if (eval != 0.0) {
scale = MAX(scale, fabs(eval * soln[kspec]));
numNonZero++;
}
}
if (multisign) {
if (fabs(ga[i] - gai[i]) > 1e-11 * scale) {
return FALSE;
}
} else {
if (fabs(ga[i] - gai[i]) > VCS_DELETE_MINORSPECIES_CUTOFF) {
return FALSE;
}
}
} else {
/*
* For normal element balances, we require absolute compliance
* even for rediculously small numbers.
*/
if (m_elType[i] == VCS_ELEM_TYPE_ABSPOS) {
return FALSE;
} else {
return FALSE;
}
}
}
}
return TRUE;
} /* vcs_elabcheck() *********************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::vcs_elabPhase(int iphase, double * const elemAbundPhase)
/*************************************************************************
*
* vcs_elabPhase:
*
* Computes the elemental abundances vector for a single phase,
* elemAbundPhase[], and returns it through the argument list.
* The mole numbers of species are taken from the current value
* in soln[].
*************************************************************************/
{
int i, j;
for (j = 0; j < m_numElemConstraints; ++j) {
elemAbundPhase[j] = 0.0;
for (i = 0; i < m_numSpeciesTot; ++i) {
if (SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
if (PhaseID[i] == iphase) {
elemAbundPhase[j] += FormulaMatrix[j][i] * soln[i];
}
}
}
}
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_elcorr(double aa[], double x[])
/**************************************************************************
*
* vcs_elcorr:
*
* This subroutine corrects for element abundances. At the end of the
* surbroutine, the total moles in all phases are recalculated again,
* because we have changed the number of moles in this routine.
*
* Input
* -> temporary work vectors:
* aa[ne*ne]
* x[ne]
*
* Return Values:
* 0 = Nothing of significance happened,
* Element abundances were and still are good.
* 1 = The solution changed significantly;
* The element abundances are now good.
* 2 = The solution changed significantly,
* The element abundances are still bad.
* 3 = The solution changed significantly,
* The element abundances are still bad and a component
* species got zeroed out.
*
* Internal data to be worked on::
*
* ga Current element abundances
* gai Required elemental abundances
* soln Current mole number of species.
* FormulaMatrix[][] Formular matrix of the species
* ne Number of elements
* nc Number of components.
*
* NOTES:
* This routine is turning out to be very problematic. There are
* lots of special cases and problems with zeroing out species.
*
* Still need to check out when we do loops over nc vs. ne.
*
*************************************************************************/
{
int i, j, retn = 0, kspec, goodSpec, its;
double xx, par, saveDir, dir;
#ifdef DEBUG
double l2before = 0.0, l2after = 0.0;
std::vector<double> ga_save(m_numElemConstraints, 0.0);
vcs_dcopy(VCS_DATA_PTR(ga_save), VCS_DATA_PTR(ga), m_numElemConstraints);
if (vcs_debug_print_lvl >= 2) {
plogf(" --- vcsc_elcorr: Element abundances correction routine");
if (m_numElemConstraints != m_numComponents) {
plogf(" (m_numComponents != m_numElemConstraints)");
}
plogf("\n");
}
for (i = 0; i < m_numElemConstraints; ++i) {
x[i] = ga[i] - gai[i];
}
l2before = 0.0;
for (i = 0; i < m_numElemConstraints; ++i) {
l2before += x[i] * x[i];
}
l2before = sqrt(l2before/m_numElemConstraints);
#endif
/*
* Special section to take out single species, single component,
* moles. These are species which have non-zero entries in the
* formula matrix, and no other species have zero values either.
*
*/
int numNonZero = 0;
bool changed = false;
bool multisign = false;
for (i = 0; i < m_numElemConstraints; ++i) {
numNonZero = 0;
multisign = false;
for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
double eval = FormulaMatrix[i][kspec];
if (eval < 0.0) {
multisign = true;
}
if (eval != 0.0) {
numNonZero++;
}
}
}
if (!multisign) {
if (numNonZero < 2) {
for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
double eval = FormulaMatrix[i][kspec];
if (eval > 0.0) {
soln[kspec] = gai[i] / eval;
changed = true;
}
}
}
} else {
int numCompNonZero = 0;
int compID = -1;
for (kspec = 0; kspec < m_numComponents; kspec++) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
double eval = FormulaMatrix[i][kspec];
if (eval > 0.0) {
compID = kspec;
numCompNonZero++;
}
}
}
if (numCompNonZero == 1) {
double diff = gai[i];
for (kspec = m_numComponents; kspec < m_numSpeciesTot; kspec++) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
double eval = FormulaMatrix[i][kspec];
diff -= eval * soln[kspec];
}
soln[compID] = MAX(0.0,diff/FormulaMatrix[i][compID]);
changed = true;
}
}
}
}
}
if (changed) {
vcs_elab();
}
/*
* Section to check for maximum bounds errors on all species
* due to elements.
* This may only be tried on element types which are VCS_ELEM_TYPE_ABSPOS.
* This is because no other species may have a negative number of these.
*
* Note, also we can do this over ne, the number of elements, not just
* the number of components.
*/
changed = false;
for (i = 0; i < m_numElemConstraints; ++i) {
int elType = m_elType[i];
if (elType == VCS_ELEM_TYPE_ABSPOS) {
for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
double atomComp = FormulaMatrix[i][kspec];
if (atomComp > 0.0) {
double maxPermissible = gai[i] / atomComp;
if (soln[kspec] > maxPermissible) {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 3) {
plogf(" --- vcs_elcorr: Reduced species %s from %g to %g due to %s max bounds constraint\n",
SpName[kspec].c_str(), soln[kspec], maxPermissible, ElName[i].c_str());
}
#endif
soln[kspec] = maxPermissible;
changed = true;
if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF) {
soln[kspec] = 0.0;
if (SSPhase[kspec]) {
spStatus[kspec] = VCS_SPECIES_ZEROEDSS;
} else {
spStatus[kspec] = VCS_SPECIES_ZEROEDMS;
}
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf(" --- vcs_elcorr: Zeroed species %s and changed status to %d due to max bounds constraint\n",
SpName[kspec].c_str(), spStatus[kspec]);
}
#endif
}
}
}
}
}
}
}
// Recalculate the element abundances if something has changed.
if (changed) {
vcs_elab();
}
/*
* Ok, do the general case. Linear algebra problem is
* of length nc, not ne, as there may be degenerate rows when
* nc .ne. ne.
*/
for (i = 0; i < m_numComponents; ++i) {
x[i] = ga[i] - gai[i];
if (fabs(x[i]) > 1.0E-13) retn = 1;
for (j = 0; j < m_numComponents; ++j) {
aa[j + i*m_numElemConstraints] = FormulaMatrix[j][i];
}
}
i = vcsUtil_mlequ(aa, m_numElemConstraints, m_numComponents, x, 1);
if (i == 1) {
plogf("vcs_elcorr ERROR: mlequ returned error condition\n");
return VCS_FAILED_CONVERGENCE;
}
/*
* Now apply the new direction without creating negative species.
*/
par = 0.5;
for (i = 0; i < m_numComponents; ++i) {
if (soln[i] > 0.0) {
xx = -x[i] / soln[i];
if (par < xx) par = xx;
}
}
if (par > 100.0) {
par = 100.0;
}
par = 1.0 / par;
if (par < 1.0 && par > 0.0) {
retn = 2;
par *= 0.9999;
for (i = 0; i < m_numComponents; ++i) {
double tmp = soln[i] + par * x[i];
if (tmp > 0.0) {
soln[i] = tmp;
} else {
if (SSPhase[i]) {
soln[i] = 0.0;
} else {
soln[i] = soln[i] * 0.0001;
}
}
}
} else {
for (i = 0; i < m_numComponents; ++i) {
double tmp = soln[i] + x[i];
if (tmp > 0.0) {
soln[i] = tmp;
} else {
if (SSPhase[i]) {
soln[i] = 0.0;
} else {
soln[i] = soln[i] * 0.0001;
}
}
}
}
/*
* We have changed the element abundances. Calculate them again
*/
vcs_elab();
/*
* We have changed the total moles in each phase. Calculate them again
*/
vcs_tmoles();
/*
* Try some ad hoc procedures for fixing the problem
*/
if (retn >= 2) {
/*
* First find a species whose adjustment is a win-win
* situation.
*/
for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
continue;
}
saveDir = 0.0;
goodSpec = TRUE;
for (i = 0; i < m_numComponents; ++i) {
dir = FormulaMatrix[i][kspec] * (gai[i] - ga[i]);
if (fabs(dir) > 1.0E-10) {
if (dir > 0.0) {
if (saveDir < 0.0) {
goodSpec = FALSE;
break;
}
} else {
if (saveDir > 0.0) {
goodSpec = FALSE;
break;
}
}
saveDir = dir;
} else {
if (FormulaMatrix[i][kspec] != 0.) {
goodSpec = FALSE;
break;
}
}
}
if (goodSpec) {
its = 0;
xx = 0.0;
for (i = 0; i < m_numComponents; ++i) {
if (FormulaMatrix[i][kspec] != 0.0) {
xx += (gai[i] - ga[i]) / FormulaMatrix[i][kspec];
its++;
}
}
if (its > 0) xx /= its;
soln[kspec] += xx;
soln[kspec] = MAX(soln[kspec], 1.0E-10);
/*
* If we are dealing with a deleted species, then
* we need to reinsert it into the active list.
*/
if (kspec >= m_numSpeciesRdc) {
vcs_reinsert_deleted(kspec);
soln[m_numSpeciesRdc - 1] = xx;
vcs_elab();
goto L_CLEANUP;
}
vcs_elab();
}
}
}
if (vcs_elabcheck(0)) {
retn = 1;
goto L_CLEANUP;
}
for (i = 0; i < m_numElemConstraints; ++i) {
if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY ||
(m_elType[i] == VCS_ELEM_TYPE_ABSPOS && gai[i] == 0.0)) {
for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
if (ga[i] > 0.0) {
if (FormulaMatrix[i][kspec] < 0.0) {
soln[kspec] -= ga[i] / FormulaMatrix[i][kspec] ;
if (soln[kspec] < 0.0) {
soln[kspec] = 0.0;
}
vcs_elab();
break;
}
}
if (ga[i] < 0.0) {
if (FormulaMatrix[i][kspec] > 0.0) {
soln[kspec] -= ga[i] / FormulaMatrix[i][kspec];
if (soln[kspec] < 0.0) {
soln[kspec] = 0.0;
}
vcs_elab();
break;
}
}
}
}
}
if (vcs_elabcheck(1)) {
retn = 1;
goto L_CLEANUP;
}
/*
* For electron charges element types, we try positive deltas
* in the species concentrations to match the desired
* electron charge exactly.
*/
for (i = 0; i < m_numElemConstraints; ++i) {
double dev = gai[i] - ga[i];
if (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE && (fabs(dev) > 1.0E-300)) {
bool useZeroed = true;
for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
if (dev < 0.0) {
if (FormulaMatrix[i][kspec] < 0.0) {
if (soln[kspec] > 0.0) {
useZeroed = false;
}
}
} else {
if (FormulaMatrix[i][kspec] > 0.0) {
if (soln[kspec] > 0.0) {
useZeroed = false;
}
}
}
}
for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
if (soln[kspec] > 0.0 || useZeroed) {
if (dev < 0.0) {
if (FormulaMatrix[i][kspec] < 0.0) {
double delta = dev / FormulaMatrix[i][kspec] ;
soln[kspec] += delta;
if (soln[kspec] < 0.0) {
soln[kspec] = 0.0;
}
vcs_elab();
break;
}
}
if (dev > 0.0) {
if (FormulaMatrix[i][kspec] > 0.0) {
double delta = dev / FormulaMatrix[i][kspec] ;
soln[kspec] += delta;
if (soln[kspec] < 0.0) {
soln[kspec] = 0.0;
}
vcs_elab();
break;
}
}
}
}
}
}
if (vcs_elabcheck(1)) {
retn = 1;
goto L_CLEANUP;
}
L_CLEANUP: ;
vcs_tmoles();
#ifdef DEBUG
l2after = 0.0;
for (i = 0; i < m_numElemConstraints; ++i) {
l2after += SQUARE(ga[i] - gai[i]);
}
l2after = sqrt(l2after/m_numElemConstraints);
if (vcs_debug_print_lvl >= 2) {
plogf(" --- Elem_Abund: Correct Initial "
" Final\n");
for (i = 0; i < m_numElemConstraints; ++i) {
plogf(" --- "); plogf("%-2.2s", ElName[i].c_str());
plogf(" %20.12E %20.12E %20.12E\n", gai[i], ga_save[i], ga[i]);
}
plogf(" --- Diff_Norm: %20.12E %20.12E\n",
l2before, l2after);
}
#endif
return retn;
} /* vcs_elcorr() ************************************************************/
}

View file

@ -0,0 +1,250 @@
/* $Author$
* $Date$
* $Revision$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
namespace VCSnonideal {
/*
* vcs_elem_rearrange:
*
* This subroutine handles the rearrangement of the constraint
* equations represented by the Formula Matrix. Rearrangement is only
* necessary when the number of components is less than the number of
* elements. For this case, some constraints can never be satisfied
* exactly, because the range space represented by the Formula
* Matrix of the components can't span the extra space. These
* constraints, which are out of the range space of the component
* Formula matrix entries, are migrated to the back of the Formula
* matrix.
*
* A prototypical example is an extra element column in
* FormulaMatrix[],
* which is identically zero. For example, let's say that argon is
* has an element column in FormulaMatrix[], but no species in the
* mechanism
* actually contains argon. Then, nc < ne. Also, without perturbation
* of FormulaMatrix[] vcs_basopt[] would produce a zero pivot
* because the matrix
* would be singular (unless the argon element column was already the
* last column of FormulaMatrix[].
* This routine borrows heavily from vcs_basopt's algorithm. It
* finds nc constraints which span the range space of the Component
* Formula matrix, and assigns them as the first nc components in the
* formular matrix. This guarrantees that vcs_basopt[] has a
* nonsingular matrix to invert.
*
* Other Variables
* aw[i] = Mole fraction work space (ne in length)
* sa[j] = Gramm-Schmidt orthog work space (ne in length)
* ss[j] = Gramm-Schmidt orthog work space (ne in length)
* sm[i+j*ne] = QR matrix work space (ne*ne in length)
*
*/
int VCS_SOLVE::vcs_elem_rearrange(double *aw, double *sa, double *sm,
double *ss) {
int j, k, l, i, jl, ml, jr, lindep, ielem;
int ncomponents = m_numComponents;
double test = -1.0E10;
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n");
plogf(" --- Subroutine elem_rearrange() called to ");
plogf("check stoich. coefficent matrix\n");
plogf(" --- and to rearrange the element ordering once\n");
}
#endif
/*
* Use a temporary work array for the element numbers
* Also make sure the value of test is unique.
*/
lindep = FALSE;
do {
lindep = FALSE;
for (i = 0; i < m_numElemConstraints; ++i) {
test -= 1.0;
aw[i] = gai[i];
if (test == aw[i]) lindep = TRUE;
}
} while (lindep);
/*
* Top of a loop of some sort based on the index JR. JR is the
* current number independent elements found.
*/
jr = -1;
do {
++jr;
/*
* Top of another loop point based on finding a linearly
* independent species
*/
do {
/*
* Search the remaining part of the mole fraction vector, AW,
* for the largest remaining species. Return its identity in K.
*/
k = m_numElemConstraints;
for (ielem = jr; ielem < m_numElemConstraints; ielem++) {
if (ElActive[ielem]) {
if (aw[ielem] != test) {
k = ielem;
break;
}
}
}
if (k == m_numElemConstraints) {
plogf("Shouldn't be here\n");
exit(-1);
}
/*
* Assign a large negative number to the element that we have
* just found, in order to take it out of further consideration.
*/
aw[k] = test;
/* *********************************************************** */
/* **** CHECK LINEAR INDEPENDENCE OF CURRENT FORMULA MATRIX */
/* **** LINE WITH PREVIOUS LINES OF THE FORMULA MATRIX ****** */
/* *********************************************************** */
/*
* Modified Gram-Schmidt Method, p. 202 Dalquist
* QR factorization of a matrix without row pivoting.
*/
jl = jr;
/*
* Fill in the row for the current element, k, under consideration
* The row will contain the Formula matrix value for that element
* from the current component.
*/
for (j = 0; j < ncomponents; ++j) {
sm[j + jr*ncomponents] = FormulaMatrix[k][j];
}
if (jl > 0) {
/*
* Compute the coefficients of JA column of the
* the upper triangular R matrix, SS(J) = R_J_JR
* (this is slightly different than Dalquist)
* R_JA_JA = 1
*/
for (j = 0; j < jl; ++j) {
ss[j] = 0.0;
for (i = 0; i < ncomponents; ++i) {
ss[j] += sm[i + jr*ncomponents] * sm[i + j*ncomponents];
}
ss[j] /= sa[j];
}
/*
* Now make the new column, (*,JR), orthogonal to the
* previous columns
*/
for (j = 0; j < jl; ++j) {
for (l = 0; l < ncomponents; ++l) {
sm[l + jr*ncomponents] -= ss[j] * sm[l + j*ncomponents];
}
}
}
/*
* Find the new length of the new column in Q.
* It will be used in the denominator in future row calcs.
*/
sa[jr] = 0.0;
for (ml = 0; ml < ncomponents; ++ml) {
sa[jr] += SQUARE(sm[ml + jr*ncomponents]);
}
/* **************************************************** */
/* **** IF NORM OF NEW ROW .LT. 1E-6 REJECT ********** */
/* **************************************************** */
if (sa[jr] < 1.0e-6) lindep = TRUE;
else lindep = FALSE;
} while(lindep);
/* ****************************************** */
/* **** REARRANGE THE DATA ****************** */
/* ****************************************** */
if (jr != k) {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf(" --- "); plogf("%-2.2s", (ElName[k]).c_str());
plogf("(%9.2g) replaces ", gai[k]);
plogf("%-2.2s", (ElName[jr]).c_str());
plogf("(%9.2g) as element %3d\n", gai[jr], jr);
}
#endif
vcs_switch_elem_pos(jr, k);
vcsUtil_dsw(aw, jr, k);
}
/*
* If we haven't found enough components, go back
* and find some more. (nc -1 is used below, because
* jr is counted from 0, via the C convention.
*/
} while (jr < (ncomponents-1));
return VCS_SUCCESS;
} /* vcs_elem_rearrange() ****************************************************/
// Swaps the indecises for all of the global data for two elements, ipos
// and jpos.
/*
* This function knows all of the element information with VCS_SOLVE, and
* can therefore switch element positions
*
* @param ipos first global element index
* @param jpos second global element index
*/
void VCS_SOLVE::vcs_switch_elem_pos(int ipos, int jpos) {
if (ipos == jpos) return;
int j;
double dtmp;
vcs_VolPhase *volPhase;
#ifdef DEBUG
if (ipos < 0 || ipos > (m_numElemConstraints - 1) ||
jpos < 0 || jpos > (m_numElemConstraints - 1) ) {
plogf("vcs_switch_elem_pos: ifunc = 0: inappropriate args: %d %d\n",
ipos, jpos);
}
#endif
/*
* Change the element Global Index list in each phase object
* to reflect the switch in the element positions.
*/
for (int iph = 0; iph < NPhase; iph++) {
volPhase = VPhaseList[iph];
for (int e = 0; e < volPhase->nElemConstraints; e++) {
if (volPhase->ElGlobalIndex[e] == ipos) {
volPhase->ElGlobalIndex[e] = jpos;
}
if (volPhase->ElGlobalIndex[e] == jpos) {
volPhase->ElGlobalIndex[e] =ipos;
}
}
}
vcsUtil_dsw(VCS_DATA_PTR(gai), ipos, jpos);
vcsUtil_dsw(VCS_DATA_PTR(ga), ipos, jpos);
vcsUtil_isw(VCS_DATA_PTR(IndEl), ipos, jpos);
vcsUtil_isw(VCS_DATA_PTR(m_elType), ipos, jpos);
vcsUtil_isw(VCS_DATA_PTR(ElActive), ipos, jpos);
for (j = 0; j < m_numSpeciesTot; ++j) {
SWAP(FormulaMatrix[ipos][j], FormulaMatrix[jpos][j], dtmp);
}
vcsUtil_stsw(ElName, ipos, jpos);
} /* vcs_switch_elem_pos() ***************************************************/
}

View file

@ -0,0 +1,64 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#define TOL_CONV 1.0E-5
namespace VCSnonideal {
/**************************************************************************
*
* vcs_funcVtot:
*
* This is the rootfinder function call for the function vcs_TV().
*
*/
double vcs_funcVtot(double xval, double Vtarget, int varID, void *fptrPassthrough, int *err)
{
VCS_SOLVE *vptr = (VCS_SOLVE *) fptrPassthrough;
static int first_time = TRUE;
int retn;
double vol;
if (varID == 0) {
vptr->T = xval;
} else if (varID == 1) {
vptr->Pres = xval;
}
#ifdef DEBUG
retn = vptr->vcs_TP(1, 1, 10000, vptr->T, vptr->Pres);
#else
retn = vptr->vcs_TP(0, 0, 10000, vptr->T, vptr->Pres);
#endif
if (retn != VCS_SUCCESS) {
plogf("vcs_funcVtot ERROR: vcs_TP returned error condition, %d\n",
retn);
*err = retn;
}
vol = vptr->vcs_VolTotal(vptr->T, vptr->Pres, VCS_DATA_PTR(vptr->soln),
VCS_DATA_PTR(vptr->VolPM));
#ifdef DEBUG
vptr->vcs_report(retn);
#endif
if (first_time) {
first_time = FALSE;
vptr->iest = FALSE;
}
return (vol - Vtarget);
}
/*****************************************************************************/
}

View file

@ -0,0 +1,509 @@
/**
* @file vcs_inest.cpp
* Methods for obtaining a good initial guess
*/
/* $Author$
* $Date$
* $Revision$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
namespace VCSnonideal {
static char pprefix[20] = " --- vcs_inest: ";
#ifdef ALTLINPROG
#else
extern int linprogmax(double *, double *, double *, double *, int, int, int);
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::inest(double *aw, double *sa, double *sm,
double *ss, double test)
/**************************************************************************
*
* inest:
*
* Estimates equilibrium compositions.
* Algorithm covered in a section of Smith and Missen's Book.
*
* Linear programming module is based on using dbolm.
***************************************************************************/
{
int conv, j, k, lt, ikl, kspec, iph, irxn, jj;
double s, s1, xl, par;
int finished;
int nspecies = m_numSpeciesTot;
int nrxn = m_numRxnTot;
vcs_VolPhase *Vphase = 0;
double *molNum = VCS_DATA_PTR(soln);
double TMolesMultiphase;
double *xtphMax = VCS_DATA_PTR(TmpPhase);
double *xtphMin = VCS_DATA_PTR(TmpPhase2);
ikl = 0;
lt = 0;
/*
* CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB
* AND molNum(I) .GE. 0.0
*
* Note, both of these programs do this.
*/
#ifdef ALTLINPROG
vcs_setMolesLinProg();
#else
std::vector<double> ax(ne*nspecies, 0.0);
std::vector<double> bb(ne, 0.0);
std::vector<double> cc(nspecies, 0.0);
int neActive = 0;
jj = 0;
for (j = 0; j < ne; j++) {
if (ElActive[j]) {
neActive++;
bb[jj] = gai[j];
jj++;
}
}
for (kspec = 0; kspec < nspecies; ++kspec) {
cc[kspec] = -ff[kspec];
jj = 0;
for (j = 0; j < ne; ++j) {
if (ElActive[j]) {
ax[jj + kspec * neActive] = FormulaMatrix[j][kspec];
jj++;
}
}
}
linprogmax(molNum, VCS_DATA_PTR(cc), VCS_DATA_PTR(ax),
VCS_DATA_PTR(bb), neActive, nspecies, neActive);
#endif
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n",
pprefix);
plogf("%s SPECIES MOLE_NUMBER -SS_ChemPotential\n", pprefix);
for (kspec = 0; kspec < nspecies; ++kspec) {
plogf("%s ", pprefix); plogf("%-12.12s", SpName[kspec].c_str());
plogf(" %15.5g %12.3g\n", molNum[kspec], -ff[kspec]);
}
plogf("%s Element Abundance Agreement returned from linear "
"programming (vcs_inest initial guess):\n",
pprefix);
plogf("%s Element Goal Actual\n", pprefix);
jj = 0;
for (j = 0; j < m_numElemConstraints; j++) {
if (ElActive[j]) {
double tmp = 0.0;
for (kspec = 0; kspec < nspecies; ++kspec) {
tmp += FormulaMatrix[j][kspec] * molNum[kspec];
}
plogf("%s ", pprefix); plogf(" %-9.9s", (ElName[j]).c_str());
plogf(" %12.3g %12.3g\n", gai[j], tmp);
jj++;
}
}
}
#endif
/*
* Make sure all species have positive definite mole numbers
* Set voltages to zero for now, until we figure out what to do
*/
vcs_dzero(VCS_DATA_PTR(ds), nspecies);
for (kspec = 0; kspec < nspecies; ++kspec) {
iph = PhaseID[kspec];
Vphase = VPhaseList[iph];
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
if (molNum[kspec] <= 0.0) {
/*
* HKM Should eventually include logic here for non SS phases
*/
if (!SSPhase[kspec]) {
molNum[kspec] = 1.0e-30;
}
}
} else {
molNum[kspec] = 0.0;
}
if (molNum[kspec] > 0.0) {
if (Vphase->Existence == 0) {
Vphase->Existence = 1;
}
} else if (SSPhase[kspec]) {
Vphase->Existence = 0;
}
}
/*
* Now find the optimized basis that spans the stoichiometric
* coefficient matrix
*/
(void) vcs_basopt(FALSE, aw, sa, sm, ss, test, &conv);
/* ***************************************************************** */
/* **** CALCULATE TOTAL GASEOUS AND LIQUID MOLES, ****************** */
/* **** CHEMICAL POTENTIALS OF BASIS ****************** */
/* ***************************************************************** */
/*
* Calculate TMoles and TPhMoles[]
*/
vcs_tmoles();
/*
* TPhMoles1[] will consist of just the component moles
*/
for (iph = 0; iph < NPhase; iph++) {
TPhMoles1[iph] = TPhInertMoles[iph] + 1.0E-20;
}
for (kspec = 0; kspec < m_numComponents; ++kspec) {
if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
TPhMoles1[PhaseID[kspec]] += molNum[kspec];
}
}
TMolesMultiphase = 0.0;
for (iph = 0; iph < NPhase; iph++) {
if (! VPhaseList[iph]->SingleSpecies) {
TMolesMultiphase += TPhMoles1[iph];
}
}
vcs_dcopy(VCS_DATA_PTR(wt), molNum, nspecies);
for (kspec = 0; kspec < m_numComponents; ++kspec) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_MOLNUM) {
wt[kspec] = 0.0;
}
}
vcs_dcopy(VCS_DATA_PTR(m_gibbsSpecies), VCS_DATA_PTR(ff), nspecies);
for (kspec = 0; kspec < m_numComponents; ++kspec) {
if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
if (! SSPhase[kspec]) {
iph = PhaseID[kspec];
m_gibbsSpecies[kspec] += log(wt[kspec] / TPhMoles[iph]);
}
} else {
wt[kspec] = 0.0;
}
}
vcs_deltag(0, true);
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
for (kspec = 0; kspec < nspecies; ++kspec) {
plogf("%s", pprefix); plogf("%-12.12s", SpName[kspec].c_str());
if (kspec < m_numComponents)
plogf("fe* = %15.5g ff = %15.5g\n", m_gibbsSpecies[kspec], ff[kspec]);
else
plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n",
m_gibbsSpecies[kspec], ff[kspec], dg[kspec-m_numComponents]);
}
}
#endif
/* ********************************************************** */
/* **** ESTIMATE REACTION ADJUSTMENTS *********************** */
/* ********************************************************** */
vcs_dzero(VCS_DATA_PTR(DelTPhMoles), NPhase);
for (iph = 0; iph < NPhase; iph++) {
xtphMax[iph] = log(TPhMoles1[iph] * 1.0E32);
xtphMin[iph] = log(TPhMoles1[iph] * 1.0E-32);
}
for (irxn = 0; irxn < nrxn; ++irxn) {
kspec = ir[irxn];
/*
* For single species phases, we will not estimate the
* mole numbers. If the phase exists, it stays. If it
* doesn't exist in the estimate, it doesn't come into
* existence here.
*/
if (! SSPhase[kspec]) {
iph = PhaseID[kspec];
if (dg[irxn] > xtphMax[iph]) dg[irxn] = 0.8 * xtphMax[iph];
if (dg[irxn] < xtphMin[iph]) dg[irxn] = 0.8 * xtphMin[iph];
/*
* HKM -> The TMolesMultiphase is a change of mine.
* It more evenly distributes the initial moles amongst
* multiple multispecies phases according to the
* relative values of the standard state free energies.
* There is no change for problems with one multispecies
* phase.
* It cut diamond4.vin iterations down from 62 to 14.
*/
ds[kspec] = 0.5 * (TPhMoles1[iph] + TMolesMultiphase)
* exp(-dg[irxn]);
for (k = 0; k < m_numComponents; ++k) {
ds[k] += sc[irxn][k] * ds[kspec];
}
for (iph = 0; iph < NPhase; iph++) {
DelTPhMoles[iph] += DnPhase[irxn][iph] * ds[kspec];
}
}
}
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
for (kspec = 0; kspec < nspecies; ++kspec) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
plogf("%sdirection (", pprefix); plogf("%-12.12s", SpName[kspec].c_str());
plogf(") = %g", ds[kspec]);
if (SSPhase[kspec]) {
if (molNum[kspec] > 0.0) {
plogf(" (ssPhase exists at w = %g moles)", molNum[kspec]);
} else {
plogf(" (ssPhase doesn't exist -> stability not checked)");
}
}
plogf("\n");
}
}
}
#endif
/* *********************************************************** */
/* **** KEEP COMPONENT SPECIES POSITIVE ********************** */
/* *********************************************************** */
par = 0.5;
for (kspec = 0; kspec < m_numComponents; ++kspec) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
if (par < -ds[kspec] / wt[kspec]) par = -ds[kspec] / wt[kspec];
}
}
par = 1. / par;
if (par <= 1.0 && par > 0.0) {
par *= 0.8;
} else {
par = 1.0;
}
/* ******************************************** */
/* **** CALCULATE NEW MOLE NUMBERS ************ */
/* ******************************************** */
finished = FALSE;
do {
for (kspec = 0; kspec < m_numComponents; ++kspec) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
molNum[kspec] = wt[kspec] + par * ds[kspec];
} else {
ds[kspec] = 0.0;
}
}
for (kspec = m_numComponents; kspec < nspecies; ++kspec) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
if (ds[kspec] != 0.0) molNum[kspec] = ds[kspec] * par;
}
}
/*
* We have a new w[] estimate, go get the
* TMoles and TPhMoles[] values
*/
vcs_tmoles();
if (lt > 0) goto finished;
/* ******************************************* */
/* **** CONVERGENCE FORCING SECTION ********** */
/* ******************************************* */
vcs_dfe(molNum, 0, 0, 0, nspecies);
for (kspec = 0, s = 0.0; kspec < nspecies; ++kspec) {
s += ds[kspec] * m_gibbsSpecies[kspec];
}
if (s == 0.0) {
finished = TRUE; continue;
}
if (s < 0.0) {
if (ikl <= 0) {
finished = TRUE; continue;
}
}
/* ***************************************** */
/* *** TRY HALF STEP SIZE ****************** */
/* ***************************************** */
if (ikl <= 0) {
s1 = s;
par *= 0.5;
ikl = 1;
continue;
}
/* **************************************************** */
/* **** FIT PARABOLA THROUGH HALF AND FULL STEPS ****** */
/* **************************************************** */
xl = (1.0 - s / (s1 - s)) * 0.5;
if (xl < 0.0) {
/* *************************************************** */
/* *** POOR DIRECTION, REDUCE STEP SIZE TO 0.2 ******* */
/* *************************************************** */
par *= 0.2;
} else {
if (xl > 1.0) {
/* *************************************************** */
/* **** TOO BIG A STEP, TAKE ORIGINAL FULL STEP ****** */
/* *************************************************** */
par *= 2.0;
} else {
/* *************************************************** */
/* **** ACCEPT RESULTS OF FORCER ********************* */
/* *************************************************** */
par = par * 2.0 * xl;
}
}
lt = 1;
} while (!finished);
finished:
;
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("%s Final Mole Numbers produced by inest:\n",
pprefix);
plogf("%s SPECIES MOLE_NUMBER\n", pprefix);
for (kspec = 0; kspec < nspecies; ++kspec) {
plogf("%s ", pprefix); plogf("%-12.12s", SpName[kspec].c_str());
plogf(" %g\n", molNum[kspec]);
}
}
#endif
} /* inest() *****************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_inest_TP(void)
/**************************************************************************
*
* vcs_inest_TP:
*
* Create an initial estimate of the solution to the thermodynamic
* equilibrium problem.
*
* Return value:
*
* 0: successful initial guess
* -1: Unsuccessful initial guess, the elemental abundances aren't
* satisfied.
***************************************************************************/
{
int retn = 0;
double test;
double tsecond = vcs_second();
test = -1.0E20;
/*
* Malloc temporary space for usage in this routine and in
* subroutines
* sm[ne*ne]
* ss[ne]
* sa[ne]
* aw[m]
*/
std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0);
std::vector<double> ss(m_numElemConstraints, 0.0);
std::vector<double> sa(m_numElemConstraints, 0.0);
std::vector<double> aw(m_numSpeciesTot+ m_numElemConstraints, 0.0);
/*
* Go get the estimate of the solution
*/
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("%sGo find an initial estimate for the equilibrium problem\n",
pprefix);
}
#endif
inest(VCS_DATA_PTR(aw), VCS_DATA_PTR(sa), VCS_DATA_PTR(sm),
VCS_DATA_PTR(ss), test);
/*
* Calculate the elemental abundances
*/
vcs_elab();
/*
* If we still fail to achieve the correct elemental abundances,
* try to fix the problem again by calling the main elemental abundances
* fixer routine, used in the main program. What this does, is that it
* attempts to tweak the mole numbers of the component species to
* satisfy the element abundance constraints.
*
* Note: We won't do this unless we have to since it involves inverting
* a matrix.
*/
int rangeCheck = vcs_elabcheck(1);
if (!vcs_elabcheck(0)) {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("%sInitial guess failed element abundances\n", pprefix);
plogf("%sCall vcs_elcorr to attempt fix\n", pprefix);
}
#endif
vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(aw));
rangeCheck = vcs_elabcheck(1);
if (!vcs_elabcheck(0)) {
plogf("%sInitial guess still fails element abundance equations\n",
pprefix);
plogf("%s - Inability to ever satisfy element abundance "
"constraints is probable\n", pprefix);
retn = -1;
} else {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
if (rangeCheck) {
plogf("%sInitial guess now satisfies element abundances\n", pprefix);
} else {
plogf("%sElement Abundances RANGE ERROR\n", pprefix);
plogf("%s - Initial guess satisfies NC=%d element abundances, "
"BUT not NE=%d element abundances\n", pprefix,
m_numComponents, m_numElemConstraints);
}
}
#endif
}
}
else {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
if (rangeCheck) {
plogf("%sInitial guess satisfies element abundances\n", pprefix);
} else {
plogf("%sElement Abundances RANGE ERROR\n", pprefix);
plogf("%s - Initial guess satisfies NC=%d element abundances, "
"BUT not NE=%d element abundances\n", pprefix,
m_numComponents, m_numElemConstraints);
}
}
#endif
}
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E\n", pprefix,
vcs_Total_Gibbs(VCS_DATA_PTR(soln), VCS_DATA_PTR(m_gibbsSpecies),
VCS_DATA_PTR(TPhMoles)));
}
#endif
/*
* Free malloced memory
*/
tsecond = vcs_second() - tsecond;
m_VCount->T_Time_inest += tsecond;
(m_VCount->T_Calls_Inest)++;
return retn;
}/**** vcs_inest() ***********************************************************/
}

View file

@ -0,0 +1,183 @@
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef _VCS_INTERNAL_H
#define _VCS_INTERNAL_H
#include "vcs_defs.h"
#include "vcs_DoubleStarStar.h"
#include "vcs_Exception.h"
#include "global.h"
namespace VCSnonideal {
//! Points to the data in a std::vector<> object
#define VCS_DATA_PTR(vvv) (&(vvv[0]))
//! define this Cantera function to replace printf
/*!
* We can replace this with printf easily
*/
#define plogf Cantera::writelogf
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/************ ERROR HANDLING *****************/
struct VCS_ERR {
int Flag;
int Species1;
int Species2;
int PrintLevel;
double Value1;
double Value2;
char Mess[120];
};
typedef struct VCS_ERR VCS_ERR_STRUCT;
extern int vcsUtil_err_check(VCS_ERR_STRUCT &vcsE, char *string1, int ival);
extern void vcsUtil_err_reset(VCS_ERR_STRUCT &vcsE);
/*********************************/
/* Function Pointer Typedefs */
/*********************************/
typedef double (*VCS_FUNC_PTR)(double, double, int, void *, int *);
/*
* Forward references
*/
class VCS_SPECIES_THERMO;
class VCS_PROB;
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
//! Amount of extra printing that is done while in debug mode.
/*!
* 0 -> none
* 1 -> some
* 2 -> alot (default)
* 3 -> everything
*/
class VCS_COUNTERS {
public:
int T_Its; /* Total number of iterations in the main loop
of vcs_TP() to solve for thermo equilibrium */
int Its; /* Current number of iterations in the main loop
of vcs_TP() to solve for thermo equilibrium */
int T_Basis_Opts; /* Total number of optimizations of the
components basis set done */
int Basis_Opts; /* Total number of optimizations of the
components basis set done */
int T_Calls_Inest; /* Current number of times the initial thermo
equilibrium estimator has been called */
int T_Calls_vcs_TP; /* Current number of calls to vcs_TP */
double T_Time_vcs_TP; /* Total time spent in vcs_TP */
double Time_vcs_TP; /* Current time spent in vcs_TP */
double T_Time_basopt; /* Total Time spent in basopt () */
double Time_basopt; /* Current Time spent in basopt () */
double T_Time_inest; /* Time spent in initial estimator */
double T_Time_vcs; /* Time spent in the vcs suite of programs */
};
/*****************************************************************************/
/**************** Prototypes *************************************************/
/*****************************************************************************/
/* Externals for vcs_funcVtot.c */
extern double vcs_funcVtot(double, double, int, void *, int *);
/* Externals defined in vcs_nondim.c */
extern double vcsUtil_gasConstant(int);
/* Externals in vcs_solve_TP.c */
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<std::string> & vecStrings, int, int);
/* Externals for vcs_root1d.c */
extern int vcsUtil_root1d(double, double, int, VCS_FUNC_PTR , void *,
double , int, double *);
/* Externals defined in vcs_timer_generic.c */
extern double vcs_second(void);
/* Externals defined in vcs_util.c */
#define USE_MEMSET
#ifdef USE_MEMSET
#include <string.h>
# 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))
# define vcs_vizero(vector, length) (void) memset(VCS_DATA_PTR(vector), 0, \
(length) * sizeof(int))
inline void vcs_vdcopy(std::vector<double> & vec_to,
const std::vector<double> & vec_from, int length) {
(void) memcpy((void *)&(vec_to[0]), (const void *) &(vec_from[0]),
(length) * sizeof(double));
}
inline void vcs_vicopy(std::vector<int> & vec_to,
const std::vector<int> & vec_from, int length) {
(void) memcpy((void *)&(vec_to[0]), (const void *) &(vec_from[0]),
(length) * sizeof(int));
}
#else
extern void vcs_dzero(double *, int);
extern void vcs_izero(int *, int);
extern void vcs_dcopy(double *, double *, int);
extern void vcs_icopy(int *, int *, int);
extern void vcs_vdzero(std::vector<double> &vvv, int len = -1);
extern void vcs_vizero(std::vector<double> &vvv, int len = -1);
void vcs_vdcopy(std::vector<double> &vec_to,
const std::vector<double> vec_from, int len = -1);
void vcs_vicopy(std::vector<int> &vec_to,
const std::vector<int> vec_from, int len = -1);
#endif
extern int vcs_amax(double *, int, int);
extern int vcs_max_int(int *, int);
extern void vcs_print_line(const char *, int);
extern void vcs_print_stringTrunc(const char *, int, int);
extern bool vcs_doubleEqual(double, double);
/****************************************************************************/
}
#endif
/****************************************************************************/

View file

@ -0,0 +1,146 @@
/* $Author$
* $Date$
* $Revision$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef hpux
#define dbocls_ dbocls
#endif
#ifdef DEBUG
//extern int vcs_debug_print_lvl;
#endif
extern "C" void dbocls_(double *W, int *MDW, int *MCON, int *MROWS,
int *NCOLS,
double *BL, double *BU, int *IND, int *IOPT,
double *X, double *RNORMC, double *RNORM,
int *MODE, double *RW, int *IW);
/*****************************************************************************
* This whole program is a wrapper for the slatec routine, DBOCLS()
* DBOCLS solves a bounded and constrained least squares problem.
******************************************************************************/
int linprogmax(double *XMOLES, double *CC, double *AX, double *BB,
int NE, int M, int NE0)
/*-----------------------------------------------------------------------
* Find XMOLES(I), i = 1, M such that
* Maximize CC dot W, subject to the NE constraints:
*
* [AX] [XMOLES] = [BB]
* and XMOLES(i) > 0
*
* Input
* ---------
* AX(NE, M) - matrix of constraints AX(I,J) = ax(i + j*ne0)
* BB(NE) - contraint values
* CC(M) - Vector of "Good Values" to maximize
*
* Output
* ---------
* XMOLES(M) - optimal value of XMOLES()
*----------------------------------------------------------------------*/
{
int MROWS, MCON, NCOLS, NX, NI, MDW, i, j, MODE;
double sum, F[1], RNORMC, RNORM, *W, *BL, *BU, *RW, *X;
int *IND, *IW, *IOPT;
MROWS = 1;
MCON = NE;
NCOLS = M;
MDW = MCON + NCOLS;
NX = 0;
NI = 0;
sum = 0.0;
for (i = 0; i < M; i++) {
sum += fabs(CC[i]);
}
F[0] = sum * 1000.;
if (F[0] <= 0.0) F[0] = 1000.;
BL = (double *) malloc(2*(NCOLS+MCON) * sizeof(double));
BU = BL + (NCOLS+MCON);
IND = (int *) malloc((NCOLS+MCON) * sizeof(int));
RW = (double *) malloc((6*NCOLS + 5*MCON) * sizeof(double));
IW = (int *) malloc((2*NCOLS + 2*MCON) * sizeof(int));
IOPT = (int *) malloc((17 + NI) * sizeof(int));
X = (double *) malloc((2*(NCOLS+MCON) + 2 + NX) * sizeof(double));
W = (double *) malloc((MDW*(NCOLS+MCON+1)) * sizeof(double));
if (W == NULL) {
plogf("linproxmax ERROR: can not malloc memory of size %d bytes\n",
(int) ((MDW*(NCOLS+MCON+1)) * sizeof(double)));
if (BL != NULL) free((void *) BL);
if (IND != NULL) free((void *) IND);
if (RW != NULL) free((void *) RW);
if (IW != NULL) free((void *) IW);
if (IOPT != NULL) free((void *) IOPT);
if (W != NULL) free((void *) W);
return -1;
}
for (j = 0; j < MCON; j++) {
for (i = 0; i < NCOLS; i++) {
W[j + i*MDW] = AX[j + i*NE0];
}
}
for (i = 0; i < NCOLS; i++) {
W[MCON + i*MDW] = CC[i];
}
W[MCON + (NCOLS)*MDW] = F[0];
IOPT[0] = 99;
for (j = 0; j < NCOLS; j++) {
IND[j] = 1;
BL[j] = 0.0;
BU[j] = 1.0e200;
}
for (j = 0; j < MCON; j++) {
IND[j + NCOLS] = 3;
BL[j + NCOLS] = BB[j];
BU[j + NCOLS] = BL[j + NCOLS];
}
dbocls_(W, &MDW, &MCON, &MROWS, &NCOLS, BL, BU, IND, IOPT,
X, &RNORMC, &RNORM, &MODE, RW, IW);
if (MODE != 0) {
plogf("Return from DBOCLS was not normal, MODE = %d\n", MODE);
plogf(" refer to subroutine DBOCLS for resolution\n");
plogf(" RNORMC = %g\n", RNORMC);
}
for (j = 0; j < NCOLS; j++) {
XMOLES[j] = X[j];
}
#ifdef DEBUG
//sum = 0.0;
//for (j = 0; j < NCOLS; j++) {
// sum += XMOLES[j] * CC[j];
//}
//if (vcs_debug_print_lvl >= 2) {
// plogf(" -- linmaxc: Final Maximized Value = %g\n", sum);
//}
#endif
free((void *)W);
free((void *)BL);
free((void *)IND);
free((void *)RW);
free((void *)IW);
free((void *)IOPT);
free((void *)X);
return 0;
}

View file

@ -0,0 +1,412 @@
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "vcs_defs.h"
#include "vcs_nasa_poly.h"
#include "vcs_species_thermo.h"
#include "vcs_internal.h"
namespace VCSnonideal {
/******************************************************************************
*
* Constructor
*/
VCS_NASA_POLY::VCS_NASA_POLY(int numTempRegions, int numEl) :
NumTempRegions(numTempRegions),
NumEl(numEl),
PhType(' ')
{
Date[0] = '\0';
SpName[0] = '\0';
PhName[0] = '\0';
ElName.resize(numEl, "");
ElComp.resize(numEl, 0.0);
if (NumTempRegions < 1) NumTempRegions = 1;
Tlimits.resize(NumTempRegions+1, 0.0);
Acoeff.resize(NumTempRegions, 7, 0.0);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
VCS_NASA_POLY *vcs_nasa_poly_create(int numTempRegions, int numEl)
/**************************************************************************
*
* vcs_nasa_poly_create:
*
* Constructor routine for the nasa polynomial structure.
* It initializes all data to zero. The number of temperature regions
* malloced is storred within the structure itself.
*
* Input
* numTempRegions: Number of temperature regions
*
* Return
* Pointer to the newly malloced structure.
* If NULL, then an out of memory condition occurred
***************************************************************************/
{
VCS_NASA_POLY *poly_ptr;
poly_ptr = new VCS_NASA_POLY(numTempRegions, numEl);
return poly_ptr;
}
/***************************************************************************
* Copy Constructor
*/
VCS_NASA_POLY::VCS_NASA_POLY(const VCS_NASA_POLY &b) :
NumTempRegions(0),
NumEl(0)
{
*this = b;
}
/******************************************************************************
*
* operator=()
*
*/
VCS_NASA_POLY& VCS_NASA_POLY::operator=(const VCS_NASA_POLY &b) {
if (&b != this) {
NumTempRegions = b.NumTempRegions;
Tlimits = b.Tlimits;
Acoeff = b.Acoeff;
NumEl = b.NumEl;
ElComp = b.ElComp;
ElName = b.ElName;
strcpy(Date, b.Date);
PhType = b.PhType;
strcpy(SpName, b.SpName);
strcpy(PhName, b.PhName);
}
return *this;
}
/*****************************************************************************
*
* ~VCS_NASA_POLY():
*
* Destructor for class
*/
VCS_NASA_POLY::~VCS_NASA_POLY() {
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void vcs_nasa_poly_destroy(VCS_NASA_POLY **poly_hdl)
/**************************************************************************
*
* vcs_nasa_poly_destroy:
*
* Destructor routine for the nasa polynomial structure.
*************************************************************************/
{
VCS_NASA_POLY *poly_ptr = *poly_hdl;
if (poly_ptr) {
delete poly_ptr;
poly_ptr = 0;
}
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double vcs_G0_NASA(double TKelvin, VCS_NASA_POLY *poly_ptr)
/**************************************************************************
*
* vcs_GibbsFE_NASA:
*
* Calculate the Gibbs free energy (in Kelvin) for a single species
* using the Nasa polynomial format.
*
* Input
* TKelvin = Temperature in Kelvin.
* poly_ptr = Pointer to structure containing the NASA Polynomial
* coefficients
*
* Return
* gibbsFE = Gibbs free energy / R -> units of kelvin
*
* Error Conditions
* VCS_THERMO_OUTOFRANGE:
* If the input temperature, is out of range of the polynomials,
* an error Flag is set, and the temperature is storred in the
* error structure.
***************************************************************************/
{
int iRegion;
double *a, gibbsFE;
double *Tlim = VCS_DATA_PTR(poly_ptr->Tlimits);
static double Tsave = -10., C0, C1, C2, C3, C4, C5;
//extern CPC_ERR_STRUCT cpcE;
/*
* Find the temperature region
*/
if (TKelvin <= *Tlim) {
#ifdef DEBUG
plogf("vcs_G0_NASA error: TKelvin below lowest bounds %g\n", *Tlim);
#endif
iRegion = 0;
if (TKelvin <= 0.0) {
gibbsFE = poly_ptr->Acoeff[0][5];
return gibbsFE;
}
goto L_FOUNDREGION;
}
for (iRegion = 0; iRegion < poly_ptr->NumTempRegions; iRegion++) {
Tlim++;
if (TKelvin <= *Tlim) goto L_FOUNDREGION;
}
#ifdef DEBUG
plogf("vcs_G0_NASA error: TKelvin above highest bounds %g\n", *(Tlim));
#endif
iRegion--;
L_FOUNDREGION:;
a = poly_ptr->Acoeff[iRegion];
if (Tsave != TKelvin) {
Tsave = TKelvin;
C0 = 1.0 - log(TKelvin);
C1 = TKelvin * 0.5;
C2 = TKelvin * TKelvin;
C3 = C2 * TKelvin;
C4 = C3 * TKelvin;
C2 /= 6.0;
C3 /= 12.0;
C4 /= 20.0;
C5 = 1.0 / TKelvin;
}
gibbsFE = a[0]*C0 - a[1]*C1 - a[2]*C2 - a[3]*C3 - a[4]*C4 + a[5]*C5 - a[6];
gibbsFE *= TKelvin;
return gibbsFE;
} /***************************************************************************/
double vcs_H0_NASA(double TKelvin, VCS_NASA_POLY *poly_ptr)
/**************************************************************************
*
* vcs_H0_NASA:
*
* Calculate the standard state Enthalpy (in Kelvin) for a single species
* using the Nasa polynomial format.
*
* Input
* TKelvin = Temperature in Kelvin.
* poly_ptr = Pointer to structure containing the NASA Polynomial
* coefficients
*
* Return
* H0 = Standard State Enthalpy / R -> units of kelvin
*
* Error Conditions
* VCS_THERMO_OUTOFRANGE:
* If the input temperature, is out of range of the polynomials,
* an error Flag is set, and the temperature is storred in the
* error structure.
***************************************************************************/
{
int iRegion;
double *a, H0;
double *Tlim = VCS_DATA_PTR(poly_ptr->Tlimits);
static double Tsave = -10., C1, C2, C3, C4, C5;
/*
* Find the temperature region
*/
if (TKelvin <= *Tlim) {
#ifdef DEBUG
plogf("vcs_H0_NASA error: TKelvin below lowest bounds\n");
#endif
iRegion = 0;
if (TKelvin <= 0.0) {
H0 = poly_ptr->Acoeff[0][6];
return H0;
}
goto L_FOUNDREGION;
}
for (iRegion = 0; iRegion < poly_ptr->NumTempRegions; iRegion++) {
Tlim++;
if (TKelvin <= *Tlim) goto L_FOUNDREGION;
}
#ifdef DEBUG
plogf("vcs_H0_NASA error: TKelvin above highest bounds\n");
#endif
iRegion--;
L_FOUNDREGION:;
a = poly_ptr->Acoeff[iRegion];
if (Tsave != TKelvin) {
Tsave = TKelvin;
C1 = TKelvin * 0.5;
C2 = TKelvin * TKelvin;
C3 = C2 * TKelvin;
C4 = C3 * TKelvin;
C2 /= 3.0;
C3 /= 4.0;
C4 /= 5.0;
C5 = 1.0 / TKelvin;
}
H0 = a[0] + a[1]*C1 + a[2]*C2 + a[3]*C3 + a[4]*C4 + a[5]*C5;
return H0;
} /***************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double vcs_Cp0_NASA(double TKelvin, VCS_NASA_POLY *poly_ptr)
/**************************************************************************
*
* vcs_Cp0_NASA:
*
* Calculate the standard state Heat Capacity at constant pressure
* (in Kelvin) for a single species using the Nasa polynomial format.
*
* Input
* TKelvin = Temperature in Kelvin.
* poly_ptr = Pointer to structure containing the NASA Polynomial
* coefficients
*
* Return
* Cp0 = Heat Capacity at constant Pressure / R -> dimensionless
*
* Error Conditions
* VCS_THERMO_OUTOFRANGE:
* If the input temperature, is out of range of the polynomials,
* an error Flag is set, and the temperature is storred in the
* error structure.
***************************************************************************/
{
int iRegion;
double *a, Cp0;
double *Tlim = VCS_DATA_PTR(poly_ptr->Tlimits);
static double Tsave = -10., C2, C3, C4;
/*
* Find the temperature region
*/
if (TKelvin <= *Tlim) {
#ifdef DEBUG
plogf("vcs_Cp0_NASA error: TKelvin below lowest bounds\n");
#endif
iRegion = 0;
if (TKelvin <= 0.0) {
Cp0 = poly_ptr->Acoeff[0][0];
return Cp0;
}
goto L_FOUNDREGION;
}
for (iRegion = 0; iRegion < poly_ptr->NumTempRegions; iRegion++) {
Tlim++;
if (TKelvin <= *Tlim) goto L_FOUNDREGION;
}
#ifdef DEBUG
plogf("vcs_Cp0_NASA error: TKelvin above highest bounds\n");
#endif
iRegion--;
L_FOUNDREGION:;
a = poly_ptr->Acoeff[iRegion];
if (Tsave != TKelvin) {
Tsave = TKelvin;
C2 = TKelvin * TKelvin;
C3 = C2 * TKelvin;
C4 = C3 * TKelvin;
}
Cp0 = a[0] + a[1]*TKelvin + a[2]*C2 + a[3]*C3 + a[4]*C4;
return Cp0;
} /***************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double vcs_S0_NASA(double TKelvin, VCS_NASA_POLY *poly_ptr)
/**************************************************************************
*
* vcs_S0_NASA:
*
* Calculates the standard state Entropy (in Kelvin) for a single species
* using the Nasa polynomial format.
*
* Input
* TKelvin = Temperature in Kelvin.
* poly_ptr = Pointer to structure containing the NASA Polynomial
* coefficients
*
* Return
* S0 = Standard State Entropy / R -> unitless
*
* Error Conditions
* VCS_THERMO_OUTOFRANGE:
* If the input temperature, is out of range of the polynomials,
* an error Flag is set, and the temperature is storred in the
* error structure.
***************************************************************************/
{
int iRegion;
double *a, S0;
double *Tlim = VCS_DATA_PTR(poly_ptr->Tlimits);
static double Tsave = -10., C0, C2, C3, C4;
/*
* Find the temperature region
*/
if (TKelvin <= *Tlim) {
#ifdef DEBUG
plogf("vcs_S0_NASA error: TKelvin below lowest bounds\n");
#endif
iRegion = 0;
if (TKelvin <= 0.0) {
S0 = 0.0;
return S0;
}
goto L_FOUNDREGION;
}
for (iRegion = 0; iRegion < poly_ptr->NumTempRegions; iRegion++) {
Tlim++;
if (TKelvin <= *Tlim) goto L_FOUNDREGION;
}
#ifdef DEBUG
plogf("vcs_S0_NASA error: TKelvin above highest bounds\n");
#endif
iRegion--;
L_FOUNDREGION:;
a = poly_ptr->Acoeff[iRegion];
if (Tsave != TKelvin) {
Tsave = TKelvin;
C0 = log(TKelvin);
C2 = TKelvin * TKelvin;
C3 = C2 * TKelvin;
C4 = C3 * TKelvin;
C2 /= 2.0;
C3 /= 3.0;
C4 /= 4.0;
}
S0 = a[0]*C0 + a[1]*TKelvin + a[2]*C2 + a[3]*C3 + a[4]*C4 + a[7];
return S0;
} /***************************************************************************/
}

View file

@ -0,0 +1,89 @@
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef VCS_NASA_POLY_H
#define VCS_NASA_POLY_H
#include <string>
#include <vector>
#include "vcs_DoubleStarStar.h"
namespace VCSnonideal {
/*
* NASA Polynomial Form for Standard state Thermo Functions.
*
*
* NumberTempRegions
* Number of temperature regions in the fits:
* Must be greater or equal to one.
*
* Tlimits[NumberTempRegions+1]:
* Temperature limits of the regions. At the intersection of
* the regions, the polynomial formulas are suppose to be
* C1 continuous.
* To Locate Region i for current temperature, TKelvin:
* Tlimits[i] <= TKelvin < Tlimits[i+1]
*
* Acoeff[NumberTempRegions][7]
* Coefficients for calculation of the standard state thermodynamic
* functions.
*
* double *a;
* for i such that Tlimits[i] <= T < Tlimits[i+1]:
* a = Acoeff[i];
*
* C_p/R = a[0] + a[1]*T + a[2] * T^2 + a[3] * T^3 + a[4] * T^4
*
* H/RT = a[0] + a[1]/2*T + a[2]/3 * T^2 + a[3]/4 * T^3 + a[4]/5 * T^4
* + a[5]/T
*
* S/R = a[0] * log(T) + a[1] * T + a[2]/2 * T^2 + a[3]/3 * T^3
* + a[4]/4 * T^4 + a[6]
*
*/
class VCS_NASA_POLY {
public:
VCS_NASA_POLY(int, int);
VCS_NASA_POLY(const VCS_NASA_POLY &b);
VCS_NASA_POLY& operator=(const VCS_NASA_POLY &);
~VCS_NASA_POLY();
int NumTempRegions;
/* Vector Of Temperature Limits -> One More Than
The Number Of Regions */
std::vector<double> Tlimits;
DoubleStarStar Acoeff;
int NumEl;
std::vector<double> ElComp;
std::vector<std::string> ElName;
char Date[12];
char PhType;
char SpName[24];
char PhName[24];
};
/* Externals for vcs_nasa_poly.c */
extern VCS_NASA_POLY *vcs_nasa_poly_create(int, int);
extern void vcs_nasa_poly_free(VCS_NASA_POLY *);
extern void vcs_nasa_poly_destroy(VCS_NASA_POLY **);;
extern double vcs_G0_NASA(double, VCS_NASA_POLY *);
extern double vcs_H0_NASA(double, VCS_NASA_POLY *);
extern double vcs_Cp0_NASA(double, VCS_NASA_POLY *);
extern double vcs_S0_NASA(double, VCS_NASA_POLY *);
}
#endif

View file

@ -0,0 +1,222 @@
/*=======================================================================
* --------------------------------------------------
* | CVS Head Information on zuzax.pchem.sandia.gov |
* --------------------------------------------------
* $RCSfile$
* $Author$
* $Date$
* $Revision$
*======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
namespace VCSnonideal {
/**************************************************************************
*
* vcs_nondimMult:
*
* Returns the multiplier for the nondimensionalization of the equations
* (this is basically equal to RT)
**************************************************************************/
double VCS_SOLVE::vcs_nondim_Farad(int mu_units, double TKelvin)
{
double Farad;
if (TKelvin <= 0.0) TKelvin = 293.15;
switch (mu_units) {
case VCS_UNITS_MKS:
case VCS_UNITS_KJMOL:
case VCS_UNITS_KCALMOL:
Farad = 1.602E-19 * 6.022136736e26/ (TKelvin * 8.314472E3);
break;
case VCS_UNITS_UNITLESS:
Farad = 1.602E-19 * 6.022136736e26;
break;
case VCS_UNITS_KELVIN:
Farad = 1.602E-19 * 6.022136736e26/ (TKelvin);
break;
default:
plogf("vcs_nondim_Farad error: unknown units: %d\n", mu_units);
exit(-1);
}
return Farad;
}
double VCS_SOLVE::vcs_nondimMult_TP(int mu_units, double TKelvin)
{
double rt;
if (TKelvin <= 0.0) TKelvin = 293.15;
switch (mu_units) {
case VCS_UNITS_KCALMOL:
rt = TKelvin * 8.314472E-3 / 4.184;
break;
case VCS_UNITS_UNITLESS:
rt = 1.0;
break;
case VCS_UNITS_KJMOL:
rt = TKelvin * 0.008314472;
break;
case VCS_UNITS_KELVIN:
rt = TKelvin;
break;
case VCS_UNITS_MKS:
rt = TKelvin * 8.314472E3;
break;
default:
plogf("vcs_nondimMult_TP error: unknown units: %d\n", mu_units);
exit(-1);
}
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:
* Nondimensionalize the problem data:
* ->nondimensionalize the free energies using
* the divisor, R * T
*
*
* HKM -> I don't think we need to modify the mole nubmers by 1E3 for the
* case of MKS units. However, what we need to do is to add a scale
* factor so that the number of moles or kmoles is ~ 1.0. Many of the
* algorithms rely on this I think in a subtle way. This is the perfect
* place to add this in.
**************************************************************************/
void VCS_SOLVE::vcs_nondim_TP(void) {
int i;
double tf;
if (UnitsState == VCS_DIMENSIONAL_G) {
UnitsState = VCS_NONDIMENSIONAL_G;
tf = 1.0 / vcs_nondimMult_TP(m_VCS_UnitsFormat, T);
for (i = 0; i < m_numSpeciesTot; ++i) {
/*
* Modify the standard state and total chemical potential data,
* FF(I), to make it dimensionless, i.e., mu / RT.
* Thus, we may divide it by the temperature.
*/
ff[i] *= tf;
m_gibbsSpecies[i] *= tf;
dg[i] *= tf;
dgl[i] *= tf;
fel[i] *= tf;
}
Faraday_dim = vcs_nondim_Farad(m_VCS_UnitsFormat, T);
if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
for (i = 0; i < m_numSpeciesTot; ++i) {
if (SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
soln[i] *= 1.0E3;
}
}
for (i = 0; i < m_numElemConstraints; ++i) {
gai[i] *= 1.0E3;
}
}
}
} /* vcs_nondim_TP() *********************************************************/
/**************************************************************************
*
* vcs_nondim_TP:
* Redimensionalize the problem data:
* ->redimensionalize the free energies using the reverse
* of vcs_nondim_TP
**************************************************************************/
void VCS_SOLVE::vcs_redim_TP(void)
{
int i;
double tf;
if (UnitsState != VCS_DIMENSIONAL_G) {
UnitsState = VCS_DIMENSIONAL_G;
tf = vcs_nondimMult_TP(m_VCS_UnitsFormat, T);
for (i = 0; i < m_numSpeciesTot; ++i) {
/*
* Modify the standard state and total chemical potential data,
* FF(I), to make it have units, i.e. mu = RT * mu_star
*/
ff[i] *= tf;
m_gibbsSpecies[i] *= tf;
dg[i] *= tf;
dgl[i] *= tf;
fel[i] *= tf;
}
Faraday_dim *= tf;
}
if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
for (i = 0; i < m_numSpeciesTot; ++i) {
if (SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
soln[i] /= 1.0E3;
}
}
for (i = 0; i < m_numElemConstraints; ++i) {
gai[i] /= 1.0E3;
}
}
} /* vcs_redim_TP() **********************************************************/
void VCS_SOLVE::vcs_printChemPotUnits(int unitsFormat) {
switch(unitsFormat) {
case VCS_UNITS_KCALMOL:
plogf("kcal/gmol");
break;
case VCS_UNITS_UNITLESS:
plogf("dimensionless");
break;
case VCS_UNITS_KJMOL:
plogf("kJ/gmol");
break;
case VCS_UNITS_KELVIN:
plogf("Kelvin");
break;
case VCS_UNITS_MKS:
plogf("J/kmol");
break;
default:
plogf("unknown units!");
exit(-1);
}
}
}

View file

@ -0,0 +1,308 @@
/**
* @file vcs_prep.cpp
* This file contains some prepatory functions.
*/
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_prob.h"
#include "vcs_VolPhase.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::vcs_SSPhase(void)
/**************************************************************************
*
* vcs_SSPhase:
*
* Calculate the status of single species phases.
*
*************************************************************************/
{
int kspec, iph;
vcs_VolPhase *Vphase;
std::vector<int> numPhSpecies(NPhase, 0);
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
numPhSpecies[PhaseID[kspec]]++;
}
/*
* Handle the special case of a single species in a phase that
* has been earmarked as a multispecies phase.
* Treat that species as a single-species phase
*/
for (iph = 0; iph < NPhase; iph++) {
Vphase = VPhaseList[iph];
Vphase->SingleSpecies = false;
if (TPhInertMoles[iph] > 0.0) {
Vphase->Existence = 2;
}
if (numPhSpecies[iph] <= 1) {
if (TPhInertMoles[iph] == 0.0) {
Vphase->SingleSpecies = true;
}
}
Vphase->NVolSpecies = numPhSpecies[iph];
}
/*
* Fill in some useful arrays here that have to do with the
* static information concerning the phase ID of species.
* SSPhase = Boolean indicating whether a species is in a
* single species phase or not.
*/
for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
iph = PhaseID[kspec];
Vphase = VPhaseList[iph];
if (Vphase->SingleSpecies) SSPhase[kspec] = TRUE;
else SSPhase[kspec] = FALSE;
}
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_prep_oneTime(int printLvl)
/**************************************************************************
*
* vcs_prep_oneTime:
*
* This routine is mostly concerned with changing the private data
* to be consistent with what's needed for solution. It is called one
* time for each new problem structure definition.
*
* This routine is always followed by vcs_prep(). Therefore, tasks
* that need to be done for every call to vcsc() should be placed in
* vcs_prep() and not in this routine.
*
* The problem structure refers to:
*
* the number and identity of the species.
* the formula matrix and thus the number of components.
* the number and identity of the phases.
* the equation of state
* the method and parameters for determining the standard state
* The method and parameters for determining the activity coefficients.
*
* Tasks:
* 0) Fill in the SSPhase[] array.
* 1) Check to see if any multispecies phases actually have only one
* species in that phase. If true, reassign that phase and species
* to be a single-species phase.
* 2) Determine the number of components in the problem if not already
* done so. During this process the order of the species is changed
* in the private data structure. All references to the species
* properties must employ the ind[] index vector.
*
* return code
* VCS_SUCCESS = everything went OK
*
**************************************************************************/
{
int kspec, i, conv, retn = VCS_SUCCESS;
double pres, test;
double *aw, *sa, *sm, *ss;
bool modifiedSoln = false;
#ifdef DEBUG
vcs_debug_print_lvl = printLvl;
#endif
/*
* Calculate the Single Species status of phases
* Also calculate the number of species per phase
*/
vcs_SSPhase();
/*
* Set an initial estimate for the number of noncomponent species
* equal to nspecies - nelements. This may be changed below
*/
m_numRxnTot = m_numSpeciesTot - m_numElemConstraints;
m_numRxnRdc = m_numRxnTot;
m_numSpeciesRdc = m_numSpeciesTot;
for (i = 0; i < m_numRxnRdc; ++i) {
ir[i] = m_numElemConstraints + i;
}
/* ***************************************************** */
/* **** DETERMINE THE NUMBER OF COMPONENTS ************* */
/* ***************************************************** */
/*
* Obtain a valid estimate of the mole fraction. This will
* be used as an initial ordering vector for prioritizing
* which species are defined as components.
*
* If a mole number estimate was supplied from the
* input file, use that mole number estimate.
*
* If a solution estimate wasn't supplied from the input file,
* supply an initial estimate for the mole fractions
* based on the relative reverse ordering of the
* chemical potentials.
*
* For voltage unknowns, set these to zero for the moment.
*/
test = -1.0e-10;
if (iest < 0) {
double sum = 0.0;
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
sum += fabs(soln[kspec]);
}
}
if (fabs(sum) < 1.0E-6) {
modifiedSoln = true;
if (Pres <= 0.0) pres = 1.0;
else pres = Pres;
retn = vcs_evalSS_TP(0, 0, T, pres);
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
soln[kspec] = - ff[kspec];
} else {
soln[kspec] = 0.0;
}
}
}
test = -1.0e20;
}
/*
* NC = number of components is in the vcs.h common block
* This call to BASOPT doesn't calculate the stoichiometric
* reaction matrix.
*/
std::vector<double> awSpace( m_numSpeciesTot + (m_numElemConstraints + 2)*(m_numElemConstraints), 0.0);
aw = VCS_DATA_PTR(awSpace);
if (aw == NULL) {
plogf("vcs_prep_oneTime: failed to get memory: global bailout\n");
return VCS_NOMEMORY;
}
sa = aw + m_numSpeciesTot;
sm = sa + m_numElemConstraints;
ss = sm + (m_numElemConstraints)*(m_numElemConstraints);
retn = vcs_basopt(TRUE, aw, sa, sm, ss, test, &conv);
if (retn != VCS_SUCCESS) {
plogf("vcs_prep_oneTime:");
plogf(" Determination of number of components failed: %d\n",
retn);
plogf(" Global Bailout!\n");
return retn;
}
if (m_numElemConstraints != m_numComponents) {
m_numRxnTot = m_numRxnRdc = m_numSpeciesTot - m_numComponents;
for (i = 0; i < m_numRxnRdc; ++i) {
ir[i] = m_numComponents + i;
}
}
/*
* The elements might need to be rearranged.
*/
awSpace.resize(m_numElemConstraints + (m_numElemConstraints + 2)*(m_numElemConstraints), 0.0);
aw = VCS_DATA_PTR(awSpace);
sa = aw + m_numElemConstraints;
sm = sa + m_numElemConstraints;
ss = sm + (m_numElemConstraints)*(m_numElemConstraints);
retn = vcs_elem_rearrange(aw, sa, sm, ss);
if (retn != VCS_SUCCESS) {
plogf("vcs_prep_oneTime:");
plogf(" Determination of element reordering failed: %d\n",
retn);
plogf(" Global Bailout!\n");
return retn;
}
// If we mucked up the solution unknowns because they were all
// zero to start with, set them back to zero here
if (modifiedSoln) {
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
soln[kspec] = 0.0;
}
}
return VCS_SUCCESS;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
// Prepare the object for re-solution
/*
* This routine is mostly concerned with changing the private data
* to be consistent with that needed for solution. It is called for
* every invocation of the vcs_solve() except for the cleanup invocation.
*
* Tasks:
* 1) Initialization of arrays to zero.
* 2) Calculate total number of moles in all phases
*
* return code
* VCS_SUCCESS = everything went OK
* VCS_PUB_BAD = There is an irreconcilable difference in the
* public data structure from when the problem was
* initially set up.
*/
int VCS_SOLVE::vcs_prep(void) {
/*
* Initialize various arrays in the data to zero
*/
vcs_dzero(VCS_DATA_PTR(m_gibbsSpecies), m_numSpeciesTot);
vcs_vdzero(fel, m_numSpeciesTot);
vcs_vdzero(wt, m_numSpeciesTot);
vcs_dzero(&(DnPhase[0][0]), m_numSpeciesTot*NPhase);
vcs_izero(&(PhaseParticipation[0][0]), m_numSpeciesTot*NPhase);
vcs_dzero(VCS_DATA_PTR(DelTPhMoles), NPhase);
vcs_dzero(VCS_DATA_PTR(TPhMoles1), NPhase);
/*
* Calculate the total number of moles in all phases.
*/
vcs_tmoles();
return VCS_SUCCESS;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
bool VCS_SOLVE::vcs_wellPosed(VCS_PROB *vprob)
/**************************************************************************
*
* vcs_wellPosed:
*
* In this routine, we check for things that will cause the algorithm
* to fail.
*
**************************************************************************/
{
double sum = 0.0;
for (int e = 0; e < vprob->ne; e++) {
sum = sum + vprob->gai[e];
}
if (sum < 1.0E-20) {
plogf("vcs_wellPosed: Element abundance is close to zero\n");
return false;
}
return true;
}
/*****************************************************************************/
}

View file

@ -0,0 +1,638 @@
/**
* @file vcs_prob.cpp
* Implementation for the Interface class for the vcs thermo
* equilibrium solver package,
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include "vcs_prob.h"
#include "vcs_VolPhase.h"
#include "vcs_species_thermo.h"
#include "vcs_internal.h"
#ifdef CANTERA_SRC_TREE
#include "ThermoPhase.h"
#include "MolalityVPSSTP.h"
#else
#include "cantera/Cantera.h"
#include "cantera/kernel/ThermoPhase.h"
#include "cantera/kernel/MolalityVPSSTP.h"
#endif
#include <string>
using namespace std;
namespace VCSnonideal {
/*
* VCS_PROB: constructor
*
* We initialize the arrays in the structure to the appropriate sizes.
* And, we initialize all of the elements of the arrays to defaults.
*/
VCS_PROB::VCS_PROB(int nsp, int nel, int nph) :
prob_type(VCS_PROBTYPE_TP),
nspecies(nsp),
NSPECIES0(0),
ne(nel),
NE0(0),
NPhase(nph),
NPHASE0(0),
T(298.15),
Pres(1.0),
Vol(0.0),
m_VCS_UnitsFormat(VCS_UNITS_UNITLESS),
/* Set the units for the chemical potential data to be
* unitless */
iest(-1), /* The default is to not expect an initial estimate
* of the species concentrations */
tolmaj(1.0E-8),
tolmin(1.0E-6),
m_Iterations(0),
m_NumBasisOptimizations(0),
m_printLvl(0)
#ifdef DEBUG
,
vcs_debug_print_lvl(0)
#endif
{
NSPECIES0 = nspecies;
if (nspecies <= 0) {
plogf("number of species is zero or neg\n");
exit(-1);
}
NE0 = ne;
if (ne <= 0) {
plogf("number of elements is zero or neg\n");
exit(-1);
}
NPHASE0 = NPhase;
if (NPhase <= 0) {
plogf("number of phases is zero or neg\n");
exit(-1);
}
if (nspecies < NPhase) {
plogf("number of species is less than number of phases\n");
exit(-1);
}
m_gibbsSpecies.resize(nspecies, 0.0);
w.resize(nspecies, 0.0);
mf.resize(nspecies, 0.0);
gai.resize(ne, 0.0);
FormulaMatrix.resize(ne, nspecies, 0.0);
SpeciesUnknownType.resize(nspecies, VCS_SPECIES_TYPE_MOLNUM);
VolPM.resize(nspecies, 0.0);
PhaseID.resize(nspecies, -1);
SpName.resize(nspecies, "");
ElName.resize(ne, "");
m_elType.resize(ne, VCS_ELEM_TYPE_ABSPOS);
ElActive.resize(ne, 1);
WtSpecies.resize(nspecies, 0.0);
Charge.resize(nspecies, 0.0);
SpeciesThermo.resize(nspecies,0);
for (int kspec = 0; kspec < nspecies; kspec++) {
VCS_SPECIES_THERMO *ts_tmp = new VCS_SPECIES_THERMO(0, 0);
if (ts_tmp == 0) {
plogf("Failed to init a ts struct\n");
exit(-1);
}
SpeciesThermo[kspec] = ts_tmp;
}
VPhaseList.resize(nph, 0);
for (int iphase = 0; iphase < NPhase; iphase++) {
VPhaseList[iphase] = new vcs_VolPhase();
}
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/*
* VCS_PROB_INPUT:destructor
*
* We need to manually free all of the arrays.
*/
VCS_PROB::~VCS_PROB() {
for (int i = 0; i < nspecies; i++) {
delete SpeciesThermo[i];
SpeciesThermo[i] = 0;
}
for (int iph = 0; iph < NPhase; iph++) {
delete VPhaseList[iph];
VPhaseList[iph] = 0;
}
}
// Resizes all of the phase lists within the structure
/*
* Note, this doesn't change the number of phases in the problem.
* It will change NPHASE0 if nsp is greater than NPHASE0.
*
* @param nPhase size to dimension all the phase lists to
* @param force If true, this will dimension the size to be equal to nPhase
* even if nPhase is less than the current value of NPHASE0
*/
void VCS_PROB::resizePhase(int nPhase, int force) {
if (force || nPhase > NPHASE0) {
NPHASE0 = nPhase;
}
}
// Resizes all of the species lists within the structure
/*
* Note, this doesn't change the number of species in the problem.
* It will change NSPECIES0 if nsp is greater than NSPECIES0.
*
* @param nsp size to dimension all the species to
* @param force If true, this will dimension the size to be equal to nsp
* even if nsp is less than the current value of NSPECIES0
*/
void VCS_PROB::resizeSpecies(int nsp, int force) {
if (force || nsp > NSPECIES0) {
m_gibbsSpecies.resize(nsp, 0.0);
w.resize(nsp, 0.0);
mf.resize(nsp, 0.0);
FormulaMatrix.resize(NE0, nsp, 0.0);
SpeciesUnknownType.resize(nsp, VCS_SPECIES_TYPE_MOLNUM);
VolPM.resize(nsp, 0.0);
PhaseID.resize(nsp, 0);
SpName.resize(nsp, "");
WtSpecies.resize(nsp, 0.0);
Charge.resize(nsp, 0.0);
NSPECIES0 = nsp;
if (nspecies > NSPECIES0) {
nspecies = NSPECIES0;
plogf("shouldn't be here\n");
exit(-1);
}
}
}
// Resizes all of the element lists within the structure
/*
* Note, this doesn't change the number of element constraints
* in the problem.
* It will change NE0 if nel is greater than NE0.
*
* @param nel size to dimension all the elements lists
* @param force If true, this will dimension the size to be equal to nel
* even if nel is less than the current value of NEL0
*/
void VCS_PROB::resizeElements(int nel, int force) {
if (force || nel > NE0) {
gai.resize(nel, 0.0);
FormulaMatrix.resize(nel, NSPECIES0, 0.0);
ElName.resize(nel, "");
m_elType.resize(nel, VCS_ELEM_TYPE_ABSPOS);
ElActive.resize(nel, 1);
NE0 = nel;
if (ne > NE0) ne = NE0;
}
}
// Calculate the element abundance vector
/*
* Calculates the element abundance vectors from the mole
* numbers
*/
void VCS_PROB::set_gai ()
{
int kspec, j;
double *ElemAbund = VCS_DATA_PTR(gai);
double *const *const fm = FormulaMatrix.baseDataAddr();
vcs_dzero(ElemAbund, ne);
for (j = 0; j < ne; j++) {
for (kspec = 0; kspec < nspecies; kspec++) {
ElemAbund[j] += fm[j][kspec] * w[kspec];
}
}
}
/*****************************************************************************/
static void print_space(int num) {
for (int j = 0; j < num; j++) (void) plogf(" ");
}
/*****************************************************************************/
static void print_char(const char letter, const int num) {
for (int i = 0; i < num; i++) plogf("%c", letter);
}
/*****************************************************************************
* prob_report():
*
* Print out the problem specification in all generality
* as it currently exists in the VCS_PROB object
*
*/
void VCS_PROB::prob_report(int print_lvl) {
m_printLvl = print_lvl;
int i, iphase;
vcs_VolPhase *Vphase = 0;
/*
* Printout the species information: PhaseID's and mole nums
*/
if (m_printLvl > 0) {
plogf("\n"); print_char('=', 80); plogf("\n");
print_char('=', 20);
plogf(" VCS_PROB: PROBLEM STATEMENT ");
print_char('=', 31); plogf("\n");
print_char('=', 80); plogf("\n");
plogf("\n");
if (prob_type == 0) {
plogf("\tSolve a constant T, P problem:\n");
plogf("\t\tT = %g K\n", T);
double pres_atm = Pres;
if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
pres_atm = Pres / 1.0133E5;
}
plogf("\t\tPres = %g atm\n", pres_atm);
} else {
plogf("\tUnknown problem type\n");
exit(-1);
}
plogf("\n");
plogf(" Phase IDs of species\n");
plogf(" species phaseID phaseName ");
plogf(" Initial_Estimated_Moles Species_Type\n");
for (i = 0; i < nspecies; i++) {
Vphase = VPhaseList[PhaseID[i]];
plogf("%16s %5d %16s", SpName[i].c_str(), PhaseID[i],
Vphase->PhaseName.c_str());
if (iest >= 0) plogf(" %-10.5g", w[i]);
else plogf(" N/A");
if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) {
plogf(" Mol_Num");
} else if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
plogf(" Voltage");
} else {
plogf(" ");
}
plogf("\n");
}
/*
* Printout of the Phase structure information
*/
plogf("\n"); print_char('-', 80); plogf("\n");
plogf(" Information about phases\n");
plogf(" PhaseName PhaseNum SingSpec GasPhase "
" EqnState NumSpec");
plogf(" TMolesInert Tmoles\n");
for (iphase = 0; iphase < NPhase; iphase++) {
Vphase = VPhaseList[iphase];
std::string EOS_cstr = string16_EOSType(Vphase->EqnState);
plogf("%16s %5d %5d %8d ", Vphase->PhaseName.c_str(),
Vphase->VP_ID, Vphase->SingleSpecies, Vphase->GasPhase);
plogf("%16s %8d %16e ", EOS_cstr.c_str(),
Vphase->NVolSpecies, Vphase->TMolesInert);
if (iest >= 0) plogf("%16e\n", Vphase->TotalMoles());
else plogf(" N/A\n");
}
plogf("\nElemental Abundances: ");
plogf(" Target_gmol ElemType ElActive\n");
double fac = 1.0;
if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
fac = 1.0E3;
}
for (i = 0; i < ne; ++i) {
print_space(26); plogf("%-2.2s", ElName[i].c_str());
plogf("%20.12E ", fac * gai[i]);
plogf("%3d %3d\n", m_elType[i], ElActive[i]);
}
plogf("\nChemical Potentials: ");
if (m_VCS_UnitsFormat == VCS_UNITS_UNITLESS) {
plogf("(unitless)");
} else if (m_VCS_UnitsFormat == VCS_UNITS_KCALMOL) {
plogf("(kcal/gmol)");
} else if (m_VCS_UnitsFormat == VCS_UNITS_KJMOL) {
plogf("(kJ/gmol)");
} else if (m_VCS_UnitsFormat == VCS_UNITS_KELVIN) {
plogf("(Kelvin)");
} else if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
plogf("(J/kmol)");
}
plogf("\n");
plogf(" Species (phase) "
" SS0ChemPot StarChemPot\n");
for (iphase = 0; iphase < NPhase; iphase++) {
Vphase = VPhaseList[iphase];
Vphase->G0_calc(T);
Vphase->GStar_calc(T, Pres);
for (int kindex = 0; kindex < Vphase->NVolSpecies; kindex++) {
int kglob = Vphase->IndSpecies[kindex];
plogf("%16s ", SpName[kglob].c_str());
if (kindex == 0) {
plogf("%16s", Vphase->PhaseName.c_str());
} else {
plogf(" ");
}
plogf("%16g %16g\n",
Vphase->SS0ChemicalPotential[kindex],
Vphase->StarChemicalPotential[kindex] );
}
}
plogf("\n"); print_char('=', 80); plogf("\n");
print_char('=', 20); plogf(" VCS_PROB: END OF PROBLEM STATEMENT ");
print_char('=', 24); plogf("\n");
print_char('=', 80); plogf("\n\n");
}
}
// Add elements to the local element list
/*
* This routine sorts through the elements defined in the
* vcs_VolPhase object. It then adds the new elements to
* the VCS_PROB object, and creates a global map, which is
* storred in the vcs_VolPhase object.
* Id and matching of elements is done strictly via the element name,
* with case not mattering.
*
* The routine also fills in the position of the element
* in the vcs_VolPhase object's ElGlobalIndex field.
*
* @param volPhase Object containing the phase to be added.
* The elements in this phase are parsed for
* addition to the global element list
*/
void VCS_PROB::addPhaseElements(vcs_VolPhase *volPhase) {
int e, eVP;
int foundPos = -1;
int neVP = volPhase->nElemConstraints;
std::string en;
std::string enVP;
/*
* Loop through the elements in the vol phase object
*/
for (eVP = 0; eVP < neVP; eVP++) {
foundPos = -1;
enVP = volPhase->ElName[eVP];
/*
* Search for matches with the existing elements.
* If found, then fill in the entry in the global
* mapping array.
*/
for (e = 0; e < ne; e++) {
en = ElName[e];
if (!strcasecmp(enVP.c_str(), en.c_str())) {
volPhase->ElGlobalIndex[eVP] = e;
foundPos = e;
}
}
if (foundPos == -1) {
int elType = volPhase->m_elType[eVP];
int elactive = volPhase->ElActive[eVP];
e = addElement(enVP.c_str(), elType, elactive);
volPhase->ElGlobalIndex[eVP] = e;
}
}
}
// This routine resizes the number of elements in the VCS_PROB object by
// adding a new element to the end of the element list
/*
* The element name is added. Formula vector entries ang element
* abundances for the new element are set to zero.
*
* Returns the index number of the new element.
*
* @param elNameNew New name of the element
* @param elType Type of the element
* @param elactive boolean indicating whether the element is active
*
* @return returns the index number of the new element
*/
int VCS_PROB::addElement(const char *elNameNew, int elType, int elactive) {
if (!elNameNew) {
plogf("error: element must have a name\n");
exit(-1);
}
int nel = ne + 1;
resizeElements(nel, 1);
ne = nel;
ElName[ne-1] = elNameNew;
m_elType[ne-1] = elType;
ElActive[ne-1] = elactive;
return (ne - 1);
}
// This routines adds entries for the formula matrix for one species
/*
* This routines adds entries for the formula matrix for this object
* for one species
*
* This object also fills in the index filed, IndSpecies, within
* the volPhase object.
*
* @param volPhase object containing the species
* @param k Species number within the volPhase k
* @param kT global Species number within this object
*
*/
int VCS_PROB::addOnePhaseSpecies(vcs_VolPhase *volPhase, int k, int kT) {
int e, eVP;
if (kT > nspecies) {
/*
* Need to expand the number of species here
*/
plogf("Shouldn't be here\n");
exit(-1);
}
double *const *const fm = volPhase->FormulaMatrix.baseDataAddr();
for (eVP = 0; eVP < volPhase->nElemConstraints; eVP++) {
e = volPhase->ElGlobalIndex[eVP];
if (e < 0) {
exit(-1);
}
FormulaMatrix[e][kT] = fm[eVP][k];
}
/*
* Tell the phase object about the current position of the
* species within the global species vector
*/
volPhase->IndSpecies[k] = kT;
return kT;
}
void VCS_PROB::reportCSV(const std::string &reportFile) {
int k;
int istart;
double vol = 0.0;
string sName;
int nphase = NPhase;
FILE * FP = fopen(reportFile.c_str(), "w");
if (!FP) {
plogf("Failure to open file\n");
exit(-1);
}
double Temp = T;
double pres = Pres;
std::vector<double> VolPM(nspecies, 0.0);
std::vector<double> activity(nspecies, 0.0);;
std::vector<double> ac(nspecies, 0.0);;
std::vector<double> mu(nspecies, 0.0);;
std::vector<double> mu0(nspecies, 0.0);;
std::vector<double> molalities(nspecies, 0.0);;
vol = 0.0;
int iK = 0;
for (int iphase = 0; iphase < nphase; iphase++) {
istart = iK;
vcs_VolPhase *volP = VPhaseList[iphase];
//const Cantera::ThermoPhase *tptr = volP->ptrThermoPhase();
int nSpeciesPhase = volP->NVolSpecies;
VolPM.resize(nSpeciesPhase, 0.0);
volP->sendToVCSVolPM(VCS_DATA_PTR(VolPM));
double TMolesPhase = volP->TotalMoles();
double VolPhaseVolumes = 0.0;
for (k = 0; k < nSpeciesPhase; k++) {
iK++;
VolPhaseVolumes += VolPM[istart + k] * mf[istart + k];
}
VolPhaseVolumes *= TMolesPhase;
vol += VolPhaseVolumes;
}
fprintf(FP,"--------------------- VCS_MULTIPHASE_EQUIL FINAL REPORT"
" -----------------------------\n");
fprintf(FP,"Temperature = %11.5g kelvin\n", Temp);
fprintf(FP,"Pressure = %11.5g Pascal\n", pres);
fprintf(FP,"Total Volume = %11.5g m**3\n", vol);
fprintf(FP,"Number Basis optimizations = %d\n", m_NumBasisOptimizations);
fprintf(FP,"Number VCS iterations = %d\n", m_Iterations);
iK = 0;
for (int iphase = 0; iphase < nphase; iphase++) {
istart = iK;
vcs_VolPhase *volP = VPhaseList[iphase];
const Cantera::ThermoPhase *tp = volP->ptrThermoPhase();
string phaseName = volP->PhaseName;
int nSpeciesPhase = volP->NVolSpecies;
volP->sendToVCSVolPM(VCS_DATA_PTR(VolPM));
double TMolesPhase = volP->TotalMoles();
//AssertTrace(TMolesPhase == m_mix->phaseMoles(iphase));
activity.resize(nSpeciesPhase, 0.0);
ac.resize(nSpeciesPhase, 0.0);
mu0.resize(nSpeciesPhase, 0.0);
mu.resize(nSpeciesPhase, 0.0);
VolPM.resize(nSpeciesPhase, 0.0);
molalities.resize(nSpeciesPhase, 0.0);
int actConvention = tp->activityConvention();
tp->getActivities(VCS_DATA_PTR(activity));
tp->getActivityCoefficients(VCS_DATA_PTR(ac));
tp->getStandardChemPotentials(VCS_DATA_PTR(mu0));
tp->getPartialMolarVolumes(VCS_DATA_PTR(VolPM));
tp->getChemPotentials(VCS_DATA_PTR(mu));
double VolPhaseVolumes = 0.0;
for (k = 0; k < nSpeciesPhase; k++) {
VolPhaseVolumes += VolPM[k] * mf[istart + k];
}
VolPhaseVolumes *= TMolesPhase;
vol += VolPhaseVolumes;
if (actConvention == 1) {
const Cantera::MolalityVPSSTP *mTP = static_cast<const Cantera::MolalityVPSSTP *>(tp);
tp->getChemPotentials(VCS_DATA_PTR(mu));
mTP->getMolalities(VCS_DATA_PTR(molalities));
tp->getChemPotentials(VCS_DATA_PTR(mu));
if (iphase == 0) {
fprintf(FP," Name, Phase, PhaseMoles, Mole_Fract, "
"Molalities, ActCoeff, Activity,"
"ChemPot_SS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
fprintf(FP," , , (kmol), , "
" , , ,"
" (J/kmol), (J/kmol), (kmol), (m**3/kmol), (m**3)\n");
}
for (k = 0; k < nSpeciesPhase; k++) {
sName = tp->speciesName(k);
fprintf(FP,"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e,"
"%11.3e, %11.3e, %11.3e, %11.3e, %11.3e\n",
sName.c_str(),
phaseName.c_str(), TMolesPhase,
mf[istart + k], molalities[k], ac[k], activity[k],
mu0[k]*1.0E-6, mu[k]*1.0E-6,
mf[istart + k] * TMolesPhase,
VolPM[k], VolPhaseVolumes );
}
} else {
if (iphase == 0) {
fprintf(FP," Name, Phase, PhaseMoles, Mole_Fract, "
"Molalities, ActCoeff, Activity,"
" ChemPotSS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
fprintf(FP," , , (kmol), , "
" , , ,"
" (J/kmol), (J/kmol), (kmol), (m**3/kmol), (m**3)\n");
}
for (k = 0; k < nSpeciesPhase; k++) {
molalities[k] = 0.0;
}
for (k = 0; k < nSpeciesPhase; k++) {
sName = tp->speciesName(k);
fprintf(FP,"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e, "
"%11.3e, %11.3e,% 11.3e, %11.3e, %11.3e\n",
sName.c_str(),
phaseName.c_str(), TMolesPhase,
mf[istart + k], molalities[k], ac[k],
activity[k], mu0[k]*1.0E-6, mu[k]*1.0E-6,
mf[istart + k] * TMolesPhase,
VolPM[k], VolPhaseVolumes );
}
}
#ifdef DEBUG
/*
* Check consistency: These should be equal
*/
tp->getChemPotentials(VCS_DATA_PTR(m_gibbsSpecies)+istart);
for (k = 0; k < nSpeciesPhase; k++) {
if (!vcs_doubleEqual(m_gibbsSpecies[istart+k], mu[k])) {
fprintf(FP,"ERROR: incompatibility!\n");
fclose(FP);
plogf("ERROR: incompatibility!\n");
exit(-1);
}
}
#endif
iK += nSpeciesPhase;
}
fclose(FP);
}
#ifdef DEBUG
void VCS_PROB::setDebugPrintLvl(int lvl) {
vcs_debug_print_lvl = lvl;
}
#endif
}

View file

@ -0,0 +1,375 @@
/**
* @file vcs_prob.h
* Header for the Interface class for the vcs thermo equilibrium solver package,
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef _VCS_PROB_H
#define _VCS_PROB_H
#include "vcs_DoubleStarStar.h"
#include "vcs_IntStarStar.h"
#include "vcs_defs.h"
#include <vector>
#include <string>
namespace VCSnonideal {
class vcs_VolPhase;
class VCS_SPECIES_THERMO;
//! Interface class for the vcs thermo equilibrium solver package,
//! which generally describes the problem to be solved.
/*!
* HKM add:
* HaveEstimate -> 0 no estimate, or estimate that doesn' satisfy elem
* abundances
* 1 have an estimate that satisfies elem_abund.
* 2 Have an estimate that minimizes a subproblem
* and satisfies elem abund.
* solnFound -> True, soln to current problem found and included here
* False, soln has not been found.
*/
class VCS_PROB {
public:
//! Problem type. I.e., the identity of what is held constant.
/*!
* Currently, T and P are held constant, and this input
* is ignored
*/
int prob_type;
//! Total number of species in the problems
int nspecies;
//! Species number used to malloc data structures
int NSPECIES0;
//! Number of element contraints in the equilibrium problem
int ne;
//! Number of element constrints used to malloc data structures
//! involving elements
int NE0;
//! Number of phases in the problem
int NPhase;
//! Number of phases used to malloc data structures
int NPHASE0;
//! Vector of chemical potentials of the species
/*!
* This is a calculated output quantity
* length = number of species
* units = m_VCS_UnitsFormat;
*/
std::vector<double> m_gibbsSpecies;
//! Total number of moles of the kth species.
/*!
* This is both an input and an output variable.
* On input, this is an estimate of the mole numbers.
* The actual element abundance vector contains the problem specification.
*
* On output, this contains the solution for the total number of moles
* of the kth species.
*
* units = m_VCS_UnitsFormat
*/
std::vector<double> w;
//! Mole fraction vector
/*!
* This is a calculated vector, calculated from w[]
* length number of species.
* -> Take out? -> No, useful for storage of a quantity often needed
*/
std::vector<double> mf;
//! Element abundances for jth element
/*!
* This is input from the input file and is considered a constant from
* thereon within the vcs_solve_TP().
* units = m_VCS_UnitsFormat
*/
std::vector<double> gai;
//! Formula Matrix for the problem
/*!
* FormulaMatrix[j][kspec] = Number of elements, j, in the kspec
* species
*/
DoubleStarStar FormulaMatrix;
//! Specifies the species unknown type
/*!
* There are two types. One is the straightforward
* species, with the mole number w[k], as the
* unknown. The second is the an interfacial
* voltage where w[k] refers to the interfacial
* voltage in volts.
* These species types correspond to metalic
* electrons corresponding to electrodes.
* The voltage and other interfacial conditions
* sets up an interfacial current, which is
* set to zero in this initial treatment.
* Later we may have non-zero interfacial currents.
*/
std::vector<int> SpeciesUnknownType;
//! Temperature (Kelvin)
/*!
* Specification of the temperature for the equilibrium problem
*/
double T;
//! Pressure
/*!
* units given by m_VCS_UnitsFormat
*/
double Pres;
//! Volume of the entire system
/*!
* units given by m_VCS_UnitsFormat
* Note, this is an output variable atm
*/
double Vol;
//! Partial Molar Volumes of species
/*!
* This is a calculated vector, calculated from w[]
* length number of species.
* -> Take out? -> No, useful for storage of a quantity often needed
*/
std::vector<double> VolPM;
//! Units for the chemical potential data, pressure data, volume,
//! and species amounts
/*!
* All internally storred quantities will have these units. Also, printed
* quantitities will display in these units.
*
* Chem_Pot Pres vol moles
* ----------------------------------------------------------------------
* -1 VCS_UNITS_KCALMOL = kcal/mol atm cm**3 gmol
* 0 VCS_UNITS_UNITLESS = MU / RT -> no units atm cm**3 gmol
* 1 VCS_UNITS_KJMOL = kJ / mol atm cm**3 gmol
* 2 VCS_UNITS_KELVIN = KELVIN -> MU / R atm cm**3 gmol
* 3 VCS_UNITS_MKS = Joules / Kmol (Cantera) Pa m**3 kmol
* ----------------------------------------------------------------------
*
* see vcs_defs.h for more information
*/
int m_VCS_UnitsFormat;
//! Specification of the initial estimate method
/*!
* iest = Initial estimate: 0 user estimate
* -1 machine estimate
*/
int iest;
//! Tolerance requirement for major species
double tolmaj;
//! Tolerance requirement for minor species
double tolmin;
//! Mapping between the species and the phases
std::vector<int> PhaseID;
//! Vector of strings containing the species names
std::vector<std::string> SpName;
//! vector of strings containing the element names
std::vector<std::string> ElName;
//! vector of Element types
std::vector<int> m_elType;
//! Specifies whether an element constraint is active
/*!
* The default is true
* Length = nelements
*/
std::vector<int> ElActive;
//! Molecular weight of species
/*!
* WtSpecies[k] = molecular weight of species in gm/mol
*/
std::vector<double> WtSpecies;
//! Charge of each species
std::vector<double> Charge;
//! Array of phase structures
std::vector<vcs_VolPhase *> VPhaseList;
// String containing the title of the run
std::string Title;
//! Vector of pointers to thermo structures which identify the model
//! and parameters for evaluating the thermodynamic
//! functions for that particular species
std::vector<VCS_SPECIES_THERMO *> SpeciesThermo;
//! Number of iterations
/*!
* This is an output variable
*/
int m_Iterations;
//! Number of basis optimizations used
/*!
* This is an output variable
*/
int m_NumBasisOptimizations;
//! Print level for print routines
int m_printLvl;
#ifdef DEBUG
//! Debug print lvl
int vcs_debug_print_lvl;
#endif
//! Constructor
/*!
* This constructor initializes the sizes within the object
* to parameter values.
*
* @param nsp number of species
* @param nel number of elements
* @param nph number of phases
*/
VCS_PROB(int nsp, int nel, int nph);
//! Destructor
~VCS_PROB();
//! Resizes all of the phase lists within the structure
/*!
* Note, this doesn't change the number of phases in the problem.
* It will change NPHASE0 if nsp is greater than NPHASE0.
*
* @param nPhase size to dimension all the phase lists to
* @param force If true, this will dimension the size to be equal to nPhase
* even if nPhase is less than the current value of NPHASE0
*/
void resizePhase(int nPhase, int force);
//! Resizes all of the species lists within the structure
/*!
* Note, this doesn't change the number of species in the problem.
* It will change NSPECIES0 if nsp is greater than NSPECIES0.
*
* @param nsp size to dimension all the species lists to
* @param force If true, this will dimension the size to be equal to nsp
* even if nsp is less than the current value of NSPECIES0
*/
void resizeSpecies(int nsp, int force);
//! Resizes all of the element lists within the structure
/*!
* Note, this doesn't change the number of element constraints in the problem.
* It will change NE0 if nel is greater than NE0.
*
* @param nel size to dimension all the elements lists
* @param force If true, this will dimension the size to be equal to nel
* even if nel is less than the current value of NEL0
*/
void resizeElements(int nel, int force);
//! Calculate the element abundance vector
/*!
* Calculates the element abundance vectors from the mole
* numbers
*/
void set_gai();
//! Print out the problem specification in all generality
//! as it currently exists in the VCS_PROB object
/*!
* @param print_lvl Parameter lvl for printing
* 0 - no printing
* 1 - all printing
*/
void prob_report(int print_lvl);
//! Add elements to the local element list
/*!
* This routine sorts through the elements defined in the
* vcs_VolPhase object. It then adds the new elements to
* the VCS_PROB object, and creates a global map, which is
* storred in the vcs_VolPhase object.
* Id and matching of elements is done strictly via the element name,
* with case not mattering.
*
* The routine also fills in the position of the element
* in the vcs_VolPhase object's ElGlobalIndex field.
*
* @param volPhase Object containing the phase to be added.
* The elements in this phase are parsed for
* addition to the global element list
*/
void addPhaseElements(vcs_VolPhase *volPhase);
//! This routine resizes the number of elements in the VCS_PROB object by
//! adding a new element to the end of the element list
/*!
* The element name is added. Formula vector entries ang element
* abundances for the new element are set to zero.
*
* Returns the index number of the new element.
*
* @param elNameNew New name of the element
* @param elType Type of the element
* @param elactive boolean indicating whether the element is active
*
* @return returns the index number of the new element
*/
int addElement(const char *elNameNew, int elType, int elactive);
//! This routines adds entries for the formula matrix for one species
/*!
* This routines adds entries for the formula matrix for this object
* for one species
*
* This object also fills in the index filed, IndSpecies, within
* the volPhase object.
*
* @param volPhase object containing the species
* @param k Species number within the volPhase k
* @param kT global Species number within this object
*
*/
int addOnePhaseSpecies(vcs_VolPhase *volPhase, int k, int kT);
void reportCSV(const std::string &reportFile);
#ifdef DEBUG
//! Set the debug level
/*!
* @param vcs_debug_print_lvl input debug level
*/
void setDebugPrintLvl(int vcs_debug_print_lvl);
#endif
};
}
#endif

View file

@ -0,0 +1,58 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_rearrange(void)
/**************************************************************************
*
* vcs_rearrange:
*
* Switch all species data back to the original order. This destroys
* the data based on reaction ordering.
**************************************************************************/
{
int i, l, j, k1;
/* ********************************************************* */
/* **** RE-ARRANGE INPUT DATA ****************************** */
/* ********************************************************* */
/* - Loop over all of the species */
for (i = 0; i < m_numSpeciesTot; ++i) {
/*
* Find the index of I in the index vector IND.
* Call it K1 and continue.
*/
for (j = 0; j < m_numSpeciesTot; ++j) {
l = ind[j];
k1 = j;
if (l == i) break;
}
/*
* - Switch the species data back from K1 into I
* -> because we loop over all species, reaction data
* are now permanently hosed.
*/
vcs_switch_pos(FALSE, i, k1);
}
return 0;
} /* vcs_rearrange() *********************************************************/
}

View file

@ -0,0 +1,400 @@
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
namespace VCSnonideal {
/*****************************************************************************/
static void print_space(int num)
{
for (int j = 0; j < num; j++) {
plogf(" ");
}
}
static void print_line(char *schar, int num) {
for (int j = 0; j < num; j++) plogf("%s", schar);
plogf("\n");
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_report(int iconv)
/**************************************************************************
*
* vcs_report:
*
* Print out a report on the state of the equilibrium problem to
* standard output.
* This prints out the current contents of the VCS_SOLVE class, V.
***************************************************************************/
{
int i, j, l, k, inertYes = FALSE, kspec;
int nspecies = m_numSpeciesTot;
double g;
char originalUnitsState = UnitsState;
std::vector<int> sortindex(nspecies,0);
std::vector<double> xy(nspecies,0.0);
/* ************************************************************** */
/* **** SORT DEPENDENT SPECIES IN DECREASING ORDER OF MOLES ***** */
/* ************************************************************** */
for (i = 0; i < nspecies; ++i) {
sortindex[i] = i;
xy[i] = soln[i];
}
/*
* Sort the XY vector, the mole fraction vector,
* and the sort index vector, sortindex, according to
* the magnitude of the mole fraction vector.
*/
for (l = m_numComponents; l < m_numSpeciesRdc; ++l) {
k = vcs_amax(VCS_DATA_PTR(xy), l, m_numSpeciesRdc);
if (k != l) {
vcsUtil_dsw(VCS_DATA_PTR(xy), k, l);
vcsUtil_isw(VCS_DATA_PTR(sortindex), k, l);
}
}
/*
* Decide whether we have to nondimensionalize the equations.
* -> For the printouts from this routine, we will use nondimensional
* representations. This may be expanded in the future.
*/
if (UnitsState == VCS_DIMENSIONAL_G) {
vcs_nondim_TP();
}
/* ******************************************************** */
/* *** PRINT OUT RESULTS ********************************** */
/* ******************************************************** */
plogf("\n\n\n\n");
print_line("-", 80);
print_line("-", 80);
plogf("\t\t VCS_TP REPORT\n");
print_line("-", 80);
print_line("-", 80);
if (iconv < 0) {
plogf(" ERROR: CONVERGENCE CRITERION NOT SATISFIED.\n");
} else if (iconv == 1) {
plogf(" RANGE SPACE ERROR: Equilibrium Found but not all Element Abundances are Satisfied\n");
}
/*
* Calculate some quantities that may need updating
*/
vcs_tmoles();
Vol = vcs_VolTotal(T, Pres, VCS_DATA_PTR(soln), VCS_DATA_PTR(VolPM));
plogf("\t\tTemperature = %15.2g Kelvin\n", T);
plogf("\t\tPressure = %15.5g Atmos\n", Pres);
plogf("\t\tVolume = %15.5g cm**3\n", Vol);
/*
* -------- TABLE OF SPECIES IN DECREASING MOLE NUMBERS --------------
*/
plogf("\n\n");
print_line("-", 80);
plogf(" Species Equilibrium moles ");
plogf("Mole Fraction ChemPot/RT SpecUnkType\n");
print_line("-", 80);
for (i = 0; i < m_numComponents; ++i) {
plogf(" %-12.12s", SpName[i].c_str());
print_space(13);
plogf("%14.7E %14.7E %12.4E", soln[i], wt[i], m_gibbsSpecies[i]);
plogf(" %3d", SpeciesUnknownType[i]);
plogf("\n");
}
for (i = m_numComponents; i < m_numSpeciesRdc; ++i) {
l = sortindex[i];
plogf(" %-12.12s", SpName[l].c_str());
print_space(13);
if (SpeciesUnknownType[l] == VCS_SPECIES_TYPE_MOLNUM) {
plogf("%14.7E %14.7E %12.4E", soln[l], wt[l], m_gibbsSpecies[l]);
plogf(" MolNum ");
} else if (SpeciesUnknownType[l] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
plogf(" NA %14.7E %12.4E", 1.0, m_gibbsSpecies[l]);
plogf(" Voltage = %14.7E", soln[l]);
} else {
plogf("we have a problem\n");
exit(-1);
}
plogf("\n");
}
for (i = 0; i < NPhase; i++) {
if (TPhInertMoles[i] > 0.0) {
inertYes = TRUE;
if (i == 0) {
plogf(" Inert Gas Species ");
} else {
plogf(" Inert Species in phase %16s ",
(VPhaseList[i])->PhaseName.c_str());
}
plogf("%14.7E %14.7E %12.4E\n", TPhInertMoles[i],
TPhInertMoles[i] / TPhMoles[i], 0.0);
}
}
if (m_numSpeciesRdc != nspecies) {
plogf("\n SPECIES WITH LESS THAN 1.0E-32 MOLES:\n\n");
for (kspec = m_numSpeciesRdc; kspec < nspecies; ++kspec) {
plogf(" %-12.12s", SpName[kspec].c_str());
plogf(" %14.7E %14.7E %12.4E",
soln[kspec], wt[kspec], dg[kspec]);
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");
}
}
print_line("-", 80);
plogf("\n");
/*
* ---------- TABLE OF SPECIES FORMATION REACTIONS ------------------
*/
plogf("\n");
print_line("-", m_numComponents*10 + 45);
plogf(" |ComponentID|");
for (j = 0; j < m_numComponents; j++) {
plogf(" %3d", j);
}
plogf(" | |\n");
plogf(" | Components|");
for (j = 0; j < m_numComponents; j++) {
plogf(" %10.10s", SpName[j].c_str());
}
plogf(" | |\n");
plogf(" NonComponent | Moles |");
for (j = 0; j < m_numComponents; j++) {
plogf(" %10.3g", soln[j]);
}
plogf(" | DG/RT Rxn |\n");
print_line("-", m_numComponents*10 + 45);
for (i = 0; i < m_numRxnTot; i++) {
int irxn = ir[i];
plogf(" %3d ", irxn);
plogf("%-10.10s", SpName[irxn].c_str());
plogf("|%10.3g |", soln[irxn]);
for (j = 0; j < m_numComponents; j++) {
plogf(" %6.2f", sc[i][j]);
}
plogf(" |%10.3g |", dg[irxn]);
plogf("\n");
}
print_line("-", m_numComponents*10 + 45);
plogf("\n");
/*
* ------------------ TABLE OF PHASE INFORMATION ---------------------
*/
std::vector<double> gaPhase(m_numElemConstraints, 0.0);
std::vector<double> gaTPhase(m_numElemConstraints, 0.0);
double totalMoles = 0.0;
double gibbsPhase = 0.0;
double gibbsTotal = 0.0;
plogf("\n\n");
plogf("\n");
print_line("-", m_numElemConstraints*10 + 58);
plogf(" | ElementID |");
for (j = 0; j < m_numElemConstraints; j++) {
plogf(" %3d", j);
}
plogf(" | |\n");
plogf(" | Element |");
for (j = 0; j < m_numElemConstraints; j++) {
plogf(" %10.10s", (ElName[j]).c_str());
}
plogf(" | |\n");
plogf(" PhaseName | MolTarget |");
for (j = 0; j < m_numElemConstraints; j++) {
plogf(" %10.3g", gai[j]);
}
plogf(" | Gibbs Total |\n");
print_line("-", m_numElemConstraints*10 + 58);
for (int iphase = 0; iphase < NPhase; iphase++) {
plogf(" %3d ", iphase);
vcs_VolPhase *VPhase = VPhaseList[iphase];
plogf("%-12.12s |",VPhase->PhaseName.c_str());
plogf("%10.3e |", TPhMoles[iphase]);
totalMoles += TPhMoles[iphase];
if (TPhMoles[iphase] != VPhase->TotalMoles()) {
if (! vcs_doubleEqual(TPhMoles[iphase], VPhase->TotalMoles())) {
plogf("We have a problem\n");
exit(-1);
}
}
vcs_elabPhase(iphase, VCS_DATA_PTR(gaPhase));
for (j = 0; j < m_numElemConstraints; j++) {
plogf(" %10.3g", gaPhase[j]);
gaTPhase[j] += gaPhase[j];
}
gibbsPhase = vcs_GibbsPhase(iphase, VCS_DATA_PTR(soln),
VCS_DATA_PTR(m_gibbsSpecies));
gibbsTotal += gibbsPhase;
plogf(" | %18.11E |\n", gibbsPhase);
}
print_line("-", m_numElemConstraints*10 + 58);
plogf(" TOTAL |%10.3e |", totalMoles);
for (j = 0; j < m_numElemConstraints; j++) {
plogf(" %10.3g", gaTPhase[j]);
}
plogf(" | %18.11E |\n", gibbsTotal);
print_line("-", m_numElemConstraints*10 + 58);
plogf("\n");
/*
* ----------- GLOBAL SATISFACTION INFORMATION -----------------------
*/
/*
* Calculate the total dimensionless Gibbs Free Energy
* -> Inert species are handled as if they had a standard free
* energy of zero
*/
g = vcs_Total_Gibbs(VCS_DATA_PTR(soln), VCS_DATA_PTR(m_gibbsSpecies),
VCS_DATA_PTR(TPhMoles));
plogf("\n\tTotal Dimensionless Gibbs Free Energy = G/RT = %15.7E\n", g);
if (inertYes)
plogf("\t\t(Inert species have standard free energy of zero)\n");
plogf("\nElemental Abundances: ");
plogf(" Actual Target Type ElActive\n");
for (i = 0; i < m_numElemConstraints; ++i) {
print_space(26); plogf("%-2.2s", (ElName[i]).c_str());
plogf("%20.12E %20.12E", ga[i], gai[i]);
plogf(" %3d %3d\n", m_elType[i], ElActive[i]);
}
plogf("\n");
/*
* ------------------ TABLE OF SPECIES CHEM POTS ---------------------
*/
plogf("\n"); print_line("-", 93);
plogf("Chemical Potentials of the Species: (dimensionless)\n");
double rt = vcs_nondimMult_TP(m_VCS_UnitsFormat, T);
plogf("\t\t(RT = %g ", rt);
vcs_printChemPotUnits(m_VCS_UnitsFormat);
plogf(")\n");
plogf(" Name TMoles StandStateChemPot "
" ln(AC) ln(X_i) | F z_i phi | ChemPot | (-lnMnaught)\n");
print_line("-", 115);
for (i = 0; i < nspecies; ++i) {
l = sortindex[i];
int pid = PhaseID[l];
plogf(" %-12.12s", SpName[l].c_str());
plogf(" %14.7E ", soln[l]);
plogf("%14.7E ", ff[l]);
plogf("%14.7E ", log(ActCoeff[l]));
double tpmoles = TPhMoles[pid];
double phi = phasePhi[pid];
double eContrib = phi * Charge[l] * Faraday_dim;
double lx = 0.0;
if (SpeciesUnknownType[l] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
lx = 0.0;
} else {
if (tpmoles > 0.0 && soln[l] > 0.0) {
lx = log(soln[l]) - log(tpmoles);
} else {
lx = m_gibbsSpecies[l] - ff[l] - log(ActCoeff[l]) + SpecLnMnaught[l];
}
}
plogf("%14.7E |", lx);
plogf("%14.7E | ", eContrib);
double tmp = ff[l] + log(ActCoeff[l]) + lx - SpecLnMnaught[l] + eContrib;
if (fabs(m_gibbsSpecies[l] - tmp) > 1.0E-8) {
plogf("\n\t\twe have a problem - doesn't add up\n");
exit(-1);
}
plogf(" %12.4E |", m_gibbsSpecies[l]);
if (SpecLnMnaught[l] != 0.0) {
plogf(" (%14.7E)", - SpecLnMnaught[l]);
}
plogf("\n");
}
print_line("-", 115);
/*
* ------------- TABLE OF SOLUTION COUNTERS --------------------------
*/
plogf("\n");
plogf("\nCounters: Iterations Time (seconds)\n");
plogf(" vcs_basopt: %5d %11.5E\n",
m_VCount->Basis_Opts, m_VCount->Time_basopt);
plogf(" vcs_TP: %5d %11.5E\n",
m_VCount->Its, m_VCount->Time_vcs_TP);
print_line("-", 80);
print_line("-", 80);
/*
* Set the Units state of the system back to where it was when we
* entered the program.
*/
if (originalUnitsState != UnitsState) {
if (originalUnitsState == VCS_DIMENSIONAL_G ) vcs_redim_TP();
else vcs_nondim_TP();
}
/*
* Return a successful completion flag
*/
return VCS_SUCCESS;
} /* vcs_report() ************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::vcs_TCounters_report(void)
/**************************************************************************
*
* vcs_TCounters_report:
*
* Print out the total Its and time counters to standard output
***************************************************************************/
{
plogf("\nTCounters: Num_Calls Total_Its Total_Time (seconds)\n");
plogf(" vcs_basopt: %5d %5d %11.5E\n",
m_VCount->T_Basis_Opts, m_VCount->T_Basis_Opts, m_VCount->T_Time_basopt);
plogf(" vcs_TP: %5d %5d %11.5E\n",
m_VCount->T_Calls_vcs_TP, m_VCount->T_Its, m_VCount->T_Time_vcs_TP);
plogf(" vcs_inest: %5d %11.5E\n",
m_VCount->T_Calls_Inest, m_VCount->T_Time_inest);
plogf(" vcs_TotalTime: %11.5E\n",
m_VCount->T_Time_vcs);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
}

View file

@ -0,0 +1,349 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_internal.h"
namespace VCSnonideal {
#define TOL_CONV 1.0E-5
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifdef DEBUG_ROOT1D
static void print_funcEval(FILE *fp, double xval, double fval, int its)
{
fprintf(fp,"\n");
fprintf(fp,"...............................................................\n");
fprintf(fp,".................. vcs_root1d Function Evaluation .............\n");
fprintf(fp,".................. iteration = %5d ........................\n", its);
fprintf(fp,".................. value = %12.5g ......................\n", xval);
fprintf(fp,".................. funct = %12.5g ......................\n", fval);
fprintf(fp,"...............................................................\n");
fprintf(fp,"\n");
}
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int vcsUtil_root1d(double xmin, double xmax, int itmax,
VCS_FUNC_PTR func, void *fptrPassthrough,
double FuncTargVal, int varID,
double *xbest)
/**************************************************************************
*
* vcs_root1d:
*
* Driver for solving a 1D function.
***************************************************************************/
{
static int callNum = 0;
const char *stre = "vcs_root1d ERROR: ";
const char *strw = "vcs_root1d WARNING: ";
int converged = FALSE, err = FALSE;
#ifdef DEBUG_ROOT1D
char fileName[80];
FILE *fp;
#endif
double x1, x2, xnew, f1, f2, fnew, slope;
int its = 0, posStraddle, retn = VCS_SUCCESS;
int foundPosF = FALSE;
int foundNegF = FALSE;
int foundStraddle = FALSE;
double xPosF, xNegF;
double fnorm; /* A valid norm for the making the function value
* dimensionless */
double c[9], f[3], xn1, xn2, x0 = 0.0, f0 = 0.0, root, theta, xquad;
callNum++;
#ifdef DEBUG_ROOT1D
sprintf(fileName, "rootfd_%d.log", callNum);
fp = fopen(fileName, "w");
fprintf(fp, " Iter TP_its xval Func_val | Reasoning\n");
fprintf(fp, "-----------------------------------------------------"
"-------------------------------\n");
#endif
if (xmax <= xmin) {
plogf("%sxmin and xmax are bad: %g %g\n", stre, xmin, xmax);
return VCS_PUB_BAD;
}
x1 = *xbest;
if (x1 < xmin || x1 > xmax) {
x1 = (xmin + xmax) / 2.0;
}
f1 = func(x1, FuncTargVal, varID, fptrPassthrough, &err);
#ifdef DEBUG_ROOT1D
print_funcEval(x1, f1, its);
fprintf(fp, "%-5d %-5d %-15.5E %-15.5E\n", -2, VCount->Its, x1, f1);
#endif
if (f1 == 0.0) {
*xbest = x1;
return VCS_SUCCESS;
}
else if (f1 > 0.0) {
foundPosF = TRUE;
xPosF = x1;
} else {
foundNegF = TRUE;
xNegF = x1;
}
x2 = x1 * 1.1;
if (x2 > xmax) x2 = x1 - (xmax - xmin) / 100.;
f2 = func(x2, FuncTargVal, varID, fptrPassthrough, &err);
#ifdef DEBUG_ROOT1D
print_funcEval(x2, f2, its);
fprintf(fp, "%-5d %-5d %-15.5E %-15.5E", -1, VCount->Its, x2, f2);
#endif
if (FuncTargVal != 0.0) {
fnorm = fabs(FuncTargVal) + 1.0E-13;
} else {
fnorm = 0.5*(fabs(f1) + fabs(f2)) + fabs(FuncTargVal);
}
if (f2 == 0.0)
return retn;
else if (f2 > 0.0) {
if (!foundPosF) {
foundPosF = TRUE;
xPosF = x2;
}
} else {
if (!foundNegF) {
foundNegF = TRUE;
xNegF = x2;
}
}
foundStraddle = foundPosF && foundNegF;
if (foundStraddle) {
if (xPosF > xNegF) posStraddle = TRUE;
else posStraddle = FALSE;
}
do {
/*
* Find an estimate of the next point to try based on
* a linear approximation.
*/
slope = (f2 - f1) / (x2 - x1);
if (slope == 0.0) {
plogf("%s functions evals produced the same result, %g, at %g and %g\n",
strw, f2, x1, x2);
xnew = 2*x2 - x1 + 1.0E-3;
} else {
xnew = x2 - f2 / slope;
}
#ifdef DEBUG_ROOT1D
fprintf(fp, " | xlin = %-9.4g", xnew);
#endif
/*
* Do a quadratic fit -> Note this algorithm seems
* to work OK. The quadratic approximation doesn't kick in until
* the end of the run, when it becomes reliable.
*/
if (its > 0) {
c[0] = 1.; c[1] = 1.; c[2] = 1.;
c[3] = x0; c[4] = x1; c[5] = x2;
c[6] = SQUARE(x0); c[7] = SQUARE(x1); c[8] = SQUARE(x2);
f[0] = - f0; f[1] = - f1; f[2] = - f2;
retn = vcsUtil_mlequ(c, 3, 3, f, 1);
if (retn == 1) goto QUAD_BAIL;
root = f[1]* f[1] - 4.0 * f[0] * f[2];
if (root >= 0.0) {
xn1 = (- f[1] + sqrt(root)) / (2.0 * f[2]);
xn2 = (- f[1] - sqrt(root)) / (2.0 * f[2]);
if (fabs(xn2 - x2) < fabs(xn1 - x2) && xn2 > 0.0 ) xquad = xn2;
else xquad = xn1;
theta = fabs(xquad - xnew) / fabs(xnew - x2);
theta = MIN(1.0, theta);
xnew = theta * xnew + (1.0 - theta) * xquad;
#ifdef DEBUG_ROOT1D
if (theta != 1.0) {
fprintf(fp, " | xquad = %-9.4g", xnew);
}
#endif
} else {
/*
* Pick out situations where the convergence may be
* accelerated.
*/
if ((DSIGN(xnew - x2) == DSIGN(x2 - x1)) &&
(DSIGN(x2 - x1) == DSIGN(x1 - x0)) ) {
xnew += xnew - x2;
#ifdef DEBUG_ROOT1D
fprintf(fp, " | xquada = %-9.4g", xnew);
#endif
}
}
}
QUAD_BAIL: ;
/*
*
* Put heuristic bounds on the step jump
*/
if ( (xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
/*
*
* If we are doing a jump inbetween two points, make sure
* the new trial is between 10% and 90% of the distance
* between the old points.
*/
slope = fabs(x2 - x1) / 10.;
if (fabs(xnew - x1) < slope) {
xnew = x1 + DSIGN(xnew-x1) * slope;
#ifdef DEBUG_ROOT1D
fprintf(fp, " | x10%% = %-9.4g", xnew);
#endif
}
if (fabs(xnew - x2) < slope) {
xnew = x2 + DSIGN(xnew-x2) * slope;
#ifdef DEBUG_ROOT1D
fprintf(fp, " | x10%% = %-9.4g", xnew);
#endif
}
} else {
/*
* If we are venturing into new ground, only allow the step jump
* to increase by 100% at each interation
*/
slope = 2.0 * fabs(x2 - x1);
if (fabs(slope) < fabs(xnew - x2)) {
xnew = x2 + DSIGN(xnew-x2) * slope;
#ifdef DEBUG_ROOT1D
fprintf(fp, " | xlimitsize = %-9.4g", xnew);
#endif
}
}
if (xnew > xmax) {
xnew = x2 + (xmax - x2) / 2.0;
#ifdef DEBUG_ROOT1D
fprintf(fp, " | xlimitmax = %-9.4g", xnew);
#endif
}
if (xnew < xmin) {
xnew = x2 + (x2 - xmin) / 2.0;
#ifdef DEBUG_ROOT1D
fprintf(fp, " | xlimitmin = %-9.4g", xnew);
#endif
}
if (foundStraddle) {
#ifdef DEBUG_ROOT1D
slope = xnew;
#endif
if (posStraddle) {
if (f2 > 0.0) {
if (xnew > x2) xnew = (xNegF + x2)/2;
if (xnew < xNegF) xnew = (xNegF + x2)/2;
} else {
if (xnew < x2) xnew = (xPosF + x2)/2;
if (xnew > xPosF) xnew = (xPosF + x2)/2;
}
} else {
if (f2 > 0.0) {
if (xnew < x2) xnew = (xNegF + x2)/2;
if (xnew > xNegF) xnew = (xNegF + x2)/2;
} else {
if (xnew > x2) xnew = (xPosF + x2)/2;
if (xnew < xPosF) xnew = (xPosF + x2)/2;
}
}
#ifdef DEBUG_ROOT1D
if (slope != xnew) {
fprintf(fp, " | xstraddle = %-9.4g", xnew);
}
#endif
}
fnew = func(xnew, FuncTargVal, varID, fptrPassthrough, &err);
#ifdef DEBUG_ROOT1D
fprintf(fp,"\n");
print_funcEval(xnew, fnew, its);
fprintf(fp, "%-5d %-5d %-15.5E %-15.5E", its, VCount->Its, xnew, fnew);
#endif
if (foundStraddle) {
if (posStraddle) {
if (fnew > 0.0) {
if (xnew < xPosF) xPosF = xnew;
} else {
if (xnew > xNegF) xNegF = xnew;
}
} else {
if (fnew > 0.0) {
if (xnew > xPosF) xPosF = xnew;
} else {
if (xnew < xNegF) xNegF = xnew;
}
}
}
if (! foundStraddle) {
if (fnew > 0.0) {
if (!foundPosF) {
foundPosF = TRUE;
xPosF = xnew;
foundStraddle = TRUE;
if (xPosF > xNegF) posStraddle = TRUE;
else posStraddle = FALSE;
}
} else {
if (!foundNegF) {
foundNegF = TRUE;
xNegF = xnew;
foundStraddle = TRUE;
if (xPosF > xNegF) posStraddle = TRUE;
else posStraddle = FALSE;
}
}
}
x0 = x1;
f0 = f1;
x1 = x2;
f1 = f2;
x2 = xnew;
f2 = fnew;
if (fabs(fnew / fnorm) < 1.0E-5) {
converged = TRUE;
}
its++;
} while (! converged && its < itmax);
if (converged) {
#ifdef DEBUG_ROOT1D
plogf("vcs_root1d success: convergence achieved\n");
fprintf(fp, " | vcs_root1d success in %d its, fnorm = %g\n", its, fnorm);
#endif
} else {
retn = VCS_FAILED_CONVERGENCE;
plogf("vcs_root1d ERROR: maximum iterations exceeded without convergence\n");
#ifdef DEBUG_ROOT1D
fprintf(fp, "\nvcs_root1d failure in %d its\n", its);
#endif
}
*xbest = x2;
#ifdef DEBUG_ROOT1D
fclose(fp);
#endif
return retn;
}
/*****************************************************************************/
}

View file

@ -0,0 +1,533 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int VCS_SOLVE::vcs_rxn_adj_cg(void)
/**************************************************************************
*
* vcs_rxn_adj_cg:
*
* Calculates reaction adjustments. This does what equation 6.4-16, p. 143
* in Smith and Missen is suppose to do. However, a full matrix is
* formed and then solved via a conjugate gradient algorithm. No
* preconditioning is done.
*
* If special branching is warranted, then the program bails out.
*
* Output
* -------
* DS(I) : reaction adjustment, where I refers to the Ith species
* 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.
*
* Special attention is taken to flag cases where the direction of the
* update is contrary to the steepest descent rule. This is an important
* attribute of the regular vcs algorithm. We don't want to violate this
***************************************************************************/
{
int irxn, j, k, kspec, soldel = 0;
double s, xx, dss;
double *dnPhase_irxn;
#ifdef DEBUG
char ANOTE[128];
plogf(" "); for (j = 0; j < 77; j++) plogf("-");
plogf("\n --- Subroutine rxn_adj_cg() called\n");
plogf(" --- Species Moles Rxn_Adjustment | Comment\n");
#endif
/*
* Precalculation loop -> we calculate quantities based on
* loops over the number of species.
* We also evaluate whether the matrix is appropriate for
* this algorithm. If not, we bail out.
*/
for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
#ifdef DEBUG
sprintf(ANOTE,"Normal Calc");
#endif
kspec = ir[irxn];
dnPhase_irxn = DnPhase[irxn];
if (soln[kspec] == 0.0 && (! SSPhase[kspec])) {
/* *******************************************************************/
/* **** MULTISPECIES PHASE WITH total moles equal to zero ************/
/* *******************************************************************/
/*
* HKM -> the statment below presupposes units in dg[]. It probably
* should be replaced with something more relativistic
*/
if (dg[irxn] < -1.0e-4) {
#ifdef DEBUG
(void) sprintf(ANOTE, "MultSpec: come alive DG = %11.3E", dg[irxn]);
#endif
ds[kspec] = 1.0e-10;
spStatus[irxn] = VCS_SPECIES_MAJOR;
--(m_numRxnMinorZeroed);
} else {
#ifdef DEBUG
(void) 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
sprintf(ANOTE,"Skipped: converged DG = %11.3E\n", dg[irxn]);
plogf(" --- "); plogf("%-12.12s", SpName[kspec].c_str());
plogf(" %12.4E %12.4E | %s\n", soln[kspec], ds[kspec], ANOTE);
#endif
continue;
}
/*
* Don't calculate for minor or nonexistent species if
* their values are to be decreasing anyway.
*/
if (spStatus[irxn] <= VCS_SPECIES_MINOR && dg[irxn] >= 0.0) {
#ifdef DEBUG
sprintf(ANOTE,"Skipped: IC = %3d and DG >0: %11.3E\n",
spStatus[irxn], dg[irxn]);
plogf(" --- "); plogf("%-12.12s", SpName[kspec].c_str());
plogf(" %12.4E %12.4E | %s\n", soln[kspec], ds[kspec], 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]) s += SQUARE(sc[irxn][j]) / soln[j];
}
for (j = 0; j < NPhase; j++) {
if (! (VPhaseList[j])->SingleSpecies) {
if (TPhMoles[j] > 0.0)
s -= SQUARE(dnPhase_irxn[j]) / TPhMoles[j];
}
}
if (s != 0.0) {
ds[kspec] = -dg[irxn] / s;
} else {
/* ************************************************************ */
/* **** REACTION IS ENTIRELY AMONGST SINGLE SPECIES PHASES **** */
/* **** DELETE ONE SOLID 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.
*/
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;
TPhMoles[PhaseID[k]] = 0.0;
#ifdef DEBUG
plogf(" --- vcs_st2 Special section to delete ");
plogf("%-12.12s", SpName[k].c_str());
plogf("\n --- 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
plogf(" --- "); plogf("%-12.12s", SpName[kspec].c_str());
plogf(" %12.4E %12.4E | %s\n", soln[kspec], ds[kspec], ANOTE);
#endif
} /* End of loop over non-component stoichiometric formation reactions */
/*
*
* When we form the Hessian we must be careful to ensure that it
* is a symmetric positive definate matrix, still. This means zeroing
* out columns when we zero out rows as well.
* -> I suggest writing a small program to make sure of this
* property.
*/
#ifdef DEBUG
plogf(" "); for (j = 0; j < 77; j++) plogf("-"); plogf("\n");
#endif
return soldel;
} /* vcs_rxn_adj_cg() ********************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::vcs_Hessian_diag_adj(int irxn, double hessianDiag_Ideal)
/**************************************************************************
*
* vcs_actCoeff_diag_adj(irxn):
*
* Calculates the diagonal contribution to the Hessian due to
* the dependence of the activity coefficients on the mole numbers.
*
* (See framemaker notes, Eqn. 20 - VCS Equations document)
*
* We allow the diagonal to be increased positively to any degree.
* We allow the diagonal to be decreased to 1/3 of the ideal solution
* value, but no more -> it must remain positive.
**************************************************************************/
{
double diag = hessianDiag_Ideal;
double hessActCoef = vcs_Hessian_actCoeff_diag(irxn);
if (hessianDiag_Ideal <= 0.0) {
plogf("We shouldn't be here\n");
exit(-1);
}
if (hessActCoef >= 0.0) {
diag += hessActCoef;
} else if (fabs(hessActCoef) < 0.6666 * hessianDiag_Ideal) {
diag += hessActCoef;
} else {
diag -= 0.6666 * hessianDiag_Ideal;
}
return diag;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::vcs_Hessian_actCoeff_diag(int irxn)
/**************************************************************************
*
* vcs_Hessian_actCoeff_diag(irxn):
*
* Calculates the diagonal contribution to the Hessian due to
* the dependence of the activity coefficients on the mole numbers.
* (See framemaker notes, Eqn. 20 - VCS Equations document)
**************************************************************************/
{
int kspec, k, l, kph;
double s;
double *sc_irxn;
kspec = ir[irxn];
kph = PhaseID[kspec];
sc_irxn = sc[irxn];
/*
* First the diagonal term of the Jacobian
*/
s = dLnActCoeffdMolNum[kspec][kspec];
/*
* Next, the other terms. Note this only a loop over the components
* So, it's not too expensive to calculate.
*/
for (l = 0; l < m_numComponents; l++) {
if (!SSPhase[l]) {
for (k = 0; k < m_numComponents; ++k) {
if (PhaseID[k] == PhaseID[l]) {
s += sc_irxn[k] * sc_irxn[l] * dLnActCoeffdMolNum[k][l];
}
}
if (kph == PhaseID[l]) {
s += sc_irxn[l] * (dLnActCoeffdMolNum[kspec][l] + dLnActCoeffdMolNum[l][kspec]);
}
}
}
return s;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void VCS_SOLVE::vcs_CalcLnActCoeffJac(const double * const moleSpeciesVCS)
/*************************************************************************
*
*
*
*
*************************************************************************/
{
/*
* Loop over all of the phases in the problem
*/
for (int iphase = 0; iphase < NPhase; iphase++) {
vcs_VolPhase *Vphase = VPhaseList[iphase];
/*
* We don't need to call single species phases;
*/
if (!Vphase->SingleSpecies) {
/*
* update the Ln Act Coeff jacobian entries with respect to the
* mole number of species in the phase
*/
Vphase->updateLnActCoeffJac(moleSpeciesVCS);
/*
* Download the resulting calculation into the full matrix
* -> This scatter calculation is carried out in the
* volume object.
*/
Vphase->sendToVCSLnActCoeffJac(dLnActCoeffdMolNum.baseDataAddr());
}
}
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::deltaG_Recalc_Rxn(int irxn, const double *const molNum,
double * const ac, double * const mu_i)
/*************************************************************************
*
* deltaG_Recalc_Rxn
* This function recalculates the deltaG for reaction irxn,
* given the mole numbers in molNum. It uses the temporary
* space mu_i, to hold the chemical potentials
*************************************************************************/
{
int kspec = irxn + m_numComponents;
int *pp_ptr = PhaseParticipation[irxn];
for (int iphase = 0; iphase < NPhase; iphase++) {
if (pp_ptr[iphase]) {
vcs_chemPotPhase(iphase, molNum, ac, mu_i);
}
}
double deltaG = mu_i[kspec];
double *sc_irxn = sc[irxn];
for (int k = 0; k < m_numComponents; k++) {
deltaG += sc_irxn[k] * mu_i[k];
}
return deltaG;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifdef DEBUG
double VCS_SOLVE::vcs_line_search(int irxn, double dx_orig, char *ANOTE)
#else
double VCS_SOLVE::vcs_line_search(int irxn, double dx_orig)
#endif
/*************************************************************************
*
* In this routine we carry out a rough line search algorithm
* to make sure that the dG doesn't switch signs prematurely.
*
*
*************************************************************************/
{
int its = 0;
int k;
int kspec = ir[irxn];
const int MAXITS = 10;
double dx = dx_orig;
double *sc_irxn = sc[irxn];
double *molNumBase = VCS_DATA_PTR(soln);
double *acBase = VCS_DATA_PTR(ActCoeff0);
double *ac = VCS_DATA_PTR(ActCoeff);
double *molNum = VCS_DATA_PTR(wt);
double molSum = 0.0;
double slope;
/*
* Calculate the deltaG value at the dx = 0.0 point
*/
double deltaGOrig = deltaG_Recalc_Rxn(irxn, molNumBase, acBase, VCS_DATA_PTR(fel));
double forig = fabs(deltaGOrig) + 1.0E-15;
if (deltaGOrig > 0.0) {
if (dx_orig > 0.0) {
dx = 0.0;
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
//plogf(" --- %s :Warning possible error dx>0 dg > 0\n", SpName[kspec]);
}
sprintf(ANOTE,"Rxn reduced to zero step size in line search: dx>0 dg > 0");
#endif
return dx;
}
} else if (deltaGOrig < 0.0) {
if (dx_orig < 0.0) {
dx = 0.0;
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
//plogf(" --- %s :Warning possible error dx<0 dg < 0\n", SpName[kspec]);
}
sprintf(ANOTE,"Rxn reduced to zero step size in line search: dx<0 dg < 0");
#endif
return dx;
}
} else if (deltaGOrig == 0.0) {
return 0.0;
}
if (dx_orig == 0.0) return 0.0;
vcs_dcopy(molNum, molNumBase, m_numSpeciesRdc);
molSum = molNumBase[kspec];
molNum[kspec] = molNumBase[kspec] + dx_orig;
for (k = 0; k < m_numComponents; k++) {
molNum[k] = molNumBase[k] + sc_irxn[k] * dx_orig;
molSum += molNumBase[k];
}
double deltaG1 = deltaG_Recalc_Rxn(irxn, molNum, ac, VCS_DATA_PTR(feTrial));
/*
* If deltaG hasn't switched signs when going the full distance
* then we are heading in the appropriate direction, and
* we should accept the current full step size
*/
if (deltaG1 * deltaGOrig > 0.0) {
dx = dx_orig;
goto finalize;
}
/*
* If we have decreased somewhat, the deltaG return after finding
* a better estimate for the line search.
*/
if (fabs(deltaG1) < 0.8*forig) {
if (deltaG1 * deltaGOrig < 0.0) {
slope = (deltaG1 - deltaGOrig) / dx_orig;
dx = -deltaGOrig / slope;
} else {
dx = dx_orig;
}
goto finalize;
}
dx = dx_orig;
for (its = 0; its < MAXITS; its++) {
/*
* Calculate the approximation to the total Gibbs free energy at
* the dx *= 0.5 point
*/
dx *= 0.5;
molNum[kspec] = molNumBase[kspec] + dx;
for (k = 0; k < m_numComponents; k++) {
molNum[k] = molNumBase[k] + sc_irxn[k] * dx;
}
double deltaG = deltaG_Recalc_Rxn(irxn, molNum, ac, VCS_DATA_PTR(feTrial));
/*
* If deltaG hasn't switched signs when going the full distance
* then we are heading in the appropriate direction, and
* we should accept the current step
*/
if (deltaG * deltaGOrig > 0.0) {
goto finalize;
}
/*
* If we have decreased somewhat, the deltaG return after finding
* a better estimate for the line search.
*/
if (fabs(deltaG) / forig < (1.0 - 0.1 * dx / dx_orig)) {
if (deltaG * deltaGOrig < 0.0) {
slope = (deltaG - deltaGOrig) / dx;
dx = -deltaGOrig / slope;
}
goto finalize;
}
}
finalize:
if (its >= MAXITS) {
#ifdef DEBUG
sprintf(ANOTE,"Rxn reduced to zero step size from %g to %g (MAXITS)",
dx_orig, dx);
return dx;
#endif
}
#ifdef DEBUG
if (dx != dx_orig) {
sprintf(ANOTE,"Line Search reduced step size from %g to %g",
dx_orig, dx);
}
#endif
return dx;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
}

View file

@ -0,0 +1,231 @@
/*!
* @file vcs_setMolesLinProg.cpp
*
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
#include "vcs_species_thermo.h"
#include "vcs_solve.h"
#include <math.h>
#include <iostream>
using namespace std;
namespace VCSnonideal {
#ifdef DEBUG
static void printProgress(const vector<string> &spName,
const vector<double> &soln,
const vector<double> &ff) {
int nsp = soln.size();
double sum = 0.0;
plogf(" --- Summary of current progress:\n");
plogf(" --- Name Moles - SSGibbs \n");
plogf(" -------------------------------------------------------------------------------------\n");
for (int k = 0; k < nsp; k++) {
plogf(" --- %20s %12.4g - %12.4g\n", spName[k].c_str(), soln[k], ff[k]);
sum += soln[k] * ff[k];
}
plogf(" --- Total sum to be minimized = %g\n", sum);
}
#endif
//! Estimate the initial mole numbers.
/*!
* This is done by running
* each reaction as far forward or backward as possible, subject
* to the constraint that all mole numbers remain
* non-negative. Reactions for which \f$ \Delta \mu^0 \f$ are
* positive are run in reverse, and ones for which it is negative
* are run in the forward direction. The end result is equivalent
* to solving the linear programming problem of minimizing the
* linear Gibbs function subject to the element and
* non-negativity constraints.
*/
int VCS_SOLVE::vcs_setMolesLinProg() {
int ik, irxn;
double test = -1.0E-10;
#ifdef DEBUG
char *pprefix = " --- seMolesLinProg ";
if (vcs_debug_print_lvl >= 2) {
plogf(" --- call setInitialMoles\n");
}
#endif
// m_mu are standard state chemical potentials
// Boolean on the end specifies standard chem potentials
// m_mix->getValidChemPotentials(not_mu, DATA_PTR(m_mu), true);
// -> This is already done coming into the routine.
double dg_rt;
int idir;
double nu;
double delta_xi, dxi_min = 1.0e10;
bool redo = true;
int jcomp;
int retn;
int iter = 0;
bool abundancesOK = true;
int usedZeroedSpecies;
std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0);
std::vector<double> ss(m_numElemConstraints, 0.0);
std::vector<double> sa(m_numElemConstraints, 0.0);
std::vector<double> wx(m_numElemConstraints, 0.0);
std::vector<double> aw(m_numSpeciesTot, 0.0);
for (ik = 0; ik < m_numSpeciesTot; ik++) {
if (SpeciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) {
soln[ik] = MAX(0.0, soln[ik]);
}
}
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
printProgress(SpName, soln, ff);
}
#endif
while (redo) {
if (!vcs_elabcheck(0)) {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("%s Mole numbers failing element abundances\n", pprefix);
plogf("%sCall vcs_elcorr to attempt fix\n", pprefix);
}
#endif
retn = vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx));
if (retn >= 2) {
abundancesOK = false;
} else {
abundancesOK = true;
}
} else {
abundancesOK = true;
}
/*
* Now find the optimized basis that spans the stoichiometric
* coefficient matrix, based on the current composition, soln[]
* We also calculate sc[][], the reaction matrix.
*/
retn = vcs_basopt(FALSE, VCS_DATA_PTR(aw), VCS_DATA_PTR(sa),
VCS_DATA_PTR(sm), VCS_DATA_PTR(ss),
test, &usedZeroedSpecies);
if (retn != VCS_SUCCESS) return retn;
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf("iteration %d\n", iter);
}
#endif
redo = false;
iter++;
if (iter > 15) break;
// loop over all reactions
for (irxn = 0; irxn < m_numRxnTot; irxn++) {
// dg_rt is the Delta_G / RT value for the reaction
ik = m_numComponents + irxn;
dg_rt = ff[ik];
dxi_min = 1.0e10;
const double *sc_irxn = sc[irxn];
for (jcomp = 0; jcomp < m_numElemConstraints; jcomp++) {
dg_rt += ff[jcomp] * sc_irxn[jcomp];
}
// fwd or rev direction.
// idir > 0 implies increasing the current species
// idir < 0 implies decreasing the current species
idir = (dg_rt < 0.0 ? 1 : -1);
if (idir < 0) {
dxi_min = soln[ik];
}
for (jcomp = 0; jcomp < m_numComponents; jcomp++) {
nu = sc_irxn[jcomp];
// set max change in progress variable by
// non-negativity requirement
if (nu*idir < 0) {
delta_xi = fabs(soln[jcomp]/nu);
// if a component has nearly zero moles, redo
// with a new set of components
if (!redo) {
if (delta_xi < 1.0e-10 && (soln[ik] >= 1.0E-10)) {
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
plogf(" --- Component too small: %s\n", SpName[jcomp].c_str());
}
#endif
redo = true;
}
}
if (delta_xi < dxi_min) dxi_min = delta_xi;
}
}
// step the composition by dxi_min, check against zero, since
// we are zeroing components and species on every step.
// Redo the iteration, if a component went from positive to zero on this step.
double ds = idir*dxi_min;
soln[ik] += ds;
soln[ik] = MAX(0.0, soln[ik]);
for (jcomp = 0; jcomp < m_numComponents; jcomp++) {
bool full = false;
if (soln[jcomp] > 1.0E-15) {
full = true;
}
soln[jcomp] += sc_irxn[jcomp] * ds;
soln[jcomp] = MAX(0.0, soln[jcomp]);
if (full) {
if (soln[jcomp] < 1.0E-60) {
redo = true;
}
}
}
}
// set the moles of the phase objects to match
// updateMixMoles();
// Update the phase objects with the contents of the soln vector
// vcs_updateVP(0);
#ifdef DEBUG
if (vcs_debug_print_lvl >= 2) {
printProgress(SpName, soln, ff);
}
#endif
}
#ifdef DEBUG
if (vcs_debug_print_lvl == 1) {
printProgress(SpName, soln, ff);
plogf(" --- setInitialMoles end\n");
}
#endif
retn = 0;
if (!abundancesOK) {
retn = -1;
} else if (iter > 15) {
retn = 1;
}
return retn;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,807 @@
/**
* @file vcs_solve.h
* Header file for the internal object that holds the problem
*/
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef _VCS_SOLVE_H
#define _VCS_SOLVE_H
/*
* Index of Symbols
* -------------------
* irxn -> refers to the species or rxn between the species and
* the components in the problem
* k -> refers to the species
* j -> refers to the element or component
*
* ### -> to be eliminated
*/
#include <vector>
#include <string>
#include "vcs_defs.h"
#include "vcs_DoubleStarStar.h"
#include "vcs_IntStarStar.h"
namespace VCSnonideal {
/*
* Forward references
*/
class vcs_VolPhase;
class VCS_SPECIES_THERMO;
class VCS_PROB;
class VCS_COUNTERS;
//! This is the main structure used to hold the internal data
//! used in vcs_solve_TP(), and to solve TP systems.
/*!
* The indecises of information in this
* structure may change when the species basis changes or when
* phases pop in and out of existence. Both of these operations
* change the species ordering.
*
*/
class VCS_SOLVE {
public:
//! Constructor for the VCS_SOLVE class
VCS_SOLVE();
//! Destructor
~VCS_SOLVE();
void InitSizes(int nspecies0, int nelements, int nphase0);
//! Solve an equilibrium problem
/*!
* This is the main interface routine to the equilibrium solver
*
* Input:
* @param vprob Object containing the equilibrium Problem statement
*
* @param ifunc Determines the operation to be done: Valid values:
* 0 -> Solve a new problem by initializing structures
* first. An initial estimate may or may not have
* been already determined. This is indicated in the
* VCS_PROB structure.
* 1 -> The problem has already been initialized and
* set up. We call this routine to resolve it
* using the problem statement and
* solution estimate contained in
* the VCS_PROB structure.
* 2 -> Don't solve a problem. Destroy all the private
* structures.
*
* @param ipr Printing of results
* ipr = 1 -> Print problem statement and final results to
* standard output
* 0 -> don't report on anything
* @param ip1 Printing of intermediate results
* IP1 = 1 -> Print intermediate results.
*
* @param maxit Maximum number of iterations for the algorithm
*
* @param iprintTime Printing of time information. Default = -1,
* implies printing if other printing is turned
* on.
*
* Output:
*
* @return
* nonzero value: failure to solve the problem at hand.
* zero : success
*/
int vcs(VCS_PROB *vprob, int ifunc, int ipr, int ip1, int maxit,
int iprintTime = -1);
int vcs_solve_TP(int, int, int);
void vcs_reinsert_deleted(int kspec);
int vcs_basopt(int ifirst, double aw[], double sa[], double sm[],
double ss[], double test, int *usedZeroedSpecies);
int vcs_species_type(int kspec);
void vcs_chemPotPhase(int iph, const double *const molNum,
double * const ac, double * const mu_i,
bool do_deleted = false);
void vcs_dfe(double *z, int kk, int ll, int lbot, int ltop);
void vcs_updateVP(int place);
int vcs_RxnStepSizes(void);
void vcs_tmoles(void);
void vcs_deltag(int l, bool doDeleted);
void vcs_switch_pos(int ifunc, int k1, int k2);
void vcs_deltag_Phase(int iphase, bool doDeleted);
//! birthGuess 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.
/*!
* Do a minor alt calculation. But, cap the mole numbers at
* 1.0E-15.
* For SS phases use VCS_DELETE_SPECIES_CUTOFF * 100.
*
* The routine makes sure the guess doesn't reduce the concentration
* of a component by more than 1/3. Note this may mean that
* the vlaue coming back from this routine is zero or a
* very small number.
*
* @param kspec Species number that is coming back to life
* @return number of moles of the species
*/
double vcs_birthGuess(int kspec);
//! Solve an equilibrium problem at a particular fixed temperature
//! and pressure
/*!
* The actual problem statement is assumed to be in the structure
* already. This is a wrapper around the solve_TP() function.
* In this wrapper, we nondimensionalize the system
* we calculate the standard state gibbs free energies of the
* species, and we decide whether to we need to use the
* initial guess algorithm.
*
* @param ipr = 1 -> Print results to standard output
* 0 -> don't report on anything
* @param ip1 = 1 -> Print intermediate results.
* 0 -> Dont print any intermediate results
* @param maxit Maximum number of iterations for the algorithm
* @param T Value of the Temperature (Kelvin)
* Param pres Value of the Pressure (units given by m_VCS_UnitsFormat variable
*
* @return Returns an integer representing the success of the algorithm
* 0 = Equilibrium Achieved
* 1 = Range space error encountered. The element abundance criteria are
* only partially satisfied. Specifically, the first NC= (number of
* components) conditions are satisfied. However, the full NE
* (number of elements) conditions are not satisfied. The equilibrirum
* condition is returned.
* -1 = Maximum number of iterations is exceeded. Convergence was not
* found.
*/
int vcs_TP(int ipr, int ip1, int maxit, double T, double pres);
int vcs_evalSS_TP(int ipr, int ip1, double Temp, double pres);
void vcs_fePrep_TP(void);
int vcs_TV(int ipr, int ip1, int maxit, double T, double VolRequest);
double vcs_VolTotal(double, double, double [], double []);
int vcs_prep_oneTime(int printLvl);
//! Prepare the object for resolution
/*!
* This routine is mostly concerned with changing the private data
* to be consistent with that needed for solution. It is called for
* every invocation of the vcs_solve() except for the cleanup invocation.
*
* Tasks:
* 1) Initialization of arrays to zero.
*
* return code
* VCS_SUCCESS = everything went OK
* VCS_PUB_BAD = There is an irreconcilable difference in the
* public data structure from when the problem was
* initially set up.
*/
int vcs_prep(void);
bool vcs_wellPosed(VCS_PROB *vprob);
int vcs_elem_rearrange(double *aw, double *sa, double *sm, double *ss);
void vcs_switch_elem_pos(int ipos, int jpos);
int vcs_rxn_adj_cg(void);
double vcs_Hessian_diag_adj(int, double);
double vcs_Hessian_actCoeff_diag(int irxn);
void vcs_CalcLnActCoeffJac(const double * const moleSpeciesVCS);
#ifdef DEBUG
double vcs_line_search(int irxn, double dx_orig, char *ANOTE);
#else
double vcs_line_search(int irxn, double dx_orig);
#endif
int vcs_report(int);
int vcs_rearrange(void);
double vcs_nondim_Farad(int mu_units, double TKelvin);
double vcs_nondimMult_TP(int mu_units, double TKelvin);
void vcs_nondim_TP(void);
void vcs_redim_TP(void);
void vcs_printChemPotUnits(int unitsFormat);
void vcs_elab(void);
int vcs_elabcheck(int ibound);
void vcs_elabPhase(int iphase, double * const elemAbundPhase);
int vcs_elcorr(double aa[], double x[]);
int vcs_inest_TP(void);
#ifdef ALTLINPROG
//! Extimate the initial mole numbers by constrained linear programming
/*!
* This is done by running
* each reaction as far forward or backward as possible, subject
* to the constraint that all mole numbers remain
* non-negative. Reactions for which \f$ \Delta \mu^0 \f$ are
* positive are run in reverse, and ones for which it is negative
* are run in the forward direction. The end result is equivalent
* to solving the linear programming problem of minimizing the
* linear Gibbs function subject to the element and
* non-negativity constraints.
*/
int vcs_setMolesLinProg();
#endif
double vcs_Total_Gibbs(double *w, double *fe, double *tPhMoles);
double vcs_GibbsPhase(int iphase, double *w, double *fe);
double vcs_Gxs_phase_calc(vcs_VolPhase *Vphase, double *mf_PO);
double vcs_Gxs_calc(int iphase);
//! Transfer the results of the equilibrium calculation back to VCS_PROB
/*!
* The VCS_PUB structure is returned to the user.
*
* @param pub Pointer to VCS_PROB object that will get the results of the
* equilibrium calculation transfered to it.
*/
int vcs_prob_update(VCS_PROB *pub);
//! Fully specify the problem to be solved using VCS_PROB
/*!
* Use the contents of the VCS_PROB to specify the contents of the
* private data, VCS_SOLVE.
*
* @param pub Pointer to VCS_PROB that will be used to
* initialize the current equilibrium problem
*/
int vcs_prob_specifyFully(const VCS_PROB *pub);
//! Specify the problem to be solved using VCS_PROB, incrementally
/*!
* Use the contents of the VCS_PROB to specify the contents of the
* private data, VCS_SOLVE.
*
* It's assumed we are solving the same problem.
*
* @param pub Pointer to VCS_PROB that will be used to
* initialize the current equilibrium problem
*/
int VCS_SOLVE::vcs_prob_specify(const VCS_PROB *pub);
private:
int zero_species(int kspec);
int delete_species(int kspec);
void delete_multiphase(int iph);
int delta_species(int kspec, double *delta_ptr);
void add_deleted(void);
int recheck_deleted(void);
//! Alternative treatment for the update of a minor species
/*!
* @param kspec Species index of the minor species
* @param irxn Rxn index of the same minor species
* @param do_delete
*/
double minor_alt_calc(int kspec, int irxn, int *do_delete
#ifdef DEBUG
, char *ANOTE
#endif
);
int force(int iti);
void vcs_switch2D(double * const * const Jac, int k1, int k2);
double l2normdg(double dg[]);
#ifdef DEBUG
void prneav(void);
void checkDelta1(double * const ds, double * const delTPhMoles, int kspec);
#endif
void inest(double *aw, double *sa, double *sm,
double *ss, double test);
void vcs_SSPhase(void);
double deltaG_Recalc_Rxn(int irxn, const double *const molNum,
double * const ac, double * const mu_i);
void delete_memory();
//! Initialize the internal counters
/*!
* Initialize the internal counters containing the subroutine call
* values and times spent in the subroutines.
*
* ifunc = 0 Initialize only those counters appropriate for the top of
* vcs_solve_TP().
* = 1 Initialize all counters.
*/
void vcs_counters_init(int ifunc);
void vcs_TCounters_report(void);
public:
//! value of the number of species used to malloc data structures
int NSPECIES0;
//! value of the number of phases used to malloc data structures
int NPHASE0;
//! Total number of species in the problems
int m_numSpeciesTot;
//! Number of element constraints in the problem
/*!
* This is typically equal to the number of elements in the problem
*/
int m_numElemConstraints;
//! Number of components calculated for the problem
int m_numComponents;
//! Total number of non-component species in the problem
int m_numRxnTot;
//! Current number of species in the problems
/*!
* Species can be deleted if they aren't
* stable under the current conditions
*/
int m_numSpeciesRdc;
//! Current number of non-component species in the problem
/*!
* Species can be deleted if they aren't
* stable under the current conditions
*/
int m_numRxnRdc;
//! Number of active species which are currently either zeroed out or
//! are minor species
int m_numRxnMinorZeroed;
//! Number of Phases in the problem
int NPhase;
//! Formula matrix for the problem
/*!
* FormulaMatrix[j][kspec] = Number of elements, j, in the kspec species
*
* Both element and species indecies are swapped.
*/
DoubleStarStar FormulaMatrix;
//! Stoichiometric coefficient matrix for for the reaction mechanism
//! expressed in Reduced Canonical Form.
/*!
* This is the stoichiometric coefficient matrix for the
* reaction which forms species K from the component species. A
* stoichiometric coefficient of one is assumed for the
* species K in this mechanism.
*
* NOTE: K = IRXN + NC
*
* sc[irxn][j] :
* j refers to the component number, and irxn
* refers to the irxn_th non-component species.
*
*
* length = [nspecies0][nelements0]
*/
DoubleStarStar sc;
//! Absolute size of the stoichiometric coefficients
/*!
* scSize[irxn] = abs(Size) of the stoichiometric
* coefficients. These are used to determine
* whether a given species should be
* handled by the alt_min treatment or
* should be handled as a major species.
*/
std::vector<double> scSize;
//! Dimensionless/Dimensional free energy for all the species in the mechanism at the
//! current T, P, and mole numbers.
/*!
* The first NC entries are for components. The following
* NR entries are for the current non-component species in the mechanism.
* The dimension of this vector is specified by the m_VCS_UnitsFormat variable.
*/
std::vector<double> m_gibbsSpecies;
//! Standard state chemical potentials for species K at the current
//! temperature and pressure.
/*!
* The first NC entries are for components. The following NR entries are
* for the current non-component species in the mechanism.
*/
std::vector<double> ff;
//! Dimensionless trial free energy for all the species in the mechanism
//! at the current T, P, and mole numbers.
/*!
* The first NC entries are for components. The following
* NR entries are for the current non-component species in the mechanism.
*/
std::vector<double> feTrial;
//! Setting for the initial estimate
/*!
* Initial estimate: 0 user estimate
* -1 machine estimate
*/
int iest;
//! Total moles of the species
/*!
* soln[k] = Total number of moles of the kth species.
* Length = Total number of species = m
*/
std::vector<double> soln;
//! Specifies the species unknown type
/*!
* There are two types. One is the straightforward
* species, with the mole number w[k], as the
* unknown. The second is the an interfacial
* voltage where w[k] refers to the interfacial
* voltage in volts.
* These species types correspond to metalic
* electrons corresponding to electrodes.
* The voltage and other interfacial conditions
* sets up an interfacial current, which is
* set to zero in this initial treatment.
* Later we may have non-zero interfacial currents.
*/
std::vector<int> SpeciesUnknownType;
//! Change in the number of moles of phase, iphase, due to the noncomponent formation
//! reaction, irxn, for species, k:
/*!
* DnPhase[irxn][iphase] = k = nc + irxn
*/
DoubleStarStar DnPhase;
//! This is 1 if the phase, iphase, participates in the formation reaction
//! irxn, and zero otherwise. PhaseParticipation[irxn][iphase]
IntStarStar PhaseParticipation;
//! electric potential of the iph phase
std::vector<double> phasePhi;
//! Tentative value of the mole number vector. It's also used to store the
//! mole fraction vector.
std::vector<double> wt;
//! Delta G(I) for the noncomponent species in the mechanism.
/*!
* Computed by the subroutine DELTAG. DG is the free
* energy change for the reaction which
* forms species K from the
* component species. This vector has length
* equal to the number of noncomponent
* species in the mechanism. It starts with
* the first current noncomponent species
* in the mechanism.
*/
std::vector<double> dg;
//! Last deltag[irxn] from the previous step
std::vector<double> dgl;
//! Reaction Adjustments for each species
/*!
* Length = number of species
*/
std::vector<double> ds;
std::vector<double> fel; /* fel[k] = Old Free Energy vector from the previous
* iteration. fe[] is copied into fel[] */
std::vector<double> ga; /* ga[j] = Element abundances for jth element from
* estimate
* -> this is calculated from the current mole
* fraction vector and BM, the formula
* vector.
* units = gmoles */
std::vector<double> gai; /* gai[j] = Element abundances for jth element
* -> corrected
* -> this is input from the input file and
* is considered a constant from thereon.
* units = gmoles */
double TMoles; /* TMoles = Total number of moles in all phases
* This number includes the inerts.
* -> Don't use this except for scaling
* purposes only */
//! total gmols of species in each phase
/*!
* This contains the total number of moles of species in each phase
*
* Length = number of phases
*/
std::vector<double> TPhMoles;
//! total gmols of species in each phase in the tentative soln vector
/*!
* This contains the total number of moles of species in each phase
* in the tentative solution vector
*
* Length = number of phases
*/
std::vector<double> TPhMoles1;
//! Temporary vector of length NPhase
std::vector<double> TmpPhase;
//! Temporary vector of length NPhase
std::vector<double> TmpPhase2;
//! Change in the total moles in each phase
/*!
* Length number of phases.
*/
std::vector<double> DelTPhMoles;
//! Temperature (Kelvin)
double T;
//! Pressure (units are Pascals)
double Pres;
//! Total kmoles of inert to add to each phase
/*!
* TPhInertMoles[iph] = Total gmoles of inert to add to each phase
* length = number of phases
*/
std::vector<double> TPhInertMoles;
double tolmaj; /* tolmaj = Tolerance requirement for major species */
double tolmin; /* tolmin = Tolerance requirement for minor species */
double tolmaj2; /* tolmaj2 = Below this, major species aren't refined
* any more */
double tolmin2; /* tolmin2 = Below this, minor species aren't refined
* any more */
std::vector<int> ind; /* ind[k] = Index vector that keeps track of the
* rearrangement
* of the species vector within the problem.
* -> At the end of each run, the species
* vector and associated data gets put back
* in the original order. */
//! Index that keeps track of the index of the species according
//! to the phase
/*!
* indPhSp[k] = Index that keeps track of the index of the species according
* to the phase
* Length = number of species
*/
std::vector<int> indPhSp;
//! Index vector that keeps track of the rearrangement of the elements
/*!
* IndEl[j]
*/
std::vector<int> IndEl;
//! Mapping between the species index for noncomponent species and the
//! full species index.
/*!
* ir[irxn] = Mapping between the species index for
* noncomponent species and the full species
* index.
* - Initially set to a value of K = NC + I
* This vector has length equal to number
* of noncomponent species in the mechanism.
* It starts with the first current
* noncomponent species in the mechanism.
*/
std::vector<int> ir;
//! Major - Minor status Vector for the noncomponent
/*!
* species irxn : 1 -> Major player VCS_SPECIES_MAJOR
* 0 -> Minor player VCS_SPECIES_MINOR
* -1 -> Mole number is zero
* in inactive phase VCS_SPECIES_ZEROEDPHASE
* -2 -> Deleted species in an
* active multicom phase VCS_SPECIES_ZEROEDMS
* -3 -> Mole number is zero
* in a stoich phase - VCS_SPECIES_ZEREODSS
* -4 -> Species is deleted
* - VCS_SPECIES_DELETED
* -> Length equal to number of
* non-components*/
std::vector<int> spStatus;
//! Mapping from the species number to the phase number
std::vector<int> PhaseID;
//! Boolean indicating whether a species to single species phase
std::vector<int> SSPhase;
//! Species string name for the kth species
/*!
* SpName[k] = Species string name for the kth species
*/
std::vector<std::string> SpName;
//! Vector of strings containing the element names
/*!
* ElName[j] = String containing element names
*/
std::vector<std::string> ElName;
//! Type of the element constraint
/*!
* m_elType[j] = type of the element
* 0 VCS_ELEM_TYPE_ABSPOS Normal element that is positive
* or zero in all species.
* 1 VCS_ELEM_TPYE_ELECTRONCHARGE element dof that corresponds
* to the electronic charge DOF.
* 2 VCS_ELEM_TYPE_CHARGENEUTRALITY element dof that
* corresponds to a required charge
* neutrality constraint on the phase.
* The element abundance is always exactly zero.
* 3 VCS_ELEM_TYPE_OTHERCONSTRAINT Other constraint which may
* mean that a species has neg 0 or pos value
* of that constraint (other than charge)
*/
std::vector<int> m_elType;
//! Specifies whether an element constraint is active
/*!
* The default is true
* Length = nelements
*/
std::vector<int> ElActive;
//! Array of Phase Structures
/*!
* Length = number of phases
*/
std::vector<vcs_VolPhase *> VPhaseList;
//! String containing the title of the run
std::string Title;
//! This specifies the current state of units for the Gibbs free energy
//! properties in the program.
/*!
*. The default is to have this unitless
*/
char UnitsState;
//! specifies the activity convention of the phase containing the species
/*!
* SpecActConvention[kspec]
* 0 = molar based
* 1 = molality based
* length = number of species
*/
std::vector<int> SpecActConvention;
//! specifies the activity convention of the phase.
/*!
* 0 = molar based
* 1 = molality based
* length = number of phases
*/
std::vector<int> PhaseActConvention;
//! specifies the ln(Mnaught) used to calculate the chemical potentials
/*!
* For molar based activity conventions
* this will be equal to 0.0
* length = number of species
*/
std::vector<double> SpecLnMnaught;
//! Activity Coefficients for Species
/*!
*
* Length = number of species
*/
std::vector<double> ActCoeff;
//! Activity Coefficients for Species
/*!
*
* Length = number of species
*/
std::vector<double> ActCoeff0;
//! Change in activity coefficient with mole number
/*!
* length = [nspecies][nspecies]
*
* (This is a temporary array that
* gets regenerated every time it's
* needed. It is not swapped wrt species
* (unused atm)
*/
DoubleStarStar dLnActCoeffdMolNum;
//! This boolean indicates whether the activity coefficients for a phase
//! are current.
std::vector<int> CurrPhAC;
//! Molecular weight of each species
/*!
* units = gm/gmol
* length = number of species
*/
std::vector<double> WtSpecies;
//! Charge of each species
/*!
* Length = number of species
*/
std::vector<double> Charge;
//! Vector of pointers to thermostructures which identify the model
//! and parameters for evaluating the thermodynamic functions for that
//! particular species.
/*!
* SpeciesThermo[k] pointer to the thermo information for the kth species
*/
std::vector<VCS_SPECIES_THERMO *> SpeciesThermo;
//! Choice of Hessians
/*!
* If this is true, then we will use a better approximation to the
* Hessian based on Jacobian of the ln(ActCoeff) with respect to mole
* numbers
*/
int UseActCoeffJac;
double Vol; /* Vol = Volume (cm^3) */
//! Partialm molar volumes of the species
/*!
* units = mks (m^3/kmol) -determined by m_VCS_UnitsFormat
* Length = number of species
*/
std::vector<double> VolPM;
//! dimensionless value of Faraday's constant
/*!
* F / RT (1/volt)
*/
double Faraday_dim;
VCS_COUNTERS *m_VCount;
#ifdef DEBUG
int vcs_debug_print_lvl;
#endif
//! Units for the chemical potential data:
/*!
* VCS_UnitsFormat = Units for the chemical potential data:
* -1: kcal/mol
* 0: MU/RT
* 1: kJ/mol
* 2: Kelvin
* 3: J / kmol
* and pressure data:
* -1: atm
* 0: atm
* 1: atm
* 2: atm
* 3: Pa
*/
int m_VCS_UnitsFormat;
};
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,494 @@
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vcs_solve.h"
#include "vcs_species_thermo.h"
#include "vcs_defs.h"
#include "vcs_VolPhase.h"
#include "vcs_nasa_poly.h"
#include "vcs_Exception.h"
#include "vcs_internal.h"
using namespace std;
namespace VCSnonideal {
/*****************************************************************************
*
* constructor():
*/
VCS_SPECIES_THERMO::VCS_SPECIES_THERMO(int indexPhase,
int indexSpeciesPhase) :
IndexPhase(indexPhase),
IndexSpeciesPhase(indexSpeciesPhase),
OwningPhase(0),
SS0_Model(VCS_SS0_CONSTANT),
SS0_feSave(0.0),
SS0_TSave(-90.0),
SS0_T0(273.15),
SS0_H0(0.0),
SS0_S0(0.0),
SS0_Cp0(0.0),
SS0_Pref(1.0),
SS0_Params(0),
SSStar_Model(VCS_SSSTAR_CONSTANT),
SSStar_Params(0),
Activity_Coeff_Model(VCS_AC_CONSTANT),
Activity_Coeff_Params(0),
SSStar_Vol_Model(VCS_SSVOL_IDEALGAS),
SSStar_Vol_Params(0),
SSStar_Vol0(-1.0),
UseCanteraCalls(false),
m_VCS_UnitsFormat(VCS_UNITS_UNITLESS)
{
/*
* Set up the numerical value for P_reference, based on the current
* global units choice.
*/
if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
SS0_Pref = 1.0133E5;
} else {
SS0_Pref = 1.0;
}
}
/******************************************************************************
*
* destructor
*/
VCS_SPECIES_THERMO::~VCS_SPECIES_THERMO()
{
if (SS0_Model == VCS_SS0_NASA_POLY) {
vcs_nasa_poly_destroy((VCS_NASA_POLY **) &(this->SS0_Params));
SS0_Params = 0;
}
}
/*****************************************************************************
*
* Copy Constructor VCS_SPECIES_THERMO
*/
VCS_SPECIES_THERMO::VCS_SPECIES_THERMO(const VCS_SPECIES_THERMO& b) :
IndexPhase(b.IndexPhase),
IndexSpeciesPhase(b.IndexSpeciesPhase),
OwningPhase(b.OwningPhase),
SS0_Model(b.SS0_Model),
SS0_feSave(b.SS0_feSave),
SS0_TSave(b.SS0_TSave),
SS0_T0(b.SS0_T0),
SS0_H0(b.SS0_H0),
SS0_S0(b.SS0_S0),
SS0_Cp0(b.SS0_Cp0),
SS0_Pref(b.SS0_Pref),
SS0_Params(0),
SSStar_Model(b.SSStar_Model),
SSStar_Params(0),
Activity_Coeff_Model(b.Activity_Coeff_Model),
Activity_Coeff_Params(0),
SSStar_Vol_Model(b.SSStar_Vol_Model),
SSStar_Vol_Params(0),
SSStar_Vol0(b.SSStar_Vol0),
UseCanteraCalls(b.UseCanteraCalls),
m_VCS_UnitsFormat(b.m_VCS_UnitsFormat)
{
switch (SS0_Model) {
case VCS_SS0_NASA_POLY:
VCS_NASA_POLY *ppp = (VCS_NASA_POLY *) b.SS0_Params;
SS0_Params = (void *) new VCS_NASA_POLY(*ppp);
break;
default:
break;
}
}
/*****************************************************************************
*
* Assignment operator for VCS_SPECIES_THERMO
*/
VCS_SPECIES_THERMO&
VCS_SPECIES_THERMO::operator=(const VCS_SPECIES_THERMO& b)
{
if (&b != this) {
IndexPhase = b.IndexPhase;
IndexSpeciesPhase = b.IndexSpeciesPhase;
OwningPhase = b.OwningPhase;
SS0_Model = b.SS0_Model;
SS0_feSave = b.SS0_feSave;
SS0_TSave = b.SS0_TSave;
SS0_T0 = b.SS0_T0;
SS0_H0 = b.SS0_H0;
SS0_S0 = b.SS0_S0;
SS0_Cp0 = b.SS0_Cp0;
SS0_Pref = b.SS0_Pref;
switch (SS0_Model) {
case VCS_SS0_NASA_POLY:
VCS_NASA_POLY *ppp = (VCS_NASA_POLY *) b.SS0_Params;
SS0_Params = (void *) new VCS_NASA_POLY(*ppp);
break;
default:
break;
}
SSStar_Model = b.SSStar_Model;
/*
* shallow copy because function is undeveloped.
*/
SSStar_Params = b.SSStar_Params;
Activity_Coeff_Model = b.Activity_Coeff_Model;
/*
* shallow copy because function is undeveloped.
*/
Activity_Coeff_Params = b.Activity_Coeff_Params;
SSStar_Vol_Model = b.SSStar_Vol_Model;
/*
* shallow copy because function is undeveloped.
*/
SSStar_Vol_Params = b.SSStar_Vol_Params;
SSStar_Vol0 = b.SSStar_Vol0;
UseCanteraCalls = b.UseCanteraCalls;
m_VCS_UnitsFormat = b.m_VCS_UnitsFormat;
}
return *this;
}
/******************************************************************************
*
* duplMyselfAsVCS_SPECIES_THERMO(): (virtual)
*
* This routine can duplicate inherited objects given a base class
* pointer. It relies on valid copy constructors.
*/
VCS_SPECIES_THERMO* VCS_SPECIES_THERMO::duplMyselfAsVCS_SPECIES_THERMO() {
VCS_SPECIES_THERMO* ptr = new VCS_SPECIES_THERMO(*this);
return ptr;
}
/**************************************************************************
*
* GStar_R_calc();
*
* This function calculates the standard state Gibbs free energy
* for species, kspec, at the solution temperature TKelvin and
* solution pressure, Pres.
*
*
* Input
* kglob = species global index.
* TKelvin = Temperature in Kelvin
* pres = pressure is given in units specified by if__ variable.
*
*
* Output
* return value = standard state free energy in units of Kelvin.
*/
double VCS_SPECIES_THERMO::GStar_R_calc(int kglob, double TKelvin,
double pres)
{
char yo[] = "VCS_SPECIES_THERMO::GStar_R_calc ";
double fe, T;
fe = G0_R_calc(kglob, TKelvin);
T = TKelvin;
if (UseCanteraCalls) {
AssertThrowVCS(m_VCS_UnitsFormat == VCS_UNITS_MKS, "Possible inconsistency");
int kspec = IndexSpeciesPhase;
fe = OwningPhase->GStar_calc_one(kspec, TKelvin, pres);
double R = vcsUtil_gasConstant(m_VCS_UnitsFormat);
fe /= R;
} else {
double pref = SS0_Pref;
switch(SSStar_Model) {
case VCS_SSSTAR_CONSTANT:
break;
case VCS_SSSTAR_IDEAL_GAS:
fe += T * log( pres/ pref );
break;
default:
plogf("%sERROR: unknown SSStar model\n", yo);
exit(-1);
}
}
return fe;
}
/**************************************************************************
*
* VolStar_calc:
*
* This function calculates the standard state molar volume
* for species, kspec, at the temperature TKelvin and pressure, Pres,
*
* Input
*
* Output
* return value = standard state volume in cm**3 per mol.
* (VCS_UNITS_MKS) m**3 / kmol
*/
double VCS_SPECIES_THERMO::
VolStar_calc(int kglob, double TKelvin, double pres)
{
char yo[] = "VCS_SPECIES_THERMO::VStar_calc ";
double vol, T;
T = TKelvin;
if (UseCanteraCalls) {
AssertThrowVCS(m_VCS_UnitsFormat == VCS_UNITS_MKS, "Possible inconsistency");
int kspec = IndexSpeciesPhase;
vol = OwningPhase->VolStar_calc_one(kspec, TKelvin, pres);
} else {
switch(SSStar_Vol_Model) {
case VCS_SSVOL_CONSTANT:
vol = SSStar_Vol0;
break;
case VCS_SSVOL_IDEALGAS:
if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
vol = 8.31451E3 * T / pres;
} else {
vol= 83.14510 / 1.01325 * T / pres;
}
break;
default:
plogf("%sERROR: unknown SSVol model\n", yo);
exit(-1);
}
}
return vol;
}
/**************************************************************************
*
* G0_R_calc:
*
* This function calculates the naught state Gibbs free energy
* for species, kspec, at the temperature TKelvin
*
* Input
* kglob = species global index.
* TKelvin = Temperature in Kelvin
*
* Output
* return value = naught state free energy in Kelvin.
*/
double VCS_SPECIES_THERMO::G0_R_calc(int kglob, double TKelvin)
{
#ifdef DEBUG
char yo[] = "VS_SPECIES_THERMO::G0_R_calc ";
#endif
double fe, H, S;
if (SS0_Model == VCS_SS0_CONSTANT) {
fe = SS0_feSave;
return fe;
}
if (TKelvin == SS0_TSave) {
fe = SS0_feSave;
return fe;
}
if (UseCanteraCalls) {
AssertThrowVCS(m_VCS_UnitsFormat == VCS_UNITS_MKS, "Possible inconsistency");
int kspec = IndexSpeciesPhase;
fe = OwningPhase->G0_calc_one(kspec, TKelvin);
double R = vcsUtil_gasConstant(m_VCS_UnitsFormat);
fe /= R;
} else {
switch (SS0_Model) {
case VCS_SS0_CONSTANT:
fe = SS0_feSave;
break;
case VCS_SS0_CONSTANT_CP:
H = SS0_H0 + (TKelvin - SS0_T0) * SS0_Cp0;
S = SS0_Cp0 + SS0_Cp0 * log((TKelvin / SS0_T0));
fe = H - TKelvin * S;
break;
case VCS_SS0_NASA_POLY:
fe = vcs_G0_NASA(TKelvin, (VCS_NASA_POLY *) SS0_Params);
break;
default:
#ifdef DEBUG
plogf("%sERROR: unknown model\n", yo);
#endif
exit(-1);
}
}
SS0_feSave = fe;
SS0_TSave = TKelvin;
return fe;
}
/**************************************************************************
*
* eval_ac:
*
* This function evaluates the activity coefficient
* for species, kspec
*
* Input
* kglob -> integer value of the species in the global
* species list within VCS_GLOB. Phase and local species id
* can be looked up within object.
*
* Note, T, P and mole fractions are obtained from the
* single private instance of VCS_GLOB
*
*
* Output
* return value = activity coefficient for species kspec
*/
double VCS_SPECIES_THERMO::eval_ac(int kglob)
{
#ifdef DEBUG
char yo[] = "VCS_SPECIES_THERMO::eval_ac ";
#endif
double ac;
/*
* Activity coefficients are frequently evaluated on a per phase
* basis. If they are, then the currPhAC[] boolean may be used
* to reduce repeated work. Just set currPhAC[iph], when the
* activity coefficients for all species in the phase are reevaluated.
*/
if (UseCanteraCalls) {
int kspec = IndexSpeciesPhase;
ac = OwningPhase->AC_calc_one(kspec);
} else {
switch (Activity_Coeff_Model) {
case VCS_AC_CONSTANT:
ac = 1.0;
break;
case VCS_AC_DEBYE_HUCKEL:
plogf("Not implemented Yet\n");
exit(-1);
break;
case VCS_AC_REGULAR_SOLN:
plogf("Not implemented Yet\n");
exit(-1);
break;
case VCS_AC_MARGULES:
plogf("Not implemented Yet\n");
exit(-1);
break;
default:
#ifdef DEBUG
plogf("%sERROR: unknown model\n", yo);
#endif
exit(-1);
}
}
return ac;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::vcs_Gxs_phase_calc(vcs_VolPhase *Vphase, double *mf_PO)
/**************************************************************************
*
* vcs_Gxs_calc:
*
* This function evaluates the Gibbs Excess free energy function for
* the phase pointed to by Vphase.
*
* There are two ways. They may be evaluated from the
* activity coefficients themselves
*
* Gxs/RT = sum_i_inphase( X_i * ln (ActCoeff_i))
*
* Or, the actual formulas for the excess Gibbs free energy may
* be used (which the activity coefficients probably came from anyway.
*
* Input
* phase_ptr => Pointer to the phase that we want to calculate
* the
* mf_PO => Vector of mole fractions in the phase
* in "Phase Order" order. This must sum to one. However
* this condition is not checked.
*
* Output
* return value = activity coefficient for species kspec
***************************************************************************/
{
int kspec, kglob;
double Gxs = 0.0, ac;
VCS_SPECIES_THERMO *ts_ptr;
if (Vphase->Activity_Coeff_Model != VCS_AC_CONSTANT) {
for (kspec = 0; kspec < Vphase->NVolSpecies; kspec++) {
kglob = Vphase->IndSpecies[kspec];
ts_ptr = SpeciesThermo[kglob];
ac = ts_ptr->eval_ac(kspec);
Gxs += mf_PO[kspec] * log(ac);
}
}
return Gxs;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
double VCS_SOLVE::vcs_Gxs_calc(int iphase)
/**************************************************************************
*
* vcs_Gxs_calc:
*
* This function evaluates the Gibbs Excess free energy function.
*
* There are two ways. They may be evaluated from the
* activity coefficients themselves
*
* Gxs/RT = sum_i_inphase( X_i * ln (ActCoeff_i))
*
* Or, the actual formulas for the excess Gibbs free energy may
* be used (which the activity coefficients probably came from anyway.
*
* Input
*
*
* Output
* return value = activity coefficient for species kspec
***************************************************************************/
{
int kspec;
double Gxs = 0.0, ac;
double totmol = TPhMoles[iphase];
vcs_VolPhase *Vphase = VPhaseList[iphase];
VCS_SPECIES_THERMO *ts_ptr;
if (totmol != 0.0 && Vphase->Activity_Coeff_Model != VCS_AC_CONSTANT) {
for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
if (PhaseID[kspec] == iphase) {
if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
ts_ptr = SpeciesThermo[kspec];
ac = ts_ptr->eval_ac(kspec);
Gxs += soln[kspec]/totmol * log(ac);
} else {
plogf("FILL IN\n");
exit(-1);
}
}
}
}
return Gxs;
}
/*****************************************************************************/
}

View file

@ -0,0 +1,264 @@
/*
* $Id$
*/
/*
* Copywrite (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#ifndef VCS_SPECIES_THERMO_H
#define VCS_SPECIES_THERMO_H
//#include <vector>
namespace VCSnonideal {
class vcs_VolPhase;
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
* Models for the species standard state Naught temperature
* dependence
*/
#define VCS_SS0_NOTHANDLED -1
#define VCS_SS0_CONSTANT 0
#define VCS_SS0_NASA_POLY 1
#define VCS_SS0_CONSTANT_CP 2
/*
* Models for the species standard state extra pressure dependence
*
*/
#define VCS_SSSTAR_NOTHANDLED -1
#define VCS_SSSTAR_CONSTANT 0
#define VCS_SSSTAR_IDEAL_GAS 1
/*
* Identifies the thermo model for the species
* This structure is shared by volumetric and surface species. However,
* each will have its own types of thermodynamic models. These
* quantities all have appropriate units. The units are specified by
* VCS_UnitsFormat.
*/
class VCS_SPECIES_THERMO {
/*
* All objects are public for ease of development
*/
public:
/**
* Index of the phase that this species belongs to.
*/
int IndexPhase;
/**
* Index of this species in the current phase.
*/
int IndexSpeciesPhase;
/**
* Pointer to the owning phase object.
*/
vcs_VolPhase *OwningPhase;
/**
* Integer representing the models for the species standard state
* Naught temperature dependence. They are listed above and start
* with VCS_SS0_...
*/
int SS0_Model;
/**
* Internal storage of the last calculation of the reference
* naught Gibbs free energy at SS0_TSave.
* (always in units of Kelvin)
*/
double SS0_feSave;
/**
* Internal storage of the last temperature used in the
* calculation of the reference naught Gibbs free energy.
* units = kelvin
*/
double SS0_TSave;
/**
* Base temperature used in the VCS_SS0_CONSTANT_CP
* model
*/
double SS0_T0;
/**
* Base enthalpy used in the VCS_SS0_CONSTANT_CP
* model
*/
double SS0_H0;
/**
* Base entropy used in the VCS_SS0_CONSTANT_CP
* model
*/
double SS0_S0;
/**
* Base heat capacity used in the VCS_SS0_CONSTANT_CP
* model
*/
double SS0_Cp0;
/**
* Value of the pressure for the reference state.
*/
double SS0_Pref;
/**
* Pointer to a list of parameters that is malloced for
* complicated reference state calculation.
*/
void *SS0_Params;
/**
* Integer value representing the star state model.
*/
int SSStar_Model;
/**
* Pointer to a list of parameters that is malloced for
* complicated reference star state calculation.
*/
void *SSStar_Params;
/**
* Integer value representing the activity coefficient model
* These are defined in vcs_VolPhase.h and start with
* VCS_AC_...
*/
int Activity_Coeff_Model;
/**
* Pointer to a list of parameters that is malloced for
* activity coefficient models.
*/
void *Activity_Coeff_Params;
/**
* Models for the standard state volume of each species
*/
int SSStar_Vol_Model;
/**
* Pointer to a list of parameters that is malloced for
* volume models
*/
void *SSStar_Vol_Params;
/**
* parameter that is used int eh VCS_SSVOL_CONSTANT model.
*/
double SSStar_Vol0;
/**
* If true, this object will call Cantera to do its member
* calculations.
*/
bool UseCanteraCalls;
int m_VCS_UnitsFormat;
/*
* constructor and destructor
*/
VCS_SPECIES_THERMO(int indexPhase, int indexSpeciesPhase);
virtual ~VCS_SPECIES_THERMO();
/*
* Copy constructor and assignment operator
*/
VCS_SPECIES_THERMO(const VCS_SPECIES_THERMO& b);
VCS_SPECIES_THERMO& operator=(const VCS_SPECIES_THERMO& b);
/*
* Duplication function for inherited classes.
*/
virtual VCS_SPECIES_THERMO* duplMyselfAsVCS_SPECIES_THERMO();
/**
* This function calculates the standard state Gibbs free energy
* for species, kspec, at the temperature TKelvin and pressure, Pres.
*
*
* Input
* TKelvin = Temperature in Kelvin
* pres = pressure is given in units specified by if__ variable.
*
*
* Output
* return value = standard state free energy in units of Kelvin.
*/
virtual double GStar_R_calc(int kspec, double TKelvin, double pres);
/**
*
* G0_calc:
*
* This function calculates the standard state Gibbs free energy
* for species, kspec, at the temperature TKelvin
*
* Input
*
*
* Output
* return value = standard state free energy in Kelvin.
*/
virtual double G0_R_calc(int kspec, double TKelvin);
/**
* cpc_ts_VStar_calc:
*
* This function calculates the standard state molar volume
* for species, kspec, at the temperature TKelvin and pressure, Pres,
*
*
* Input
*
*
* Output
* return value = standard state volume in cm**3 per mol.
* (if__=3) m**3 / kmol
*/
virtual double VolStar_calc(int kglob, double TKelvin, double Pres);
/**
* This function evaluates the activity coefficient
* for species, kspec
*
* Input
* kspec -> integer value of the species in the global
* species list within VCS_SOLVE. Phase and local species id
* can be looked up within object.
*
* Note, T, P and mole fractions are obtained from the
* single private instance of VCS_SOLVE
*
*
*
* Output
* return value = activity coefficient for species kspec
*/
virtual double eval_ac(int kspec);
/**
* Get the pointer to the vcs_VolPhase object for this species.
*/
};
/* Externals for vcs_species_thermo.c */
//extern double vcs_Gxs_phase_calc(vcs_VolPhase *, double *);
//extern double vcs_Gxs_calc(int iphase);
}
#endif

View file

@ -0,0 +1,67 @@
/*====================================================================
* ------------------------
* | CVS File Information |
* ------------------------
* $RCSfile$
* $Author$
* $Date$
* $Revision$
* $Name$
*====================================================================*/
#include <time.h>
#include "vcs_internal.h"
#ifdef COUGAR
#define HAVE_MD_TIMER
#endif
namespace VCSnonideal {
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
#ifndef HAVE_MD_TIMER
double vcs_second(void)
/*************************************************************************
*
* vcs_second()
*
* Returns system cpu and wall clock time in seconds. This
* is a strictly Ansi C timer, since clock() is defined as an
* Ansi C function. On some machines clock() returns type
* unsigned long (HP) and on others (SUN) it returns type long.
* An attempt to recover the actual time for clocks which have
* rolled over is made also. However, it only works if this
* function is called fairly regularily during
* the solution procedure.
*
* clock() -> returns the time in microseconds. Division by
* the macro CLOCKS_PER_SEC recovers the time in seconds.
*************************************************************************/
{
static clock_t last_num_ticks = 0;
static double inv_clocks_per_sec = 1./(double)CLOCKS_PER_SEC;
static double clock_width =
(double)(1L<<((int)sizeof(clock_t)*8-2))*4./(double)CLOCKS_PER_SEC;
static int clock_rollovers = 0;
clock_t num_ticks = clock();
if (num_ticks < last_num_ticks) {
clock_rollovers++;
}
double value = num_ticks * inv_clocks_per_sec;
if (clock_rollovers) {
value += clock_rollovers * clock_width;
}
last_num_ticks = num_ticks;
return(value);
}
#else
#include <nx.h>
double vcs_second(void)
{
return dclock();
}
#endif
}

View file

@ -0,0 +1,445 @@
/* ======================================================================= */
/* -------------------------------------------------- */
/* | RCS Head Information on zuzax.pchem.sandia.gov | */
/* -------------------------------------------------- */
/* $RCSfile$ */
/* $Author$ */
/* $Date$ */
/* $Revision$ */
/* ======================================================================= */
#include <cstdlib>
#include <cmath>
#include "vcs_internal.h"
namespace VCSnonideal {
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifndef USE_MEMSET
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() *************************************************************/
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifndef USE_MEMSET
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() *************************************************************/
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifndef USE_MEMSET
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() *************************************************************/
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifndef USE_MEMSET
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() *************************************************************/
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#ifndef USE_MEMSET
/*
* vcs_vdzero
*
* zeroes a double vector
*/
void vcs_vdzero(std::vector<double> &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<int> &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<double> &vec_to,
const std::vector<double> & 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<int> &vec_to,
const std::vector<int> & vec_from, int length) {
std::copy(vec_from.begin(), vec_from.begin() + length, vec_to.begin());
}
#endif
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int vcs_amax(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(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
*/
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;
}
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);
}
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 {
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)
/*************************************************************************
* vcs_doubleEqual()
*
* Simple routine to check whether two doubles are equal up to
* 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;
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
}