Added vcs_nonideal, another equilibrium solver that can handle
nonideal thermo multiphase systems.
This commit is contained in:
parent
daa7cbfe95
commit
d0e99aec18
47 changed files with 21542 additions and 8 deletions
|
|
@ -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}" ; \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
140
Cantera/src/equil/vcs_DoubleStarStar.cpp
Normal file
140
Cantera/src/equil/vcs_DoubleStarStar.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
124
Cantera/src/equil/vcs_DoubleStarStar.h
Normal file
124
Cantera/src/equil/vcs_DoubleStarStar.h
Normal 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
|
||||
|
||||
|
||||
14
Cantera/src/equil/vcs_Exception.cpp
Normal file
14
Cantera/src/equil/vcs_Exception.cpp
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
45
Cantera/src/equil/vcs_Exception.h
Normal file
45
Cantera/src/equil/vcs_Exception.h
Normal 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
|
||||
101
Cantera/src/equil/vcs_Gibbs.cpp
Normal file
101
Cantera/src/equil/vcs_Gibbs.cpp
Normal 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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
|
||||
141
Cantera/src/equil/vcs_IntStarStar.cpp
Normal file
141
Cantera/src/equil/vcs_IntStarStar.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
106
Cantera/src/equil/vcs_IntStarStar.h
Normal file
106
Cantera/src/equil/vcs_IntStarStar.h
Normal 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
|
||||
|
||||
|
||||
1774
Cantera/src/equil/vcs_MultiPhaseEquil.cpp
Normal file
1774
Cantera/src/equil/vcs_MultiPhaseEquil.cpp
Normal file
File diff suppressed because it is too large
Load diff
362
Cantera/src/equil/vcs_MultiPhaseEquil.h
Normal file
362
Cantera/src/equil/vcs_MultiPhaseEquil.h
Normal 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
|
||||
93
Cantera/src/equil/vcs_SpeciesProperties.cpp
Normal file
93
Cantera/src/equil/vcs_SpeciesProperties.cpp
Normal 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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
66
Cantera/src/equil/vcs_SpeciesProperties.h
Normal file
66
Cantera/src/equil/vcs_SpeciesProperties.h
Normal 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
|
||||
196
Cantera/src/equil/vcs_TP.cpp
Normal file
196
Cantera/src/equil/vcs_TP.cpp
Normal 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() ********************************************************/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
112
Cantera/src/equil/vcs_TV.cpp
Normal file
112
Cantera/src/equil/vcs_TV.cpp
Normal 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;
|
||||
}
|
||||
/**************************************************************************/
|
||||
}
|
||||
|
||||
978
Cantera/src/equil/vcs_VolPhase.cpp
Normal file
978
Cantera/src/equil/vcs_VolPhase.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
750
Cantera/src/equil/vcs_VolPhase.h
Normal file
750
Cantera/src/equil/vcs_VolPhase.h
Normal 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
|
||||
1325
Cantera/src/equil/vcs_dbocls.c
Normal file
1325
Cantera/src/equil/vcs_dbocls.c
Normal file
File diff suppressed because it is too large
Load diff
957
Cantera/src/equil/vcs_dbols.c
Normal file
957
Cantera/src/equil/vcs_dbols.c
Normal 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_ */
|
||||
|
||||
262
Cantera/src/equil/vcs_defs.h
Normal file
262
Cantera/src/equil/vcs_defs.h
Normal 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
|
||||
294
Cantera/src/equil/vcs_dvout.c
Normal file
294
Cantera/src/equil/vcs_dvout.c
Normal 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_ */
|
||||
|
||||
602
Cantera/src/equil/vcs_elem.cpp
Normal file
602
Cantera/src/equil/vcs_elem.cpp
Normal 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() ************************************************************/
|
||||
|
||||
}
|
||||
|
||||
250
Cantera/src/equil/vcs_elem_rearrange.cpp
Normal file
250
Cantera/src/equil/vcs_elem_rearrange.cpp
Normal 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() ***************************************************/
|
||||
}
|
||||
|
||||
64
Cantera/src/equil/vcs_funcVtot.cpp
Normal file
64
Cantera/src/equil/vcs_funcVtot.cpp
Normal 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);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
509
Cantera/src/equil/vcs_inest.cpp
Normal file
509
Cantera/src/equil/vcs_inest.cpp
Normal 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() ***********************************************************/
|
||||
|
||||
}
|
||||
|
||||
183
Cantera/src/equil/vcs_internal.h
Normal file
183
Cantera/src/equil/vcs_internal.h
Normal 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
|
||||
/****************************************************************************/
|
||||
146
Cantera/src/equil/vcs_linmaxc.cpp
Normal file
146
Cantera/src/equil/vcs_linmaxc.cpp
Normal 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;
|
||||
}
|
||||
412
Cantera/src/equil/vcs_nasa_poly.cpp
Normal file
412
Cantera/src/equil/vcs_nasa_poly.cpp
Normal 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;
|
||||
} /***************************************************************************/
|
||||
|
||||
}
|
||||
|
||||
89
Cantera/src/equil/vcs_nasa_poly.h
Normal file
89
Cantera/src/equil/vcs_nasa_poly.h
Normal 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
|
||||
222
Cantera/src/equil/vcs_nondim.cpp
Normal file
222
Cantera/src/equil/vcs_nondim.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
308
Cantera/src/equil/vcs_prep.cpp
Normal file
308
Cantera/src/equil/vcs_prep.cpp
Normal 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;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
}
|
||||
638
Cantera/src/equil/vcs_prob.cpp
Normal file
638
Cantera/src/equil/vcs_prob.cpp
Normal 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
|
||||
|
||||
}
|
||||
375
Cantera/src/equil/vcs_prob.h
Normal file
375
Cantera/src/equil/vcs_prob.h
Normal 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
|
||||
58
Cantera/src/equil/vcs_rearrange.cpp
Normal file
58
Cantera/src/equil/vcs_rearrange.cpp
Normal 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() *********************************************************/
|
||||
|
||||
}
|
||||
|
||||
400
Cantera/src/equil/vcs_report.cpp
Normal file
400
Cantera/src/equil/vcs_report.cpp
Normal 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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
349
Cantera/src/equil/vcs_root1d.cpp
Normal file
349
Cantera/src/equil/vcs_root1d.cpp
Normal 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;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
533
Cantera/src/equil/vcs_rxnadj.cpp
Normal file
533
Cantera/src/equil/vcs_rxnadj.cpp
Normal 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;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
}
|
||||
|
||||
231
Cantera/src/equil/vcs_setMolesLinProg.cpp
Normal file
231
Cantera/src/equil/vcs_setMolesLinProg.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1024
Cantera/src/equil/vcs_solve.cpp
Normal file
1024
Cantera/src/equil/vcs_solve.cpp
Normal file
File diff suppressed because it is too large
Load diff
807
Cantera/src/equil/vcs_solve.h
Normal file
807
Cantera/src/equil/vcs_solve.h
Normal 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
|
||||
|
||||
4984
Cantera/src/equil/vcs_solve_TP.cpp
Normal file
4984
Cantera/src/equil/vcs_solve_TP.cpp
Normal file
File diff suppressed because it is too large
Load diff
494
Cantera/src/equil/vcs_species_thermo.cpp
Normal file
494
Cantera/src/equil/vcs_species_thermo.cpp
Normal 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;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
}
|
||||
264
Cantera/src/equil/vcs_species_thermo.h
Normal file
264
Cantera/src/equil/vcs_species_thermo.h
Normal 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
|
||||
67
Cantera/src/equil/vcs_timer_generic.cpp
Normal file
67
Cantera/src/equil/vcs_timer_generic.cpp
Normal 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
|
||||
|
||||
}
|
||||
|
||||
445
Cantera/src/equil/vcs_util.cpp
Normal file
445
Cantera/src/equil/vcs_util.cpp
Normal 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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue