cantera/Cantera/src/equil/vcs_equilibrate.cpp
2008-05-06 23:31:13 +00:00

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;
}
}