386 lines
13 KiB
C++
386 lines
13 KiB
C++
/**
|
|
* @file vcs_equilibrate.cpp
|
|
* Driver routines for equilibrium solvers
|
|
*/
|
|
/*
|
|
*
|
|
* $Id$
|
|
*/
|
|
/*
|
|
* Copywrite (2006) 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_MultiPhaseEquil.h"
|
|
#include "vcs_prob.h"
|
|
#include "vcs_internal.h"
|
|
#include "vcs_VolPhase.h"
|
|
#include "vcs_species_thermo.h"
|
|
#include "vcs_SpeciesProperties.h"
|
|
#include "vcs_VolPhase.h"
|
|
#include "vcs_solve.h"
|
|
#include "equil.h"
|
|
|
|
#include "ct_defs.h"
|
|
#include "mix_defs.h"
|
|
#include "speciesThermoTypes.h"
|
|
#ifdef WITH_IDEAL_SOLUTIONS
|
|
#include "IdealSolidSolnPhase.h"
|
|
#endif
|
|
#ifdef WITH_ELECTROLYTES
|
|
#include "IdealMolalSoln.h"
|
|
#endif
|
|
#include "ChemEquil.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace Cantera;
|
|
using namespace std;
|
|
|
|
namespace Cantera {
|
|
|
|
/*
|
|
* Set a single-phase chemical solution to chemical equilibrium.
|
|
* 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 integer indicating whether the solver
|
|
* should estimate its own initial condition.
|
|
* If 0, the initial mole fraction vector
|
|
* in the %ThermoPhase object is used as the
|
|
* initial condition.
|
|
* If 1, the initial mole fraction vector
|
|
* is used if the element abundances are
|
|
* satisfied.
|
|
* if -1, the initial mole fraction vector
|
|
* is thrown out, and an estimate is
|
|
* formulated.
|
|
*
|
|
* @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
|
|
*/
|
|
int vcs_equilibrate(thermo_t& s, const char* XY,
|
|
int estimateEquil, int printLvl,
|
|
int solver,
|
|
doublereal rtol, int maxsteps, int maxiter,
|
|
int loglevel) {
|
|
MultiPhase* m = 0;
|
|
int retn = 1;
|
|
int retnSub = 0;
|
|
|
|
beginLogGroup("equilibrate", loglevel);
|
|
// retry:
|
|
addLogEntry("Single-phase equilibrate function");
|
|
{
|
|
beginLogGroup("arguments");
|
|
addLogEntry("phase",s.id());
|
|
addLogEntry("XY",XY);
|
|
addLogEntry("solver",solver);
|
|
addLogEntry("rtol",rtol);
|
|
addLogEntry("maxsteps",maxsteps);
|
|
addLogEntry("maxiter",maxiter);
|
|
addLogEntry("loglevel",loglevel);
|
|
endLogGroup("arguments");
|
|
}
|
|
|
|
if (solver == 2) {
|
|
m = new MultiPhase;
|
|
try {
|
|
/*
|
|
* Set the kmoles of the phase to 1.0, arbitrarily.
|
|
* It actually doesn't matter.
|
|
*/
|
|
m->addPhase(&s, 1.0);
|
|
m->init();
|
|
|
|
retn = vcs_equilibrate(*m, XY, estimateEquil, printLvl, solver,
|
|
rtol, maxsteps, maxiter, loglevel);
|
|
if (retn == 1) {
|
|
addLogEntry("MultiPhaseEquil solver succeeded.");
|
|
} else {
|
|
addLogEntry("MultiPhaseEquil solver returned an error code: ", retn);
|
|
}
|
|
delete m;
|
|
}
|
|
catch (CanteraError &err) {
|
|
addLogEntry("MultiPhaseEquil solver failed.");
|
|
delete m;
|
|
throw err;
|
|
}
|
|
} else if (solver == 1) {
|
|
m = new MultiPhase;
|
|
try {
|
|
m->addPhase(&s, 1.0);
|
|
m->init();
|
|
(void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1);
|
|
if (loglevel > 0)
|
|
addLogEntry("MultiPhaseEquil solver succeeded.");
|
|
delete m;
|
|
retn = 1;
|
|
}
|
|
catch (CanteraError &err) {
|
|
if (loglevel > 0) {
|
|
addLogEntry("MultiPhaseEquil solver failed.");
|
|
}
|
|
delete m;
|
|
throw err;
|
|
}
|
|
} else if (solver == 0) {
|
|
ChemEquil *e = new ChemEquil;
|
|
try {
|
|
e->options.maxIterations = maxsteps;
|
|
e->options.relTolerance = rtol;
|
|
bool useThermoPhaseElementPotentials = false;
|
|
if (estimateEquil == 0) {
|
|
useThermoPhaseElementPotentials = true;
|
|
}
|
|
retnSub = e->equilibrate(s, XY,
|
|
useThermoPhaseElementPotentials, loglevel-1);
|
|
if (retnSub < 0) {
|
|
if (loglevel > 0) {
|
|
addLogEntry("ChemEquil solver failed.");
|
|
}
|
|
delete e;
|
|
throw CanteraError("equilibrate",
|
|
"ChemEquil equilibrium solver failed");
|
|
}
|
|
retn = 1;
|
|
s.setElementPotentials(e->elementPotentials());
|
|
delete e;
|
|
if (loglevel > 0) {
|
|
addLogEntry("ChemEquil solver succeeded.");
|
|
}
|
|
}
|
|
catch (CanteraError &err) {
|
|
if (loglevel > 0) {
|
|
addLogEntry("ChemEquil solver failed.");
|
|
}
|
|
delete e;
|
|
throw err;
|
|
}
|
|
} else {
|
|
throw CanteraError("vcs_equilibrate",
|
|
"unknown solver");
|
|
}
|
|
|
|
/*
|
|
* We are here only for a success
|
|
*/
|
|
endLogGroup("equilibrate");
|
|
return retn;
|
|
}
|
|
|
|
// 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 specifying the two properties to
|
|
* be held constant
|
|
*
|
|
* @param estimateEquil integer indicating whether the solver
|
|
* should estimate its own initial condition.
|
|
* If 0, the initial mole fraction vector
|
|
* in the %ThermoPhase object is used as the
|
|
* initial condition.
|
|
* If 1, the initial mole fraction vector
|
|
* is used if the element abundances are
|
|
* satisfied.
|
|
* if -1, the initial mole fraction vector
|
|
* is thrown out, and an estimate is
|
|
* formulated.
|
|
*
|
|
* @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,
|
|
int estimateEquil, int printLvl, int solver,
|
|
doublereal tol, int maxsteps, int maxiter,
|
|
int loglevel) {
|
|
int ixy = _equilflag(XY);
|
|
int retn = vcs_equilibrate_1(s, ixy, estimateEquil, printLvl, solver,
|
|
tol, maxsteps, maxiter, loglevel);
|
|
return retn;
|
|
};
|
|
|
|
|
|
// 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 integer indicating whether the solver
|
|
* should estimate its own initial condition.
|
|
* If 0, the initial mole fraction vector
|
|
* in the %ThermoPhase object is used as the
|
|
* initial condition.
|
|
* If 1, the initial mole fraction vector
|
|
* is used if the element abundances are
|
|
* satisfied.
|
|
* if -1, the initial mole fraction vector
|
|
* is thrown out, and an estimate is
|
|
* formulated.
|
|
*
|
|
* @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,
|
|
int estimateEquil, int printLvl, int solver,
|
|
doublereal tol, int maxsteps, int maxiter, int loglevel) {
|
|
static int counter = 0;
|
|
int retn = 1;
|
|
beginLogGroup("equilibrate",loglevel);
|
|
addLogEntry("multiphase equilibrate function");
|
|
beginLogGroup("arguments");
|
|
addLogEntry("XY",ixy);
|
|
addLogEntry("tol",tol);
|
|
addLogEntry("maxsteps",maxsteps);
|
|
addLogEntry("maxiter",maxiter);
|
|
addLogEntry("loglevel",loglevel);
|
|
endLogGroup("arguments");
|
|
int printLvlSub = MAX(0, printLvl-1);
|
|
|
|
s.init();
|
|
|
|
if (solver == 2) {
|
|
try {
|
|
VCSnonideal::vcs_MultiPhaseEquil *eqsolve = new VCSnonideal::vcs_MultiPhaseEquil(&s, printLvlSub);
|
|
int err = eqsolve->equilibrate(ixy, estimateEquil, printLvlSub,
|
|
tol, maxsteps, maxiter);
|
|
if (err != 0) {
|
|
retn = -1;
|
|
addLogEntry("vcs_equilibrate Error - ", err);
|
|
} else {
|
|
addLogEntry("vcs_equilibrate Success - ", err);
|
|
}
|
|
endLogGroup("equilibrate");
|
|
// hard code a csv output file.
|
|
if (printLvl > 0) {
|
|
string reportFile = "vcs_equilibrate_res.csv";
|
|
if (counter > 0) {
|
|
reportFile = "vcs_equilibrate_res_" + int2str(counter) + ".csv";
|
|
}
|
|
eqsolve->reportCSV(reportFile);
|
|
counter++;
|
|
}
|
|
delete eqsolve;
|
|
}
|
|
catch (CanteraError &e) {
|
|
retn = -1;
|
|
addLogEntry("Failure.", lastErrorMessage());
|
|
endLogGroup("equilibrate");
|
|
throw e;
|
|
}
|
|
} else if (solver == 1) {
|
|
if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) {
|
|
try {
|
|
double err = s.equilibrate(ixy, tol, maxsteps, maxiter, loglevel);
|
|
if (loglevel > 0) {
|
|
addLogEntry("Success. Error",err);
|
|
endLogGroup("equilibrate");
|
|
}
|
|
return 0;
|
|
}
|
|
catch (CanteraError &e) {
|
|
if (loglevel > 0) {
|
|
addLogEntry("Failure.",lastErrorMessage());
|
|
endLogGroup("equilibrate");
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
else {
|
|
if (loglevel > 0) {
|
|
addLogEntry("multiphase equilibrium can be done only for TP, HP, SP, or TV");
|
|
endLogGroup("equilibrate");
|
|
}
|
|
throw CanteraError("equilibrate","unsupported option");
|
|
//return -1.0;
|
|
}
|
|
} else {
|
|
throw CanteraError("vcs_equilibrate_1", "unknown solver");
|
|
}
|
|
return retn;
|
|
}
|
|
}
|