diff --git a/Cantera/Makefile.in b/Cantera/Makefile.in index 1d0500e66..8af85d494 100755 --- a/Cantera/Makefile.in +++ b/Cantera/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: hkmoffa $ -# $Date: 2007/05/06 17:16:43 $ -# $Revision: 1.8 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001 California Institute of Technology # See file License.txt for licensing information diff --git a/Cantera/clib/src/clib_defs.h b/Cantera/clib/src/clib_defs.h index f3fa601f7..7e89e7dc2 100755 --- a/Cantera/clib/src/clib_defs.h +++ b/Cantera/clib/src/clib_defs.h @@ -48,8 +48,6 @@ #endif namespace Cantera {} -//using namespace Cantera; namespace std {} -//using namespace std; #endif diff --git a/Cantera/clib/src/ctfunc.cpp b/Cantera/clib/src/ctfunc.cpp index 8e7fd442a..646c4ba9e 100755 --- a/Cantera/clib/src/ctfunc.cpp +++ b/Cantera/clib/src/ctfunc.cpp @@ -17,10 +17,11 @@ #include "Func1.h" #include "ctexceptions.h" -using namespace Cantera; #include "Cabinet.h" +using namespace Cantera; +using namespace std; typedef Func1 func_t; diff --git a/Cantera/clib/src/ctonedim.cpp b/Cantera/clib/src/ctonedim.cpp index 9295c2ed5..7f592f3da 100644 --- a/Cantera/clib/src/ctonedim.cpp +++ b/Cantera/clib/src/ctonedim.cpp @@ -565,12 +565,13 @@ extern "C" { catch (CanteraError) { return -1; } } - int DLL_EXPORT sim1D_writeStats(int i) { + int DLL_EXPORT sim1D_writeStats(int i, int printTime) { try { - _sim1D(i)->writeStats(); + _sim1D(i)->writeStats(printTime); return 0; + } catch (CanteraError) { + return -1; } - catch (CanteraError) { return -1; } } int DLL_EXPORT sim1D_domainIndex(int i, char* name) { diff --git a/Cantera/clib/src/ctonedim.h b/Cantera/clib/src/ctonedim.h index 8bf95e442..76b00dd93 100644 --- a/Cantera/clib/src/ctonedim.h +++ b/Cantera/clib/src/ctonedim.h @@ -84,7 +84,7 @@ extern "C" { EEXXTT int DLL_CPREFIX sim1D_save(int i, char* fname, char* id, char* desc); EEXXTT int DLL_CPREFIX sim1D_restore(int i, char* fname, char* id); - EEXXTT int DLL_CPREFIX sim1D_writeStats(int i); + EEXXTT int DLL_CPREFIX sim1D_writeStats(int i, int printTime = 1); EEXXTT int DLL_CPREFIX sim1D_domainIndex(int i, char* name); EEXXTT double DLL_CPREFIX sim1D_value(int i, int idom, int icomp, int localPoint); EEXXTT double DLL_CPREFIX sim1D_workValue(int i, int idom, diff --git a/Cantera/clib/src/ctreactor.cpp b/Cantera/clib/src/ctreactor.cpp index 0e8fff638..8b12ae5c2 100755 --- a/Cantera/clib/src/ctreactor.cpp +++ b/Cantera/clib/src/ctreactor.cpp @@ -27,6 +27,8 @@ #include "Storage.h" using namespace CanteraZeroD; +using namespace Cantera; +using namespace std; typedef ReactorBase reactor_t; typedef ReactorNet reactornet_t; diff --git a/Cantera/clib/src/ctstagn.cpp b/Cantera/clib/src/ctstagn.cpp index f7bd67846..f32076cc1 100755 --- a/Cantera/clib/src/ctstagn.cpp +++ b/Cantera/clib/src/ctstagn.cpp @@ -429,8 +429,8 @@ extern "C" { return 0; } - int DLL_EXPORT onedim_writeStats(int i) { - _onedim(i)->writeStats(); + int DLL_EXPORT onedim_writeStats(int i, int printTime) { + _onedim(i)->writeStats(printTime); return 0; } diff --git a/Cantera/clib/src/ctstagn.h b/Cantera/clib/src/ctstagn.h index 4b4b721bf..86742055f 100755 --- a/Cantera/clib/src/ctstagn.h +++ b/Cantera/clib/src/ctstagn.h @@ -68,7 +68,7 @@ extern "C" { int DLL_IMPORT onedim_settransientmode(int i, double dt, double* x); int DLL_IMPORT onedim_setnewtonoptions(int i, int maxage); int DLL_IMPORT onedim_resize(int i); - int DLL_IMPORT onedim_writeStats(int i); + int DLL_IMPORT onedim_writeStats(int i, int printTime = 1); double DLL_IMPORT onedim_timestep(int i, int nsteps, double dt, double* x, double* xnew, int loglevel); int DLL_IMPORT onedim_save(int i, char* fname, char* id, char* desc, double* soln); diff --git a/Cantera/clib/src/ctxml.cpp b/Cantera/clib/src/ctxml.cpp index 57b237293..7c1049ebf 100644 --- a/Cantera/clib/src/ctxml.cpp +++ b/Cantera/clib/src/ctxml.cpp @@ -24,6 +24,7 @@ using namespace std; using namespace Cantera; +using namespace ctml; // Assign storage for the static member of the Templated Cabinet class diff --git a/Cantera/cxx/Makefile.in b/Cantera/cxx/Makefile.in index b142632e9..49b15123e 100644 --- a/Cantera/cxx/Makefile.in +++ b/Cantera/cxx/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: hkmoffa $ -# $Date: 2009/04/04 03:27:43 $ -# $Revision: 1.14 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001 California Institute of Technology # See file License.txt for licensing information @@ -18,7 +18,7 @@ INSTALL_TSC = ../../../bin/install_tsc CXX_H = Cantera.h equilibrium.h IncompressibleSolid.h \ kinetics.h onedim.h surface.h GRI30.h integrators.h \ Metal.h PureFluid.h transport.h Edge.h \ - IdealGasMix.h Interface.h numerics.h \ + IdealGasMix.h Interface.h numerics.h solvers.h \ reactionpaths.h zerodim.h importPhase.h thermo.h \ radiation.h spectra.h electrolyteThermo.h Cantera.mak Cantera_bt.mak diff --git a/Cantera/cxx/demos/NASA_coeffs/NASA_coeffs.cpp b/Cantera/cxx/demos/NASA_coeffs/NASA_coeffs.cpp index 913e9e362..d8efa570b 100644 --- a/Cantera/cxx/demos/NASA_coeffs/NASA_coeffs.cpp +++ b/Cantera/cxx/demos/NASA_coeffs/NASA_coeffs.cpp @@ -12,6 +12,7 @@ using namespace std; using namespace Cantera; +using namespace Cantera_CXX; // The program is put into a function so that error handling code can diff --git a/Cantera/cxx/demos/combustor/combustor.cpp b/Cantera/cxx/demos/combustor/combustor.cpp index b8a3c0c45..8f6c44ff4 100644 --- a/Cantera/cxx/demos/combustor/combustor.cpp +++ b/Cantera/cxx/demos/combustor/combustor.cpp @@ -12,6 +12,9 @@ #include using namespace CanteraZeroD; +using namespace Cantera; +using namespace Cantera_CXX; +using namespace std; void runexample() { diff --git a/Cantera/cxx/demos/flamespeed/flamespeed.cpp b/Cantera/cxx/demos/flamespeed/flamespeed.cpp index c55f6d7ba..8a43fe489 100644 --- a/Cantera/cxx/demos/flamespeed/flamespeed.cpp +++ b/Cantera/cxx/demos/flamespeed/flamespeed.cpp @@ -17,6 +17,7 @@ using namespace Cantera; using namespace Cantera_CXX; +using namespace std; int flamespeed(int np, void* p) { try { diff --git a/Cantera/cxx/demos/kinetics1/example_utils.h b/Cantera/cxx/demos/kinetics1/example_utils.h index 59e62ef7d..a4697ae38 100644 --- a/Cantera/cxx/demos/kinetics1/example_utils.h +++ b/Cantera/cxx/demos/kinetics1/example_utils.h @@ -5,11 +5,8 @@ #include namespace Cantera{} -using namespace Cantera; namespace std{} -using namespace std; namespace CanteraZeroD{} -using namespace CanteraZeroD; // Save the temperature, density, pressure, and mole fractions at one // time @@ -48,18 +45,18 @@ void makeDataLabels(const G& gas, V& names) { } template -void plotSoln(string fname, string fmt, string title, const G& gas, const A& soln) { - vector names; +void plotSoln(std::string fname, std::string fmt, std::string title, const G& gas, const A& soln) { + std::vector names; makeDataLabels(gas, names); writePlotFile(fname, fmt, title, names, soln); } -inline void writeCanteraHeader(ostream& s) { - s << endl; - s << " Cantera version " << "CANTERA_VERSION" << endl; - s << " Copyright California Institute of Technology, 2002." << endl; - s << " http://www.cantera.org" << endl; - s << endl; +inline void writeCanteraHeader(std::ostream& s) { + s << std::endl; + s << " Cantera version " << "CANTERA_VERSION" << std::endl; + s << " Copyright California Institute of Technology, 2002." << std::endl; + s << " http://www.cantera.org" << std::endl; + s << std::endl; } #endif diff --git a/Cantera/cxx/demos/kinetics1/kinetics1.cpp b/Cantera/cxx/demos/kinetics1/kinetics1.cpp index e78d95096..08ad2e152 100644 --- a/Cantera/cxx/demos/kinetics1/kinetics1.cpp +++ b/Cantera/cxx/demos/kinetics1/kinetics1.cpp @@ -2,9 +2,9 @@ // // zero-dimensional kinetics example program // -// $Author: hkmoffa $ -// $Revision: 1.2 $ -// $Date: 2009/05/13 21:52:29 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // @@ -24,6 +24,10 @@ #include #include "example_utils.h" +using namespace std; +using namespace Cantera; +using namespace CanteraZeroD; +using namespace Cantera_CXX; int kinetics1(int np, void* p) { diff --git a/Cantera/cxx/include/Cantera.h b/Cantera/cxx/include/Cantera.h index 0093fe998..8ac96d93e 100755 --- a/Cantera/cxx/include/Cantera.h +++ b/Cantera/cxx/include/Cantera.h @@ -1,7 +1,6 @@ /** * @file Cantera.h - * Basic include file to be used in all Cantera application - * environments. + * Basic include file to be used in all Cantera application environments. */ /* @@ -11,18 +10,24 @@ // Copyright 2001 California Institute of Technology +/* + * Note, this include should be the first include that code containing the + * Cantera namespace sees when in the Cantera application environment. + */ + #ifndef CANTERA_H_INCL #define CANTERA_H_INCL -// definitions +// If we are using this file, then we are in the Cantera Apps environment. +// Define a variable to signify this fact. #ifndef CANTERA_APP #define CANTERA_APP #endif +// define the presence of the Cantera_CXX namespace namespace Cantera_CXX{ } -using namespace Cantera_CXX; - +// Include global typedefs and values for physical constants using SI units #include "kernel/ct_defs.h" // some useful functions @@ -31,9 +36,6 @@ using namespace Cantera_CXX; // the CanteraError exception class #include "kernel/ctexceptions.h" -// -//#include "kernel/importCTML.h" - // The Cantera logger class #include "kernel/logger.h" @@ -46,10 +48,9 @@ using namespace Cantera_CXX; // Include string utility routines #include "kernel/stringUtils.h" +// Include the array object +#include "kernel/Array.h" + #endif - - - - diff --git a/Cantera/cxx/include/Cantera.mak.in b/Cantera/cxx/include/Cantera.mak.in index 29d63639f..b45e9bd32 100644 --- a/Cantera/cxx/include/Cantera.mak.in +++ b/Cantera/cxx/include/Cantera.mak.in @@ -15,16 +15,16 @@ # # ##################################################################### -# $Id: Cantera.mak.in,v 1.5 2009/01/09 23:26:41 hkmoffa Exp $ +# $Id$ # # # This variable determines whether we are making this example in the # build tree environment or in the install tree environment. # in_CanteraBuildTree = 0 - +# CANTERA_VERSION=@ctversion@ - +# ############################################################################### # CANTERA CORE ############################################################################### @@ -88,9 +88,13 @@ CANTERA_SUNDIALS_LIB_DIR=@sundials_lib_dir@ ifeq ($(CANTERA_use_sundials), 1) CANTERA_CVODE_LIBS=-L$(CANTERA_SUNDIALS_LIB_DIR) @CVODE_LIBS@ CANTERA_CVODE_LIBS_DEP=@sundials_lib_dep@ +CANTERA_SUNDIALS_LIBS=-L$(CANTERA_SUNDIALS_LIB_DIR) @sundials_lib@ +CANTERA_SUNDIALS_LIBS_DEP=@sundials_lib_dep@ else CANTERA_CVODE_LIBS= -L$(CANTERA_LIBSDIR) -lcvode CANTERA_CVODE_LIBS_DEP=$(CANTERA_LIBSDIR)/libcvode.a +CANTERA_SUNDIALS_LIBS=-L$(CANTERA_LIBSDIR) -lcvode +CANTERA_SUNDIALS_LIBS_DEP=-L$(CANTERA_LIBSDIR)/libcvode.a endif # ####################################################################### @@ -133,14 +137,13 @@ CANTERA_DEFINES = -DCANTERA_VERSION=@ctversion@ CANTERA_TOTAL_LIBS2 = -L$(CANTERA_LIBSDIR) @LOCAL_LIBS@ # CANTERA_TOTAL_LIBS= $(CANTERA_CORE_LIBS) $(CANTERA_BOOST_LIBS) \ - $(CANTERA_CVODE_LIBS) $(CANTERA_BLAS_LAPACK_LIBS) \ + $(CANTERA_SUNDIALS_LIBS) $(CANTERA_BLAS_LAPACK_LIBS) \ $(CANTERA_F2C_LIBS) # CANTERA_TOTAL_LIBS_DEP= $(CANTERA_CORE_LIBS_DEP) \ - $(CANTERA_CVODE_LIBS_DEP) \ + $(CANTERA_SUNDIALS_LIBS_DEP) \ $(CANTERA_BLAS_LAPACK_LIBS_DEP) # -# # Dependency Line # CANTERA_LIBS_DEP= @INSTALL_LIBS_DEP@ $(CANTERA_LIBDIR)/libctcxx.a diff --git a/Cantera/cxx/include/Cantera_bt.mak.in b/Cantera/cxx/include/Cantera_bt.mak.in index b98df72c3..00839668c 100644 --- a/Cantera/cxx/include/Cantera_bt.mak.in +++ b/Cantera/cxx/include/Cantera_bt.mak.in @@ -15,13 +15,17 @@ # # ##################################################################### -# $Id: Cantera_bt.mak.in,v 1.2 2008/01/21 21:17:52 hkmoffa Exp $ +# $Id$ # # # This variable determines whether we are making this example in the # build tree environment or in the install tree environment. # in_CanteraBuildTree = 0 +# +CANTERA_VERSION=@ctversion@ +# +CANTERA_VERSION=@ctversion@ CANTERA_VERSION=@ctversion@ @@ -112,18 +116,17 @@ CANTERA_F2C_LIBS= -L$(CANTERA_LIBSDIR) -lctf2c else CANTERA_F2C_LIBS= @F2C_SYSTEMLIB@ endif - - +# ##################################################################### # COMBINATIONS OF INCLUDES AND LIBS #################################################################### - +# CANTERA_TOTAL_INCLUDES= $(CANTERA_CORE_INCLUDES) $(CANTERA_BOOST_INCLUDES) $(CANTERA_CVODE_INCLUDE) # # You can add this into the compilation environment to identify the version number # CANTERA_DEFINES = -DCANTERA_VERSION=@ctversion@ - +# CANTERA_TOTAL_LIBS2 = @LOCAL_LIB_DIRS@ @LOCAL_LIBS@ CANTERA_TOTAL_LIBS= $(CANTERA_CORE_LIBS) $(CANTERA_BOOST_LIBS) \ diff --git a/Cantera/cxx/include/Edge.h b/Cantera/cxx/include/Edge.h index 0ae5f8ba6..40eaa25e7 100644 --- a/Cantera/cxx/include/Edge.h +++ b/Cantera/cxx/include/Edge.h @@ -7,7 +7,6 @@ #include "kernel/EdgeKinetics.h" #include "kernel/importKinetics.h" -using namespace Cantera; namespace Cantera_CXX { class Edge : diff --git a/Cantera/cxx/include/GRI30.h b/Cantera/cxx/include/GRI30.h index 6bc28cb26..d11afede0 100644 --- a/Cantera/cxx/include/GRI30.h +++ b/Cantera/cxx/include/GRI30.h @@ -11,6 +11,7 @@ #include "kernel/importKinetics.h" #include "kernel/stringUtils.h" + namespace Cantera_CXX { /** diff --git a/Cantera/cxx/include/Interface.h b/Cantera/cxx/include/Interface.h index 0734fd233..48fe96479 100644 --- a/Cantera/cxx/include/Interface.h +++ b/Cantera/cxx/include/Interface.h @@ -15,77 +15,128 @@ #include "Cantera.h" #include "thermo.h" #include "kinetics.h" -// #include "kernel/SurfPhase.h" -// #include "kernel/InterfaceKinetics.h" -// #include "kernel/importKinetics.h" + /** * This namespace is used for the Cantera C++ user interface. */ namespace Cantera_CXX { - /** - * An interface between multiple bulk phases. This class is - * defined mostly for convenience. It inherits both from - * Cantera::SurfPhase and Cantera::InterfaceKinetics. It therefore - * represents a surface phase, and also acts as the kinetics - * manager to manage reaction occurring on the surface, possibly - * involving species from other phases. + + //! An interface between multiple bulk phases. + /*! + * This class isdefined mostly for convenience. It inherits both from + * Cantera::SurfPhase and Cantera::InterfaceKinetics. It therefore + * represents a surface phase, and also acts as the kinetics + * manager to manage reactions occurring on the surface, possibly + * involving species from other phases. + */ + class Interface : + public Cantera::SurfPhase, + public Cantera::InterfaceKinetics + { + public: + + + //! Constructor. + /*! + * Construct an Interface instance from a specification in an input file. + * + * @param infile. Cantera input file in CTI or CTML format. + * @param id Identification string to distinguish between + * multiple definitions within one input file. + * @param otherPhases Neighboring phases that may participate in the + * reactions on this interface. Don't include the + * surface phase + * + * @deprecated + * While it's convenient to have the surface phase and the interfacial reaction + * together, this class doesn't satisfy the primary issue, which is one + * of instantiation of all the ThermoPhase classes that accompany a + * surface reaction. This is accomplished by the PhaseList class along with + * the ReactingSurface class. These classes will be migrated into Cantera + * soon. */ - class Interface : - public Cantera::SurfPhase, - public Cantera::InterfaceKinetics + Interface(std::string infile, std::string id, + std::vector otherPhases) : + m_ok(false), + m_r(0) { - public: - - /** - * Constructor. Construct an Interface instance from - * a specification in an input file. - * @param infile. Cantera input file in CTI or CTML format. - * @param id Identification string to distinguish between - * multiple definitions within one input file. - * @param phases Neighboring phases that may participate in the - * reactions on this interface. - */ - Interface(std::string infile, std::string id, - std::vector phases) - : m_ok(false), m_r(0) { - m_r = Cantera::get_XML_File(infile); - if (id == "-") id = ""; - - Cantera::XML_Node* x = Cantera::get_XML_Node("#"+id, m_r); - if (!x) - throw Cantera::CanteraError("Interface","error in get_XML_Node"); - - Cantera::importPhase(*x, this); - phases.push_back(this); - Cantera::importKinetics(*x, phases, this); - m_ok = true; - } - - /// Destructor. Does nothing. - virtual ~Interface() {} - - bool operator!() { return !m_ok;} - bool ready() const { return m_ok; } - - protected: - bool m_ok; - Cantera::XML_Node* m_r; - - private: - }; - - /** - * Import an instance of class Interface from a specification in an - * input file. This is the preferred method to create an Interface - * instance. - */ - inline Interface* importInterface(std::string infile, std::string id, - std::vector phases) { - return new Interface(infile, id, phases); + m_r = Cantera::get_XML_File(infile); + if (id == "-") id = ""; + + Cantera::XML_Node* x = Cantera::get_XML_Node("#"+id, m_r); + if (!x) { + throw Cantera::CanteraError("Interface","error in get_XML_Node"); + } + Cantera::importPhase(*x, this); + otherPhases.push_back(this); + Cantera::importKinetics(*x, otherPhases, this); + m_ok = true; } + //! Copy Constructor + /*! + * @param ii Interface object to be copied. + */ + Interface(const Interface& ii) : + Cantera::SurfPhase(ii), + Cantera::InterfaceKinetics(ii), + m_ok(ii.m_ok), + m_r(ii.m_r) + { + } + + //! Assignment operator + /*! + * @param right Interface object to be copied. + */ + Interface & operator=(const Interface &right) { + if (this == &right) return *this; + Cantera::SurfPhase::operator=(right); + Cantera::InterfaceKinetics::operator=(right); + m_ok = right.m_ok; + m_r = right.m_r; + return *this; + } + + //! Destructor. Does nothing. + virtual ~Interface() { + } + + //! Not operator + bool operator!() { + return !m_ok; + } + + //! return whether the object has been instantiated + /*! + * @return Returns a bool. + */ + bool ready() const { + return m_ok; + } + + protected: + + //! Flag indicating that the object has been instantiated + bool m_ok; + + //! XML_Node pointer to the XML File object that contains the Surface and the Interfacial Reaction object + //! description + Cantera::XML_Node* m_r; + + }; + + + //! Import an instance of class Interface from a specification in an input file. + /*! + * This is the preferred method to create an Interface instance. + */ + Interface* importInterface(std::string infile, std::string id, std::vector phases) { + return new Interface(infile, id, phases); + } + } diff --git a/Cantera/cxx/include/electrolyteThermo.h b/Cantera/cxx/include/electrolyteThermo.h index cdd1db33c..aef557f24 100644 --- a/Cantera/cxx/include/electrolyteThermo.h +++ b/Cantera/cxx/include/electrolyteThermo.h @@ -9,8 +9,8 @@ #ifndef CT_ELECTROLYTETHERMO_INCL #define CT_ELECTROLYTETHERMO_INCL -#include "thermo.h" +#ifdef WITH_ELECTROLYTES #include "kernel/electrolytes.h" #include "kernel/MolalityVPSSTP.h" #include "kernel/VPStandardStateTP.h" @@ -26,3 +26,5 @@ #include "kernel/VPSSMgr_Water_HKFT.h" #include "kernel/VPSSMgr_Water_ConstVol.h" #endif + +#endif diff --git a/Cantera/cxx/include/integrators.h b/Cantera/cxx/include/integrators.h index 69a603dae..de9d23719 100755 --- a/Cantera/cxx/include/integrators.h +++ b/Cantera/cxx/include/integrators.h @@ -6,5 +6,7 @@ #define CT_INTEG_H_INCL #include "kernel/Integrator.h" +#include "kernel/DAE_Solver.h" +#include "kernel/IDA_Solver.h" #endif diff --git a/Cantera/cxx/include/numerics.h b/Cantera/cxx/include/numerics.h index ea143c3dd..0aa803eac 100755 --- a/Cantera/cxx/include/numerics.h +++ b/Cantera/cxx/include/numerics.h @@ -4,5 +4,6 @@ #include "kernel/DenseMatrix.h" #include "kernel/BandMatrix.h" #include "kernel/SquareMatrix.h" +#include "kernel/NonlinearSolver.h" #endif diff --git a/Cantera/cxx/include/solvers.h b/Cantera/cxx/include/solvers.h new file mode 100644 index 000000000..b8c76bf2a --- /dev/null +++ b/Cantera/cxx/include/solvers.h @@ -0,0 +1,12 @@ +/** + * @file solvers.h + * solvers of small embedded problems + */ +#ifndef CT_SOLVERS_H_INCL +#define CT_SOLVERS_H_INCL + +#include "kernel/ResidEval.h" + +#include "kernel/solveProb.h" + +#endif diff --git a/Cantera/cxx/include/thermo.h b/Cantera/cxx/include/thermo.h index a27b23336..5eff5eaea 100755 --- a/Cantera/cxx/include/thermo.h +++ b/Cantera/cxx/include/thermo.h @@ -14,4 +14,33 @@ #include "kernel/SurfPhase.h" #include "kernel/EdgePhase.h" + +#ifdef WITH_IDEAL_SOLUTIONS + +#include "kernel/GibbsExcessVPSSTP.h" +#include "kernel/MargulesVPSSTP.h" + +#endif + +#ifdef WITH_ELECTROLYTES + +#include "electrolyteThermo.h" + +#endif + + +#ifdef WITH_LATTICE_SOLID + +#include "kernel/LatticePhase.h" +#include "kernel/LatticeSolidPhase.h" + +#endif + +#ifdef WITH_PURE_FLUIDS + + +#endif + + + #endif diff --git a/Cantera/cxx/include/transport.h b/Cantera/cxx/include/transport.h index be76ab861..035753e74 100755 --- a/Cantera/cxx/include/transport.h +++ b/Cantera/cxx/include/transport.h @@ -13,4 +13,5 @@ #include "kernel/DustyGasTransport.h" #include "kernel/MultiTransport.h" #include "kernel/MixTransport.h" +#include "kernel/LiquidTransport.h" #endif diff --git a/Cantera/cxx/include/zerodim.h b/Cantera/cxx/include/zerodim.h index 168039815..fb32b807d 100644 --- a/Cantera/cxx/include/zerodim.h +++ b/Cantera/cxx/include/zerodim.h @@ -11,7 +11,6 @@ #include "kernel/FlowReactor.h" #include "kernel/ConstPressureReactor.h" -using namespace CanteraZeroD; #endif diff --git a/Cantera/fortran/f77demos/Makefile.in b/Cantera/fortran/f77demos/Makefile.in index d99410041..8ba8599e5 100644 --- a/Cantera/fortran/f77demos/Makefile.in +++ b/Cantera/fortran/f77demos/Makefile.in @@ -18,6 +18,10 @@ FORT = @F77@ # Fortran compile flags FORT_FLAGS = @FFLAGS@ +FCLIBS= @FCLIBS@ +FLIBS = @FLIBS@ + + # Fortran libraries FORT_LIBS = @LCXX_FLIBS@ @LCXX_END_LIBS@ @FLIBS@ diff --git a/Cantera/fortran/src/Makefile.in b/Cantera/fortran/src/Makefile.in index 15f80f708..66f59382f 100644 --- a/Cantera/fortran/src/Makefile.in +++ b/Cantera/fortran/src/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: hkmoffa $ -# $Date: 2009/04/04 03:23:32 $ -# $Revision: 1.21 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001 California Institute of Technology # diff --git a/Cantera/fortran/src/fct.cpp b/Cantera/fortran/src/fct.cpp index d6d7145b1..29f7a812a 100644 --- a/Cantera/fortran/src/fct.cpp +++ b/Cantera/fortran/src/fct.cpp @@ -7,7 +7,7 @@ * pointers are passed to or from the calling application. */ /* - * $Id: fct.cpp,v 1.14 2009/07/23 16:56:48 hkmoffa Exp $ + * $Id$ */ // turn off warnings under Windows @@ -30,6 +30,9 @@ #include "flib_defs.h" +using namespace Cantera; +using namespace std; + // Assert that there is storage // for the templated classes' static member // (needed to compile on solaris) @@ -39,7 +42,7 @@ inline XML_Node* _xml(const integer* n) { return Cabinet::cabinet()->item(*n); } -inline ThermoPhase* _fph(const integer* n) { +inline Cantera::ThermoPhase* _fph(const integer* n) { return th(*n); } diff --git a/Cantera/fortran/src/fctxml.cpp b/Cantera/fortran/src/fctxml.cpp index 17c96f165..246c187da 100644 --- a/Cantera/fortran/src/fctxml.cpp +++ b/Cantera/fortran/src/fctxml.cpp @@ -4,8 +4,8 @@ */ /* - * $Revision: 1.9 $ - * $Date: 2009/07/23 17:03:04 $ + * $Revision$ + * $Date$ */ // Copyright 2001 California Institute of Technology @@ -19,6 +19,7 @@ using namespace ctml; using namespace std; +using namespace Cantera; #include "../../clib/src/Cabinet.h" diff --git a/Cantera/fortran/src/flib_defs.h b/Cantera/fortran/src/flib_defs.h index 3da47e4a9..e879a2479 100644 --- a/Cantera/fortran/src/flib_defs.h +++ b/Cantera/fortran/src/flib_defs.h @@ -21,8 +21,6 @@ typedef integer status_t; namespace Cantera {} -using namespace Cantera; namespace std{} -using namespace std; #endif diff --git a/Cantera/matlab/Makefile.in b/Cantera/matlab/Makefile.in index fa4000812..0bfbed956 100644 --- a/Cantera/matlab/Makefile.in +++ b/Cantera/matlab/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: hkmoffa $ -# $Date: 2009/07/06 23:52:40 $ -# $Revision: 1.33 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001-2004 California Institute of Technology # See file License.txt for licensing information diff --git a/Cantera/matlab/cantera/Contents.m b/Cantera/matlab/cantera/Contents.m index c5a94f3e5..5a4f155ec 100755 --- a/Cantera/matlab/cantera/Contents.m +++ b/Cantera/matlab/cantera/Contents.m @@ -33,7 +33,7 @@ % ctclear - Clear all objects from memory. % % Copyright 2002 California Institute of Technology -% $Revision: 1.1.1.1 $ $Date: 2003/04/14 17:57:49 $ +% $Revision$ $Date$ diff --git a/Cantera/matlab/cantera/private/ctfunctions.cpp b/Cantera/matlab/cantera/private/ctfunctions.cpp index 49c4edcad..f6b937e22 100644 --- a/Cantera/matlab/cantera/private/ctfunctions.cpp +++ b/Cantera/matlab/cantera/private/ctfunctions.cpp @@ -2,7 +2,7 @@ * @file ctfunctions.cpp */ /* - * $Id: ctfunctions.cpp,v 1.10 2009/07/11 16:43:12 hkmoffa Exp $ + * $Id$ */ #include "mex.h" diff --git a/Cantera/matlab/cantera/private/ctmatutils.h b/Cantera/matlab/cantera/private/ctmatutils.h index ffabe9d40..17e4f3369 100755 --- a/Cantera/matlab/cantera/private/ctmatutils.h +++ b/Cantera/matlab/cantera/private/ctmatutils.h @@ -2,7 +2,6 @@ const double Undef = -999.123; //const double DERR = -999.999; #include -using namespace std; void reportError(); @@ -24,13 +23,13 @@ inline char* getString(const mxArray* p) { int m = mxGetM(p); int n = mxGetN(p); int buflen = m*n + 1; - string msg; + std::string msg; if (m == 1) { input_buf = (char*)mxCalloc(buflen, sizeof(char)); status = mxGetString(p, input_buf, buflen); if(status != 0) { - msg = string(input_buf) + msg = std::string(input_buf) + "\nNot enough space. String is truncated."; mexWarnMsgTxt(msg.c_str()); } diff --git a/Cantera/matlab/cantera/private/mixturemethods.cpp b/Cantera/matlab/cantera/private/mixturemethods.cpp index 671c8d901..fc0018012 100644 --- a/Cantera/matlab/cantera/private/mixturemethods.cpp +++ b/Cantera/matlab/cantera/private/mixturemethods.cpp @@ -2,7 +2,7 @@ * @file mixturemethods.cpp */ /* - * $Id: mixturemethods.cpp,v 1.3 2009/07/11 16:43:12 hkmoffa Exp $ + * $Id$ */ #include "mex.h" #include "../../../clib/src/ctmultiphase.h" diff --git a/Cantera/matlab/cantera/private/mllogger.h b/Cantera/matlab/cantera/private/mllogger.h index 2c4ac8d96..94844c42a 100644 --- a/Cantera/matlab/cantera/private/mllogger.h +++ b/Cantera/matlab/cantera/private/mllogger.h @@ -2,7 +2,7 @@ * @file mlloger.h */ /* - * $Id: mllogger.h,v 1.5 2009/07/11 16:43:12 hkmoffa Exp $ + * $Id$ */ #ifndef MLLOGGER_H @@ -13,7 +13,6 @@ #include "cantera/kernel/logger.h" #include -//using namespace std; static std::string ss = "disp(' "; diff --git a/Cantera/matlab/cantera/private/phasemethods.cpp b/Cantera/matlab/cantera/private/phasemethods.cpp index df75fa57e..3a958f1df 100644 --- a/Cantera/matlab/cantera/private/phasemethods.cpp +++ b/Cantera/matlab/cantera/private/phasemethods.cpp @@ -2,7 +2,7 @@ * @file phasemethods.cpp */ /* - * $Id: phasemethods.cpp,v 1.5 2009/07/11 16:43:12 hkmoffa Exp $ + * $Id$ */ #include "mex.h" diff --git a/Cantera/matlab/cantera/private/reactormethods.cpp b/Cantera/matlab/cantera/private/reactormethods.cpp index b22cf37fb..49bad594c 100644 --- a/Cantera/matlab/cantera/private/reactormethods.cpp +++ b/Cantera/matlab/cantera/private/reactormethods.cpp @@ -2,7 +2,7 @@ * @file reactormethods.cpp */ /* - * $Id: reactormethods.cpp,v 1.5 2009/07/11 16:43:12 hkmoffa Exp $ + * $Id$ */ #include "mex.h" diff --git a/Cantera/matlab/cantera/private/reactornetmethods.cpp b/Cantera/matlab/cantera/private/reactornetmethods.cpp index 27b678809..766ae885f 100644 --- a/Cantera/matlab/cantera/private/reactornetmethods.cpp +++ b/Cantera/matlab/cantera/private/reactornetmethods.cpp @@ -2,7 +2,7 @@ * @file reactornetmethods.cpp */ /* - * $Id: reactornetmethods.cpp,v 1.4 2009/07/11 16:43:13 hkmoffa Exp $ + * $Id$ */ #include "mex.h" diff --git a/Cantera/matlab/cantera/private/thermomethods.cpp b/Cantera/matlab/cantera/private/thermomethods.cpp index c2fb43512..02286ed88 100644 --- a/Cantera/matlab/cantera/private/thermomethods.cpp +++ b/Cantera/matlab/cantera/private/thermomethods.cpp @@ -2,7 +2,7 @@ * @file thermomethods.cpp */ /* - * $Id: thermomethods.cpp,v 1.11 2009/07/11 16:43:13 hkmoffa Exp $ + * $Id$ */ #include "mex.h" #include "../../../clib/src/ct.h" diff --git a/Cantera/matlab/cantera/private/wallmethods.cpp b/Cantera/matlab/cantera/private/wallmethods.cpp index 004b4c652..1b7cf7e20 100644 --- a/Cantera/matlab/cantera/private/wallmethods.cpp +++ b/Cantera/matlab/cantera/private/wallmethods.cpp @@ -2,7 +2,7 @@ * @file wallmethods.cpp */ /* - * $Id: wallmethods.cpp,v 1.5 2009/07/11 16:43:13 hkmoffa Exp $ + * $Id$ */ #include "mex.h" #include "../../../clib/src/ctreactor.h" diff --git a/Cantera/matlab/cantera/private/xmlmethods.cpp b/Cantera/matlab/cantera/private/xmlmethods.cpp index 5cc4ed959..00397e429 100644 --- a/Cantera/matlab/cantera/private/xmlmethods.cpp +++ b/Cantera/matlab/cantera/private/xmlmethods.cpp @@ -2,7 +2,7 @@ * @file xmlmethods.cpp */ /* - * $Id: xmlmethods.cpp,v 1.5 2009/07/11 16:43:13 hkmoffa Exp $ + * $Id$ */ #include "mex.h" diff --git a/Cantera/matlab/setup_winmatlab.py b/Cantera/matlab/setup_winmatlab.py index 6207f9815..c41132377 100644 --- a/Cantera/matlab/setup_winmatlab.py +++ b/Cantera/matlab/setup_winmatlab.py @@ -1,7 +1,7 @@ # # python script to create a few key files for the windows build # -# $Id: setup_winmatlab.py,v 1.29 2009/07/20 19:38:53 hkmoffa Exp $ +# $Id$ # import sys import os diff --git a/Cantera/python/Cantera/Edge.py b/Cantera/python/Cantera/Edge.py index 32a8c512f..a6c661186 100644 --- a/Cantera/python/Cantera/Edge.py +++ b/Cantera/python/Cantera/Edge.py @@ -7,7 +7,7 @@ from SurfacePhase import EdgePhase from Kinetics import Kinetics import XML -__revision__ = "$Id: Edge.py,v 1.1 2006/04/23 07:27:10 dggoodwin Exp $" +__revision__ = "$Id$" class Edge(EdgePhase, Kinetics): """ diff --git a/Cantera/python/Cantera/Interface.py b/Cantera/python/Cantera/Interface.py index 7a7307966..8a26d8f61 100644 --- a/Cantera/python/Cantera/Interface.py +++ b/Cantera/python/Cantera/Interface.py @@ -7,7 +7,7 @@ from SurfacePhase import SurfacePhase, EdgePhase from Kinetics import Kinetics import XML -__revision__ = "$Id: Interface.py,v 1.8 2007/02/17 10:48:09 dggoodwin Exp $" +__revision__ = "$Id$" class Interface(SurfacePhase, Kinetics): """ diff --git a/Cantera/python/Cantera/OneD/onedim.py b/Cantera/python/Cantera/OneD/onedim.py index 3710100a0..9e6782815 100644 --- a/Cantera/python/Cantera/OneD/onedim.py +++ b/Cantera/python/Cantera/OneD/onedim.py @@ -615,9 +615,14 @@ class Stack: """ return _cantera.sim1D_restore(self._hndl, file, id) - def showStats(self): - """Show the statistics for the last solution.""" - return _cantera.sim1D_writeStats(self._hndl) + def showStats(self, printTime = 1): + """Show the statistics for the last solution. + If invoked with no arguments or with a non-zero argument, the + timing statistics will be printed. If invoked with a zero argument, + the timing will not be printed. + Default: print timing enabled. + """ + return _cantera.sim1D_writeStats(self._hndl, _onoff[printTime]) def domainIndex(self, name): """Integer index of the domain with name 'name'""" diff --git a/Cantera/python/Cantera/Phase.py b/Cantera/python/Cantera/Phase.py index c5cc1fdba..ed65174e8 100755 --- a/Cantera/python/Cantera/Phase.py +++ b/Cantera/python/Cantera/Phase.py @@ -10,7 +10,7 @@ import types from Cantera.num import asarray from exceptions import CanteraError -__revision__ = "$Id: Phase.py,v 1.9 2007/05/25 14:17:38 dggoodwin Exp $" +__revision__ = "$Id$" # return true is x is a sequence def _isseq(n, x): diff --git a/Cantera/python/Cantera/importFromFile.py b/Cantera/python/Cantera/importFromFile.py index 448d13074..4d9f3ae5f 100755 --- a/Cantera/python/Cantera/importFromFile.py +++ b/Cantera/python/Cantera/importFromFile.py @@ -8,7 +8,7 @@ import Interface import Edge import XML -__revision__ = "$Id: importFromFile.py,v 1.12 2007/02/17 10:48:09 dggoodwin Exp $" +__revision__ = "$Id$" def importPhase(file, name = '', loglevel = 0, debug = 0): """Import one phase from an input file. If 'name' is specified, the diff --git a/Cantera/python/Makefile.in b/Cantera/python/Makefile.in index bec87b2dc..2fed5438f 100755 --- a/Cantera/python/Makefile.in +++ b/Cantera/python/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: hkmoffa $ -# $Date: 2009/04/19 21:11:51 $ -# $Revision: 1.31 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001 California Institute of Technology # See file License.txt for licensing information diff --git a/Cantera/python/ctml_writer.py b/Cantera/python/ctml_writer.py index 1d78f79cd..9754a7d53 100644 --- a/Cantera/python/ctml_writer.py +++ b/Cantera/python/ctml_writer.py @@ -16,7 +16,7 @@ # # -# $Id: ctml_writer.py,v 1.25 2007/12/30 04:19:38 dggoodwin Exp $ +# $Id$ import string diff --git a/Cantera/python/examples/flames/npflame1/npflame1.py b/Cantera/python/examples/flames/npflame1/npflame1.py index 12fe3b10b..79b1d36f7 100644 --- a/Cantera/python/examples/flames/npflame1/npflame1.py +++ b/Cantera/python/examples/flames/npflame1/npflame1.py @@ -118,7 +118,7 @@ fcsv.close() print 'solution saved to npflame1.csv' f.showSolution() -f.showStats() +f.showStats(0) diff --git a/Cantera/python/examples/flames/npflame1/output_blessed_0.txt b/Cantera/python/examples/flames/npflame1/output_blessed_0.txt index d0eeebeb9..355a57a1d 100644 --- a/Cantera/python/examples/flames/npflame1/output_blessed_0.txt +++ b/Cantera/python/examples/flames/npflame1/output_blessed_0.txt @@ -2588,14 +2588,14 @@ solution saved to npflame1.csv Statistics: Grid Functions Time Jacobians Time - 8 589 1.2400 22 1.3700 - 8 820 1.7500 49 3.2200 - 13 1341 6.2100 45 6.8000 - 20 2488 19.5700 45 12.2500 - 30 253 3.1500 17 7.8000 - 44 61 1.1300 3 2.1700 - 66 25 0.7400 2 2.4100 - 106 31 1.4700 2 4.4300 - 155 24 1.6800 2 7.2600 - 173 12 0.9400 1 4.2700 - 178 2 0.1600 1 4.4600 + 8 589 NA 22 NA + 8 820 NA 49 NA + 13 1341 NA 45 NA + 20 2488 NA 45 NA + 30 253 NA 17 NA + 44 61 NA 3 NA + 66 25 NA 2 NA + 106 31 NA 2 NA + 155 24 NA 2 NA + 173 12 NA 1 NA + 178 2 NA 1 NA diff --git a/Cantera/python/examples/flames/npflame1/runtest b/Cantera/python/examples/flames/npflame1/runtest index 5d830d68a..bbea0cef4 100755 --- a/Cantera/python/examples/flames/npflame1/runtest +++ b/Cantera/python/examples/flames/npflame1/runtest @@ -2,7 +2,7 @@ # # temp_success="1" -/bin/rm -f output_0.txt npflame1.csv diff_csv.txt diff_out_0.txt +/bin/rm -f output_0.txt npflame1.csv diff_csv.txt diff_out_0.txt npflame1.xml ########################################################################## prog=npflame1.py @@ -40,7 +40,7 @@ then fi retnCSVTotal=1 -if test $retnStat_csv_0 = "1" +if test $retnStat_csv_0 = "0" then retnCSVTotal=0 fi @@ -57,7 +57,7 @@ else echo " see diff_csv.txt " if test $retnTotal != "0" then - echo " ASCII files are different too - see diff_test*.txt" + echo " ASCII files are different too - see diff_out_0.txt" fi fi diff --git a/Cantera/python/examples/surface_chemistry/catcomb_stagflow/output_blessed_0.txt b/Cantera/python/examples/surface_chemistry/catcomb_stagflow/output_blessed_0.txt index e34efe4a3..917ccdfbb 100644 --- a/Cantera/python/examples/surface_chemistry/catcomb_stagflow/output_blessed_0.txt +++ b/Cantera/python/examples/surface_chemistry/catcomb_stagflow/output_blessed_0.txt @@ -729,27 +729,27 @@ no new points needed in flow C(S) 1.368e-07 O(S) 0.867 -Solution saved to file catcomb.xml as solution soln1. +Solution saved to file catcomb.xml as solution soln1_2. solution saved to catcomb.csv Statistics: Grid Functions Time Jacobians Time - 8 38 0.0400 3 0.2100 - 9 16 0.0300 2 0.1800 - 10 8 0.0300 1 0.1000 - 10 16 0.0500 2 0.2200 - 10 10 0.0200 1 0.1100 - 10 14 0.0300 2 0.2200 - 10 16 0.0500 2 0.2100 - 10 14 0.0300 2 0.2200 - 10 8 0.0300 1 0.1000 - 10 41 0.1200 3 0.3100 - 17 37 0.1100 3 0.4800 - 25 26 0.1500 2 0.4900 - 28 11 0.0700 1 0.2800 - 29 11 0.0600 1 0.2900 - 30 6 0.0300 1 0.3100 - 32 6 0.0500 1 0.3300 - 33 4 0.0200 1 0.3500 - 34 2 0.0000 1 0.3600 + 8 38 0.0400 3 0.1200 + 9 16 0.0100 2 0.0900 + 10 8 0.0100 1 0.0600 + 10 16 0.0300 2 0.1100 + 10 10 0.0200 1 0.0500 + 10 14 0.0200 2 0.1100 + 10 16 0.0400 2 0.1100 + 10 14 0.0200 2 0.1100 + 10 8 0.0100 1 0.0500 + 10 41 0.0500 3 0.1600 + 17 37 0.1100 3 0.3600 + 25 26 0.1100 2 0.3900 + 28 11 0.0500 1 0.2200 + 29 11 0.1000 1 0.2300 + 30 6 0.0300 1 0.2400 + 32 6 0.0400 1 0.2600 + 33 4 0.0300 1 0.2600 + 34 2 0.0000 1 0.2800 diff --git a/Cantera/python/examples/surface_chemistry/catcomb_stagflow/runtest b/Cantera/python/examples/surface_chemistry/catcomb_stagflow/runtest index 3048b8df8..d5c072113 100755 --- a/Cantera/python/examples/surface_chemistry/catcomb_stagflow/runtest +++ b/Cantera/python/examples/surface_chemistry/catcomb_stagflow/runtest @@ -40,7 +40,7 @@ then fi retnCSVTotal=1 -if test $retnStat_csv_0 = "1" +if test $retnStat_csv_0 = "0" then retnCSVTotal=0 fi diff --git a/Cantera/python/examples/surface_chemistry/diamond_cvd/runtest b/Cantera/python/examples/surface_chemistry/diamond_cvd/runtest index c4b4c05a1..a194e6e53 100755 --- a/Cantera/python/examples/surface_chemistry/diamond_cvd/runtest +++ b/Cantera/python/examples/surface_chemistry/diamond_cvd/runtest @@ -40,7 +40,7 @@ then fi retnCSVTotal=1 -if test $retnStat_csv_0 = "1" +if test $retnStat_csv_0 = "0" then retnCSVTotal=0 fi diff --git a/Cantera/python/examples/transport/output_blessed_0.txt b/Cantera/python/examples/transport/output_blessed_0.txt index 0e67ec2b6..d46c48f75 100644 --- a/Cantera/python/examples/transport/output_blessed_0.txt +++ b/Cantera/python/examples/transport/output_blessed_0.txt @@ -1,31 +1,31 @@ [[ 6.04406471e-06 1.01738100e-06 3.25467803e-15 9.44878921e-07 - 3.20196626e-07 3.45252809e-15 3.12341397e-15 3.09815027e-15 - 2.93166212e-15] + 3.20196626e-07 3.45252809e-15 3.12341397e-15 3.09815027e-15 + 2.93166212e-15] [ 5.08690499e-15 1.00940773e-05 2.95033119e-15 8.72973220e-07 - 2.90021521e-07 3.22819878e-15 2.88500792e-15 2.86100892e-15 - 2.70458750e-15] + 2.90021521e-07 3.22819878e-15 2.88500792e-15 2.86100892e-15 + 2.70458750e-15] [ 3.25467803e-15 5.90066238e-07 2.40899947e-06 8.67150386e-07 - 2.75178768e-07 3.02514701e-15 2.87336197e-15 2.85661971e-15 - 2.73675664e-15] + 2.75178768e-07 3.02514701e-15 2.87336197e-15 2.85661971e-15 + 2.73675664e-15] [ 3.14959640e-15 5.81982147e-07 2.89050129e-15 2.56318977e-06 - 2.87270338e-07 3.25199672e-15 3.05588867e-15 3.04247847e-15 - 2.94726056e-15] + 2.87270338e-07 3.25199672e-15 3.05588867e-15 3.04247847e-15 + 2.94726056e-15] [ 3.20196626e-15 5.80043042e-07 2.75178768e-15 8.61811015e-07 - 2.62146728e-06 2.99922209e-15 2.85602138e-15 2.83971549e-15 - 2.72221044e-15] + 2.62146728e-06 2.99922209e-15 2.85602138e-15 2.83971549e-15 + 2.72221044e-15] [ 3.45252809e-15 6.45639757e-07 3.02514701e-15 9.75599015e-07 - 2.99922209e-07 2.08849997e-06 3.19672263e-15 3.17885565e-15 - 3.07926377e-15] + 2.99922209e-07 2.08849997e-06 3.19672263e-15 3.17885565e-15 + 3.07926377e-15] [ 3.12341397e-15 5.77001585e-07 2.87336197e-15 9.16766600e-07 - 2.85602138e-07 3.19672263e-15 1.62315735e-06 3.02939857e-15 - 2.93566827e-15] + 2.85602138e-07 3.19672263e-15 1.62315735e-06 3.02939857e-15 + 2.93566827e-15] [ 3.09815027e-15 5.72201784e-07 2.85661971e-15 9.12743541e-07 - 2.83971549e-07 3.17885565e-15 3.02939857e-15 1.60480867e-06 - 2.92422492e-15] + 2.83971549e-07 3.17885565e-15 3.02939857e-15 1.60480867e-06 + 2.92422492e-15] [ 2.93166212e-15 5.40917501e-07 2.73675664e-15 8.84178169e-07 - 2.72221044e-07 3.07926377e-15 2.93566827e-15 2.92422492e-15 - 1.51904485e-06]] + 2.72221044e-07 3.07926377e-15 2.93566827e-15 2.92422492e-15 + 1.51904485e-06]] [-0. -0. -0. -0. -0. -0. -0. -0. -0.] -[ -7.04749149e-14 -1.88567695e-05 -3.64733235e-14 -9.21405522e-06 - -3.58390239e-06 -3.54030661e-14 -3.04704797e-14 -3.02364800e-14 - -2.89579939e-14] +[ -6.90966189e-14 -1.84036152e-05 -3.65042941e-14 -9.29059107e-06 + -3.58923841e-06 -3.54785016e-14 -3.07335477e-14 -3.05071031e-14 + -2.92655613e-14] diff --git a/Cantera/python/setup.py.in b/Cantera/python/setup.py.in index 957fa1e62..8d068621c 100644 --- a/Cantera/python/setup.py.in +++ b/Cantera/python/setup.py.in @@ -11,10 +11,11 @@ libs = [] platform = sys.platform flibs = [] -if @build_with_f2c@ <> 1: - flibstr = '@FLIBS@' - f1 = flibstr.replace('-l', ' ') - flibs = f1.split() +# HKM -> not clear we need FLIBS here +#if @build_with_f2c@ == 1: +# flibstr = '@FLIBS@' +# f1 = flibstr.replace('-l', ' ') +# flibs = f1.split() linkargs = '@LCXX_FLAGS@' diff --git a/Cantera/python/src/Makefile.in b/Cantera/python/src/Makefile.in index 4791f646d..2a68ff12f 100755 --- a/Cantera/python/src/Makefile.in +++ b/Cantera/python/src/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: dggoodwin $ -# $Date: 2003/04/14 17:57:50 $ -# $Revision: 1.1.1.1 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001 California Institute of Technology # diff --git a/Cantera/python/src/ctkinetics_methods.cpp b/Cantera/python/src/ctkinetics_methods.cpp index 45cd77c19..a9309a4b0 100644 --- a/Cantera/python/src/ctkinetics_methods.cpp +++ b/Cantera/python/src/ctkinetics_methods.cpp @@ -4,7 +4,7 @@ */ /* - * $Id: ctkinetics_methods.cpp,v 1.8 2009/04/19 21:03:10 hkmoffa Exp $ + * $Id$ */ diff --git a/Cantera/python/src/ctonedim_methods.cpp b/Cantera/python/src/ctonedim_methods.cpp index 397419f1d..16f533134 100644 --- a/Cantera/python/src/ctonedim_methods.cpp +++ b/Cantera/python/src/ctonedim_methods.cpp @@ -1,6 +1,6 @@ /* - * $Id: ctonedim_methods.cpp,v 1.12 2009/03/24 19:13:02 hkmoffa Exp $ + * $Id$ */ @@ -870,11 +870,14 @@ py_sim1D_writeStats(PyObject *self, PyObject *args) { int _val; int i; - if (!PyArg_ParseTuple(args, "i:sim1D_writeStats", &i)) + int printTime; + if (!PyArg_ParseTuple(args, "ii:sim1D_writeStats", &i, &printTime)) { return NULL; - - _val = sim1D_writeStats(i); - if (int(_val) == -1) return reportCanteraError(); + } + _val = sim1D_writeStats(i, printTime); + if (int(_val) == -1) { + return reportCanteraError(); + } return Py_BuildValue("i",_val); } diff --git a/Cantera/python/src/pylogger.h b/Cantera/python/src/pylogger.h index 9a84139cb..a60ac2447 100644 --- a/Cantera/python/src/pylogger.h +++ b/Cantera/python/src/pylogger.h @@ -5,7 +5,6 @@ #include #include "cantera/kernel/logger.h" -using namespace std; static std::string ss = "print \"\"\" "; @@ -18,7 +17,7 @@ namespace Cantera { Py_Logger() {} virtual ~Py_Logger() {} - virtual void write(const string& s) { + virtual void write(const std::string& s) { char ch = s[0]; int n = 0; while (ch != '\0') { @@ -35,7 +34,7 @@ namespace Cantera { } virtual void error(const std::string& msg) { - string err = "raise \""+msg+"\""; + std::string err = "raise \""+msg+"\""; PyRun_SimpleString((char *)err.c_str()); } diff --git a/Cantera/src/Makefile.in b/Cantera/src/Makefile.in index 4408231f2..01072f159 100755 --- a/Cantera/src/Makefile.in +++ b/Cantera/src/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: dggoodwin $ -# $Date: 2007/12/15 17:15:50 $ -# $Revision: 1.58 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2001 California Institute of Technology # diff --git a/Cantera/src/base/Array.h b/Cantera/src/base/Array.h index bde5f28c6..ae5e472df 100644 --- a/Cantera/src/base/Array.h +++ b/Cantera/src/base/Array.h @@ -19,6 +19,8 @@ #include "ctexceptions.h" #include "utilities.h" +#include + namespace Cantera { @@ -118,6 +120,16 @@ namespace Cantera { m_data.resize(n*m, v); } + //! Copy the data from one array into another without doing any checking + /*! + * This differs from the assignment operator as no resizing is done and memcpy() is used. + * @param y Array to be copied + */ + void copyData(const Array2D& y) { + size_t n = sizeof(doublereal) * m_nrows * m_ncols; + (void) memcpy(DATA_PTR(m_data), y.ptrColumn(0), n); + } + //! Append a column to the existing matrix using a std vector /*! * This operation will add a column onto the existing matrix. @@ -223,6 +235,17 @@ namespace Cantera { for (; b != end(); ++b, ++xb, ++yb) *b = a*(*xb) + *yb; } + //! Set all of the entries to zero + inline void zero() { + int nn = m_nrows * m_ncols; + if (nn > 0) { + /* + * Using memset is the fastest way to zero a contiguous + * section of memory. + */ + (void) memset((void *) &m_data[0], 0, nn * sizeof(doublereal)); + } + } //! Allows setting elements using the syntax A(i,j) = x. /*! diff --git a/Cantera/src/base/checkFinite.cpp b/Cantera/src/base/checkFinite.cpp index be4fa224d..443d3d8a7 100644 --- a/Cantera/src/base/checkFinite.cpp +++ b/Cantera/src/base/checkFinite.cpp @@ -50,11 +50,11 @@ namespace mdp { void checkFinite(const double tmp) throw(std::range_error) { if (_finite(tmp)) { if(_isnan(tmp)) { - printf("ERROR: we have encountered a nan!\n"); + printf("checkFinite() ERROR: we have encountered a nan!\n"); } else if (_fpclass(tmp) == _FPCLASS_PINF) { - printf("ERROR: we have encountered a pos inf!\n"); + printf("checkFinite() ERROR: we have encountered a pos inf!\n"); } else { - printf("ERROR: we have encountered a neg inf!\n"); + printf("checkFinite() ERROR: we have encountered a neg inf!\n"); } const std::string s = "checkFinite()"; throw std::range_error(s); @@ -64,11 +64,11 @@ namespace mdp { void checkFinite(const double tmp) throw(std::range_error) { if (! finite(tmp)) { if(isnan(tmp)) { - printf("ERROR: we have encountered a nan!\n"); + printf("checkFinite() ERROR: we have encountered a nan!\n"); } else if (isinf(tmp) == 1) { - printf("ERROR: we have encountered a pos inf!\n"); + printf("checkFinite() ERROR: we have encountered a pos inf!\n"); } else { - printf("ERROR: we have encountered a neg inf!\n"); + printf("checkFinite() ERROR: we have encountered a neg inf!\n"); } const std::string s = "checkFinite()"; throw std::range_error(s); @@ -102,7 +102,7 @@ namespace mdp { checkFinite(tmp); if (fabs(tmp) >= trigger) { char sbuf[64]; - sprintf(sbuf, "checkMagnitude: Trigger %g exceeded: %g\n", trigger, + sprintf(sbuf, "checkMagnitude() ERROR: Trigger %g exceeded: %g\n", trigger, tmp); throw std::range_error(sbuf); } @@ -119,16 +119,16 @@ namespace mdp { void checkZeroFinite(const double tmp) throw(std::range_error) { if ((tmp == 0.0) || (! _finite(tmp))) { if (tmp == 0.0) { - printf("ERROR: we have encountered a zero!\n"); + printf("checkZeroFinite() ERROR: we have encountered a zero!\n"); } else if(_isnan(tmp)) { - printf("ERROR: we have encountered a nan!\n"); + printf("checkZeroFinite() ERROR: we have encountered a nan!\n"); } else if (_fpclass(tmp) == _FPCLASS_PINF) { - printf("ERROR: we have encountered a pos inf!\n"); + printf("checkZeroFinite() ERROR: we have encountered a pos inf!\n"); } else { - printf("ERROR: we have encountered a neg inf!\n"); + printf("checkZeroFinite() ERROR: we have encountered a neg inf!\n"); } char sbuf[64]; - sprintf(sbuf, "checkZeroFinite: zero or indef exceeded: %g\n", + sprintf(sbuf, "checkZeroFinite() ERROR: zero or indef exceeded: %g\n", tmp); throw std::range_error(sbuf); } @@ -137,16 +137,16 @@ void checkZeroFinite(const double tmp) throw(std::range_error) { void checkZeroFinite(const double tmp) throw(std::range_error) { if ((tmp == 0.0) || (! finite(tmp))) { if (tmp == 0.0) { - printf("ERROR: we have encountered a zero!\n"); + printf("checkZeroFinite() ERROR: we have encountered a zero!\n"); } else if(isnan(tmp)) { - printf("ERROR: we have encountered a nan!\n"); + printf("checkZeroFinite() ERROR: we have encountered a nan!\n"); } else if (isinf(tmp) == 1) { - printf("ERROR: we have encountered a pos inf!\n"); + printf("checkZeroFinite() ERROR: we have encountered a pos inf!\n"); } else { - printf("ERROR: we have encountered a neg inf!\n"); + printf("checkZeroFinite() ERROR: we have encountered a neg inf!\n"); } char sbuf[64]; - sprintf(sbuf, "checkZeroFinite: zero or indef exceeded: %g\n", + sprintf(sbuf, "checkZeroFinite() ERROR: zero or indef exceeded: %g\n", tmp); throw std::range_error(sbuf); } diff --git a/Cantera/src/base/ctexceptions.h b/Cantera/src/base/ctexceptions.h index 1c29cbd36..1a7d9c0f4 100644 --- a/Cantera/src/base/ctexceptions.h +++ b/Cantera/src/base/ctexceptions.h @@ -90,14 +90,14 @@ namespace Cantera { CanteraError(std::string procedure, std::string msg); //! Destructor for base class does nothing - virtual ~CanteraError() throw() {} + virtual ~CanteraError() throw(); protected: //! Empty base constructor is made protected so that it may be used only by //! inherited classes. /*! * We want to discourage throwing an error containing no information. */ - CanteraError() {} + CanteraError(); }; //! Array size error. diff --git a/Cantera/src/base/ctml.cpp b/Cantera/src/base/ctml.cpp index f287ed95f..ca4185b91 100644 --- a/Cantera/src/base/ctml.cpp +++ b/Cantera/src/base/ctml.cpp @@ -37,10 +37,20 @@ using namespace Cantera; namespace ctml { + std::string FP_Format = "%23.15E"; + std::string INT_Format = "%8d"; + + //==================================================================================================================== + //! Convert a floating point value from a string to a double + /*! + * @param val String value input + * + * @return Returns a double + */ static doublereal fpValue(std::string val) { return atof(stripws(val).c_str()); } - + //==================================================================================================================== // This function adds a child node with the name, "bool", with a value // consisting of a single bool /* @@ -79,7 +89,7 @@ namespace ctml { XML_Node& f = node.addChild("bool", v); f.addAttribute("title", title); } - + //==================================================================================================================== // This function adds a child node with the name, "integer", with a value // consisting of a single integer /* @@ -118,12 +128,17 @@ namespace ctml { */ void addInteger(Cantera::XML_Node& node, const std::string &title, const int val, const std::string units, const std::string type) { - XML_Node& f = node.addChild("integer",val); - f.addAttribute("title",title); +#ifdef CTML_VERSION_1_4 + XML_Node& f = node.addChild("integer", val); + f.addAttribute("title", title); +#else + XML_Node& f = node.addChild(title, val); +#endif + f.addAttribute("vtype", "integer"); if (type != "") f.addAttribute("type",type); if (units != "") f.addAttribute("units",units); } - + //==================================================================================================================== // This function adds a child node with the name, "intArray", with a value // consisting of a comma separated list of integers /* @@ -179,24 +194,30 @@ namespace ctml { void addIntegerArray(Cantera::XML_Node& node, const std::string &title, const int n, const int* const vals, const std::string units, const std::string type, const doublereal minval, const doublereal maxval) { - std::string fmt = "%8d"; int i; std::string v = ""; for (i = 0; i < n; i++) { - v += int2str(vals[i],fmt); + v += int2str(vals[i],INT_Format); if (i == n-1) v += "\n"; else if (i > 0 && (i+1) % 3 == 0) v += ",\n"; else v += ", "; } - XML_Node& f = node.addChild("intArray",v); +#ifdef CTML_VERSION_1_4 + XML_Node& f = node.addChild("intArray",v); f.addAttribute("title",title); +#else + XML_Node& f = node.addChild(title, v); +#endif if (type != "") f.addAttribute("type",type); f.addAttribute("size",n); +#ifndef CTML_VERSION_1_4 + f.addAttribute("vtype", "intArray"); +#endif if (units != "") f.addAttribute("units",units); if (minval != Undef) f.addAttribute("min",minval); if (maxval != Undef) f.addAttribute("max",maxval); } - + //==================================================================================================================== // This function adds a child node with the name, "float", with a value // consisting of a single floating point number /* @@ -243,19 +264,19 @@ namespace ctml { const doublereal val, const std::string units, const std::string type, const doublereal minval, const doublereal maxval) { - string fmt = "%17.9E"; #ifdef CTML_VERSION_1_4 - XML_Node& f = node.addChild("float",val,fmt); - f.addAttribute("title",title); + XML_Node& f = node.addChild("float", val, ctml::FP_Format); + f.addAttribute("title", title); #else - XML_Node& f = node.addChild(title,val,fmt); + XML_Node& f = node.addChild(title, val, ctml::FP_Format); #endif if (type != "") f.addAttribute("type",type); if (units != "") f.addAttribute("units",units); + f.addAttribute("vtype", "float"); if (minval != Undef) f.addAttribute("min",minval); if (maxval != Undef) f.addAttribute("max",maxval); } - + //==================================================================================================================== // This function adds a child node with the name, "floatArray", with a value // consisting of a comma separated list of floats /* @@ -293,7 +314,7 @@ namespace ctml { * @param unitsString String name of the Units attribute. This is an optional * parameter. The default is to * have an empty string. - * @param typeString String type. This is an optional parameter. The default + * @param type String type. This is an optional parameter. The default * is to have an empty string. * @param minval Minimum allowed value of the int. This is an optional * parameter. The default is the @@ -312,11 +333,10 @@ namespace ctml { const doublereal* const vals, const std::string units, const std::string type, const doublereal minval, const doublereal maxval) { - std::string fmt = "%17.9E"; int i; std::string v = ""; for (i = 0; i < n; i++) { - v += fp2str(vals[i],fmt); + v += fp2str(vals[i],FP_Format); if (i == n-1) v += "\n"; else if (i > 0 && (i+1) % 3 == 0) v += ",\n"; else v += ", "; @@ -329,7 +349,87 @@ namespace ctml { if (minval != Undef) f.addAttribute("min",minval); if (maxval != Undef) f.addAttribute("max",maxval); } - + //==================================================================================================================== + // This function adds a child node with the name given by the first parameter with a value + // consisting of a comma separated list of floats + /* + * This function will add a child node to the current XML node, with the + * name given in the list. It will have a title attribute, and the body + * of the XML node will be filled out with a comma separated list of + * integers + * + * Example: + * + * Code snipet: + * @verbatum + const XML_Node &node; + std::string titleString = "additionalTemperatures"; + int n = 3; + int Tcases[3] = [273.15, 298.15, 373.15]; + std::string typeString = "optional"; + std::string units = "Kelvin"; + addNamedFloatArray(node, titleString, n, &cases[0], typeString, units); + @endverbatum + * + * Creates the following the snippet in the XML file: + * @verbatum + + + 273.15, 298.15, 373.15 + <\additionalTemperatures> + <\parentNode> + @endverbatum + * + * @param node reference to the XML_Node object of the parent XML element + * @param name Name of the XML node + * @param n Length of the doubles vector. + * @param values Pointer to a vector of doubles + * @param unitsString String name of the Units attribute. This is an optional + * parameter. The default is to + * have an empty string. + * @param type String type. This is an optional parameter. The default + * is to have an empty string. + * @param minval Minimum allowed value of the int. This is an optional + * parameter. The default is the + * special double, Cantera::Undef, which means to ignore the + * entry. + * @param maxval Maximum allowed value of the int. This is an optional + * parameter. The default is the + * special double, Cantera::Undef, which means to ignore the + * entry. + * + * @todo I don't think this is used. Figure out what is used for writing integers, + * and codify that. unitsString shouldn't be here, since it's an int. + * typeString should be codified as to its usage. + */ + void addNamedFloatArray(Cantera::XML_Node& node, const std::string &name, const int n, + const doublereal* const vals, const std::string units, + const std::string type, const doublereal minval, + const doublereal maxval) { + int i; + std::string v = ""; + for (i = 0; i < n; i++) { + v += fp2str(vals[i],FP_Format); + if (i == n-1) v += "\n"; + else if (i > 0 && (i+1) % 3 == 0) v += ",\n"; + else v += ", "; + } + XML_Node& f = node.addChild(name, v); + if (type != "") { + f.addAttribute("type",type); + } + /* + * Add vtype, which indicates the type of the value. Here we specify it as a list of floats separated + * by commas, with a length given by size attribute. + */ + f.addAttribute("vtype", "floatArray"); + + f.addAttribute("size", n); + if (units != "") f.addAttribute("units", units); + if (minval != Undef) f.addAttribute("min", minval); + if (maxval != Undef) f.addAttribute("max", maxval); + } + //==================================================================================================================== // This function adds a child node with the name string with a string value // to the current node /* @@ -376,7 +476,7 @@ namespace ctml { } return 0; } - + //==================================================================================================================== // This function reads a child node with the name string and returns // its xml value as the return string /* @@ -409,7 +509,7 @@ namespace ctml { if (!parent.hasChild(nameString)) return ""; return parent(nameString); } - + //==================================================================================================================== // This function reads a child node with the name, "string", with a specific // title attribute named "titleString" /* @@ -433,10 +533,11 @@ namespace ctml { <\string> @endverbatum * - * @param node reference to the XML_Node object of the parent XML element + * @param node Reference to the XML_Node object of the parent XML element * @param titleString String name of the title attribute of the child node * @param valueString Value string that is found in the child node. output variable - * @param typeString String type. This is an optional output variable + * @param typeString String type. This is an optional output variable. It is filled + * with the attribute "type" of the XML entry. */ void getString(const Cantera::XML_Node& node, const std::string &titleString, std::string& valueString, std::string& typeString) { @@ -451,7 +552,70 @@ namespace ctml { } } - + //==================================================================================================================== + // This function attempts to read a named child node and returns with the contents in the value string. + // title attribute named "titleString" + /* + * This function will read a child node to the current XML node, with the + * name "string". It must have a title attribute, named titleString, and the body + * of the XML node will be read into the valueString output argument. + * + * If the child node is not found then the empty string is returned. + * + * Example: + * + * Code snipet: + * @verbatum + const XML_Node &node; + std::string valueString; + std::string typeString; + std::string nameString = "timeIncrement"; + getString(XML_Node& node, nameString, valueString, valueString, typeString); + @endverbatum + * + * Reads the following the snippet in the XML file: + * + * * @verbatum + + valueString + <\nameString> + @endverbatum + * + * or alternatively as a retrofit and special case, it also reads the following case + * + * @verbatum + + valueString + <\string> + @endverbatum + * + * @param node Reference to the XML_Node object of the parent XML element + * @param nameString Name of the XML Node input variable + * @param valueString Value string that is found in the child node. output variable + * @param typeString String type. This is an optional output variable. It is filled + * with the attribute "type" of the XML entry. output variable + */ + void getNamedStringValue(const Cantera::XML_Node& node, const std::string &nameString, std::string& valueString, + std::string& typeString) + { + valueString = ""; + typeString = ""; + if (node.hasChild(nameString)) { + XML_Node &xc = node.child(nameString); + valueString = xc.value(); + typeString = xc["type"]; + } else { + XML_Node* s = getByTitle(node, nameString); + if (s) { + if (s->name() == "string") { + valueString = (*s).value(); + typeString = (*s)["type"]; + return; + } + } + } + } + //==================================================================================================================== // Get a vector of integer values from a child element. /* * Returns a std::map containing a keyed values for child XML_Nodes @@ -512,7 +676,7 @@ namespace ctml { } } - + //==================================================================================================================== // Get a vector of floating-point values from a child element. /* * Returns a std::map containing a keyed values for child XML_Nodes @@ -554,7 +718,7 @@ namespace ctml { * @param v Output map of the results. * @param convert Turn on conversion to SI units */ - void getFloats(const Cantera::XML_Node& node, std::map& v, + void getFloats(const Cantera::XML_Node& node, std::map & v, const bool convert) { std::vector f; node.getChildren("float",f); @@ -590,7 +754,7 @@ namespace ctml { } } - + //==================================================================================================================== // Get a floating-point value from a child element. /* * Returns a double value for the child named 'name' of element 'parent'. If @@ -624,8 +788,7 @@ namespace ctml { * and "" , for no conversion. The default value is "" * which implies that no conversion is allowed. */ - doublereal getFloat(const Cantera::XML_Node& parent, - const std::string &name, + doublereal getFloat(const Cantera::XML_Node& parent, const std::string &name, const std::string type) { if (!parent.hasChild(name)) throw CanteraError("getFloat (called from XML Node \"" + @@ -635,7 +798,39 @@ namespace ctml { return getFloatCurrent(node, type); } - + //==================================================================================================================== + // Get a floating-point value from the current XML element + /* + * Returns a doublereal value from the current element. If + * 'type' is supplied and matches a known unit type, unit + * conversion to SI will be done if the child element has an attribute 'units'. + * + * Note, it's an error for the child element not to exist. + * + * Example: + * + * Code snipet: + * @verbatim + const XML_Node &State_XMLNode; + doublereal pres = OneAtm; + if (state_XMLNode.hasChild("pressure")) { + XML_Node *pres_XMLNode = State_XMLNode.getChild("pressure"); + pres = getFloatCurrent(pres_XMLNode, "toSI"); + } + @endverbatim + * + * Rreads the corresponding XML file: + * @verbatim + + 101325.0 + <\state> + @endverbatim + * + * @param currXML reference to the current XML_Node object + * @param type String type. Currently known types are "toSI" and "actEnergy", + * and "" , for no conversion. The default value is "", + * which implies that no conversion is allowed. + */ doublereal getFloatCurrent(const Cantera::XML_Node& node, const std::string type) { doublereal x, x0, x1, fctr = 1.0; @@ -691,7 +886,7 @@ namespace ctml { return fctr*x; } - + //==================================================================================================================== bool getOptionalFloat(const Cantera::XML_Node& parent, const std::string &name, doublereal &fltRtn, @@ -702,7 +897,7 @@ namespace ctml { } return false; } - + //==================================================================================================================== // Get an optional floating-point value from a child element. /* * Returns a doublereal value for the child named 'name' of element 'parent'. If @@ -765,7 +960,37 @@ namespace ctml { val /= fctr; return val; } - + //==================================================================================================================== + // Get an optional model name from a named child node. + /* + * Returns the model name attribute for the child named 'nodeName' of element 'parent'. + * Note, it's optional for the child node to exist + * + * Example: + * + * Code snipet: + * @verbatim + std::string modelName = ""; + bool exists = getOptionalModel(transportNode, "compositionDependence", + modelName); + @endverbatim + * + * Reads the corresponding XML file: + * + * @verbatim + + + + @endverbatim + * + * On return modelName is set to "Solvent_Only". + * + * @param parent Reference to the XML_Node object of the parent XML element + * @param nodeName Name of the XML child element + * @param modelName On return this contains the contents of the model attribute + * + * @return True if the nodeName XML node exists. False otherwise. + */ bool getOptionalModel(const Cantera::XML_Node& parent, const std::string nodeName, std::string &modelName) { if (parent.hasChild(nodeName)) { @@ -775,7 +1000,7 @@ namespace ctml { } return false; } - + //==================================================================================================================== // Get an integer value from a child element. /* * Returns an integer value for the child named 'name' of element 'parent'. @@ -796,7 +1021,7 @@ namespace ctml { * reads the corresponding XML file: * @verbatum - 10 + 10 <\numProcs> <\state> @endverbatum * @@ -833,7 +1058,7 @@ namespace ctml { } return x; } - + //==================================================================================================================== // This function reads the current node or a child node of the current node // with the default name, "floatArray", with a value field // consisting of a comma separated list of floats @@ -890,11 +1115,13 @@ namespace ctml { * The default value for the node name is floatArray * * @return Returns the number of floats read + * + * @note change the v to a std::vector to eliminate a doxygen error. No idea why doxygen needs this. */ - int getFloatArray(const Cantera::XML_Node& node, Cantera::vector_fp& v, + int getFloatArray(const Cantera::XML_Node& node, std::vector & v, const bool convert, const std::string unitsString, const std::string nodeName) { - string::size_type icom; + std::string::size_type icom; string numstr; doublereal dtmp; string nn = node.name(); @@ -908,6 +1135,11 @@ namespace ctml { + nodeName + "but accessed " + node.name()); } else { readNode = ll[0]; + ll.clear(); + readNode->getChildren("floatArray", ll); + if (ll.size() > 0) { + readNode = ll[0]; + } } } @@ -974,7 +1206,97 @@ namespace ctml { } return v.size(); } + //==================================================================================================================== + int getNamedFloatArray(const Cantera::XML_Node& parentNode, const std::string & nodeName, std::vector & v, + const bool convert, const std::string unitsString) { + std::string::size_type icom; + std::string numstr; + doublereal dtmp; + std::string nn = parentNode.name(); + v.clear(); + const Cantera::XML_Node *readNode = parentNode.findByName(nodeName); + if (!readNode) { + return 0; + } + + doublereal vmin = Undef; + doublereal vmax = Undef; + doublereal funit = 1.0; + /* + * Get the attributes field, units, from the XML node + */ + std::string units = (*readNode)["units"]; + if (units != "" && convert) { + if (unitsString == "actEnergy" && units != "") { + funit = actEnergyToSI(units); + } else if (unitsString != "" && units != "") { + funit = toSI(units); + } + } + if ((*readNode)["min"] != "") + vmin = atofCheck((*readNode)["min"].c_str()); + if ((*readNode)["max"] != "") + vmax = atofCheck((*readNode)["max"].c_str()); + + int expectedSize = 0; + nn = (*readNode)["size"]; + expectedSize = atoi(nn.c_str()); + + nn = (*readNode)["vtype"]; + if (nn != "floatArray") { + throw CanteraError("getNamedFloatArray", + "node named " + nodeName + "didn't have correct vtype"); + } + + doublereal vv; + std::string val = readNode->value(); + while (1 > 0) { + icom = val.find(','); + if (icom != string::npos) { + numstr = val.substr(0,icom); + val = val.substr(icom+1,val.size()); + dtmp = atofCheck(numstr.c_str()); + v.push_back(dtmp); + } + else { + /* + * This little bit of code is to allow for the + * possibility of a comma being the last + * item in the value text. This was allowed in + * previous versions of Cantera, even though it + * would appear to be odd. So, we keep the + * possibilty in for backwards compatibility. + */ + int nlen = strlen(val.c_str()); + if (nlen > 0) { + dtmp = atofCheck(val.c_str()); + v.push_back(dtmp); + } + break; + } + vv = v.back(); + if (vmin != Undef && vv < vmin - Tiny) { + writelog("\nWarning: value "+fp2str(vv)+ + " is below lower limit of " +fp2str(vmin)+".\n"); + } + if (vmax != Undef && vv > vmax + Tiny) { + writelog("\nWarning: value "+fp2str(vv)+ + " is above upper limit of " +fp2str(vmin)+".\n"); + } + } + int nv = v.size(); + for (int n = 0; n < nv; n++) { + v[n] *= funit; + } + if (nv != expectedSize) { + throw CanteraError("getNamedFloatArray", + "node named " + nodeName + "didn't have correct number of floats" + + int2str(expectedSize) + " vs " + int2str(nv)); + } + return nv; + } + //==================================================================================================================== // This routine is used to interpret the value portions of XML // elements that contain colon separated pairs. /* @@ -1012,7 +1334,7 @@ namespace ctml { m[key] = val; } } - + //==================================================================================================================== // This function interprets the value portion of an XML element // as a series of "Pairs" separated by white space. /* @@ -1062,7 +1384,7 @@ namespace ctml { } return n; } - + //==================================================================================================================== // This function interprets the value portion of an XML element // as a series of "Matrix ids and entries" separated by white space. /* @@ -1193,7 +1515,7 @@ namespace ctml { } } } - + //==================================================================================================================== // This function interprets the value portion of an XML element // as a string. It then separates the string up into tokens // according to the location of white space. @@ -1207,7 +1529,7 @@ namespace ctml { std::string val = node.value(); tokenizeString(val, v); } - + //==================================================================================================================== // This function reads a child node with the default name, "floatArray", with a value // consisting of a comma separated list of floats /* @@ -1221,26 +1543,27 @@ namespace ctml { * separating each field. * If the node array has an units attribute field, then * the units are used to convert the floats, iff convert is true. + * This function is a wrapper around the function getFloatArray(). * * Example: * * Code snipet: - * @verbatum + * @verbatim const XML_Node &State_XMLNode; vector_fp v; bool convert = true; unitsString = ""; nodeName="floatArray"; getFloatArray(State_XMLNode, v, convert, unitsString, nodeName); - @endverbatum + @endverbatim * * reads the corresponding XML file: * - * @verbatum + * @verbatim 32.4, 1, 100. <\floatArray> <\state> - @endverbatum + @endverbatim * * Will produce the vector * @@ -1250,19 +1573,15 @@ namespace ctml { * * * @param node XML parent node of the floatArray - * @param v Output vector of floats containing the floatArray information. - * @param convert Conversion to SI is carried out if this boolean is - * True. The default is true. - * @param typeString String name of the type attribute. This is an optional - * parameter. The default is to have an empty string. - * The only string that is recognized is actEnergy. - * Anything else has no effect. This affects what - * units converter is used. - * @param nodeName XML Name of the XML node to read. - * The default value for the node name is floatArray + * @param typeString Returns the type attribute of the current node. + * @param xmin Returns the minimum value attribute of the + * current node. + * @param xmax Returns the maximum value attribute of the + * current node. + * @param coeffs Output vector of floats containing the floatArray information. */ void getFunction(const Cantera::XML_Node& node, std::string& type, doublereal& xmin, - doublereal& xmax, Cantera::vector_fp& coeffs) { + doublereal& xmax, std::vector & coeffs) { const XML_Node& c = node.child("floatArray"); coeffs.clear(); getFloatArray(c,coeffs); @@ -1272,4 +1591,5 @@ namespace ctml { if (node["max"] != "") xmax = fpValue(node["max"]); type = node["type"]; } + //==================================================================================================================== } diff --git a/Cantera/src/base/ctml.h b/Cantera/src/base/ctml.h index 85d6f8a3b..6199a3e3d 100644 --- a/Cantera/src/base/ctml.h +++ b/Cantera/src/base/ctml.h @@ -22,6 +22,9 @@ //! The ctml namespace adds functionality to the XML object, by providing //! standard functions that read, write, and interpret XML files and //! object trees. +/*! + * Standardization of reads and write from Cantera files occur here. + */ namespace ctml { //! const Specifying the CTML version number @@ -30,6 +33,10 @@ namespace ctml { */ const std::string CTML_Version = "1.4.1"; + extern std::string FP_Format; + + extern std::string INT_Format; + //! This function adds a child node with the name, "bool", with a value //! consisting of a single bool /*! @@ -279,6 +286,15 @@ namespace ctml { const doublereal minval = Cantera::Undef, const doublereal maxval = Cantera::Undef); + void addNamedFloatArray(Cantera::XML_Node& parentNode, const std::string &name, const int n, + const doublereal* const vals, const std::string units = "", + const std::string type = "", + const doublereal minval = Cantera::Undef, + const doublereal maxval = Cantera::Undef); + + + + //! This function adds a child node with the name string with a string value //! to the current node /*! @@ -367,7 +383,7 @@ namespace ctml { * The default value for the node name is floatArray * @return Returns the number of floats read into v. */ - int getFloatArray(const Cantera::XML_Node& node, Cantera::vector_fp& v, + int getFloatArray(const Cantera::XML_Node& node, std::vector & v, const bool convert=true, const std::string unitsString="", const std::string nodeName = "floatArray"); @@ -570,8 +586,7 @@ namespace ctml { /*! * Returns a doublereal value from the current element. If * 'type' is supplied and matches a known unit type, unit - * conversion to SI will be done if the child element has an attribute - * 'units'. + * conversion to SI will be done if the child element has an attribute 'units'. * * Note, it's an error for the child element not to exist. * @@ -587,7 +602,7 @@ namespace ctml { } @endverbatim * - * reads the corresponding XML file: + * Rreads the corresponding XML file: * @verbatim 101325.0 @@ -682,7 +697,7 @@ namespace ctml { * @param v Output map of the results. * @param convert Turn on conversion to SI units */ - void getFloats(const Cantera::XML_Node& node, std::map& v, + void getFloats(const Cantera::XML_Node& node, std::map& v, const bool convert=true); //! Get an integer value from a child element. @@ -778,7 +793,7 @@ namespace ctml { * @param nodeName Name of the XML child element * @param modelName On return this contains the contents of the model attribute * - * @return True if the nodeName XML node exists. False otherwise + * @return True if the nodeName XML node exists. False otherwise. */ bool getOptionalModel(const Cantera::XML_Node& parent, const std::string nodeName, std::string &modelName); @@ -831,12 +846,10 @@ namespace ctml { * current node. * @param xmax Returns the maximum value attribute of the * current node. - * @param v Output vector of floats containing the floatArray - * information. + * @param coeffs Output vector of floats containing the floatArray information. */ void getFunction(const Cantera::XML_Node& node, std::string& typeString, - doublereal& xmin, doublereal& xmax, Cantera::vector_fp& v); - + doublereal& xmin, doublereal& xmax, std::vector & coeffs); //! Search the child nodes of the current node for an XML Node with a Title //! attribute of a given name. @@ -851,6 +864,40 @@ namespace ctml { //! This function reads a child node with the name string with a specific //! title attribute named titleString + /*! + * This function will read a child node to the current XML node with the name "string". + * It must have a title attribute, named titleString, and the body + * of the XML node will be read into the valueString output argument. + * + * If the child node is not found then the empty string is returned. + * + * Example: + * + * Code snipet: + * @verbatim + const XML_Node &node; + getString(XML_Node& node, std::string titleString, std::string valueString, + std::string typeString); + @endverbatim + * + * Reads the following the snippet in the XML file: + * @verbatim + + valueString + <\string> + @endverbatim + * + * @param node Reference to the XML_Node object of the parent XML element + * @param titleString String name of the title attribute of the child node + * @param valueString Value string that is found in the child node. output variable + * @param typeString String type. This is an optional output variable. It is filled + * with the attribute "type" of the XML entry. + */ + void getString(const Cantera::XML_Node& node, const std::string &titleString, + std::string& valueString, std::string& typeString); + + //! This function attempts to read a named child node and returns with the contents in the value string. + //! title attribute named "titleString" /*! * This function will read a child node to the current XML node, with the * name "string". It must have a title attribute, named titleString, and the body @@ -861,26 +908,39 @@ namespace ctml { * Example: * * Code snipet: - * @verbatim - const XML_Node &node; - getString(XML_Node& node, std::string titleString, std::string valueString, - std::string typeString); - @endverbatim + * @verbatum + const XML_Node &node; + std::string valueString; + std::string typeString; + std::string nameString = "timeIncrement"; + getString(XML_Node& node, nameString, valueString, valueString, typeString); + @endverbatum * * Reads the following the snippet in the XML file: - * @verbatim - + * + * * @verbatum + + valueString + <\nameString> + @endverbatum + * + * or alternatively as a retrofit and special case, it also reads the following case + * + * @verbatum + valueString <\string> - @endverbatim + @endverbatum * - * @param node reference to the XML_Node object of the parent XML element - * @param titleString String name of the title attribute of the child node - * @param valueString Value string that is found in the child node. output variable - * @param typeString String type. This is an optional output variable + * @param node Reference to the XML_Node object of the parent XML element + * @param nameString Name of the XML Node input variable + * @param valueString Value string that is found in the child node. output variable + * @param typeString String type. This is an optional output variable. It is filled + * with the attribute "type" of the XML entry. output variable */ - void getString(const Cantera::XML_Node& node, const std::string &titleString, - std::string& valueString, std::string& typeString); + void getNamedStringValue(const Cantera::XML_Node& node, const std::string &nameString, std::string& valueString, + std::string& typeString); + //! This function reads a child node with the name, nameString, and returns //! its xml value as the return string diff --git a/Cantera/src/base/mdp_allo.cpp b/Cantera/src/base/mdp_allo.cpp index d650ed919..d5673d454 100644 --- a/Cantera/src/base/mdp_allo.cpp +++ b/Cantera/src/base/mdp_allo.cpp @@ -1658,7 +1658,7 @@ namespace mdp { } else { int m = len % 7; if (m != 0) { - for (int i = 0; i < m; m++) { + for (int i = 0; i < m; i++) { v[i] = value; } if (len < 7) return; @@ -1697,6 +1697,30 @@ namespace mdp { (void) memset((void *)v, 0, len * sizeof(double)); } } + + /****************************************************************************/ + /****************************************************************************/ + /****************************************************************************/ + + void mdp_zero_int_1(int * const v, const int len) + + /************************************************************************** + * + * mdp_zero_int_1: + * + * Zeroes out an int vector + * + * Input + * ------------- + * v = Vector of values to be set to zero + * len = Length of the vector + **************************************************************************/ + { + if (len > 0) { + (void) memset((void *)v, 0, len * sizeof(int)); + } + } + /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ @@ -1727,7 +1751,7 @@ namespace mdp { } else { int m = len % 7; if (m != 0) { - for (int i = 0; i < m; m++) { + for (int i = 0; i < m; i++) { dstart[i] = value; } if (len < 7) return; @@ -1771,7 +1795,7 @@ namespace mdp { } else { int m = len % 7; if (m != 0) { - for (int i = 0; i < m; m++) { + for (int i = 0; i < m; i++) { v[i] = value; } if (len < 7) return; diff --git a/Cantera/src/base/mdp_allo.h b/Cantera/src/base/mdp_allo.h index ef41f9b95..1b196bf3f 100644 --- a/Cantera/src/base/mdp_allo.h +++ b/Cantera/src/base/mdp_allo.h @@ -45,7 +45,7 @@ * then it may be freed, always (and vica-versa). * * Where possible, the low leve routines - * memcopy and memset are used to copy or zero memory. + * memcpy and memset are used to copy or zero memory. * * No array bounds checking is ever done within these routines. buyer beware. * The bounds of arrays are not carried with the array object, ever. @@ -674,6 +674,13 @@ namespace mdp { */ extern void mdp_zero_dbl_1(double * const v , const int len); + //! Zeroes an int vector + /*! + * @param v = Vector of values to be assigned + * @param len = Length of the vector + */ + extern void mdp_zero_int_1(int * const v , const int len); + //! Assigns a single value to a double matrix. Contiguous data for the //! matrix is assumed. /*! diff --git a/Cantera/src/base/misc.cpp b/Cantera/src/base/misc.cpp index ae43253ab..b8acb15a8 100644 --- a/Cantera/src/base/misc.cpp +++ b/Cantera/src/base/misc.cpp @@ -53,11 +53,20 @@ using namespace std; #include #include -static boost::mutex dir_mutex; // For input directory access -static boost::mutex msg_mutex; // For access to string messages -static boost::mutex app_mutex; // Application state including creating singleton -//static boost::mutex log_mutex; // Logger pointer -static boost::mutex xml_mutex; // XML file storage +//! Mutex for input directory access +static boost::mutex dir_mutex; + +//! Mutex for access to string messages +static boost::mutex msg_mutex; + +//! Mutex for creating singeltons within the application object +static boost::mutex app_mutex; + +// Mutex for controlling access to the log file +//static boost::mutex log_mutex; + +//! Mutex for controlling access to XML file storage +static boost::mutex xml_mutex; //! Macro for locking input directory access #define DIR_LOCK() boost::mutex::scoped_lock d_lock(dir_mutex) @@ -1515,6 +1524,15 @@ protected: CanteraError::CanteraError(std::string proc, std::string msg) { app()->addError(proc, msg); } + + CanteraError::CanteraError() + { + } + + CanteraError::~CanteraError() throw() + { + } + ArraySizeError::ArraySizeError(std::string proc, int sz, int reqd) : CanteraError(proc, "Array size ("+int2str(sz)+ @@ -1888,9 +1906,13 @@ protected: #endif // WITH_HTML_LOGS - - /// split a string at a '#' sign. Used to separate a file name - /// from an id string. + //=============================================================================================================== + //! split a string at a '#' sign. Used to separate a file name from an id string. + /*! + * @param src Original string to be split up. This is unchanged. + * @param file Output string representing the first part of the string, which is the filename. + * @param id Output string representing the last part of the string, which is the id. + */ static void split_at_pound(const std::string& src, std::string& file, std::string& id) { string::size_type ipound = src.find('#'); if (ipound != string::npos) { @@ -1902,6 +1924,7 @@ protected: file = src; } } + //=============================================================================================================== /* * This routine will locate an XML node in either the input * XML tree or in another input file specified by the file diff --git a/Cantera/src/base/stringUtils.cpp b/Cantera/src/base/stringUtils.cpp index 54eb66d32..88d19251c 100644 --- a/Cantera/src/base/stringUtils.cpp +++ b/Cantera/src/base/stringUtils.cpp @@ -35,7 +35,7 @@ namespace Cantera { - + //================================================================================================ // Convert a double into a c++ string /* * This routine doesn't assume a formatting. You @@ -62,7 +62,7 @@ namespace Cantera { } return std::string(" "); } - + //================================================================================================ /* * Convert an integer number to a std::string using sprintf. */ @@ -75,7 +75,7 @@ namespace Cantera { } return std::string(" "); } - + //================================================================================================ // Convert an int to a string /* * @param n int to be converted @@ -89,14 +89,14 @@ namespace Cantera { } return std::string(" "); } - + //================================================================================================ std::string lowercase(const std::string &s) { int n = static_cast(s.size()); std::string lc(s); for (int i = 0; i < n; i++) lc[i] = tolower(s[i]); return lc; } - + //================================================================================================ //! Return the position of the first printable //! character in the string /*! @@ -113,7 +113,7 @@ namespace Cantera { } return i; } - + //================================================================================================ //! Return the position of the last printable //! character in the string /*! @@ -129,7 +129,7 @@ namespace Cantera { if (s[i] != ' ' && isprint(s[i])) break; return i; } - + //================================================================================================ // Strip the leading and trailing white space // from a string /* @@ -145,7 +145,7 @@ namespace Cantera { int ilast = lastChar(s); return s.substr(ifirst, ilast - ifirst + 1); } - + //================================================================================================ // Strip non-printing characters wherever they are /* * @param s Input string @@ -163,8 +163,7 @@ namespace Cantera { } return ss; } - - + //================================================================================================ // Parse a composition string into a map consisting of individual key:composition // pairs. /* @@ -218,7 +217,7 @@ namespace Cantera { } while (s != ""); } - + //================================================================================================ // Parse a composition string into individual key:composition // pairs /* @@ -249,7 +248,7 @@ namespace Cantera { } while (s != ""); } - + //================================================================================================ int fillArrayFromString(const std::string& str, doublereal* const a, const char delim) { std::string::size_type iloc; @@ -271,7 +270,7 @@ namespace Cantera { } return count; } - + //================================================================================================ // Get the file name without the path or extension /* * @param fullPath Input file name consisting @@ -296,20 +295,19 @@ namespace Cantera { } return file; } - - + //================================================================================================ int intValue(std::string val) { return std::atoi(stripws(val).c_str()); } - + //================================================================================================ doublereal fpValue(std::string val) { return std::atof(stripws(val).c_str()); } - + //================================================================================================ doublereal fpValueCheck(std::string val) { return atofCheck(stripws(val).c_str()); } - + //================================================================================================ // Generate a logfile name based on an input file name /* * It tries to find the basename. Then, it appends a .log @@ -324,7 +322,7 @@ namespace Cantera { logfile += ".log"; return logfile; } - + //================================================================================================ // Line wrap a string via a copy operation /* * @param s Input string to be line wrapped @@ -346,8 +344,46 @@ namespace Cantera { } return r; } - - + //================================================================================================ + // Parse a name string, separating out the phase name from the species name + /* + * Name strings must not contain these internal characters "; \n \t " + * Only one colon is allowed, the one separating the phase name from the + * species name. Therefore, names may not include a colon. + * + * @param nameStr (input) Name string containing the phase name and the species + * name separated by a colon. The phase name is optional. + * example: "silane:SiH4" + * @param phaseName (output) Name of the phase, if specified. If not specified, + * a blank string is returned. + * @return (output) Species name is returned. If nameStr is blank + * an empty string is returned. + */ + std::string parseSpeciesName(const std::string& nameStr, std::string &phaseName) { + std::string s = stripws(nameStr); + std::string::size_type ibegin, iend, icolon; + phaseName = ""; + ibegin = s.find_first_not_of(" ;\n\t"); + if (ibegin != std::string::npos) { + s = s.substr(ibegin,s.size()); + icolon = s.find(':'); + iend = s.find_first_of(" ;\n\t"); + if (icolon != std::string::npos) { + phaseName = s.substr(0, icolon); + s = s.substr(icolon+1, s.size()); + icolon = s.find(':'); + if (icolon != std::string::npos) { + throw CanteraError("parseSpeciesName()", "two colons in name: " + nameStr); + } + } + if (iend != std::string::npos) { + throw CanteraError("parseSpeciesName()", + "Species name has \" ;/\n/\t\" in the middle of it: " + nameStr); + } + } + return s; + } + //================================================================================================ // Routine strips off white space from a c character string /* * This routine strips off blanks and tabs (only leading and trailing @@ -396,7 +432,7 @@ namespace Cantera { str[j] = '\0'; return (j); } - + //================================================================================================ // Translate a char string into a single double /* * atofCheck is a wrapper around the C stdlib routine atof(). @@ -472,7 +508,7 @@ namespace Cantera { free(eptr); return rval; } - + //================================================================================================ // Interpret one or two token string as a single double /* * This is similar to atof(). However, the second token @@ -502,7 +538,15 @@ namespace Cantera { doublereal val = atofCheck(v[0].c_str()); return (val * fp); } - + //================================================================================================ + //! Find the first white space in a string + /*! + * Returns the location of the first white space character in a string + * + * @param val Input string to be parsed + * @return In a size_type variable, return the location of the first white space character. + * Return npos if none is found + */ static std::string::size_type findFirstWS(const std::string& val) { std::string::size_type ibegin = std::string::npos; int j = 0; @@ -518,7 +562,15 @@ namespace Cantera { } return ibegin; } - + //================================================================================================ + //! Find the first non-white space in a string + /*! + * Returns the location of the first non-white space character in a string + * + * @param val Input string to be parsed + * @return In a size_type variable, return the location of the first nonwhite space character. + * Return npos if none is found + */ static std::string::size_type findFirstNotOfWS(const std::string& val) { std::string::size_type ibegin = std::string::npos; int j = 0; @@ -534,7 +586,7 @@ namespace Cantera { } return ibegin; } - + //================================================================================================ // This function separates a string up into tokens // according to the location of white space. /* @@ -566,6 +618,6 @@ namespace Cantera { } } } - + //================================================================================================ } diff --git a/Cantera/src/base/stringUtils.h b/Cantera/src/base/stringUtils.h index 4dc6c7dbf..0194dc984 100644 --- a/Cantera/src/base/stringUtils.h +++ b/Cantera/src/base/stringUtils.h @@ -182,6 +182,22 @@ namespace Cantera { */ doublereal fpValueCheck(std::string val); + //! Parse a name string, separating out the phase name from the species name + /*! + * Name strings must not contain these internal characters "; \n \t ," + * Only one colon is allowed, the one separating the phase name from the + * species name. Therefore, names may not include a colon. + * + * @param nameStr (input) Name string containing the phase name and the species + * name separated by a colon. The phase name is optional. + * example: "silane:SiH4" + * @param phaseName (output) Name of the phase, if specified. If not specified, + * a blank string is returned. + * @return (output) Species name is returned. If nameStr is blank + * an empty string is returned. + */ + std::string parseSpeciesName(const std::string& nameStr, std::string &phaseName); + //! Line wrap a string via a copy operation /*! * @param s Input string to be line wrapped diff --git a/Cantera/src/base/units.h b/Cantera/src/base/units.h index 2a6a68e33..ac988cb23 100644 --- a/Cantera/src/base/units.h +++ b/Cantera/src/base/units.h @@ -173,6 +173,7 @@ namespace Cantera { static boost::mutex units_mutex; #endif + //! Units class constructor, containing the default mappings between //! strings and units. Unit() : @@ -215,6 +216,7 @@ namespace Cantera { // temperature m_u["K"] = 1.0; m_u["C"] = 1.0; + m_u["Kelvin"] = 1.0; // mass m_u["gm"] = 1.0e-3; @@ -232,6 +234,12 @@ namespace Cantera { m_u["hr"] = 3600.0; m_u["ms"] = 0.001; + // electric potential + m_u["volt"] = 1.0; + + // charge + m_u["coulomb"] = 1.0; + /* // frequency - Took frequency out to reevaluate it. Inverse cm is probably the wrong default unit m_u["hZ"] = 0.01/(lightSpeed); diff --git a/Cantera/src/base/utilities.h b/Cantera/src/base/utilities.h index 19aead0a4..3628c5317 100644 --- a/Cantera/src/base/utilities.h +++ b/Cantera/src/base/utilities.h @@ -686,6 +686,7 @@ namespace Cantera { } } + //@} } diff --git a/Cantera/src/base/vec_functions.h b/Cantera/src/base/vec_functions.h index c3b14fff1..d3ed6ebd3 100644 --- a/Cantera/src/base/vec_functions.h +++ b/Cantera/src/base/vec_functions.h @@ -181,7 +181,7 @@ namespace Cantera { inline void fbo_copy_dbl_1(doublereal * const copyTo, const doublereal * const copyFrom, const int len) { if (len > 0) { - (void) memcpy((void *)copyTo, (const void *)copyFrom, len * sizeof(doublereal)); + (void) std::memcpy((void *)copyTo, (const void *)copyFrom, len * sizeof(doublereal)); } } @@ -196,7 +196,7 @@ namespace Cantera { inline void fvo_copy_dbl_1(std::vector ©To, const std::vector ©From, const int len) { if (len > 0) { - (void) memcpy((void *)(©To[0]), (const void *)(©From[0]), len * sizeof(doublereal)); + (void) std::memcpy((void *)(©To[0]), (const void *)(©From[0]), len * sizeof(doublereal)); } } @@ -209,7 +209,7 @@ namespace Cantera { */ inline void fbo_zero_dbl_1(doublereal * const v, const int len) { if (len > 0) { - (void) memset((void *)v, 0, len * sizeof(doublereal)); + (void) std::memset((void *)v, 0, len * sizeof(doublereal)); } } @@ -222,7 +222,7 @@ namespace Cantera { */ inline void fvo_zero_dbl_1(std::vector &v, const int len) { if (len > 0) { - (void) memset((void *)(&v[0]), 0, len * sizeof(doublereal)); + (void) std::memset((void *)(&v[0]), 0, len * sizeof(doublereal)); } } diff --git a/Cantera/src/base/xml.cpp b/Cantera/src/base/xml.cpp index 927f36a04..2fd3ea015 100644 --- a/Cantera/src/base/xml.cpp +++ b/Cantera/src/base/xml.cpp @@ -52,9 +52,8 @@ namespace Cantera { */ XML_Error(int line=0) : m_line(line), - m_msg(0) + m_msg("Error in XML file") { - m_msg = "Error in XML file"; if (line > 0) { m_msg += " at line " + int2str(line+1); } @@ -221,10 +220,12 @@ namespace Cantera { else return aline.substr(j+1, i - j - 1); } - /** - * Find the first position of a character, q, in string s, - * which is not immediately preceded by the backslash character - * '\' + + //! Find the first position of a character, q, in string, s, which is not immediately preceded by the backslash character + /*! + * @param s Input string + * @param q Search for this character + * @param istart Defaults to 0 */ static string::size_type findUnbackslashed(std::string s, const char q, std::string::size_type istart = 0) { @@ -392,13 +393,15 @@ namespace Cantera { ////////////////////////// XML_Node ///////////////////////////////// - XML_Node::XML_Node(const char * cnm) - : m_name(""), - m_value(""), - m_parent(0), - m_locked(false), - m_nchildren(0), - m_iscomment(false) + XML_Node::XML_Node(const char * cnm) : + m_name(""), + m_value(""), + m_parent(0), + m_root(0), + m_locked(false), + m_nchildren(0), + m_iscomment(false) , + m_linenum(0) { if (! cnm) { m_name = "--"; @@ -416,19 +419,21 @@ namespace Cantera { * @param nm Name of the node. * The default name of the node is "--" * - * @param p pointer to the root for this node in the tree. - * The default is 0 indicating this is the top of the tree. + * @param parent Pointer to the parent for this node in the tree. + * A value of zero 0 indicates this is the top of the tree. */ - XML_Node::XML_Node(const std::string nm, XML_Node * const p) - : m_name(nm), - m_value(""), - m_parent(p), - m_locked(false), - m_nchildren(0), - m_iscomment(false) + XML_Node::XML_Node(const std::string nm, XML_Node * const parent) : + m_name(nm), + m_value(""), + m_parent(parent), + m_root(0), + m_locked(false), + m_nchildren(0), + m_iscomment(false), + m_linenum(0) { - if (!p) m_root = this; - else m_root = &p->root(); + if (!parent) m_root = this; + else m_root = &(parent->root()); } // Copy constructor @@ -439,11 +444,15 @@ namespace Cantera { m_name(""), m_value(""), m_parent(0), + m_root(0), m_locked(false), m_nchildren(0), - m_iscomment(false) + m_iscomment(right.m_iscomment), + m_linenum(right.m_linenum) { m_root = this; + m_name = right.m_name; + m_value = right.m_value; right.copy(this); } @@ -516,26 +525,47 @@ namespace Cantera { addChild("comment", comment); } - // Add a child node to the current node - /* - * This will add an XML_Node as a child to the current node. - * Note, this actually adds the node. Therefore, node is changed. - * There is no copy made of the child node. + + //! Merge an existing node as a child node to the current node + /*! + * This will merge an XML_Node as a child to the current node. + * Note, this actually adds the node. Therefore, the current node is changed. + * There is no copy made of the child node. The child node should not be deleted in the future. * * @param node Reference to a child XML_Node object * - * @return returns a reference to the added node + * @return Returns a reference to the added child node */ - XML_Node& XML_Node::addChild(XML_Node& node) { + XML_Node& XML_Node::mergeAsChild(XML_Node& node) { m_children.push_back(&node); m_nchildren = static_cast(m_children.size()); - m_childindex[node.name()] = m_children.back(); + m_childindex.insert(pair(node.name(), m_children.back())); node.setRoot(root()); node.setParent(this); return *m_children.back(); } - // Add a child node to the current node with a specified name + // Add a child node to the current node by makeing a copy of an existing node tree + /* + * This will add an XML_Node as a child to the current node. + * Note, this actually adds the node. Therefore, node is changed. + * A copy is made of the underlying tree. + * + * @param node Reference to a child XML_Node object + * + * @return returns a reference to the added node + */ + XML_Node& XML_Node::addChild(const XML_Node& node) { + XML_Node *xx = new XML_Node(node); + m_children.push_back(xx); + m_nchildren = static_cast(m_children.size()); + m_childindex.insert( pair(xx->name(), xx)); + xx->setRoot(root()); + xx->setParent(this); + return *m_children.back(); + } + + // Add a new malloced child node to the current node with a specified name /* * This will add an XML_Node as a child to the current node. * The node will be blank except for the specified name. @@ -548,13 +578,17 @@ namespace Cantera { XML_Node *xxx = new XML_Node(sname, this); m_children.push_back(xxx); m_nchildren = static_cast(m_children.size()); - m_childindex[sname] = m_children.back(); + m_childindex.insert(pair(sname, xxx)); xxx->setRoot(root()); xxx->setParent(this); return *m_children.back(); } - // Add a child node to the current xml node, and at the + XML_Node& XML_Node::addChild(const char *cstring) { + return addChild(std::string(cstring)); + } + + // Add a new malloced child node to the current xml node, and at the // same time add a value to the child /* * Resulting XML string: @@ -763,6 +797,10 @@ namespace Cantera { return m_attribs; } + const std::map& XML_Node::attribsConst() const { + return m_attribs; + } + // Set the line number /* * @param n the member data m_linenum is set to n @@ -833,15 +871,29 @@ namespace Cantera { const std::vector& XML_Node::children() const { return m_children; } - - // return the number of children + //===================================================================================================================== + // Return the number of children /* - * + * @param discardComments Bool indicating whether we should ignore comments in the count. defaults to false */ - int XML_Node::nChildren() const { + int XML_Node::nChildren(const bool discardComments) const { + if (discardComments) { + int count = 0; + for (int i = 0; i < m_nchildren; i++) { + XML_Node *xc = m_children[i]; + if (!(xc->isComment())) { + count++; + } + } + return count; + } return m_nchildren; } - + //===================================================================================================================== + bool XML_Node::isComment() const { + return m_iscomment; + } + //===================================================================================================================== // Require that the current xml node have an attribute named // by the first argument, a, and that this attribute have the // the string value listed in the second argument, v. @@ -908,9 +960,65 @@ namespace Cantera { } return scResult; } - + //==================================================================================================================== + // This routine carries out a search for an XML node based + // on both the xml element name and the attribute ID and an integer index. + /* + * If exact matches are found for all fields, the pointer + * to the matching XML Node is returned. The search is only carried out on + * the current element and the child elements of the current element. + * + * The "id" attribute may be defaulted by setting it to "". + * In this case the pointer to the first xml element matching the name + * only is returned. + * + * @param nameTarget Name of the XML Node that is being searched for + * @param idTarget "id" attribute of the XML Node that the routine + * looks for + * @param index Integer describing the index. The index is an + * attribute of the form index = "3" + * + * @return Returns the pointer to the XML node that fits the criteria + * + */ + XML_Node* XML_Node::findNameIDIndex(const std::string & nameTarget, + const std::string & idTarget, const int index_i) const { + XML_Node *scResult = 0; + XML_Node *sc; + std::string idattrib = id(); + std::string ii = attrib("index"); + std::string index_s = int2str(index_i); + int iMax = -1000000; + if (name() == nameTarget) { + if (idTarget == "" || idTarget == idattrib) { + if (index_s == ii) { + return const_cast(this); + } + } + } + for (int n = 0; n < m_nchildren; n++) { + sc = m_children[n]; + if (sc->name() == nameTarget) { + ii = sc->attrib("index"); + int indexR = atoi(ii.c_str()); + idattrib = sc->id(); + if (idTarget == idattrib || idTarget == "") { + if (index_s == ii) { + return sc; + } + } + if (indexR > iMax) { + scResult = sc; + iMax = indexR; + } + } + } + + return scResult; + } + //==================================================================================================================== // This routine carries out a recursive search for an XML node based - // on the xml element attribute ID. + // on the xml element attribute, "id" . /* * If exact match is found, the pointer * to the matching XML Node is returned. If not, 0 is returned. @@ -962,17 +1070,19 @@ namespace Cantera { * */ XML_Node* XML_Node::findByAttr(const std::string& attr, - const std::string& val) const { + const std::string& val, int depth) const { if (hasAttrib(attr)) { if (attrib(attr) == val) { return const_cast(this); } } - XML_Node* r = 0; - int n = nChildren(); - for (int i = 0; i < n; i++) { - r = m_children[i]->findByAttr(attr, val); - if (r != 0) return r; + if (depth > 0) { + XML_Node* r = 0; + int n = nChildren(); + for (int i = 0; i < n; i++) { + r = m_children[i]->findByAttr(attr, val, depth - 1); + if (r != 0) return r; + } } return 0; } @@ -988,15 +1098,17 @@ namespace Cantera { * * @return Returns the pointer to the XML node that fits the criteria */ - XML_Node* XML_Node::findByName(const std::string& nm) { + XML_Node* XML_Node::findByName(const std::string& nm, int depth) { if (name() == nm) { return this; } - XML_Node* r = 0; - int n = nChildren(); - for (int i = 0; i < n; i++) { - r = m_children[i]->findByName(nm); - if (r != 0) return r; + if (depth > 0) { + XML_Node* r = 0; + int n = nChildren(); + for (int i = 0; i < n; i++) { + r = m_children[i]->findByName(nm); + if (r != 0) return r; + } } return 0; } @@ -1012,15 +1124,17 @@ namespace Cantera { * * @return Returns the pointer to the XML node that fits the criteria */ - const XML_Node* XML_Node::findByName(const std::string& nm) const { + const XML_Node* XML_Node::findByName(const std::string& nm, int depth) const { if (name() == nm) { return const_cast(this); } - const XML_Node* r = 0; - int n = nChildren(); - for (int i = 0; i < n; i++) { - r = m_children[i]->findByName(nm); - if (r != 0) return r; + if (depth > 0) { + const XML_Node* r = 0; + int n = nChildren(); + for (int i = 0; i < n; i++) { + r = m_children[i]->findByName(nm); + if (r != 0) return r; + } } return 0; } @@ -1079,8 +1193,7 @@ namespace Cantera { } else { if (node->name() != nm.substr(1,nm.size()-1)) - throw XML_TagMismatch(node->name(), - nm.substr(1,nm.size()-1), lnum); + throw XML_TagMismatch(node->name(), nm.substr(1,nm.size()-1), lnum); node = node->parent(); } } @@ -1154,6 +1267,7 @@ namespace Cantera { int ndc; node_dest->addValue(m_value); node_dest->setName(m_name); + node_dest->setLineNumber(m_linenum); if (m_name == "") return; map::const_iterator b = m_attribs.begin(); for (; b != m_attribs.end(); ++b) { @@ -1164,12 +1278,15 @@ namespace Cantera { for (int n = 0; n < m_nchildren; n++) { sc = m_children[n]; ndc = node_dest->nChildren(); + // Here is where we do a malloc of the child node. (void) node_dest->addChild(sc->name()); dc = vsc[ndc]; sc->copy(dc); } } + + // Set the lock for this node void XML_Node::lock() { m_locked = true; @@ -1241,7 +1358,7 @@ namespace Cantera { * main recursive routine. It doesn't put a final endl * on. This is fixed up in the public method. */ - void XML_Node::write_int(std::ostream& s, int level) const { + void XML_Node::write_int(std::ostream& s, int level, int numRecursivesAllowed) const { if (m_name == "") return; @@ -1320,7 +1437,7 @@ namespace Cantera { bool doSpace = true; bool doNewLine = false; int ll = static_cast(m_value.size()) - 1; - if (ll > 15) { + if (ll > 25) { doNewLine = true; } if (m_name == "floatArray") { @@ -1351,9 +1468,11 @@ namespace Cantera { } } int i; - for (i = 0; i < m_nchildren; i++) { - s << endl; - m_children[i]->write_int(s,level + 2); + if (numRecursivesAllowed > 0) { + for (i = 0; i < m_nchildren; i++) { + s << endl; + m_children[i]->write_int(s,level + 2, numRecursivesAllowed - 1); + } } if (m_nchildren > 0) s << endl << indent; s << ""; @@ -1370,14 +1489,14 @@ namespace Cantera { * is skipped and the children are processed. "--" is used * to denote the top of the tree. */ - void XML_Node::write(std::ostream& s, const int level) const { + void XML_Node::write(std::ostream& s, const int level, int numRecursivesAllowed) const { if (m_name == "--" && m_root == this) { for (int i = 0; i < m_nchildren; i++) { - m_children[i]->write_int(s,level); + m_children[i]->write_int(s,level, numRecursivesAllowed-1); s << endl; } } else { - write_int(s, level); + write_int(s, level, numRecursivesAllowed); s << endl; } } @@ -1387,7 +1506,10 @@ namespace Cantera { } void XML_Node::setRoot(const XML_Node& root) { - m_root = const_cast(&root); + m_root = const_cast(&root); + for (int i = 0; i < m_nchildren; i++) { + m_children[i]->setRoot(root); + } } XML_Node * findXMLPhase(XML_Node *root, diff --git a/Cantera/src/base/xml.h b/Cantera/src/base/xml.h index f3063ba9f..b81fe6c00 100644 --- a/Cantera/src/base/xml.h +++ b/Cantera/src/base/xml.h @@ -45,8 +45,7 @@ namespace Cantera { */ XML_Reader(std::istream& input); - //! Read a single character from the input stream - //! and return it + //! Read a single character from the input stream and returns it /*! * All low level reads occur through this function. * The function also keeps track of the line numbers. @@ -130,13 +129,14 @@ namespace Cantera { std::string readValue(); protected: - //! Input Stream containing the XML file + + //! Input stream containing the XML file std::istream& m_s; public: + //! Line count int m_line; - }; @@ -156,6 +156,10 @@ namespace Cantera { class XML_Node { public: + //! Value_type for the lookup multimap m_childindex. This is a convenience definition + //! for manipulating the multimap + typedef std::pair CIPair; + //! Default constructor for XML_Node, representing a tree structure /*! * Constructor for an XML_Node, which is a node in a tree-like structure @@ -175,10 +179,10 @@ namespace Cantera { * @param nm Name of the node. * The default name of the node is "--" * - * @param p pointer to the root for this node in the tree. - * The default is 0 indicating this is the top of the tree. + * @param parent Pointer to the parent for this node in the tree. + * A value of 0 indicates this is the top of the tree. */ - XML_Node(const std::string nm, XML_Node * const p); + XML_Node(const std::string nm, XML_Node * const parent); //! Copy constructor /*! @@ -203,18 +207,31 @@ namespace Cantera { */ void addComment(const std::string &comment); - //! Add a child node to the current node + //! Merge an existing node as a child node to the current node /*! - * This will add an XML_Node as a child to the current node. + * This will merge an XML_Node as a child to the current node. * Note, this actually adds the node. Therefore, the current node is changed. - * There is no copy made of the child node. + * There is no copy made of the child node. The child node should not be deleted in the future * * @param node Reference to a child XML_Node object * * @return Returns a reference to the added child node */ - XML_Node& addChild(XML_Node& node); + XML_Node& mergeAsChild(XML_Node& node); + // Add a child node to the current node by makeing a copy of an existing node tree + /* + * This will add an XML_Node as a child to the current node. + * Note, this actually adds the node. Therefore, node is changed. + * A copy is made of the underlying tree + * + * @param node Reference to a child XML_Node object + * + * @return returns a reference to the added node + */ + XML_Node& addChild(const XML_Node& node); + + //! Add a child node to the current node with a specified name /*! * This will add an XML_Node as a child to the current node. @@ -226,6 +243,17 @@ namespace Cantera { */ XML_Node& addChild(const std::string &sname); + //! Add a child node to the current node with a specified name + /*! + * This will add an XML_Node as a child to the current node. + * The node will be blank except for the specified name. + * + * @param cstring Name of the new child as a c string + * + * @return Returns a reference to the added node + */ + XML_Node& addChild(const char * cstring); + //! Add a child node to the current xml node, and at the //! same time add a value to the child /*! @@ -388,6 +416,7 @@ namespace Cantera { void clear(); private: + //! Returns a changeable value of the attributes map for the current node /*! * Note this is a simple accessor routine. And, it is a private function. @@ -397,6 +426,13 @@ namespace Cantera { public: + //! Returns an unchangeable value of the attributs map for the current node + /*! + * + * @return Returns an unchangeable reference to the attributes map + */ + const std::map& attribsConst() const; + //! Set the line number /*! * @param n the member data m_linenum is set to n @@ -408,7 +444,6 @@ namespace Cantera { * @return returns the member data m_linenum */ int lineNumber() const; - //! Returns a pointer to the parent node of the current node XML_Node* parent() const; @@ -472,12 +507,16 @@ namespace Cantera { */ const std::vector& children() const; - //! return the number of children + //! Return the number of children /*! - * + * @param discardComments If true comments are discarded when adding up the number of children. + * Defaults to false. */ - int nChildren() const; + int nChildren(bool discardComments = false) const; + //! Boolean function indicating whether a comment + bool isComment() const; + //! Require that the current xml node have an attribute named //! by the first argument, a, and that this attribute have the //! the string value listed in the second argument, v. @@ -512,8 +551,31 @@ namespace Cantera { XML_Node* findNameID(const std::string &nameTarget, const std::string &idTarget) const; + //! This routine carries out a search for an XML node based + //! on both the xml element name and the attribute ID and an integer index. + /*! + * If exact matches are found for all fields, the pointer + * to the matching XML Node is returned. The search is only carried out on + * the current element and the child elements of the current element. + * + * The "id" attribute may be defaulted by setting it to "". + * In this case the pointer to the first xml element matching the name + * only is returned. + * + * @param nameTarget Name of the XML Node that is being searched for + * @param idTarget "id" attribute of the XML Node that the routine + * looks for + * @param index Integer describing the index. The index is an + * attribute of the form index = "3" + * + * @return Returns the pointer to the XML node that fits the criteria + * + */ + XML_Node* findNameIDIndex(const std::string &nameTarget, + const std::string &idTarget, const int index) const; + //! This routine carries out a recursive search for an XML node based - //! on the xml element attribute ID. + //! on the xml element attribute, "id" /*! * If exact match is found, the pointer * to the matching XML Node is returned. If not, 0 is returned. @@ -546,11 +608,14 @@ namespace Cantera { * @param attr Attribute of the XML Node that the routine * looks for * @param val Value of the attribute + * @param depth Depth of the search. A value of 1 means that only the + * immediate children are searched. * * @return Returns the pointer to the XML node that fits the criteria * */ - XML_Node* findByAttr(const std::string& attr, const std::string& val) const; + XML_Node* findByAttr(const std::string& attr, const std::string& val, + int depth = 100000) const; //! This routine carries out a recursive search for an XML node based //! on the name of the node. @@ -560,10 +625,12 @@ namespace Cantera { * This is the const version of the routine. * * @param nm Name of the XML node + * @param depth Depth of the search. A value of 1 means that only the + * immediate children are searched. * * @return Returns the pointer to the XML node that fits the criteria */ - const XML_Node* findByName(const std::string& nm) const; + const XML_Node* findByName(const std::string& nm, int depth = 100000) const; //! This routine carries out a recursive search for an XML node based //! on the name of the node. @@ -573,10 +640,12 @@ namespace Cantera { * This is the non-const version of the routine. * * @param nm Name of the XML node + * @param depth Depth of the search. A value of 1 means that only the + * immediate children are searched. * * @return Returns the pointer to the XML node that fits the criteria */ - XML_Node* findByName(const std::string& nm); + XML_Node* findByName(const std::string& nm, int depth = 100000); //! Get a vector of pointers to XML_Node containing all of the children //! of the current node which matches the input name @@ -588,9 +657,11 @@ namespace Cantera { */ void getChildren(const std::string &name, std::vector& children) const; - //! Return a changeable reference to a child of the current node, - //! named by the argument + //! Return a changeable reference to a child of the current node, named by the argument /*! + * Note the underlying data allows for more than one XML element with the same name. + * This routine returns the first child with the given name. + * * @param loc Name of the child to return */ XML_Node& child(const std::string &loc) const; @@ -614,9 +685,10 @@ namespace Cantera { * to denote the top of the tree. * * @param s ostream to write to - * @param level Indentation level to work from + * @param level Indentation level to work from + * @param numRecursivesAllowed Number of recursive calls allowed */ - void write(std::ostream& s, const int level = 0) const; + void write(std::ostream& s, const int level = 0, int numRecursivesAllowed = 60000) const; //! Return the root of the current XML_Node tree /*! @@ -677,15 +749,16 @@ namespace Cantera { //! Write an XML subtree to an output stream. /*! - * This is the - * main recursive routine. It doesn't put a final endl - * on. This is fixed up in the public method. + * This is the main recursive routine. It doesn't put a final endl + * on. This is fixed up in the public method. A method to only write out a limited + * amount of the xml tree has been added. * * * @param s ostream to write to * @param level Indentation level to work from + * @param numRecurvivesAllowed Number of recursive calls allowed */ - void write_int(std::ostream& s, int level = 0) const; + void write_int(std::ostream& s, int level = 0, int numRecursivesAllowed = 60000) const; protected: @@ -719,9 +792,10 @@ namespace Cantera { /*! * m_childindex[node.name()] = XML_Node *pointer * - * This object helps to speed up searches + * This object helps to speed up searches. + * The value_type for this multimap is CIPair. */ - std::map m_childindex; + std::multimap m_childindex; //! Storage of attributes for a node /*! @@ -757,7 +831,7 @@ namespace Cantera { //! True if the current node is a comment node bool m_iscomment; - //! the member data m_linenum + //! The member data m_linenum /*! * Currently, unimplemented functionality */ diff --git a/Cantera/src/converters/CKParser.cpp b/Cantera/src/converters/CKParser.cpp index b51b408ea..03d5336e6 100755 --- a/Cantera/src/converters/CKParser.cpp +++ b/Cantera/src/converters/CKParser.cpp @@ -22,7 +22,6 @@ #include "ckr_utils.h" #include "writelog.h" #include -//#include "../stringUtils.h" #include using namespace std; diff --git a/Cantera/src/converters/CKParser.h b/Cantera/src/converters/CKParser.h index f8da04605..90ab2a3f5 100755 --- a/Cantera/src/converters/CKParser.h +++ b/Cantera/src/converters/CKParser.h @@ -16,7 +16,6 @@ #include #include #include -//using namespace std; #include "ckr_defs.h" #include "Element.h" @@ -58,17 +57,17 @@ namespace ckr { bool readElementSection(elementList& elements); bool readSpeciesSection(speciesList& species); - bool readThermoSection(vector& names, + bool readThermoSection(std::vector& names, speciesTable& speciesData, vector_fp& temp, - int& optionFlag, ostream& log); - bool readReactionSection(const vector& speciesNames, - vector& elementNames, + int& optionFlag, std::ostream& log); + bool readReactionSection(const std::vector& speciesNames, + std::vector& elementNames, reactionList& reactions, ReactionUnits& units); bool advanceToKeyword(const std::string& kw, const std::string& stop); bool verbose; bool debug; - bool readNASA9ThermoSection(std::vector& names, + bool readNASA9ThermoSection(std::vector& names, speciesTable& species, vector_fp& temp, int& optionFlag, std::ostream& log); diff --git a/Cantera/src/converters/CKReader.h b/Cantera/src/converters/CKReader.h index 4c4274c7a..61b02b217 100755 --- a/Cantera/src/converters/CKReader.h +++ b/Cantera/src/converters/CKReader.h @@ -23,7 +23,6 @@ #include #include -using namespace std; namespace ckr { diff --git a/Cantera/src/converters/Constituent.h b/Cantera/src/converters/Constituent.h index d8daf5d06..c81773045 100755 --- a/Cantera/src/converters/Constituent.h +++ b/Cantera/src/converters/Constituent.h @@ -11,7 +11,6 @@ #include #include -using namespace std; namespace ckr { @@ -22,7 +21,7 @@ namespace ckr { */ class Constituent { public: - string name; //!< The name of the object. + std::string name; //!< The name of the object. double number; //!< The number of units (molecules, etc.). }; diff --git a/Cantera/src/converters/Element.h b/Cantera/src/converters/Element.h index 5ba352502..30c6b9070 100755 --- a/Cantera/src/converters/Element.h +++ b/Cantera/src/converters/Element.h @@ -11,8 +11,8 @@ #include #include +#include -using namespace std; namespace ckr { @@ -41,7 +41,7 @@ public: /// Construct a new empty Element object - Element(const string& nm, double wt) : + Element(const std::string& nm, double wt) : name(nm), atomicWeight(wt), valid(0), @@ -54,12 +54,12 @@ public: /// Destructor ~Element() {} - string name; //!< Element name + std::string name; //!< Element name double atomicWeight; //!< Atomic weight in amu int valid; //!< flag returned by validation routines int index; //!< index number bool weightFromDB; //!< true if atomic weight is not specified - string comment; //!< comment in input file + std::string comment; //!< comment in input file /** @@ -72,11 +72,11 @@ public: bool operator!=(const Element& e) const { return !(*this == e); } - friend ostream& operator<<(ostream& s, const Element& e) { + friend std::ostream& operator<<(std::ostream& s, const Element& e) { s << e.name; if (!e.weightFromDB) s << "/" << e.atomicWeight << "/"; if (e.comment != "") - s << " !" << e.comment << endl; + s << " !" << e.comment << std::endl; else s << " "; return s; @@ -84,18 +84,10 @@ public: }; /// a list (vector) of Elements -typedef vector elementList; +typedef std::vector elementList; } #endif - - - - - - - - diff --git a/Cantera/src/converters/Reaction.cpp b/Cantera/src/converters/Reaction.cpp index fd4b57d2d..bce59d0ee 100755 --- a/Cantera/src/converters/Reaction.cpp +++ b/Cantera/src/converters/Reaction.cpp @@ -14,6 +14,8 @@ #include #include +using namespace std; + namespace ckr { Reaction forwardReaction(const Reaction& rxn) { diff --git a/Cantera/src/converters/Reaction.h b/Cantera/src/converters/Reaction.h index c626ea87e..52c3c4948 100755 --- a/Cantera/src/converters/Reaction.h +++ b/Cantera/src/converters/Reaction.h @@ -12,7 +12,7 @@ #include #include #include -using namespace std; +#include #include "ckr_defs.h" #include "ckr_utils.h" @@ -183,7 +183,7 @@ namespace ckr { * third body collision partners, or a species name if only * one species does. */ - string thirdBody; + std::string thirdBody; /// Reaction number. int number; @@ -192,21 +192,21 @@ namespace ckr { * list of species that participate as reactants, * and their stoichiometric coefficients */ - vector reactants; + std::vector reactants; - mutable map fwdOrder; + mutable std::map fwdOrder; /** * list of species that participate as products, * and their stoichiometric coefficients */ - vector products; + std::vector products; /** * map from species names to enhanced third-body collision efficiencies */ - mutable map e3b; + mutable std::map e3b; /** * Forward rate coefficient. For falloff reactions, this is the @@ -231,28 +231,28 @@ namespace ckr { /** * auxiliary data not handled elsewhere. */ - mutable map otherAuxData; + mutable std::map otherAuxData; /** * input file lines */ - vector lines; + std::vector lines; /** * comments */ - vector comment; + std::vector comment; // methods - double stoichCoefficient(const string& s) const; + double stoichCoefficient(const std::string& s) const; bool operator==(const Reaction& r) const; - void write(ostream& s) const; + void write(std::ostream& s) const; }; /// a list of Reaction objects - typedef vector reactionList; + typedef std::vector reactionList; Reaction forwardReaction(const Reaction& rxn); Reaction reverseReaction(const Reaction& rxn); diff --git a/Cantera/src/converters/RxnSpecies.h b/Cantera/src/converters/RxnSpecies.h index e49b46a79..7565fafbe 100755 --- a/Cantera/src/converters/RxnSpecies.h +++ b/Cantera/src/converters/RxnSpecies.h @@ -11,15 +11,11 @@ #include #include -//#include "Cantera.h" - -using namespace std; namespace ckr { - typedef vector_int group_t; - typedef vector grouplist_t; - + typedef vector_int group_t; + typedef std::vector grouplist_t; /** * A class for species in a reaction. @@ -29,7 +25,7 @@ class RxnSpecies { public: RxnSpecies() : number(0) {} - string name; //!< The name of the object. + std::string name; //!< The name of the object. double number; //!< The number of units (molecules, etc.). grouplist_t groups; }; diff --git a/Cantera/src/converters/Species.h b/Cantera/src/converters/Species.h index 9b82c7d3a..37afde930 100755 --- a/Cantera/src/converters/Species.h +++ b/Cantera/src/converters/Species.h @@ -58,19 +58,19 @@ namespace ckr { int thermoFormatType; //! Species Name - string name; - string id; //!< ID tag from 'date' field in input - string phase; //!< Phase string. Usually "G", "L", or "S". + std::string name; + std::string id; //!< ID tag from 'date' field in input + std::string phase; //!< Phase string. Usually "G", "L", or "S". double tlow; //!< Min temperature for thermo data fit double tmid; //!< Mid temperature for thermo data fit double thigh; //!< Max temperature for thermo data fit /// list of Constituent objects defining elemental composition - vector elements; + std::vector elements; /// map from element symbols to atom numbers - mutable map comp; + mutable std::map comp; /// polynomial coefficients for the lower temperature range vector_fp lowCoeffs; @@ -91,7 +91,7 @@ namespace ckr { /// position in the list of species in the input file int index; - string m_commentsRef; + std::string m_commentsRef; private: //! Delete private data @@ -99,10 +99,10 @@ namespace ckr { }; //! Shorthand for a list of Species - typedef vector speciesList; + typedef std::vector speciesList; //! A map from species names to Species objects - typedef map speciesTable; + typedef std::map speciesTable; } #endif diff --git a/Cantera/src/converters/ckr_defs.h b/Cantera/src/converters/ckr_defs.h index 8138974f7..52ffb68d5 100755 --- a/Cantera/src/converters/ckr_defs.h +++ b/Cantera/src/converters/ckr_defs.h @@ -14,9 +14,6 @@ #include #include #include -//using namespace std; - -//#include "../ctvector.h" /// the namespace for the CKReader packaage namespace ckr { diff --git a/Cantera/src/converters/ckr_utils.h b/Cantera/src/converters/ckr_utils.h index 634a6ace4..04c6f5260 100755 --- a/Cantera/src/converters/ckr_utils.h +++ b/Cantera/src/converters/ckr_utils.h @@ -17,7 +17,6 @@ #include #include -using namespace std; #ifdef WIN32 #define TYPENAME_KEYWORD @@ -35,9 +34,9 @@ namespace ckr { */ template -void getMapKeys(const map& mp, vector& keys) { +void getMapKeys(const std::map& mp, std::vector& keys) { keys.clear(); - TYPENAME_KEYWORD map::const_iterator i = mp.begin(); + TYPENAME_KEYWORD std::map::const_iterator i = mp.begin(); for (; i != mp.end(); ++i) keys.push_back(i->first); } @@ -49,9 +48,9 @@ void getMapKeys(const map& mp, vector& keys) { */ template -void getMapValues(const map& mp, vector& values) { +void getMapValues(const std::map& mp, std::vector& values) { values.clear(); - TYPENAME_KEYWORD map::const_iterator i = mp.begin(); + TYPENAME_KEYWORD std::map::const_iterator i = mp.begin(); for (; i != mp.end(); ++i) values.push_back(i->second); } @@ -120,10 +119,10 @@ inline bool valid(L& list) { /// Remove all white space from string s. -void removeWhiteSpace(string& s); +void removeWhiteSpace(std::string& s); -void getTokens(string& begin, - int n, vector& toks, char delim=' '); +void getTokens(std::string& begin, + int n, std::vector& toks, char delim=' '); /** @@ -137,12 +136,12 @@ void getTokens(string& begin, * */ -bool match(const string& s1, const string& s2); +bool match(const std::string& s1, const std::string& s2); /** * Check whether string 'word' begins with a Chemkin keyword. */ -inline bool isKeyword(string word) +inline bool isKeyword(std::string word) { return (match(word, "ELEM") || match(word, "SPEC") || @@ -152,8 +151,8 @@ inline bool isKeyword(string word) } -bool extractSlashData(string& s, string& name, string& data); -string capitalize(const string& word); +bool extractSlashData(std::string& s, std::string& name, std::string& data); +std::string capitalize(const std::string& word); } diff --git a/Cantera/src/converters/writelog.h b/Cantera/src/converters/writelog.h index b079d90bf..906fc57d9 100755 --- a/Cantera/src/converters/writelog.h +++ b/Cantera/src/converters/writelog.h @@ -12,15 +12,13 @@ #include #include #include -//using namespace std; #include "Species.h" #include "Reaction.h" -//#include "Cantera.h" namespace ckr { - std::string newTask(string msg); + std::string newTask(std::string msg); bool writeFalloff(int type, const vector_fp& c, std::ostream& log); bool writeRateCoeff(const RateCoeff& k, std::ostream& log); void printReactionEquation(std::ostream& f, const Reaction& r); diff --git a/Cantera/src/equil/BasisOptimize.cpp b/Cantera/src/equil/BasisOptimize.cpp index b98d36ff4..a6bcc476b 100644 --- a/Cantera/src/equil/BasisOptimize.cpp +++ b/Cantera/src/equil/BasisOptimize.cpp @@ -22,11 +22,68 @@ using namespace std; namespace Cantera { int BasisOptimize_print_lvl = 0; } + +//! 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. +/*! + * + * @param str String -> must be null terminated. + * @param space space limit for the printing. + * @param alignment 0 centered + * 1 right aligned + * 2 left aligned + */ static void print_stringTrunc(const char *str, int space, int alignment); #endif + + //! Finds the location of the maximum component in a double vector INPUT + /*! + * @param x Vector to search + * @param j j <= i < n : i is the range of indecises to search in X(*) + * @param n Length of the vector + * + * @return index of the greatest value on X(*) searched + */ static int amax(double *x, int j, int n); + +//! Switch the position in the vector +/*! + * @param orderVector Vector to be manipulated + * @param jr first position + * @param kspec second species + */ static void switch_pos(vector_int &orderVector, int jr, int kspec); + + + //! Invert an nxn matrix and solve m rhs's + /*! + * + * Solve C X + B = 0; + * + * This routine uses Gauss elimination and is optimized for the solution + * of lots of rhs's. + * A crude form of row pivoting is used here. + * + * @param c C is the matrix to be inverted + * @param idem first dimension in the calling routine + * idem >= n must be true + * @param n number of rows and columns in the matrix + * @param b rhs of the matrix problem + * @param m number of rhs to be solved for + * + * c[i+j*idem] = c_i_j = Matrix to be inverted: i = row number + * j = column number + * b[i+j*idem] = b_i_j = vectors of rhs's: i = row number + * j = column number + * (each column is a new rhs) + * + * @return Retuns the value + * 1 : Matrix is singluar + * 0 : solution is OK + * + * The solution is returned in the matrix b. + */ static int mlequ(double *c, int idem, int n, double *b, int m); //@{ diff --git a/Cantera/src/equil/Makefile.in b/Cantera/src/equil/Makefile.in index 363c44348..0cdec0ecd 100644 --- a/Cantera/src/equil/Makefile.in +++ b/Cantera/src/equil/Makefile.in @@ -74,7 +74,7 @@ VCSNONIDEAL_OBJ = vcs_solve_TP.o vcs_VolPhase.o vcs_solve.o vcs_prob.o \ vcs_root1d.o vcs_rxnadj.o \ vcs_SpeciesProperties.o vcs_equilibrate.o \ vcs_prep.o vcs_species_thermo.o vcs_Gibbs.o vcs_phaseStability.o \ - $(DALT_OBJ) + vcs_solve_phaseStability.o $(DALT_OBJ) VCSNONIDEAL_H = vcs_internal.h vcs_VolPhase.h vcs_solve.h vcs_prob.h \ vcs_IntStarStar.h vcs_DoubleStarStar.h vcs_defs.h \ diff --git a/Cantera/src/equil/MultiPhase.cpp b/Cantera/src/equil/MultiPhase.cpp index 81dcb4865..53c17ef45 100644 --- a/Cantera/src/equil/MultiPhase.cpp +++ b/Cantera/src/equil/MultiPhase.cpp @@ -21,7 +21,8 @@ using namespace std; namespace Cantera { - /// Constructor. + //==================================================================================================================== + // Constructor. MultiPhase::MultiPhase() : m_np(0), m_temp(0.0), @@ -33,8 +34,67 @@ namespace Cantera { m_Tmin(1.0), m_Tmax(100000.0) { + } + //==================================================================================================================== + // Copy Constructor + /* + * @param right Object to be copied + */ + MultiPhase::MultiPhase(const MultiPhase &right) : + m_np(0), + m_temp(0.0), + m_press(0.0), + m_nel(0), + m_nsp(0), + m_init(false), + m_eloc(-1), + m_Tmin(1.0), + m_Tmax(100000.0) + { + operator=(right); } - + //==================================================================================================================== + // Destructor. + /* + * Does nothing. Class MultiPhase does not take + * "ownership" (i.e. responsibility for destroying) the + * phase objects. + */ + MultiPhase::~MultiPhase() + { + } + //==================================================================================================================== + // Assignment operator + /* + * @param right Object to be copied + */ + MultiPhase& MultiPhase::operator=(const MultiPhase& right) + { + if (&right != this) { + m_moles = right.m_moles; + // shallow copy of phase pointers + m_phase = right.m_phase; + m_atoms = right.m_atoms; + m_moleFractions = right.m_moleFractions; + m_spphase = right.m_spphase; + m_spstart = right.m_spstart; + m_enames = right.m_enames; + m_enamemap = right.m_enamemap; + m_np = right.m_np; + m_temp = right.m_temp; + m_press = right.m_press; + m_nel = right.m_nel; + m_nsp = right.m_nsp; + m_init = right.m_init; + m_eloc = right.m_eloc; + m_temp_OK = right.m_temp_OK; + m_Tmin = right.m_Tmin; + m_Tmax = right.m_Tmax; + m_elemAbundances = right.m_elemAbundances; + } + return *this; + } + //==================================================================================================================== void MultiPhase:: addPhases(MultiPhase& mix) { index_t n; @@ -42,7 +102,7 @@ namespace Cantera { addPhase(mix.m_phase[n], mix.m_moles[n]); } } - + //==================================================================================================================== void MultiPhase:: addPhases(phase_list& phases, const vector_fp& phaseMoles) { index_t np = phases.size(); @@ -52,7 +112,7 @@ namespace Cantera { } init(); } - + //==================================================================================================================== void MultiPhase:: addPhase(phase_t* p, doublereal moles) { if (m_init) { @@ -121,8 +181,7 @@ namespace Cantera { if (t < m_Tmax) m_Tmax = t; } } - - + //==================================================================================================================== // Process phases and build atomic composition array. This method // must be called after all phases are added, before doing // anything else with the mixture. After init() has been called, @@ -183,9 +242,10 @@ namespace Cantera { updateMoleFractions(); + updatePhases(); } - + //==================================================================================================================== // Return a reference to phase n. The state of phase n is // also updated to match the state stored locally in the // mixture object. @@ -196,15 +256,17 @@ namespace Cantera { m_phase[n]->setPressure(m_press); return *m_phase[n]; } - + //==================================================================================================================== /// Moles of species \c k. doublereal MultiPhase::speciesMoles(index_t k) const { index_t ip = m_spphase[k]; return m_moles[ip]*m_moleFractions[k]; } - - /// Total moles of element m, summed over all - /// phases + //==================================================================================================================== + // Total moles of global element \a m, summed over all phases. + /* + * @param m Index of the global element + */ doublereal MultiPhase::elementMoles(index_t m) const { doublereal sum = 0.0, phasesum; index_t i, k = 0, ik, nsp; @@ -219,8 +281,8 @@ namespace Cantera { } return sum; } - - /// Total charge, summed over all phases + //==================================================================================================================== + // Total charge, summed over all phases doublereal MultiPhase::charge() const { doublereal sum = 0.0; index_t i; @@ -229,8 +291,11 @@ namespace Cantera { } return sum; } - + //==================================================================================================================== int MultiPhase::speciesIndex(std::string speciesName, std::string phaseName) { + if (!m_init) { + init(); + } int p = phaseIndex(phaseName); if (p < 0) { throw CanteraError("MultiPhase::speciesIndex", "phase not found: " + phaseName); @@ -241,7 +306,7 @@ namespace Cantera { } return m_spstart[p] + k; } - + //==================================================================================================================== /// Net charge of one phase (Coulombs). The net charge is computed as /// \f[ Q_p = N_p \sum_k F z_k X_k \f] /// where the sum runs only over species in phase \a p. @@ -255,7 +320,7 @@ namespace Cantera { } return Faraday*phasesum*m_moles[p]; } - + //==================================================================================================================== /// Get the chemical potentials of all species in all phases. void MultiPhase::getChemPotentials(doublereal* mu) const { @@ -266,7 +331,7 @@ namespace Cantera { loc += m_phase[i]->nSpecies(); } } - + //==================================================================================================================== // Get chemical potentials of species with valid thermo // data. This method is designed for use in computing chemical // equilibrium by Gibbs minimization. For solution phases (more @@ -312,7 +377,7 @@ namespace Cantera { loc += m_phase[i]->nSpecies(); } } - + //==================================================================================================================== /// True if species \a k belongs to a solution phase. bool MultiPhase::solutionSpecies(index_t k) const { if (m_phase[m_spphase[k]]->nSpecies() > 1) @@ -320,47 +385,59 @@ namespace Cantera { else return false; } - + //==================================================================================================================== /// The Gibbs free energy of the mixture (J). doublereal MultiPhase::gibbs() const { index_t i; doublereal sum = 0.0; updatePhases(); - for (i = 0; i < m_np; i++) - sum += m_phase[i]->gibbs_mole() * m_moles[i]; + for (i = 0; i < m_np; i++) { + if (m_moles[i] > 0.0) { + sum += m_phase[i]->gibbs_mole() * m_moles[i]; + } + } return sum; } - + //==================================================================================================================== /// The enthalpy of the mixture (J). doublereal MultiPhase::enthalpy() const { index_t i; doublereal sum = 0.0; updatePhases(); - for (i = 0; i < m_np; i++) - sum += m_phase[i]->enthalpy_mole() * m_moles[i]; + for (i = 0; i < m_np; i++) { + if (m_moles[i] > 0.0) { + sum += m_phase[i]->enthalpy_mole() * m_moles[i]; + } + } return sum; } - + //==================================================================================================================== /// The internal energy of the mixture (J). doublereal MultiPhase::IntEnergy() const { index_t i; doublereal sum = 0.0; updatePhases(); - for (i = 0; i < m_np; i++) - sum += m_phase[i]->intEnergy_mole() * m_moles[i]; + for (i = 0; i < m_np; i++) { + if (m_moles[i] > 0.0) { + sum += m_phase[i]->intEnergy_mole() * m_moles[i]; + } + } return sum; } - + //==================================================================================================================== /// The entropy of the mixture (J/K). doublereal MultiPhase::entropy() const { index_t i; doublereal sum = 0.0; updatePhases(); - for (i = 0; i < m_np; i++) - sum += m_phase[i]->entropy_mole() * m_moles[i]; + for (i = 0; i < m_np; i++) { + if (m_moles[i] > 0.0) { + sum += m_phase[i]->entropy_mole() * m_moles[i]; + } + } return sum; } - + //==================================================================================================================== /// The specific heat at constant pressure and composition (J/K). /// Note that this does not account for changes in composition of /// the mixture with temperature. @@ -368,16 +445,22 @@ namespace Cantera { index_t i; doublereal sum = 0.0; updatePhases(); - for (i = 0; i < m_np; i++) - sum += m_phase[i]->cp_mole() * m_moles[i]; + for (i = 0; i < m_np; i++) { + if (m_moles[i] > 0.0) { + sum += m_phase[i]->cp_mole() * m_moles[i]; + } + } return sum; } - + //==================================================================================================================== /// Set the mole fractions of phase \a n to the values in /// array \a x. void MultiPhase::setPhaseMoleFractions(const index_t n, const doublereal* const x) { + if (!m_init) { + init(); + } phase_t* p = m_phase[n]; p->setState_TPX(m_temp, m_press, x); int nsp = p->nSpecies(); @@ -386,7 +469,7 @@ namespace Cantera { m_moleFractions[istart+k] = x[k]; } } - + //==================================================================================================================== // Set the species moles using a map. The map \a xMap maps // species name strings to mole numbers. Mole numbers that are // less than or equal to zero will be set to zero. @@ -400,7 +483,7 @@ namespace Cantera { } setMoles(DATA_PTR(moles)); } - + //==================================================================================================================== // Set the species moles using a string. Unspecified species are // set to zero. void MultiPhase::setMolesByName(const std::string& x) { @@ -419,7 +502,7 @@ namespace Cantera { parseCompString(x, xx); setMolesByName(xx); } - + //==================================================================================================================== // Get the mole numbers of all species in the multiphase // object void MultiPhase::getMoles(doublereal * molNum) const { @@ -438,7 +521,7 @@ namespace Cantera { } } } - + //==================================================================================================================== /// Set the species moles to the values in array \a n. The state /// of each phase object is also updated to have the specified /// composition and the mixture temperature and pressure. @@ -470,7 +553,7 @@ namespace Cantera { loc += nsp; } } - + //==================================================================================================================== void MultiPhase::addSpeciesMoles(const int indexS, const doublereal addedMoles) { vector_fp tmpMoles(m_nsp, 0.0); getMoles(DATA_PTR(tmpMoles)); @@ -480,21 +563,21 @@ namespace Cantera { } setMoles(DATA_PTR(tmpMoles)); } - + //==================================================================================================================== void MultiPhase::setState_TP(const doublereal T, const doublereal Pres) { if (!m_init) init(); m_temp = T; m_press = Pres; updatePhases(); } - + //==================================================================================================================== void MultiPhase::setState_TPMoles(const doublereal T, const doublereal Pres, const doublereal *n) { m_temp = T; m_press = Pres; setMoles(n); } - + //==================================================================================================================== void MultiPhase::getElemAbundances(doublereal *elemAbundances) const { index_t eGlobal; calcElemAbundances(); @@ -502,7 +585,7 @@ namespace Cantera { elemAbundances[eGlobal] = m_elemAbundances[eGlobal]; } } - + //==================================================================================================================== // Internal routine to calculate the element abundance vector void MultiPhase::calcElemAbundances() const { index_t loc = 0; @@ -526,17 +609,18 @@ namespace Cantera { loc += nspPhase; } } - + //==================================================================================================================== /// The total mixture volume [m^3]. doublereal MultiPhase::volume() const { int i; doublereal sum = 0; for (i = 0; i < int(m_np); i++) { - sum += m_moles[i]/m_phase[i]->molarDensity(); + double vol = 1.0/m_phase[i]->molarDensity(); + sum += m_moles[i] * vol; } return sum; } - + //==================================================================================================================== doublereal MultiPhase::equilibrate(int XY, doublereal err, int maxsteps, int maxiter, int loglevel) { doublereal error; @@ -850,18 +934,18 @@ namespace Cantera { } } #endif - + //==================================================================================================================== void MultiPhase::setTemperature(const doublereal T) { if (!m_init) init(); m_temp = T; updatePhases(); } - + //==================================================================================================================== // Name of element \a m. std::string MultiPhase::elementName(int m) const { return m_enames[m]; } - + //==================================================================================================================== // Index of element with name \a name. int MultiPhase::elementIndex(std::string name) const { for (size_t e = 0; e < m_nel; e++) { @@ -871,25 +955,25 @@ namespace Cantera { } return -1; } - + //==================================================================================================================== // Name of species with global index \a k. std::string MultiPhase::speciesName(const int k) const { return m_snames[k]; } - + //==================================================================================================================== doublereal MultiPhase::nAtoms(const int kGlob, const int mGlob) const { return m_atoms(mGlob, kGlob); } - + //==================================================================================================================== void MultiPhase::getMoleFractions(doublereal* const x) const { std::copy(m_moleFractions.begin(), m_moleFractions.end(), x); } - + //==================================================================================================================== std::string MultiPhase::phaseName(const index_t iph) const { const phase_t *tptr = m_phase[iph]; return tptr->id(); } - + //==================================================================================================================== int MultiPhase::phaseIndex(const std::string &pName) const { std::string tmp; for (int iph = 0; iph < (int) m_np; iph++) { @@ -901,32 +985,33 @@ namespace Cantera { } return -1; } - + //==================================================================================================================== doublereal MultiPhase::phaseMoles(const index_t n) const { return m_moles[n]; } - + //==================================================================================================================== void MultiPhase::setPhaseMoles(const index_t n, const doublereal moles) { m_moles[n] = moles; } - + //==================================================================================================================== int MultiPhase::speciesPhaseIndex(const index_t kGlob) const { return m_spphase[kGlob]; } - + //==================================================================================================================== doublereal MultiPhase::moleFraction(const index_t kGlob) const{ return m_moleFractions[kGlob]; } - + //==================================================================================================================== bool MultiPhase::tempOK(const index_t p) const { return m_temp_OK[p]; } - + //==================================================================================================================== /// Update the locally-stored species mole fractions. void MultiPhase::updateMoleFractions() { uploadMoleFractionsFromPhases(); } + //==================================================================================================================== /// Update the locally-stored species mole fractions. void MultiPhase::uploadMoleFractionsFromPhases() { index_t ip, loc = 0; @@ -937,7 +1022,7 @@ namespace Cantera { } calcElemAbundances(); } - + //==================================================================================================================== //------------------------------------------------------------- // // protected methods @@ -964,6 +1049,6 @@ namespace Cantera { } } } - + //==================================================================================================================== } diff --git a/Cantera/src/equil/MultiPhase.h b/Cantera/src/equil/MultiPhase.h index 516dfbc31..5b56e7bee 100644 --- a/Cantera/src/equil/MultiPhase.h +++ b/Cantera/src/equil/MultiPhase.h @@ -85,13 +85,25 @@ namespace Cantera { */ MultiPhase(); + //! Copy Constructor + /*! + * @param right Object to be copied + */ + MultiPhase(const MultiPhase &right); + //! Destructor. /*! * Does nothing. Class MultiPhase does not take * "ownership" (i.e. responsibility for destroying) the * phase objects. */ - virtual ~MultiPhase() {} + virtual ~MultiPhase(); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + MultiPhase& operator=(const MultiPhase& right); //! Add a vector of phases to the mixture /*! @@ -111,7 +123,7 @@ namespace Cantera { //! Add a phase to the mixture. /*! - * This function must be called befure the init() function is called, + * This function must be called before the init() function is called, * which serves to freeze the MultiPhase. * * @param p pointer to the phase object @@ -258,7 +270,7 @@ namespace Cantera { /// conditions for which they are stable. doublereal maxTemp() const { return m_Tmax; } - /// Total charge (Coulombs). + //! Total charge summed over all phases (Coulombs). doublereal charge() const; /// Charge (Coulombs) of phase with index \a p. @@ -267,7 +279,7 @@ namespace Cantera { */ doublereal phaseCharge(index_t p) const; - /// Total moles of global element \a m, summed over all phases. + //! Total moles of global element \a m, summed over all phases. /*! * @param m Index of the global element */ @@ -549,8 +561,6 @@ namespace Cantera { */ void uploadMoleFractionsFromPhases(); - private: - //! Set the states of the phase objects to the locally-stored //! state within this MultiPhase object. /*! @@ -567,6 +577,7 @@ namespace Cantera { */ void updatePhases() const; + private: //! Calculate the element abundance vector void calcElemAbundances() const; diff --git a/Cantera/src/equil/equil.h b/Cantera/src/equil/equil.h index 937b70a4a..c8d4498a8 100644 --- a/Cantera/src/equil/equil.h +++ b/Cantera/src/equil/equil.h @@ -19,6 +19,7 @@ //#include "ChemEquil.h" #include "MultiPhase.h" +#include "vcs_defs.h" namespace Cantera { @@ -72,7 +73,7 @@ namespace Cantera { * @ingroup equil */ int equilibrate(thermo_t& s, const char* XY, - int solver = -1, doublereal rtol = 1.0e-9, int maxsteps = 5000, + int solver = -1, doublereal rtol = 1.0e-9, int maxsteps = VCS_MAXSTEPS, int maxiter = 100, int loglevel = -99); //! Equilibrate a MultiPhase object diff --git a/Cantera/src/equil/vcs_MultiPhaseEquil.cpp b/Cantera/src/equil/vcs_MultiPhaseEquil.cpp index 9d8863917..5446bb00c 100644 --- a/Cantera/src/equil/vcs_MultiPhaseEquil.cpp +++ b/Cantera/src/equil/vcs_MultiPhaseEquil.cpp @@ -42,7 +42,7 @@ using namespace std; //using namespace VCSnonideal; namespace VCSnonideal { - + //==================================================================================================================== vcs_MultiPhaseEquil::vcs_MultiPhaseEquil() : m_vprob(0), @@ -51,7 +51,7 @@ namespace VCSnonideal { m_vsolvePtr(0) { } - + //==================================================================================================================== vcs_MultiPhaseEquil::vcs_MultiPhaseEquil(mix_t* mix, int printLvl) : m_vprob(0), m_mix(0), @@ -89,7 +89,7 @@ namespace VCSnonideal { m_vsolvePtr = 0; } } - + //==================================================================================================================== int vcs_MultiPhaseEquil::equilibrate_TV(int XY, doublereal xtarget, int estimateEquil, int printLvl, doublereal err, @@ -209,7 +209,7 @@ namespace VCSnonideal { return iSuccess; } - + //==================================================================================================================== int vcs_MultiPhaseEquil::equilibrate_HP(doublereal Htarget, int XY, double Tlow, double Thigh, int estimateEquil, @@ -359,7 +359,7 @@ namespace VCSnonideal { done:; return iSuccess; } - + //==================================================================================================================== int vcs_MultiPhaseEquil::equilibrate_SP(doublereal Starget, double Tlow, double Thigh, int estimateEquil, @@ -515,7 +515,7 @@ namespace VCSnonideal { done:; return iSuccess; } - + //==================================================================================================================== /* * Equilibrate the solution using the current element abundances @@ -566,7 +566,7 @@ namespace VCSnonideal { } return iSuccess; } - + //==================================================================================================================== /* * Equilibrate the solution using the current element abundances */ @@ -733,7 +733,7 @@ namespace VCSnonideal { } - + //==================================================================================================================== /************************************************************************** * * @@ -897,11 +897,15 @@ namespace VCSnonideal { fclose(FP); } - + //! print char repeatedly to log file + /*! + * @param letter letter to be repeated + * @param num Number of times repeated + */ static void print_char(const char letter, const int num) { for (int i = 0; i < num; i++) plogf("%c", letter); } - + //==================================================================================================================== /* * * @@ -1280,7 +1284,7 @@ namespace VCSnonideal { vcs_VolPhase *VolPhase = vprob->VPhaseList[iphase]; std::string sEOS = string16_EOSType(VolPhase->m_eqnState); plogf("%16s %5d %5d %8d %16s %8d %16e ", VolPhase->PhaseName.c_str(), - VolPhase->VP_ID, VolPhase->m_singleSpecies, + VolPhase->VP_ID_, VolPhase->m_singleSpecies, VolPhase->m_gasPhase, sEOS.c_str(), VolPhase->nSpecies(), VolPhase->totalMolesInert() ); plogf("%16e\n", VolPhase->totalMoles()); @@ -1295,7 +1299,7 @@ namespace VCSnonideal { return VCS_SUCCESS; } - + //==================================================================================================================== // Transfer the current state of mphase into the VCS_PROB object /* * The basic problem has already been set up. @@ -1402,7 +1406,7 @@ namespace VCSnonideal { vcs_VolPhase *VolPhase = vprob->VPhaseList[iphase]; std::string sEOS = string16_EOSType(VolPhase->m_eqnState); plogf("%16s %5d %5d %8d %16s %8d %16e ", VolPhase->PhaseName.c_str(), - VolPhase->VP_ID, VolPhase->m_singleSpecies, + VolPhase->VP_ID_, VolPhase->m_singleSpecies, VolPhase->m_gasPhase, sEOS.c_str(), VolPhase->nSpecies(), VolPhase->totalMolesInert() ); plogf("%16e\n", VolPhase->totalMoles() ); @@ -1417,7 +1421,7 @@ namespace VCSnonideal { return VCS_SUCCESS; } - + //==================================================================================================================== // This routine hasn't been checked yet void vcs_MultiPhaseEquil::getStoichVector(index_t rxn, Cantera::vector_fp& nu) { int nsp = m_vsolvePtr->m_numSpeciesTot; @@ -1438,7 +1442,7 @@ namespace VCSnonideal { } } - + //==================================================================================================================== int vcs_MultiPhaseEquil::numComponents() const { int nc = -1; if (m_vsolvePtr) { @@ -1446,7 +1450,7 @@ namespace VCSnonideal { } return nc; } - + //==================================================================================================================== int vcs_MultiPhaseEquil::numElemConstraints() const { int nec = -1; if (m_vsolvePtr) { @@ -1455,11 +1459,180 @@ namespace VCSnonideal { return nec; } - + //==================================================================================================================== int vcs_MultiPhaseEquil::component(int m) const { int nc = numComponents(); if (m < nc) return m_vsolvePtr->m_speciesMapIndex[m]; else return -1; } + //==================================================================================================================== + // Determine the phase stability of a phase at the current conditions + /* + * Equilibration of the solution is not done before the determination is made. + * + * @param iph Phase number to determine the equilibrium. If the phase + * has a non-zero mole number.... + * + * @param funcStab Value of the phase pop function + * + * @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 loglevel Determines the amount of printing to the HTML + * output file. + */ + int vcs_MultiPhaseEquil::determine_PhaseStability(int iph, double &funcStab, int printLvl, int loglevel) { + + + clockWC tickTock; + int nsp = m_mix->nSpecies(); + int nel = m_mix->nElements(); + int nph = m_mix->nPhases(); + if (m_vprob == 0) { + m_vprob = new VCS_PROB(nsp, nel, nph); + } + m_printLvl = printLvl; + m_vprob->m_printLvl = printLvl; + + /* + * Extract the current state information + * from the MultiPhase object and + * Transfer it to VCS_PROB object. + */ + int res = vcs_Cantera_update_vprob(m_mix, m_vprob); + if (res != 0) { + plogf("problems\n"); + } + + + + // Check obvious bounds on the temperature and pressure + // NOTE, we may want to do more here with the real bounds + // given by the ThermoPhase objects. + double T = m_mix->temperature(); + if (T <= 0.0) { + throw CanteraError("vcs_MultiPhaseEquil::determine_PhaseStability", + "Temperature less than zero on input"); + } + double pres = m_mix->pressure(); + if (pres <= 0.0) { + throw CanteraError("vcs_MultiPhaseEquil::determine_PhaseStability", + "Pressure less than zero on input"); + } + + beginLogGroup("vcs_MultiPhaseEquil::determine_PhaseStability", loglevel); + addLogEntry("problem type", "fixed T,P"); + addLogEntry("Temperature", T); + addLogEntry("Pressure", pres); + + + /* + * Print out the problem specification from the point of + * view of the vprob object. + */ + m_vprob->prob_report(m_printLvl); + + /* + * Call the thermo Program + */ + int ip1 = m_printLvl; + if (m_printLvl >= 3) { + ip1 = m_printLvl - 2; + } else { + ip1 = 0; + } + if (!m_vsolvePtr) { + m_vsolvePtr = new VCS_SOLVE(); + } + int iStable = m_vsolvePtr->vcs_PS(m_vprob, iph, printLvl, funcStab); + + /* + * Transfer the information back to the MultiPhase object. + * Note we don't just call setMoles, because some multispecies + * solution phases may be zeroed out, and that would cause a problem + * for that routine. Also, the mole fractions of such zereod out + * phases actually contain information about likely reemergent + * states. + */ + m_mix->uploadMoleFractionsFromPhases(); + // for (int i = 0; i < m_vprob->nspecies; i++) { + // plogf("%d %15.3e\n", m_vprob->m_gibbsSpecies[i]); + //} + m_mix->getChemPotentials(DATA_PTR(m_vprob->m_gibbsSpecies)); + //for (int i = 0; i < m_vprob->nspecies; i++) { + // plogf("%d %15.3e\n", m_vprob->m_gibbsSpecies[i]); + //} + + double te = tickTock.secondsWC(); + if (printLvl > 0) { + plogf("\n Results from vcs_PS:\n"); + + plogf("\n"); + plogf("Temperature = %g Kelvin\n", m_vprob->T); + plogf("Pressure = %g Pa\n", m_vprob->PresPA); + std::string sss = m_mix->phaseName(iph); + if (iStable) { + plogf("Phase %d named %s is stable, function value = %g > 0\n", iph, sss.c_str(), funcStab); + } else { + plogf("Phase %d named %s is not stable + function value = %g < 0\n", iph, sss.c_str(), funcStab); + } + plogf("\n"); + plogf("----------------------------------------" + "---------------------\n"); + plogf(" Name Mole_Number"); + if (m_vprob->m_VCS_UnitsFormat == VCS_UNITS_MKS) { + plogf("(kmol)"); + } else { + plogf("(gmol)"); + } + plogf(" Mole_Fraction Chem_Potential"); + if (m_vprob->m_VCS_UnitsFormat == VCS_UNITS_KCALMOL) + plogf(" (kcal/mol)\n"); + else if (m_vprob->m_VCS_UnitsFormat == VCS_UNITS_UNITLESS) + plogf(" (Dimensionless)\n"); + else if (m_vprob->m_VCS_UnitsFormat == VCS_UNITS_KJMOL) + plogf(" (kJ/mol)\n"); + else if (m_vprob->m_VCS_UnitsFormat == VCS_UNITS_KELVIN) + plogf(" (Kelvin)\n"); + else if (m_vprob->m_VCS_UnitsFormat == VCS_UNITS_MKS) + plogf(" (J/kmol)\n"); + plogf("-------------------------------------------------------------\n"); + for (int i = 0; i < m_vprob->nspecies; i++) { + plogf("%-12s", m_vprob->SpName[i].c_str()); + if (m_vprob->SpeciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf(" %15.3e %15.3e ", 0.0, m_vprob->mf[i]); + plogf("%15.3e\n", m_vprob->m_gibbsSpecies[i]); + } else { + plogf(" %15.3e %15.3e ", m_vprob->w[i], m_vprob->mf[i]); + if (m_vprob->w[i] <= 0.0) { + int iph = m_vprob->PhaseID[i]; + vcs_VolPhase *VPhase = m_vprob->VPhaseList[iph]; + //if (VPhase->nSpecies() > 1) { + // plogf(" -1.000e+300\n"); + //} else { + plogf("%15.3e\n", m_vprob->m_gibbsSpecies[i]); + //} + } else { + plogf("%15.3e\n", m_vprob->m_gibbsSpecies[i]); + } + } + } + plogf("------------------------------------------" + "-------------------\n"); + if (printLvl > 2) { + if (m_vsolvePtr->m_timing_print_lvl > 0) { + plogf("Total time = %12.6e seconds\n", te); + } + } + } + if (loglevel > 0) { + endLogGroup(); + } + return iStable; + } +//==================================================================================================================== + } diff --git a/Cantera/src/equil/vcs_MultiPhaseEquil.h b/Cantera/src/equil/vcs_MultiPhaseEquil.h index 3b35973a4..bba5f4d1e 100644 --- a/Cantera/src/equil/vcs_MultiPhaseEquil.h +++ b/Cantera/src/equil/vcs_MultiPhaseEquil.h @@ -15,7 +15,7 @@ #include "ct_defs.h" #include "MultiPhase.h" - +#include "vcs_defs.h" namespace Cantera { @@ -81,7 +81,7 @@ namespace Cantera { int vcs_equilibrate(thermo_t& s, const char* XY, int estimateEquil = 0, int printLvl = 0, int solver = -1, doublereal rtol = 1.0e-9, - int maxsteps = 5000, + int maxsteps = VCS_MAXSTEPS, int maxiter = 100, int loglevel = -99); @@ -142,7 +142,7 @@ namespace Cantera { int vcs_equilibrate(MultiPhase& s, const char* XY, int estimateEquil = 0, int printLvl = 0, int solver = 2, - doublereal rtol = 1.0e-9, int maxsteps = 5000, + doublereal rtol = 1.0e-9, int maxsteps = VCS_MAXSTEPS, int maxiter = 100, int loglevel = -99); //! Set a multi-phase chemical solution to chemical equilibrium. @@ -154,7 +154,7 @@ namespace Cantera { * 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 s The MultiPhase object to be set to an equilibrium state * * @param ixy An integer specifying the two properties to be held * constant. @@ -202,9 +202,33 @@ namespace Cantera { int vcs_equilibrate_1(MultiPhase& s, int ixy, int estimateEquil = 0, int printLvl = 0, int solver = 2, - doublereal rtol = 1.0e-9, int maxsteps = 5000, + doublereal rtol = 1.0e-9, int maxsteps = VCS_MAXSTEPS, int maxiter = 100, int loglevel = -99); + //! Determine the phase stability of a single phase given the current conditions + //! in a MultiPhase object + /*! + * + * @param s The MultiPhase object to be set to an equilibrium state + * @param iphase Phase index within the multiphase object to be + * tested for stability. + * @param funcStab Function value that tests equilibrium. > 0 indicates stable + * < 0 indicates unstable + * + * @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 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_determine_PhaseStability(MultiPhase& s, int iphase, + double &funcStab, int printLvl, int loglevel); + } namespace VCSnonideal { @@ -355,7 +379,7 @@ namespace VCSnonideal { */ int equilibrate(int XY, int estimateEquil = 0, int printLvl= 0, doublereal err = 1.0e-6, - int maxsteps = 5000, int loglevel=-99); + int maxsteps = VCS_MAXSTEPS, int loglevel=-99); //! Equilibrate the solution using the current element abundances //! storred in the MultiPhase object using constant T and P @@ -385,7 +409,7 @@ namespace VCSnonideal { */ int equilibrate_TP(int estimateEquil = 0, int printLvl= 0, doublereal err = 1.0e-6, - int maxsteps = 5000, int loglevel=-99); + int maxsteps = VCS_MAXSTEPS, int loglevel=-99); //! Equilibrate the solution using the current element abundances //! storred in the MultiPhase object using either constant H and P @@ -439,7 +463,7 @@ namespace VCSnonideal { int equilibrate_HP(doublereal Htarget, int XY, double Tlow, double Thigh, int estimateEquil = 0, int printLvl = 0, doublereal err = 1.0E-6, - int maxsteps = 5000, int loglevel=-99); + int maxsteps = VCS_MAXSTEPS, int loglevel=-99); //! Equilibrate the solution using the current element abundances //! storred in the MultiPhase object using constant S and P. @@ -490,7 +514,7 @@ namespace VCSnonideal { int equilibrate_SP(doublereal Starget, double Tlow, double Thigh, int estimateEquil = 0, int printLvl = 0, doublereal err = 1.0E-6, - int maxsteps = 5000, int loglevel=-99); + int maxsteps = VCS_MAXSTEPS, int loglevel=-99); //! Equilibrate the solution using the current element abundances @@ -532,13 +556,28 @@ namespace VCSnonideal { * * @param maxsteps max steps allowed. * - * @param loglevel Determines the amount of printing to the HTML + * @param logLevel Determines the amount of printing to the HTML * output file. */ int equilibrate_TV(int XY, doublereal xtarget, int estimateEquil = 0, int printLvl = 0, doublereal err = 1.0E-6, - int maxsteps = 5000, int loglevel = -99); + int maxsteps = VCS_MAXSTEPS, int logLevel = -99); + + //! Determine the phase stability of a phase at the current conditions + /*! + * Equilibration of the solution is not done before the determination is made. + * + * @param iph Phase number to determine the equilibrium. If the phase + * has a non-zero mole number.... + * @param funcStab Value of the phase pop function + * @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 logLevel Determines the amount of printing to the HTML output file. + */ + int determine_PhaseStability(int iph, double &funcStab, int printLvl= 0, int logLevel = -99); //! Report the equilibrium answer in a comma separated table format /*! @@ -563,6 +602,8 @@ namespace VCSnonideal { */ int numElemConstraints() const; + + // Friend functions friend int vcs_Cantera_to_vprob(Cantera::MultiPhase *mphase, @@ -638,13 +679,21 @@ namespace VCSnonideal { //! Pointer to the object that does all of the equilibration work. /*! * VCS_SOLVE will have different ordering for species and element constraints - * than this object or the VCS_PROB object. - * This object owns the pointer. + * than this object or the VCS_PROB object. This object owns the pointer. */ VCSnonideal::VCS_SOLVE *m_vsolvePtr; + }; + //! Global hook for turning on and off time printing. + /*! + * Default is to allow printing. But, you can assign this to zero + * globally to turn off all time printing. + * This is helpful for test suite purposes where you are interested + * in differences in text files. + */ + extern int vcs_timing_print_lvl; + } - - #endif + diff --git a/Cantera/src/equil/vcs_VolPhase.cpp b/Cantera/src/equil/vcs_VolPhase.cpp index 760f919ff..87ca0124c 100644 --- a/Cantera/src/equil/vcs_VolPhase.cpp +++ b/Cantera/src/equil/vcs_VolPhase.cpp @@ -32,7 +32,7 @@ namespace VCSnonideal { */ vcs_VolPhase::vcs_VolPhase(VCS_SOLVE * owningSolverObject) : m_owningSolverObject(0), - VP_ID(-1), + VP_ID_(-1), Domain_ID(-1), m_singleSpecies(true), m_gasPhase(false), @@ -51,6 +51,8 @@ namespace VCSnonideal { m_useCanteraCalls(false), TP_ptr(0), v_totalMoles(0.0), + creationMoleNumbers_(0), + creationGlobalRxnNumbers_(0), m_phiVarIndex(-1), m_totalVol(0.0), m_vcsStateStatus(VCS_STATECALC_OLD), @@ -61,9 +63,8 @@ namespace VCSnonideal { m_UpToDate_VolPM(false), m_UpToDate_GStar(false), m_UpToDate_G0(false), - Temp(273.15), - Pres(1.01325E5), - RefPres(1.01325E5) + Temp_(273.15), + Pres_(1.01325E5) { m_owningSolverObject = owningSolverObject; } @@ -94,7 +95,7 @@ namespace VCSnonideal { */ vcs_VolPhase::vcs_VolPhase(const vcs_VolPhase& b) : m_owningSolverObject(b.m_owningSolverObject), - VP_ID(b.VP_ID), + VP_ID_(b.VP_ID_), Domain_ID(b.Domain_ID), m_singleSpecies(b.m_singleSpecies), m_gasPhase(b.m_gasPhase), @@ -110,7 +111,9 @@ namespace VCSnonideal { m_MFStartIndex(b.m_MFStartIndex), m_useCanteraCalls(b.m_useCanteraCalls), TP_ptr(b.TP_ptr), - v_totalMoles(b.v_totalMoles), + v_totalMoles(b.v_totalMoles), + creationMoleNumbers_(0), + creationGlobalRxnNumbers_(0), m_phiVarIndex(-1), m_totalVol(b.m_totalVol), m_vcsStateStatus(VCS_STATECALC_OLD), @@ -121,8 +124,8 @@ namespace VCSnonideal { m_UpToDate_VolPM(false), m_UpToDate_GStar(false), m_UpToDate_G0(false), - Temp(b.Temp), - Pres(b.Pres) + Temp_(b.Temp_), + Pres_(b.Pres_) { /* * Call the Assignment operator to do the heavy @@ -147,42 +150,35 @@ namespace VCSnonideal { // operator but is true for a copy constructor // m_owningSolverObject = b.m_owningSolverObject; - VP_ID = b.VP_ID; + VP_ID_ = b.VP_ID_; Domain_ID = b.Domain_ID; m_singleSpecies = b.m_singleSpecies; m_gasPhase = b.m_gasPhase; m_eqnState = b.m_eqnState; - - m_numSpecies = b.m_numSpecies; - m_numElemConstraints = b.m_numElemConstraints; ChargeNeutralityElement = b.ChargeNeutralityElement; - - + p_VCS_UnitsFormat = b.p_VCS_UnitsFormat; + p_activityConvention= b.p_activityConvention; + m_numElemConstraints = b.m_numElemConstraints; m_elementNames.resize(b.m_numElemConstraints); for (int e = 0; e < b.m_numElemConstraints; e++) { m_elementNames[e] = b.m_elementNames[e]; } - m_elementActive = b.m_elementActive; m_elementType = b.m_elementType; - m_formulaMatrix.resize(m_numElemConstraints, m_numSpecies, 0.0); for (int e = 0; e < m_numElemConstraints; e++) { for (int k = 0; k < m_numSpecies; k++) { m_formulaMatrix[e][k] = b.m_formulaMatrix[e][k]; } } - m_speciesUnknownType = b.m_speciesUnknownType; m_elemGlobalIndex = b.m_elemGlobalIndex; m_numSpecies = b.m_numSpecies; PhaseName = b.PhaseName; m_totalMolesInert = b.m_totalMolesInert; - p_activityConvention= b.p_activityConvention; m_isIdealSoln = b.m_isIdealSoln; m_existence = b.m_existence; m_MFStartIndex = b.m_MFStartIndex; - /* * Do a shallow copy because we haven' figured this out. */ @@ -200,8 +196,6 @@ namespace VCSnonideal { ListSpeciesPtr[k] = new vcs_SpeciesProperties(*(b.ListSpeciesPtr[k])); } - - p_VCS_UnitsFormat = b.p_VCS_UnitsFormat; m_useCanteraCalls = b.m_useCanteraCalls; /* * Do a shallow copy of the ThermoPhase object pointer. @@ -212,32 +206,29 @@ namespace VCSnonideal { */ TP_ptr = b.TP_ptr; v_totalMoles = b.v_totalMoles; - - Xmol = b.Xmol; - fractionCreationDelta_ = b.fractionCreationDelta_; - - m_phi = b.m_phi; + Xmol_ = b.Xmol_; + creationMoleNumbers_ = b.creationMoleNumbers_; + creationGlobalRxnNumbers_ = b.creationGlobalRxnNumbers_; m_phiVarIndex = b.m_phiVarIndex; - + m_totalVol = b.m_totalVol; SS0ChemicalPotential = b.SS0ChemicalPotential; StarChemicalPotential = b.StarChemicalPotential; - StarMolarVol = b.StarMolarVol; PartialMolarVol = b.PartialMolarVol; ActCoeff = b.ActCoeff; - dLnActCoeffdMolNumber = b.dLnActCoeffdMolNumber; - - m_UpToDate = false; m_vcsStateStatus = b.m_vcsStateStatus; + m_phi = b.m_phi; + m_UpToDate = false; m_UpToDate_AC = false; m_UpToDate_VolStar = false; m_UpToDate_VolPM = false; m_UpToDate_GStar = false; m_UpToDate_G0 = false; - Temp = b.Temp; - Pres = b.Pres; - setState_TP(Temp, Pres); + Temp_ = b.Temp_; + Pres_ = b.Pres_; + + setState_TP(Temp_, Pres_); _updateMoleFractionDependencies(); } return *this; @@ -261,17 +252,17 @@ namespace VCSnonideal { m_phi = 0.0; m_phiVarIndex = -1; - if (phaseNum == VP_ID) { + if (phaseNum == VP_ID_) { if (strcmp(PhaseName.c_str(), phaseName)) { plogf("Strings are different: %s %s :unknown situation\n", PhaseName.c_str(), phaseName); exit(EXIT_FAILURE); } } else { - VP_ID = phaseNum; + VP_ID_ = phaseNum; if (!phaseName) { char itmp[40]; - sprintf(itmp, "Phase_%d", VP_ID); + sprintf(itmp, "Phase_%d", VP_ID_); PhaseName = itmp; } else { PhaseName = phaseName; @@ -308,11 +299,13 @@ namespace VCSnonideal { ListSpeciesPtr[i] = new vcs_SpeciesProperties(phaseNum, i, this); } - Xmol.resize(nspecies, 0.0); - fractionCreationDelta_.resize(nspecies, 0.0); + Xmol_.resize(nspecies, 0.0); + creationMoleNumbers_.resize(nspecies, 0.0); + creationGlobalRxnNumbers_.resize(nspecies, -1); for (int i = 0; i < nspecies; i++) { - Xmol[i] = 1.0/nspecies; - fractionCreationDelta_[i] = 1.0/nspecies; + Xmol_[i] = 1.0/nspecies; + creationMoleNumbers_[i] = 1.0/nspecies; + creationGlobalRxnNumbers_[i] = IndSpecies[i] - m_numElemConstraints; } SS0ChemicalPotential.resize(nspecies, -1.0); @@ -401,7 +394,7 @@ namespace VCSnonideal { vcs_SpeciesProperties *sProp = ListSpeciesPtr[k]; VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo; SS0ChemicalPotential[k] = - R * (sTherm->G0_R_calc(kglob, Temp)); + R * (sTherm->G0_R_calc(kglob, Temp_)); } } m_UpToDate_G0 = true; @@ -442,7 +435,7 @@ namespace VCSnonideal { vcs_SpeciesProperties *sProp = ListSpeciesPtr[k]; VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo; StarChemicalPotential[k] = - R * (sTherm->GStar_R_calc(kglob, Temp, Pres)); + R * (sTherm->GStar_R_calc(kglob, Temp_, Pres_)); } } m_UpToDate_GStar = true; @@ -478,12 +471,12 @@ namespace VCSnonideal { void vcs_VolPhase::setMoleFractions(const double * const xmol) { double sum = -1.0; for (int k = 0; k < m_numSpecies; k++) { - Xmol[k] = xmol[k]; + Xmol_[k] = xmol[k]; sum+= xmol[k]; } if (std::fabs(sum) > 1.0E-13) { for (int k = 0; k < m_numSpecies; k++) { - Xmol[k] /= sum; + Xmol_[k] /= sum; } } _updateMoleFractionDependencies(); @@ -500,7 +493,7 @@ namespace VCSnonideal { void vcs_VolPhase::_updateMoleFractionDependencies() { if (m_useCanteraCalls) { if (TP_ptr) { - TP_ptr->setState_PX(Pres, &(Xmol[m_MFStartIndex])); + TP_ptr->setState_PX(Pres_, &(Xmol_[m_MFStartIndex])); } } if (!m_isIdealSoln) { @@ -512,7 +505,11 @@ namespace VCSnonideal { // Return a const reference to the mole fraction vector in the phase const std::vector & vcs_VolPhase::moleFractions() const { - return Xmol; + return Xmol_; + } + + double vcs_VolPhase::moleFraction(int k) const { + return Xmol_[k]; } /***************************************************************************/ @@ -546,19 +543,28 @@ namespace VCSnonideal { m_existence = VCS_PHASE_EXIST_NO; } } + double fractotal = 1.0; v_totalMoles = totalMoles; + if (m_totalMolesInert > 0.0) { + if (m_totalMolesInert > v_totalMoles) { + printf("vcs_VolPhase::setMolesFractionsState: inerts greater than total: %g %g\n", + v_totalMoles, m_totalMolesInert); + exit(EXIT_FAILURE); + } + fractotal = 1.0 - m_totalMolesInert/v_totalMoles; + } double sum = 0.0; for (int k = 0; k < m_numSpecies; k++) { - Xmol[k] = moleFractions[k]; + Xmol_[k] = moleFractions[k]; sum += moleFractions[k]; } if (sum == 0.0) { printf("vcs_VolPhase::setMolesFractionsState: inappropriate usage\n"); exit(EXIT_FAILURE); } - if (sum != 1.0) { + if (sum != fractotal) { for (int k = 0; k < m_numSpecies; k++) { - Xmol[k] /= sum; + Xmol_[k] *= (fractotal /sum); } } _updateMoleFractionDependencies(); @@ -633,7 +639,7 @@ namespace VCSnonideal { if (m_speciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { kglob = IndSpecies[k]; tmp = MAX(0.0, molesSpeciesVCS[kglob]); - Xmol[k] = tmp / v_totalMoles; + Xmol_[k] = tmp / v_totalMoles; } } m_existence = VCS_PHASE_EXIST_YES; @@ -642,7 +648,7 @@ namespace VCSnonideal { // for the mole fractions, when the phase doesn't exist. // This is currently unimplemented. //for (int k = 0; k < m_numSpecies; k++) { - // Xmol[k] = 1.0 / m_numSpecies; + // Xmol_[k] = 1.0 / m_numSpecies; //} m_existence = VCS_PHASE_EXIST_NO; } @@ -653,9 +659,9 @@ namespace VCSnonideal { if (m_phiVarIndex >= 0) { kglob = IndSpecies[m_phiVarIndex]; if (m_numSpecies == 1) { - Xmol[m_phiVarIndex] = 1.0; + Xmol_[m_phiVarIndex] = 1.0; } else { - Xmol[m_phiVarIndex] = 0.0; + Xmol_[m_phiVarIndex] = 0.0; } double phi = molesSpeciesVCS[kglob]; setElectricPotential(phi); @@ -675,7 +681,8 @@ namespace VCSnonideal { */ if (stateCalc == VCS_STATECALC_OLD) { if (v_totalMoles > 0.0) { - fractionCreationDelta_ = Xmol; + vcs_dcopy(VCS_DATA_PTR(creationMoleNumbers_), VCS_DATA_PTR(Xmol_), m_numSpecies); + } } @@ -711,7 +718,7 @@ namespace VCSnonideal { /* * Check for consistency with TPhMoles[] */ - double Tcheck = TPhMoles[VP_ID]; + double Tcheck = TPhMoles[VP_ID_]; if (Tcheck != v_totalMoles) { if (vcs_doubleEqual(Tcheck, v_totalMoles)) { Tcheck = v_totalMoles; @@ -848,8 +855,8 @@ namespace VCSnonideal { */ void vcs_VolPhase::setState_TP(const double temp, const double pres) { - if (Temp == temp) { - if (Pres == pres) { + if (Temp_ == temp) { + if (Pres_ == pres) { return; } } @@ -857,8 +864,8 @@ namespace VCSnonideal { TP_ptr->setElectricPotential(m_phi); TP_ptr->setState_TP(temp, pres); } - Temp = temp; - Pres = pres; + Temp_ = temp; + Pres_ = pres; m_UpToDate_AC = false; m_UpToDate_VolStar = false; m_UpToDate_VolPM = false; @@ -877,7 +884,7 @@ namespace VCSnonideal { * @param temperature_Kelvin (Kelvin) */ void vcs_VolPhase::setState_T(const double temp) { - setState_TP(temp, Pres); + setState_TP(temp, Pres_); } /***************************************************************************/ @@ -899,7 +906,7 @@ namespace VCSnonideal { int kglob = IndSpecies[k]; vcs_SpeciesProperties *sProp = ListSpeciesPtr[k]; VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo; - StarMolarVol[k] = (sTherm->VolStar_calc(kglob, Temp, Pres)); + StarMolarVol[k] = (sTherm->VolStar_calc(kglob, Temp_, Pres_)); } } m_UpToDate_VolStar = true; @@ -944,7 +951,7 @@ namespace VCSnonideal { kglob = IndSpecies[k]; vcs_SpeciesProperties *sProp = ListSpeciesPtr[k]; VCS_SPECIES_THERMO *sTherm = sProp->SpeciesThermo; - StarMolarVol[k] = (sTherm->VolStar_calc(kglob, Temp, Pres)); + StarMolarVol[k] = (sTherm->VolStar_calc(kglob, Temp_, Pres_)); } for (k = 0; k < m_numSpecies; k++) { PartialMolarVol[k] = StarMolarVol[k]; @@ -953,13 +960,13 @@ namespace VCSnonideal { m_totalVol = 0.0; for (k = 0; k < m_numSpecies; k++) { - m_totalVol += PartialMolarVol[k] * Xmol[k]; + m_totalVol += PartialMolarVol[k] * Xmol_[k]; } m_totalVol *= v_totalMoles; if (m_totalMolesInert > 0.0) { if (m_gasPhase) { - double volI = m_totalMolesInert * 8314.47215 * Temp / Pres; + double volI = m_totalMolesInert * 8314.47215 * Temp_ / Pres_; m_totalVol += volI; } else { printf("unknown situation\n"); @@ -977,18 +984,33 @@ namespace VCSnonideal { */ void vcs_VolPhase::_updateLnActCoeffJac() { int k, j; - double deltaMoles_j = 0.0; - + /* * Evaluate the current base activity coefficients if necessary */ if (!m_UpToDate_AC) { _updateActCoeff(); } +#ifndef NOOLD + if (!TP_ptr) return; + TP_ptr->getdlnActCoeffdlnN(m_numSpecies, &dLnActCoeffdMolNumber[0][0]); + for (j = 0; j < m_numSpecies; j++) { + double moles_j_base = v_totalMoles * Xmol_[j]; + double * const lnActCoeffCol = dLnActCoeffdMolNumber[j]; + if (moles_j_base < 1.0E-200) { + moles_j_base = 1.0E-7 * moles_j_base + 1.0E-20 * v_totalMoles + 1.0E-150; + } + for (k = 0; k < m_numSpecies; k++) { + lnActCoeffCol[k] /= moles_j_base; + } + } +#endif - // Make copies of ActCoeff and Xmol for use in taking differences + + double deltaMoles_j = 0.0; + // Make copies of ActCoeff and Xmol_ for use in taking differences std::vector ActCoeff_Base(ActCoeff); - std::vector Xmol_Base(Xmol); + std::vector Xmol_Base(Xmol_); double TMoles_base = v_totalMoles; /* @@ -997,20 +1019,20 @@ namespace VCSnonideal { for (j = 0; j < m_numSpecies; j++) { /* * Calculate a value for the delta moles of species j - * -> NOte Xmol[] and Tmoles are always positive or zero + * -> NOte Xmol_[] and Tmoles are always positive or zero * quantities. */ double moles_j_base = v_totalMoles * Xmol_Base[j]; - deltaMoles_j = 1.0E-7 * moles_j_base + 1.0E-20 * v_totalMoles + 1.0E-150; + deltaMoles_j = 1.0E-7 * moles_j_base + 1.0E-13 * v_totalMoles + 1.0E-150; /* * Now, update the total moles in the phase and all of the * mole fractions based on this. */ v_totalMoles = TMoles_base + deltaMoles_j; for (k = 0; k < m_numSpecies; k++) { - Xmol[k] = Xmol_Base[k] * TMoles_base / v_totalMoles; + Xmol_[k] = Xmol_Base[k] * TMoles_base / v_totalMoles; } - Xmol[j] = (moles_j_base + deltaMoles_j) / v_totalMoles; + Xmol_[j] = (moles_j_base + deltaMoles_j) / v_totalMoles; /* * Go get new values for the activity coefficients. @@ -1023,14 +1045,21 @@ namespace VCSnonideal { */ double * const lnActCoeffCol = dLnActCoeffdMolNumber[j]; for (k = 0; k < m_numSpecies; k++) { - lnActCoeffCol[k] = (ActCoeff[k] - ActCoeff_Base[k]) / + double tmp; + tmp = (ActCoeff[k] - ActCoeff_Base[k]) / ((ActCoeff[k] + ActCoeff_Base[k]) * 0.5 * deltaMoles_j); + if (fabs(tmp - lnActCoeffCol[k]) > 1.0E-4 * fabs(tmp) + fabs(lnActCoeffCol[k])) { + // printf(" we have an error\n"); + + } + //tmp = lnActCoeffCol[k]; + } /* - * Revert to the base case Xmol, v_totalMoles + * Revert to the base case Xmol_, v_totalMoles */ v_totalMoles = TMoles_base; - vcs_vdcopy(Xmol, Xmol_Base, m_numSpecies); + vcs_vdcopy(Xmol_, Xmol_Base, m_numSpecies); } /* * Go get base values for the activity coefficients. @@ -1041,6 +1070,7 @@ namespace VCSnonideal { setMoleFractions(VCS_DATA_PTR(Xmol_Base)); _updateMoleFractionDependencies(); _updateActCoeff(); + } /***************************************************************************/ @@ -1093,9 +1123,9 @@ namespace VCSnonideal { TP_ptr = tp_ptr; if (TP_ptr) { m_useCanteraCalls = true; - Temp = TP_ptr->temperature(); - Pres = TP_ptr->pressure(); - setState_TP(Temp, Pres); + Temp_ = TP_ptr->temperature(); + Pres_ = TP_ptr->pressure(); + setState_TP(Temp_, Pres_); p_VCS_UnitsFormat = VCS_UNITS_MKS; m_phi = TP_ptr->electricPotential(); int nsp = TP_ptr->nSpecies(); @@ -1104,10 +1134,10 @@ namespace VCSnonideal { if (m_numSpecies != 0) { plogf("Warning Nsp != NVolSpeces: %d %d \n", nsp, m_numSpecies); } - resize(VP_ID, nsp, nelem, PhaseName.c_str()); + resize(VP_ID_, nsp, nelem, PhaseName.c_str()); } - TP_ptr->getMoleFractions(VCS_DATA_PTR(Xmol)); - fractionCreationDelta_ = Xmol; + TP_ptr->getMoleFractions(VCS_DATA_PTR(Xmol_)); + vcs_dcopy(VCS_DATA_PTR(creationMoleNumbers_), VCS_DATA_PTR(Xmol_), m_numSpecies); _updateMoleFractionDependencies(); /* @@ -1155,20 +1185,22 @@ namespace VCSnonideal { /***************************************************************************/ double vcs_VolPhase::molefraction(int k) const { - return Xmol[k]; + return Xmol_[k]; } /***************************************************************************/ - void vcs_VolPhase::setFractionCreationDeltas(const double * const F_k) { - for (int k = 0; k < m_numSpecies; k++) { - fractionCreationDelta_[k] = F_k[k]; - } + void vcs_VolPhase::setCreationMoleNumbers(const double * const n_k, + const std::vector &creationGlobalRxnNumbers) { + vcs_dcopy(VCS_DATA_PTR(creationMoleNumbers_), n_k, m_numSpecies); + vcs_icopy(VCS_DATA_PTR(creationGlobalRxnNumbers_), VCS_DATA_PTR(creationGlobalRxnNumbers), m_numSpecies); } /***************************************************************************/ - const std::vector & vcs_VolPhase::fractionCreationDeltas() const { - return fractionCreationDelta_; + const std::vector & vcs_VolPhase::creationMoleNumbers(std::vector &creationGlobalRxnNumbers) const { + creationGlobalRxnNumbers = creationGlobalRxnNumbers_; + return creationMoleNumbers_; } + /***************************************************************************/ // Sets the total moles in the phase @@ -1378,9 +1410,11 @@ namespace VCSnonideal { * @return Returns the VCS_SOLVE species index of the that species * This changes as rearrangements are carried out. */ - void vcs_VolPhase::setSpGlobalIndexVCS(const int spIndex, - const int spGlobalIndex) { + void vcs_VolPhase::setSpGlobalIndexVCS(const int spIndex, const int spGlobalIndex) { IndSpecies[spIndex] = spGlobalIndex; + if (spGlobalIndex >= m_numElemConstraints) { + creationGlobalRxnNumbers_[spIndex] = spGlobalIndex - m_numElemConstraints; + } } /**********************************************************************/ @@ -1560,6 +1594,7 @@ namespace VCSnonideal { for (eT = 0; eT < nebase; eT++) { ename = tPhase->elementName(eT); m_elementNames[e] = ename; + m_elementType[e] = tPhase->elementType(eT); e++; } @@ -1567,7 +1602,7 @@ namespace VCSnonideal { std::string pname = tPhase->id(); if (pname == "") { char sss[50]; - sprintf(sss, "phase%d", VP_ID); + sprintf(sss, "phase%d", VP_ID_); pname = sss; } ename = "cn_" + pname; diff --git a/Cantera/src/equil/vcs_VolPhase.h b/Cantera/src/equil/vcs_VolPhase.h index 808558a16..15cd25d3c 100644 --- a/Cantera/src/equil/vcs_VolPhase.h +++ b/Cantera/src/equil/vcs_VolPhase.h @@ -419,15 +419,19 @@ namespace VCSnonideal { //! object. const std::vector & moleFractions() const; - //! Sets the fractionCreationDelta's within the phase object - /*! - * @param F_k Pointer to a vector of F_k's - */ - void setFractionCreationDeltas( const double * const F_k); + double moleFraction(int klocal) const; - //! Return a const reference to the fractionCreationDeltas storred in the - //! object. - const std::vector & fractionCreationDeltas() const; + //! Sets the creationMoleNum's within the phase object + /*! + * @param F_k Pointer to a vector of n_k's + */ + void setCreationMoleNumbers(const double * const n_k, const std::vector &creationGlobalRxnNumbers); + + //! Return a const reference to the creationMoleNumbers storred in the object. + /*! + * @return Returns a const reference to the vector of creationMoleNumbers + */ + const std::vector & creationMoleNumbers(std::vector &creationGlobalRxnNumbers) const; //! Returns whether the phase is an ideal solution phase bool isIdealSoln() const; @@ -673,7 +677,7 @@ namespace VCSnonideal { * miscibility gap, these numbers will stay the * same after the split. */ - int VP_ID; + int VP_ID_; //! ID of the surface or volume domain in which the //! this phase exists @@ -871,15 +875,28 @@ namespace VCSnonideal { //! Vector of the current mole fractions for species //! in the phase - std::vector Xmol; + std::vector Xmol_; - //! Vector of current fractionalCreationDeltas + //! Vector of current creationMoleNumbers_ /*! - * These are the actual unknowns in the problem + * These are the actual unknowns in the phase stability problem */ - std::vector fractionCreationDelta_; + std::vector creationMoleNumbers_; - + //! Vector of creation global reaction numbers for the phase stability problem + /*! + * The phase stability problem requires a global reaction number for each + * species in the phase. Usually this is the krxn = kglob - M for species + * in the phase that are not components. For component species, the + * choice of the reaction is one which maximimes the chance that the phase + * pops into (or remains in) existence. + * The index here is the local phase species index. + * the value of the variable is the global vcs reaction number. Note, + * that the global reaction number will go out of order when the species positions + * are swapped. So, this number has to be recalculated. + */ + std::vector creationGlobalRxnNumbers_; + //! 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; @@ -998,13 +1015,12 @@ namespace VCSnonideal { mutable bool m_UpToDate_G0; //! Current value of the temperature for this object, and underlying objects - double Temp; + double Temp_; //! Current value of the pressure for this object, and underlying objects - double Pres; + double Pres_; - //! Reference pressure for the phase - double RefPres; + }; diff --git a/Cantera/src/equil/vcs_defs.h b/Cantera/src/equil/vcs_defs.h index 056859ff6..2c50ffaa1 100644 --- a/Cantera/src/equil/vcs_defs.h +++ b/Cantera/src/equil/vcs_defs.h @@ -78,7 +78,8 @@ namespace VCSnonideal { /*! * @name Sizes of Phases and Cutoff Mole Numbers - * + * + * All size parameters are listed here * @{ */ @@ -103,14 +104,27 @@ namespace VCSnonideal { //! 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-12 +#define VCS_DELETE_PHASE_CUTOFF 1.0e-13 #endif + //! Relative mole number of species in a phase that is created + //! We want this to be comfortably larger than the VCS_DELETE_PHASE_CUTOFF value + //! so that the phase can have a chance to survive. +#ifndef VCS_POP_PHASE_MOLENUM +#define VCS_POP_PHASE_MOLENUM 1.0e-11 +#endif + + //! Cutoff moles below which a phase or species which //! comprises the bulk of an element's total concentration //! is deleted. #ifndef VCS_DELETE_ELEMENTABS_CUTOFF #define VCS_DELETE_ELEMENTABS_CUTOFF 1.0e-280 +#endif + + //! Maximum steps in the inner loop +#ifndef VCS_MAXSTEPS +#define VCS_MAXSTEPS 50000 #endif //@} @@ -132,7 +146,16 @@ namespace VCSnonideal { * These defines are valid values for spStatus() */ //@{ - //! Species is a component + + //! Species is a component which can never be nonzero because of a + //! stoichiometric constraint + /*! + * An example of this would be a species that contains Ni. But, + * the amount of Ni elements is exactly zero. + */ +#define VCS_SPECIES_COMPONENT_STOICHZERO 3 + + //! Species is a component which can be nonzero #define VCS_SPECIES_COMPONENT 2 //! Species is a major species @@ -209,10 +232,11 @@ namespace VCSnonideal { //! Species lies in a multicomponent phase that is active, //! but species concentration is zero due to stoich constraint /*! - * The species lies in a multicomponent phase which - * currently does exist. Its concentration is currently - * identically zero, though the phase exists. This is - * a permament condition due to stoich constraints + * The species lies in a multicomponent phase which currently does exist. Its concentration is currently + * identically zero, though the phase exists. This is a permament condition due to stoich constraints. + * + * An example of this would be a species that contains Ni. But, + * the amount of Ni elements in the current problem statement is exactly zero. */ #define VCS_SPECIES_STOICHZERO -8 @@ -290,6 +314,11 @@ namespace VCSnonideal { * constraint to one category. * @{ */ + + + //! An element constraint that is current turned off +#define VCS_ELEM_TYPE_TURNEDOFF -1 + //! Normal element constraint consisting of positive coefficients for the //! formula matrix. /*! @@ -311,11 +340,37 @@ namespace VCSnonideal { */ #define VCS_ELEM_TYPE_CHARGENEUTRALITY 2 + //! Constraint associated with maintaing a fixed lattice stoichiometry int eh + //! solids + /*! + * The constraint may have positive or negative values. The lattice 0 species will + * have negative values while higher lattices will have positive values + */ +#define VCS_ELEM_TYPE_LATTICERATIO 3 + + //! Constraint associated with maintaining frozen kinetic equilibria in + //! some functional groups within molecules + /*! + * We seek here to say that some functional groups or ionic states should be + * treated as if they are separate elements given the time scale of the problem. + * This will be abs positive constraint. We have not implemented any examples yet. + * A requirement will be that we must be able to add and subtract these contraints. + */ +#define VCS_ELEM_TYPE_KINETICFROZEN 4 + + //! Constraint associated with the maintenance of a surface phase + /*! + * We don't have any examples of this yet either. However, surfaces only exist + * because they are interfaces between bulk layers. If we want to treat surfaces + * within thermodynamic systems we must come up with a way to constrain their total + * number. + */ +#define VCS_ELEM_TYPE_SURFACECONSTRAINT 5 //! Other constraint equations /*! * currently there are none */ -#define VCS_ELEM_TYPE_OTHERCONSTRAINT 3 +#define VCS_ELEM_TYPE_OTHERCONSTRAINT 6 //@} /*! diff --git a/Cantera/src/equil/vcs_equilibrate.cpp b/Cantera/src/equil/vcs_equilibrate.cpp index ed46e6c14..03692c6b5 100644 --- a/Cantera/src/equil/vcs_equilibrate.cpp +++ b/Cantera/src/equil/vcs_equilibrate.cpp @@ -327,10 +327,8 @@ namespace Cantera { if (solver == 2) { try { - VCSnonideal::vcs_MultiPhaseEquil *eqsolve = - new VCSnonideal::vcs_MultiPhaseEquil(&s, printLvlSub); - int err = eqsolve->equilibrate(ixy, estimateEquil, printLvlSub, - tol, maxsteps, loglevel); + VCSnonideal::vcs_MultiPhaseEquil *eqsolve = new VCSnonideal::vcs_MultiPhaseEquil(&s, printLvlSub); + int err = eqsolve->equilibrate(ixy, estimateEquil, printLvlSub, tol, maxsteps, loglevel); if (err != 0) { retn = -1; addLogEntry("vcs_equilibrate Error - ", err); @@ -386,4 +384,70 @@ namespace Cantera { } return retn; } + + //==================================================================================================================== + // Determine the phase stability of a single phase given the current conditions + // in a MultiPhase object + /* + * + * @param s The MultiPhase object to be set to an equilibrium state + * @param iphase Phase index within the multiphase object to be + * tested for stability. + * @param funcStab Function value that tests equilibrium. > 0 indicates stable + * < 0 indicates unstable + * + * @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 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_determine_PhaseStability(MultiPhase& s, int iphase, + double &funcStab, int printLvl, int loglevel) + { + int iStab = 0; + static int counter = 0; + beginLogGroup("PhaseStability",loglevel); + addLogEntry("multiphase phase stability function"); + beginLogGroup("arguments"); + addLogEntry("iphase",iphase); + addLogEntry("loglevel",loglevel); + endLogGroup("arguments"); + + int printLvlSub = MAX(0, printLvl-1); + + s.init(); + try { + VCSnonideal::vcs_MultiPhaseEquil *eqsolve = new VCSnonideal::vcs_MultiPhaseEquil(&s, printLvlSub); + iStab = eqsolve->determine_PhaseStability(iphase, funcStab, printLvlSub, loglevel); + if (iStab != 0) { + addLogEntry("Phase is stable - ", iphase); + } else { + addLogEntry("Phase is not stable - ", iphase); + } + endLogGroup("PhaseStability"); + // hard code a csv output file. + if (printLvl > 0) { + string reportFile = "vcs_phaseStability.csv"; + if (counter > 0) { + reportFile = "vcs_phaseStability_" + int2str(counter) + ".csv"; + } + eqsolve->reportCSV(reportFile); + counter++; + } + delete eqsolve; + } + catch (CanteraError &e) { + addLogEntry("Failure.", lastErrorMessage()); + endLogGroup("equilibrate"); + throw e; + } + return iStab; + } + //==================================================================================================================== } diff --git a/Cantera/src/equil/vcs_internal.h b/Cantera/src/equil/vcs_internal.h index b816240e2..cda63dada 100644 --- a/Cantera/src/equil/vcs_internal.h +++ b/Cantera/src/equil/vcs_internal.h @@ -158,6 +158,42 @@ namespace VCSnonideal { */ int vcsUtil_mlequ(double *c, int idem, int n, double *b, int m); + //! Invert an n x n matrix and solve m rhs's + /*! + * Solve a square matrix with multiple right hand sides + * + * \f[ + * C X + B = 0; + * \f] + * + * This routine uses Gauss-Jordan elimination and is optimized for the solution + * of lots of rhs's. Full row and column pivoting is used here. It's been + * shown to be necessary in at least one case. + * The matrix C is destroyed during the solve. + * + * @return The solution x[] is returned in the matrix B. + * Routine returns an integer representing success: + * - 1 : Matrix is singluar + * - 0 : solution is OK + * + * @param c Matrix to be inverted. c is in fortran format, i.e., rows + * are the inner loop. Row numbers equal to idem. + * c[i+j*idem] = c_i_j = Matrix to be inverted: + * - i = row number + * - j = column number + * + * @param idem number of row dimensions in c + * @param n Number of rows and columns in c + * @param b Multiple RHS. Note, b is actually the negative of + * most formulations. Row numbers equal to idem. + * b[i+j*idem] = b_i_j = vectors of rhs's: + * - i = row number + * - j = column number + * (each column is a new rhs) + * @param m number of rhs's + */ + int vcsUtil_gaussj(double *c, int idem, int n, double *b, int m); + //! Swap values in vector of doubles /*! * Switches the value of x[i1] with x[i2] @@ -249,8 +285,6 @@ namespace VCSnonideal { #include "Cantera.h" #include "kernel/vcs_internal.h" - using namespace Cantera; - using namespace VCSnonideal; const double g_cgs = 980.; const double mass_cyl = 0.066; diff --git a/Cantera/src/equil/vcs_linmaxc.cpp b/Cantera/src/equil/vcs_linmaxc.cpp index 813324eb7..fc0dd7688 100644 --- a/Cantera/src/equil/vcs_linmaxc.cpp +++ b/Cantera/src/equil/vcs_linmaxc.cpp @@ -43,7 +43,7 @@ int linprogmax(double *XMOLES, double *CC, double *AX, double *BB, /*----------------------------------------------------------------------- * Find XMOLES(I), i = 1, M such that - * Maximize CC dot W, subject to the NE constraints: + * Maximize CC dot XMOLES, subject to the NE constraints: * * [AX] [XMOLES] = [BB] * and XMOLES(i) > 0 diff --git a/Cantera/src/equil/vcs_phaseStability.cpp b/Cantera/src/equil/vcs_phaseStability.cpp index a0a560abf..3307f6954 100644 --- a/Cantera/src/equil/vcs_phaseStability.cpp +++ b/Cantera/src/equil/vcs_phaseStability.cpp @@ -1,8 +1,17 @@ -/* ======================================================================= */ -/* $RCSfile: vcs_phaseStability.cpp,v $ */ -/* $Date$ */ -/* $Revision$ */ -/* ======================================================================= */ +/** + * @file vcs_phaseStability.cpp + * Implementation class for functions associated with determining the stability of a phase + * (see Class \link Cantera::VCS_SOLVE VCS_SOLVE\endlink and \ref equilfunctions ). + */ + +/* + * $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" @@ -20,13 +29,16 @@ using namespace std; namespace VCSnonideal { - - // Utility function that evaluates whether a phase can be popped - // into existence + //==================================================================================================================== + // Utility function that evaluates whether a phase can be popped into existence /* * A phase can be popped iff the stoichiometric coefficients for the * component species, whose concentrations will be lowered during the * process, are positive by at least a small degree. + * + * If one of the phase species is a zeroed component, then the phase can + * be popped if the component increases in mole number as the phase moles + * are increased. * * @param iphasePop id of the phase, which is currently zeroed, * @@ -52,6 +64,13 @@ namespace VCSnonideal { */ for (int k = 0; k < Vphase->nSpecies(); k++) { int kspec = Vphase->spGlobalIndexVCS(k); +#ifdef DEBUG_MODE + if (m_molNumSpecies_old[kspec] > 0.0) { + printf("ERROR vcs_popPhasePossible we shouldn't be here %d %g > 0.0", + kspec, m_molNumSpecies_old[kspec]); + exit(-1); + } +#endif int irxn = kspec - m_numComponents; if (irxn >= 0) { int iPopPossible = true; @@ -62,7 +81,7 @@ namespace VCSnonideal { double negChangeComp = - stoicC * 1.0; if (negChangeComp > 0.0) { // TODO: We may have to come up with a tolerance here - if (m_molNumSpecies_old[j] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.1) { + if (m_molNumSpecies_old[j] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { iPopPossible = false; } } @@ -72,17 +91,216 @@ namespace VCSnonideal { if (iPopPossible == true) { return true; } + } else { + /* + * We are here when the species in the phase is a component. Its mole number is zero. + * We loop through the regular reaction looking for a reaction that can pop the + * component. + */ + //printf("WE are here at new logic - CHECK\n"); + for (int jrxn = 0; jrxn < m_numRxnRdc; jrxn++) { + bool foundJrxn = false; + // First, if the component is a product of the reaction + if (m_stoichCoeffRxnMatrix[jrxn][kspec] > 0.0) { + foundJrxn = true; + for (int kcomp = 0; kcomp < m_numComponents; kcomp++) { + if (m_stoichCoeffRxnMatrix[jrxn][kcomp] < 0.0) { + if (m_molNumSpecies_old[kcomp] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + foundJrxn = false; + } + } + } + if (foundJrxn) { + //printf("We have found a component phase pop! CHECK1 \n"); + return true; + } + } + // Second we are here if the component is a reactant in the reaction, and the reaction goes backwards. + else if (m_stoichCoeffRxnMatrix[jrxn][kspec] < 0.0) { + foundJrxn = true; + int jspec = jrxn + m_numComponents; + if (m_molNumSpecies_old[jspec] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + foundJrxn = false; + continue; + } + for (int kcomp = 0; kcomp < m_numComponents; kcomp++) { + if (m_stoichCoeffRxnMatrix[jrxn][kcomp] > 0.0) { + if (m_molNumSpecies_old[kcomp] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + foundJrxn = false; + } + } + } + if (foundJrxn) { + //printf("We have found a component phase pop! CHECK2 \n"); + return true; + } + } + } } } return false; } + //==================================================================================================================== + + int inList(const std::vector &list, int val) + { + for (int i = 0; i < (int) list.size(); i++) { + if (val == list[i]) { + return i; + } + } + return -1; + } + + //==================================================================================================================== + // Determine the list of problems that need to be checked to see if there are any phases pops + /* + * This routine evaluates and fills in the following quantities + * phasePopProblemLists_ + * + * Need to work in species that are zeroed by element constraints + * + * @return Returns the number of problems that must be checked. + */ + int VCS_SOLVE::vcs_phasePopDeterminePossibleList() { + int nfound = 0; + int irxn, kspec; + vcs_VolPhase *Vphase = 0; + int iph, j, k; + int nsp; + double stoicC; + double molComp; + std::vector linkedPhases; + phasePopProblemLists_.clear(); + + /* + * This is a vector over each component. + * For zeroed components it lists the phases, which are currently zeroed, + * which have a species with a positive stoichiometric value wrt the component. + * Therefore, we could pop the component species and pop that phase at the same time + * if we considered no other factors than keeping the component mole number positve. + * + * It does not count species with positive stoichiometric values if that species + * already has a positive mole number. The phase is already popped. + */ + std::vector< std::vector > zeroedComponentLinkedPhasePops(m_numComponents); + /* + * The logic below calculates zeroedComponentLinkedPhasePops + */ + for (j = 0; j < m_numComponents; j++) { + if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + molComp = m_molNumSpecies_old[j]; + if (molComp <= 0.0) { + std::vector &jList = zeroedComponentLinkedPhasePops[j]; + iph = m_phaseID[j]; + jList.push_back(iph); + for (irxn = 0; irxn < m_numRxnTot; irxn++) { + kspec = irxn + m_numComponents; + iph = m_phaseID[kspec]; + Vphase = m_VolPhaseList[iph]; + int existence = Vphase->exists(); + if (existence < 0) { + stoicC = m_stoichCoeffRxnMatrix[irxn][j]; + if (stoicC > 0.0) { + if (inList(jList, iph) != -1) { + jList.push_back(iph); + } + } + } + } + } + } + } + /* + * This is a vector over each zeroed phase + * For zeroed phases, it lists the components, which are currently zereoed, + * which have a species with a negative stoichiometric value wrt one or more species in the phase. + * Cut out components which have a pos stoichiometric value with another species in the phase. + */ + std::vector< std::vector > zeroedPhaseLinkedZeroComponents(m_numPhases); + /* + * The logic below calculates zeroedPhaseLinkedZeroComponents + */ + for (iph = 0; iph < m_numPhases; iph++) { + std::vector &iphList = zeroedPhaseLinkedZeroComponents[iph]; + iphList.clear(); + Vphase = m_VolPhaseList[iph]; + int existence = Vphase->exists(); + if (existence < 0) { + + linkedPhases.clear(); + nsp = Vphase->nSpecies(); + for (k = 0; k < nsp; k++) { + + kspec = Vphase->spGlobalIndexVCS(k); + irxn = kspec - m_numComponents; + + for (j = 0; j < m_numComponents; j++) { + if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + molComp = m_molNumSpecies_old[j]; + if (molComp <= 0.0) { + stoicC = m_stoichCoeffRxnMatrix[irxn][j]; + if (stoicC < 0.0) { + bool foundPos = false; + for (int kk = 0; kk < nsp; kk++) { + int kkspec = Vphase->spGlobalIndexVCS(kk); + int iirxn = kkspec - m_numComponents; + if (iirxn >= 0) { + if (m_stoichCoeffRxnMatrix[iirxn][j] > 0.0) { + foundPos = true; + } + } + } + if (!foundPos) { + if (inList(iphList, j) != -1) { + iphList.push_back(j); + } + } + } + } + } + } + } + } + } + + /* + * Now fill in the phasePopProblemLists_ list. + * + */ + for (iph = 0; iph < m_numPhases; iph++) { + Vphase = m_VolPhaseList[iph]; + int existence = Vphase->exists(); + if (existence < 0) { + std::vector &iphList = zeroedPhaseLinkedZeroComponents[iph]; + std::vector popProblem(0); + popProblem.push_back(iph); + for (int i = 0; i < (int) iphList.size(); i++) { + j = iphList[i]; + std::vector &jList = zeroedComponentLinkedPhasePops[j]; + for (int jjl = 0; jjl < (int) jList.size(); jjl++) { + int jph = jList[jjl]; + if (inList(popProblem, jph) != -1) { + popProblem.push_back(jph); + } + } + } + phasePopProblemLists_.push_back(popProblem); + } + } + + return nfound; + } + + + //==================================================================================================================== // Decision as to whether a phase pops back into existence /* - * @return returns the phase id of the phase that pops back into + * @return returns the phase id of the phases that pops back into * existence. Returns -1 if there are no phases */ - int VCS_SOLVE::vcs_popPhaseID() { + int VCS_SOLVE::vcs_popPhaseID(std::vector & phasePopPhaseIDs) { int iphasePop = -1; int iph; int irxn, kspec; @@ -95,8 +313,8 @@ namespace VCSnonideal { char anote[128]; if (m_debug_print_lvl >= 2) { plogf(" --- vcs_popPhaseID() called\n"); - plogf(" --- Phase Status F_e MoleNum\n"); - plogf(" --------------------------------------------------------------\n"); + plogf(" --- Phase Status F_e MoleNum\n"); + plogf(" --------------------------------------------------------------------------\n"); } #endif for (iph = 0; iph < m_numPhases; iph++) { @@ -109,7 +327,7 @@ namespace VCSnonideal { #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { - plogf(" --- %18s %5d NA %11.3e\n", + plogf(" --- %18s %5d NA %11.3e\n", Vphase->PhaseName.c_str(), existence, m_tPhaseMoles_old[iph]); @@ -138,10 +356,19 @@ namespace VCSnonideal { #endif } } +#ifdef DEBUG_MODE + if (Fephase < 0.0) { + strcpy(anote," (not stable)"); + if (m_tPhaseMoles_old[iph] > 0.0) { + printf("shouldn't be here\n"); + exit(-1); + } + } +#endif #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { - plogf(" --- %18s %5d NA %11.3g %s\n", + plogf(" --- %18s %5d %10.3g %10.3g %s\n", Vphase->PhaseName.c_str(), existence, Fephase, m_tPhaseMoles_old[iph], anote); @@ -186,16 +413,24 @@ namespace VCSnonideal { } } } + phasePopPhaseIDs.resize(0); + if (iphasePop >= 0) { + phasePopPhaseIDs.push_back(iphasePop); + } + /* + * Insert logic here to figure out if phase pops are linked together. Only do one linked + * pop at a time. + */ #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { - plogf(" --------------------------------------------------------------\n"); + plogf(" ---------------------------------------------------------------------\n"); } #endif return iphasePop; } - + //==================================================================================================================== // Calculates the deltas of the reactions due to phases popping // into existence /* @@ -224,6 +459,7 @@ namespace VCSnonideal { int kspec = Vphase->spGlobalIndexVCS(0); // Identify the formation reaction for that species int irxn = kspec - m_numComponents; + std::vector creationGlobalRxnNumbers; doublereal s; int j, k; @@ -322,7 +558,7 @@ namespace VCSnonideal { } else { vector fracDelta(Vphase->nSpecies()); vector X_est(Vphase->nSpecies()); - fracDelta = Vphase->fractionCreationDeltas(); + fracDelta = Vphase->creationMoleNumbers(creationGlobalRxnNumbers); double sumFrac = 0.0; for (k = 0; k < Vphase->nSpecies(); k++) { @@ -415,7 +651,7 @@ namespace VCSnonideal { // - + //==================================================================================================================== double VCS_SOLVE::vcs_phaseStabilityTest(const int iph) { /* @@ -434,6 +670,8 @@ namespace VCSnonideal { vector fracDelta_new(Vphase->nSpecies(), 0.0); vector fracDelta_old(Vphase->nSpecies(), 0.0); vector fracDelta_raw(Vphase->nSpecies(), 0.0); + vector creationGlobalRxnNumbers(Vphase->nSpecies(), -1); + vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_Deficient), VCS_DATA_PTR(m_deltaGRxn_old), m_numRxnRdc); vector m_feSpecies_Deficient(m_numComponents, 0.0); doublereal damp = 1.0; @@ -449,7 +687,7 @@ namespace VCSnonideal { // Get the storred estimate for the composition of the phase if // it gets created - fracDelta_new = Vphase->fractionCreationDeltas(); + fracDelta_new = Vphase->creationMoleNumbers(creationGlobalRxnNumbers); bool oneIsComponent = false; @@ -479,10 +717,16 @@ namespace VCSnonideal { " normUpdate damp FuncPhaseStability\n", KP, KP, KP, KP); plogf(" --------------------------------------------------------------" "--------------------------------------------------------\n"); - } else { + } else if (m_debug_print_lvl == 1) { plogf(" --- vcs_phaseStabilityTest() called for phase %d\n", iph); } #endif + + for (k = 0; k < Vphase->nSpecies(); k++) { + if (fracDelta_new[k] < 1.0E-13) { + fracDelta_new[k] = 1.0E-13; + } + } bool converged = false; for (int its = 0; its < 200 && (!converged); its++) { @@ -491,6 +735,8 @@ namespace VCSnonideal { fracDelta_old = fracDelta_new; dirProdOld = dirProd; + + // Given a set of fracDelta's, we calculate the fracDelta's // for the component species, if any for (i = 0; i < (int) componentList.size(); i++) { @@ -511,6 +757,10 @@ namespace VCSnonideal { for (k = 0; k < Vphase->nSpecies(); k++) { sumFrac += fracDelta_old[k]; } + // Necessary because this can be identically zero. -> we need to fix this algorithm! + if (sumFrac <= 0.0) { + sumFrac = 1.0; + } double sum_Xcomp = 0.0; for (k = 0; k < Vphase->nSpecies(); k++) { X_est[k] = fracDelta_old[k] / sumFrac; @@ -533,18 +783,16 @@ namespace VCSnonideal { Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, VCS_DATA_PTR(m_actCoeffSpecies_new)); /* - * first Calculate altered chemical potentials for component species + * First calculate altered chemical potentials for component species * belonging to this phase. */ for (i = 0; i < (int) componentList.size(); i++) { kc = componentList[i]; kc_spec = Vphase->spGlobalIndexVCS(kc); if ( X_est[kc] > VCS_DELETE_MINORSPECIES_CUTOFF) { - m_feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] - + log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]); + m_feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] + log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]); } else { - m_feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] - + log(m_actCoeffSpecies_new[kc_spec] * VCS_DELETE_MINORSPECIES_CUTOFF); + m_feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] + log(m_actCoeffSpecies_new[kc_spec] * VCS_DELETE_MINORSPECIES_CUTOFF); } } @@ -561,8 +809,7 @@ namespace VCSnonideal { } double *dtmp_ptr = m_stoichCoeffRxnMatrix[irxn]; if (dtmp_ptr[kc_spec] != 0.0) { - m_deltaGRxn_Deficient[irxn] += - dtmp_ptr[kc_spec] * (m_feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]); + m_deltaGRxn_Deficient[irxn] += dtmp_ptr[kc_spec] * (m_feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]); } } @@ -697,7 +944,7 @@ namespace VCSnonideal { if (converged) { Vphase->setMoleFractionsState(0.0, VCS_DATA_PTR(X_est), VCS_STATECALC_PHASESTABILITY); - Vphase->setFractionCreationDeltas( VCS_DATA_PTR(fracDelta_new)); + Vphase->setCreationMoleNumbers(VCS_DATA_PTR(fracDelta_new), creationGlobalRxnNumbers); } @@ -719,6 +966,7 @@ namespace VCSnonideal { #endif return funcPhaseStability; } - + //==================================================================================================================== } +//====================================================================================================================== diff --git a/Cantera/src/equil/vcs_prob.cpp b/Cantera/src/equil/vcs_prob.cpp index 6d1891b4c..7fe4d6542 100644 --- a/Cantera/src/equil/vcs_prob.cpp +++ b/Cantera/src/equil/vcs_prob.cpp @@ -284,7 +284,7 @@ namespace VCSnonideal { Vphase = VPhaseList[iphase]; std::string EOS_cstr = string16_EOSType(Vphase->m_eqnState); plogf("%16s %5d %5d %8d ", Vphase->PhaseName.c_str(), - Vphase->VP_ID, Vphase->m_singleSpecies, Vphase->m_gasPhase); + Vphase->VP_ID_, Vphase->m_singleSpecies, Vphase->m_gasPhase); plogf("%16s %8d %16e ", EOS_cstr.c_str(), Vphase->nSpecies(), Vphase->totalMolesInert()); if (iest >= 0) plogf("%16e\n", Vphase->totalMoles()); diff --git a/Cantera/src/equil/vcs_rxnadj.cpp b/Cantera/src/equil/vcs_rxnadj.cpp index 0a4983045..da1bd9bba 100644 --- a/Cantera/src/equil/vcs_rxnadj.cpp +++ b/Cantera/src/equil/vcs_rxnadj.cpp @@ -43,8 +43,9 @@ namespace VCSnonideal { * in this routine. The species is a noncomponent * - 2 : Same as one but, the zeroed species is a component. */ - int VCS_SOLVE::vcs_RxnStepSizes() { - int j, irxn, kspec, soldel = 0, iph; + int VCS_SOLVE::vcs_RxnStepSizes(int & forceComponentCalc, int &kSpecial) { + int j, irxn, kspec, iph; + int iphDel = -1; double s, xx, dss; int k = 0; vcs_VolPhase *Vphase = 0; @@ -306,6 +307,34 @@ namespace VCSnonideal { * added back into the component species. */ if (dss != 0.0) { + + if ((k == kspec) && (m_SSPhase[kspec] != 1)) { + /* + * Found out that we can be in this spot, when components of multispecies phases + * are zeroed, leaving noncomponent species of the same phase having all of the + * mole numbers of that phases. it seems that we can suggest a zero of the species + * and the code will recover. + */ +#ifdef DEBUG_MODE + sprintf(ANOTE, "Delta damped from %g to %g due to delete %s", + m_deltaMolNumSpecies[kspec], + -m_molNumSpecies_old[kspec], m_speciesName[kspec].c_str()); +#endif + m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", m_speciesName[kspec].c_str()); + plogf(" %12.4E %12.4E %12.4E | %s\n", + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], + m_deltaGRxn_new[irxn], ANOTE); + } +#endif + continue; + } + /* + * Delete the single species phase + */ +#ifdef OLDSTUFF m_molNumSpecies_old[kspec] += dss; m_tPhaseMoles_old[m_phaseID[kspec]] += dss; for (j = 0; j < m_numComponents; ++j) { @@ -324,29 +353,53 @@ namespace VCSnonideal { exit(EXIT_FAILURE); } } +#else + + for (j = 0; j < m_numSpeciesTot; j++) { + m_deltaMolNumSpecies[j] = 0.0; + } + m_deltaMolNumSpecies[kspec] = dss; + for (j = 0; j < m_numComponents; ++j) { + m_deltaMolNumSpecies[j] = dss * m_stoichCoeffRxnMatrix[irxn][j]; + } + + iphDel = m_phaseID[k]; + kSpecial = k; + #ifdef DEBUG_MODE + if (k != kspec) { + sprintf(ANOTE, "Delete component SS phase %d named %s - SS phases only", + iphDel, m_speciesName[k].c_str()); + } else { + sprintf(ANOTE, "Delete this SS phase %d - SS components only", iphDel); + } if (m_debug_print_lvl >= 2) { - plogf(" --- vcs_RxnStepSizes Special section to delete %s", + plogf(" --- %-12.12s", m_speciesName[kspec].c_str()); + plogf(" %12.4E %12.4E %12.4E | %s\n", + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], + m_deltaGRxn_new[irxn], ANOTE); + plogf(" --- vcs_RxnStepSizes Special section to set up to delete %s", m_speciesName[k].c_str()); plogendl(); } + #endif - /* - * We need to immediately recompute the - * component basis, because we just zeroed - * it out. - */ - soldel = 1; if (k != kspec) { - soldel = 2; + forceComponentCalc = 1; #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { - plogf(" --- Immediate return to get new basis - Restart iteration\n"); + plogf(" --- Force a component recalculation \n"); plogendl(); } #endif - return soldel; } +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" "); vcs_print_line("-", 82); + } +#endif + return iphDel; +#endif } } } /* End of regular processing */ @@ -365,13 +418,12 @@ namespace VCSnonideal { plogf(" "); vcs_print_line("-", 82); } #endif - return soldel; + return iphDel; } - /*****************************************************************************/ - - - //! Calculates reaction adjustments using a full Hessian approximation - /*! + + //==================================================================================================================== + // Calculates reaction adjustments using a full Hessian approximation + /* * 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 @@ -586,8 +638,8 @@ namespace VCSnonideal { #endif return soldel; } - /*****************************************************************************/ + //==================================================================================================================== // Calculates the diagonal contribution to the Hessian due to // the dependence of the activity coefficients on the mole numbers. /* @@ -615,8 +667,8 @@ namespace VCSnonideal { } return diag; } - /*****************************************************************************/ + //==================================================================================================================== //! Calculates the diagonal contribution to the Hessian due to //! the dependence of the activity coefficients on the mole numbers. /*! @@ -653,8 +705,7 @@ namespace VCSnonideal { } return s; } - /*****************************************************************************/ - + //==================================================================================================================== // Recalculate all of the activity coefficients in all of the phases // based on input mole numbers /* diff --git a/Cantera/src/equil/vcs_solve.cpp b/Cantera/src/equil/vcs_solve.cpp index 108d1dcbc..7ba67cf3c 100644 --- a/Cantera/src/equil/vcs_solve.cpp +++ b/Cantera/src/equil/vcs_solve.cpp @@ -411,9 +411,7 @@ namespace VCSnonideal { * a 2x2 Newton's method, using loops over vcs_TP() to * calculate the residual and Jacobian) */ - iconv = vcs_TP(ipr, ip1, maxit, vprob->T, vprob->PresPA); - /* * If requested to print anything out, go ahead and do so; @@ -520,9 +518,18 @@ namespace VCSnonideal { * FormulaMatrix[] -> Copy the formula matrix over */ for (i = 0; i < nspecies; i++) { + bool nonzero = false; for (j = 0; j < nelements; j++) { + if (pub->FormulaMatrix[j][i] != 0.0) { + nonzero = true; + } m_formulaMatrix[j][i] = pub->FormulaMatrix[j][i]; } + if (!nonzero) { + plogf("vcs_prob_specifyFully:: species %d %s has a zero formula matrix!\n", i, + pub->SpName[i].c_str()); + return VCS_PUB_BAD; + } } /* @@ -575,17 +582,31 @@ namespace VCSnonideal { /* * Formulate the Goal Element Abundance Vector */ + double sum; if (pub->gai.size() != 0) { - for (i = 0; i < nelements; i++) m_elemAbundancesGoal[i] = pub->gai[i]; + for (i = 0; i < nelements; i++) { + m_elemAbundancesGoal[i] = pub->gai[i]; + if (pub->m_elType[i] == VCS_ELEM_TYPE_LATTICERATIO) { + if (m_elemAbundancesGoal[i] < 1.0E-10) { + m_elemAbundancesGoal[i] = 0.0; + } + } + } } else { if (m_doEstimateEquil == 0) { for (j = 0; j < nelements; j++) { m_elemAbundancesGoal[j] = 0.0; for (kspec = 0; kspec < nspecies; kspec++) { if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + sum += m_molNumSpecies_old[kspec]; m_elemAbundancesGoal[j] += m_formulaMatrix[j][kspec] * m_molNumSpecies_old[kspec]; } } + if (pub->m_elType[j] == VCS_ELEM_TYPE_LATTICERATIO) { + if (m_elemAbundancesGoal[j] < 1.0E-10 * sum) { + m_elemAbundancesGoal[j] = 0.0; + } + } } } else { plogf("%sElement Abundances, m_elemAbundancesGoal[], not specified\n", ser); @@ -719,8 +740,10 @@ namespace VCSnonideal { m_elementName[i].c_str(), m_elemAbundancesGoal[i]); exit(EXIT_FAILURE); } else { - plogf("Charge neutrality condition %s not zero, %g. Setting it zero\n", - m_elementName[i].c_str(), m_elemAbundancesGoal[i]); + if (m_debug_print_lvl >= 2) { + plogf("Charge neutrality condition %s not zero, %g. Setting it zero\n", + m_elementName[i].c_str(), m_elemAbundancesGoal[i]); + } m_elemAbundancesGoal[i] = 0.0; } @@ -869,9 +892,9 @@ namespace VCSnonideal { vcs_VolPhase *vPhase = m_VolPhaseList[iph]; vcs_VolPhase *pub_phase_ptr = pub->VPhaseList[iph]; - if (vPhase->VP_ID != pub_phase_ptr->VP_ID) { + if (vPhase->VP_ID_ != pub_phase_ptr->VP_ID_) { plogf("%sPhase numbers have changed:%d %d\n", yo.c_str(), - vPhase->VP_ID, pub_phase_ptr->VP_ID); + vPhase->VP_ID_, pub_phase_ptr->VP_ID_); retn = VCS_PUB_BAD; } @@ -898,7 +921,7 @@ namespace VCSnonideal { retn = VCS_PUB_BAD; } - if (vPhase->PhaseName == pub_phase_ptr->PhaseName) { + if (vPhase->PhaseName != pub_phase_ptr->PhaseName) { plogf("%sPhaseName value have changed:%s %s\n", yo.c_str(), vPhase->PhaseName.c_str(), pub_phase_ptr->PhaseName.c_str()); @@ -968,7 +991,7 @@ namespace VCSnonideal { pub->w[i] = m_molNumSpecies_old[k1]; } else { pub->w[i] = 0.0; - plogf("voltage species = %g\n", m_molNumSpecies_old[k1]); + // plogf("voltage species = %g\n", m_molNumSpecies_old[k1]); } //pub->mf[i] = m_molNumSpecies_new[k1]; pub->m_gibbsSpecies[i] = m_feSpecies_old[k1]; diff --git a/Cantera/src/equil/vcs_solve.h b/Cantera/src/equil/vcs_solve.h index 64acf7ee0..e0c52b12a 100644 --- a/Cantera/src/equil/vcs_solve.h +++ b/Cantera/src/equil/vcs_solve.h @@ -1,12 +1,13 @@ /** * @file vcs_solve.h - * Header file for the internal object that holds the problem + * Header file for the internal object that holds the vcs equilibrium problem + * (see Class \link Cantera::VCS_SOLVE VCS_SOLVE\endlink and \ref equilfunctions ). */ /* * $Id$ */ /* - * Copywrite (2005) Sandia Corporation. Under the terms of + *_ 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. */ @@ -146,6 +147,9 @@ public: */ int vcs_solve_TP(int print_lvl, int printDetails, int maxit); + + int vcs_PS(VCS_PROB *vprob, int iph, int printLvl, double &feStable); + void vcs_reinsert_deleted(int kspec); //! Choose the optimum species basis for the calculations @@ -200,7 +204,7 @@ public: * m_stoichCoeffRxnMatrix[irxn][jcomp] * Stoichiometric coefficient matrix for the reaction mechanism * expressed in Reduced Canonical Form. - * j refers to the component number, and irxn + * jcomp refers to the component number, and irxn * refers to the irxn_th non-component species. * * m_deltaMolNumPhase[irxn] @@ -491,17 +495,23 @@ public: */ void vcs_dfe(const int stateCalc, const int ll, const int lbot, const int ltop); + //! Print out a table of chemical potentials + /*! + * @param vcsState Determines where to get the mole numbers from. + * - VCS_STATECALC_OLD -> from m_molNumSpecies_old + * - VCS_STATECALC_NEW -> from m_molNumSpecies_new + */ + void vcs_printSpeciesChemPot(const int stateCalc) const; + //! This routine uploads the state of the system into all of the //! vcs_VolumePhase objects in the current problem. /*! * @param vcsState Determines where to get the mole numbers from. * - VCS_STATECALC_OLD -> from m_molNumSpecies_old * - VCS_STATECALC_NEW -> from m_molNumSpecies_new - * */ void vcs_updateVP(const int stateCalc); - //! Utility function that evaluates whether a phase can be popped //! into existence /*! @@ -512,12 +522,30 @@ public: */ bool vcs_popPhasePossible(const int iphasePop) const; + + //! Determine the list of problems that need to be checked to see if there are any phases pops + /*! + * This routine evaluates and fills in the following quantities + * phasePopProblemLists_ + * + * @return Returns the number of problems that must be checked. + */ + int vcs_phasePopDeterminePossibleList(); + + + + + + //! Decision as to whether a phase pops back into existence /*! + * @param phasePopPhaseIDs Vector containing the phase ids of the phases + * that will be popped this step. + * * @return returns the phase id of the phase that pops back into * existence. Returns -1 if there are no phases */ - int vcs_popPhaseID(); + int vcs_popPhaseID(std::vector &phasePopPhaseIDs); //! Calculates the deltas of the reactions due to phases popping //! into existence @@ -532,6 +560,7 @@ public: */ int vcs_popPhaseRxnStepSizes(const int iphasePop); + //! Calculates formation reaction step sizes. /*! * This is equation 6.4-16, p. 143 in Smith and Missen. @@ -546,13 +575,13 @@ public: * Special branching occurs sometimes. This causes the component basis * to be reevaluated * - * @return Returns an int representing the status of the step - * - 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. + * @param forceComponentRecalc integer flagging whether a component recalculation needs + * to be carried out. + * @param kSpecial species number of phase being zeroed. + * + * @return Returns an int representing which phase may need to be zeroed */ - int vcs_RxnStepSizes(); + int vcs_RxnStepSizes(int & forceComponentCalc, int & kSpecial); //! Calculates the total number of moles of species in all phases. /*! @@ -599,6 +628,8 @@ public: void vcs_deltag(const int l, const bool doDeleted, const int vcsState, const bool alterZeroedPhases = true); + void vcs_printDeltaG(const int stateCalc); + //! Calculate deltag of formation for all species in a single phase. /*! * Calculate deltag of formation for all species in a single @@ -663,7 +694,8 @@ public: * have. */ double vcs_birthGuess(const int kspec); - + + int vcs_solve_phaseStability(const int iphase, int ifunc, double &funcval, int print_lvl); //! Main program to test whether a deleted phase should be brought //! back into existence @@ -1234,16 +1266,16 @@ private: * the mole numbers of the component species. Therefore the following * approximation is valid for a small component of an ideal phase: * - * 0 = m_deltaGrxn_old(I) + log(molNum_new(I)/molNum_old(I)) + * 0 = m_deltaGRxn_old(I) + log(molNum_new(I)/molNum_old(I)) * - * m_deltaGrxn_old contains the contribution from + * m_deltaGRxn_old contains the contribution from * * m_feSpecies_old(I) = * m_SSfeSpecies(I) + * log(ActCoeff[i] * molNum_old(I) / m_tPhaseMoles_old(iph)) * Thus, * - * molNum_new(I)= molNum_old(I) * EXP(-m_deltaGrxn_old(I)) + * molNum_new(I)= molNum_old(I) * EXP(-m_deltaGRxn_old(I)) * * Most of this section is mainly restricting the update to reasonable * values. @@ -1438,7 +1470,7 @@ public: //! Number of components calculated for the problem int m_numComponents; - //! Total number of non-component species in the problem + //! Total number of non-component species in the problem int m_numRxnTot; //! Current number of species in the problems @@ -1448,7 +1480,7 @@ public: */ int m_numSpeciesRdc; - //! Current number of non-component species in the problem + //! Current number of non-component species in the problem /*! * Species can be deleted if they aren't * stable under the current conditions @@ -1470,20 +1502,19 @@ public: */ DoubleStarStar m_formulaMatrix; - //! Stoichiometric coefficient matrix for the reaction mechanism - //! expressed in Reduced Canonical Form. + //! Stoichiometric coefficient matrix 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. + * reaction which forms species kspec from the component species. A + * stoichiometric coefficient of one is assumed for the species kspec in this mechanism. * - * NOTE: kspec = Irxn + m_numComponents + * NOTE: kspec = irxn + m_numComponents * - * sc[irxn][j] : - * j refers to the component number, and irxn - * refers to the irxn_th non-component species. - * + * m_stoichCoeffRxnMatrix[irxn][j] : + * j refers to the component number, and irxn refers to the irxn_th non-component species. + * The stoichiometric coefficents multilpled by the Formula coefficients of the + * component species add up to the negative value of the number of elements in + * the species kspec. * * length = [nspecies0][nelements0] */ @@ -1596,8 +1627,10 @@ public: //! Last deltag[irxn] from the previous step std::vector m_deltaGRxn_old; - //! Last deltag[irxn] from the previous step with additions for - //! possible births of zeroed phases. + //! Last deltag[irxn] from the previous step with additions for possible births of zeroed phases for component species + /*! + * + */ std::vector m_deltaGRxn_Deficient; //! Temporary vector of Rxn DeltaG's @@ -1662,10 +1695,10 @@ public: std::vector m_tPhaseMoles_new; //! Temporary vector of length NPhase - std::vector m_TmpPhase; + mutable std::vector m_TmpPhase; //! Temporary vector of length NPhase - std::vector m_TmpPhase2; + mutable std::vector m_TmpPhase2; //! Change in the total moles in each phase /*! @@ -1958,6 +1991,8 @@ public: */ std::vector m_chargeSpecies; + std::vector > phasePopProblemLists_; + //! Vector of pointers to thermostructures which identify the model //! and parameters for evaluating the thermodynamic functions for that //! particular species. @@ -2038,6 +2073,8 @@ public: */ int m_VCS_UnitsFormat; + friend class vcs_phaseStabilitySolve; + }; #ifdef ALTLINPROG diff --git a/Cantera/src/equil/vcs_solve_TP.cpp b/Cantera/src/equil/vcs_solve_TP.cpp index 5d8bae98b..59c4e9824 100644 --- a/Cantera/src/equil/vcs_solve_TP.cpp +++ b/Cantera/src/equil/vcs_solve_TP.cpp @@ -122,6 +122,9 @@ namespace VCSnonideal { double *dnPhase_irxn; double atomComp; int iphasePop; + int forceComponentCalc = 1; + int iphaseDelete; /* integer that determines which phase is being deleted */ + std::vector phasePopPhaseIDs(0); #ifdef DEBUG_MODE char ANOTE[128]; /* @@ -215,20 +218,20 @@ namespace VCSnonideal { if (m_VCS_UnitsFormat == VCS_UNITS_MKS) { plogf(" Stan. Chem. Pot. in J/kmol\n"); } - plogf("\n SPECIES FORMULA VECTOR"); - print_space(29); - plogf(" STAN_CHEM_POT EQUILIBRIUM_EST. Species_Type\n\n"); - print_space(14); - for (i = 0; i < m_numElemConstraints; ++i) plogf(" %-2.2s", m_elementName[i].c_str()); - plogf(" SI(I)\n"); + plogf("\n SPECIES FORMULA VECTOR "); + print_space(41); + plogf(" STAN_CHEM_POT EQUILIBRIUM_EST. Species_Type\n\n"); + print_space(20); + for (i = 0; i < m_numElemConstraints; ++i) plogf("%-4.4s ", m_elementName[i].c_str()); + plogf(" PhaseID\n"); RT = vcs_nondimMult_TP(m_VCS_UnitsFormat, m_temperature); for (i = 0; i < m_numSpeciesTot; ++i) { - plogf(" %-12s", m_speciesName[i].c_str()); + plogf(" %-18.18s", m_speciesName[i].c_str()); for (j = 0; j < m_numElemConstraints; ++j) { - plogf("%3g", m_formulaMatrix[j][i]); + plogf("% -7.3g ", m_formulaMatrix[j][i]); } - plogf("%3d", m_phaseID[i]); - print_space(47-m_numElemConstraints*3); + plogf(" %3d ", m_phaseID[i]); + print_space(55-m_numElemConstraints*8); plogf("%12.5E %12.5E", RT * m_SSfeSpecies[i], m_molNumSpecies_old[i]); if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { plogf(" Mol_Num"); @@ -284,6 +287,8 @@ namespace VCSnonideal { // Update the phase objects with the contents of the soln vector vcs_updateVP(VCS_STATECALC_OLD); vcs_deltag(0, false, VCS_STATECALC_OLD); + // Turn off the force componentCalc flag + forceComponentCalc = 0; if (conv) { goto L_RETURN_BLOCK; @@ -376,30 +381,34 @@ namespace VCSnonideal { check_tmoles(); #endif vcs_tmoles(); + /*************************************************************************/ + /************** COPY OLD into NEW and ZERO VECTORS ***********************/ + /*************************************************************************/ /* * Copy the old solution into the new solution as an initial guess */ - vcs_dcopy(VCS_DATA_PTR(m_feSpecies_new), - VCS_DATA_PTR(m_feSpecies_old), m_numSpeciesRdc); - vcs_dcopy(VCS_DATA_PTR(m_actCoeffSpecies_new), - VCS_DATA_PTR(m_actCoeffSpecies_old), m_numSpeciesRdc); + vcs_dcopy(VCS_DATA_PTR(m_feSpecies_new), VCS_DATA_PTR(m_feSpecies_old), m_numSpeciesRdc); + vcs_dcopy(VCS_DATA_PTR(m_actCoeffSpecies_new), VCS_DATA_PTR(m_actCoeffSpecies_old), m_numSpeciesRdc); vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_new), VCS_DATA_PTR(m_deltaGRxn_old), m_numRxnRdc); vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_Deficient), VCS_DATA_PTR(m_deltaGRxn_old), m_numRxnRdc); + vcs_dcopy(VCS_DATA_PTR(m_tPhaseMoles_new), VCS_DATA_PTR(m_tPhaseMoles_old), m_numPhases); - /* Go find a new reaction adjustment -> - * i.e., change in extent of reaction for each reaction. - * + /* * Zero out the entire vector of updates. We sometimes would * query these values below, and we want to be sure that no * information is left from previous iterations. */ vcs_dzero(VCS_DATA_PTR(m_deltaMolNumSpecies), m_numSpeciesTot); + /*************************************************************************/ + /************** DETERMINE IF DEAD PHASES POP INTO EXISTENCE **************/ + /*************************************************************************/ /* * First step is a major branch in the algorithm. * We first determine if a phase pops into existence. */ - iphasePop = vcs_popPhaseID(); + phasePopPhaseIDs.clear(); + iphasePop = vcs_popPhaseID(phasePopPhaseIDs); /* * */ @@ -416,18 +425,21 @@ namespace VCSnonideal { #endif } } + + /*************************************************************************/ + /* DETERMINE THE REACTION STEP SIZES FOR MAIN STEP AND IF PHASES DIE *****/ + /*************************************************************************/ + /* + * Don't do this step if there is a phase pop + */ + iphaseDelete = -1; if (iphasePop < 0) { /* * Figure out the new reaction step sizes * for the major species (do minor species in the future too) */ - - soldel = vcs_RxnStepSizes(); - - if (soldel == 2) { - goto L_COMPONENT_CALC; - } - + kspec = -1; + iphaseDelete = vcs_RxnStepSizes(forceComponentCalc, kspec); } #ifdef DEBUG_MODE else { @@ -476,657 +488,702 @@ namespace VCSnonideal { * * * - */ + */ + if (iphaseDelete >= 0) { #ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - plogf(" --- Main Loop Treatment of each non-component species "); - if (iti == 0) plogf("- Full Calculation:\n"); - else plogf("- Major Components Calculation:\n"); - plogf(" --- Species IC "); - plogf(" KMoles Tent_KMoles Rxn_Adj | Comment \n"); - } + if (m_debug_print_lvl >= 2) { + plogf(" --- Main Loop Treatment -> Circumvented due to Phase Deletion "); + plogendl(); + } #endif - - for (irxn = 0; irxn < m_numRxnRdc; irxn++) { - kspec = m_indexRxnToSpecies[irxn]; - sc_irxn = m_stoichCoeffRxnMatrix[irxn]; - iph = m_phaseID[kspec]; - Vphase = m_VolPhaseList[iph]; -#ifdef DEBUG_MODE - ANOTE[0] = '\0'; -#endif - if (iphasePop >= 0) { - if (iph == iphasePop) { - dx = m_deltaMolNumSpecies[kspec]; - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec]; -#ifdef DEBUG_MODE - sprintf(ANOTE, "Phase pop"); -#endif - } else { - dx = 0.0; - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; + + for (k = 0; k < m_numSpeciesTot; k++) { + m_molNumSpecies_new[k] = m_molNumSpecies_old[k] + m_deltaMolNumSpecies[k]; + iph = m_phaseID[k]; + m_tPhaseMoles_new[iph] += m_deltaMolNumSpecies[k]; + } + if (kspec >= m_numComponents) { + if (m_molNumSpecies_new[k] != 0.0) { + printf("vcs_solve_tp:: we shouldn't be here!\n"); + exit(EXIT_FAILURE); } - } else { + if (m_SSPhase[kspec] == 1) { + m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS; + } else { + printf("vcs_solve_tp:: we shouldn't be here!\n"); + exit(EXIT_FAILURE); + } + ++m_numRxnMinorZeroed; + allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc); + } + /* + * Set the flags indicating the mole numbers in the vcs_VolPhase + * objects are out of date. + */ + vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW); + + /* + * Calculate the new chemical potentials using the tentative + * solution values. We only calculate a subset of these, because + * we have only updated a subset of the W(). + */ + vcs_dfe(VCS_STATECALC_NEW, 0, 0, m_numSpeciesTot); + + /* + * Evaluate DeltaG for all components if ITI=0, and for + * major components only if ITI NE 0 + */ + vcs_deltag(0, false, VCS_STATECALC_NEW); + } else { +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- Main Loop Treatment of each non-component species "); + if (iti == 0) plogf("- Full Calculation:\n"); + else plogf("- Major Components Calculation:\n"); + plogf(" --- Species IC "); + plogf(" KMoles Tent_KMoles Rxn_Adj | Comment \n"); + } +#endif + for (irxn = 0; irxn < m_numRxnRdc; irxn++) { + kspec = m_indexRxnToSpecies[irxn]; + sc_irxn = m_stoichCoeffRxnMatrix[irxn]; + iph = m_phaseID[kspec]; + Vphase = m_VolPhaseList[iph]; +#ifdef DEBUG_MODE + ANOTE[0] = '\0'; +#endif + if (iphasePop >= 0) { + if (iph == iphasePop) { + dx = m_deltaMolNumSpecies[kspec]; + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec]; +#ifdef DEBUG_MODE + sprintf(ANOTE, "Phase pop"); +#endif + } else { + dx = 0.0; + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; + } + } else { - if (m_speciesStatus[kspec] == VCS_SPECIES_INTERFACIALVOLTAGE) { - /********************************************************************/ - /************************ VOLTAGE SPECIES ***************************/ - /********************************************************************/ + if (m_speciesStatus[kspec] == VCS_SPECIES_INTERFACIALVOLTAGE) { + /********************************************************************/ + /************************ VOLTAGE SPECIES ***************************/ + /********************************************************************/ #ifdef DEBUG_MODE - dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE); + dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE); #else - dx = vcs_minor_alt_calc(kspec, irxn, &soldel); + dx = vcs_minor_alt_calc(kspec, irxn, &soldel); #endif - m_deltaMolNumSpecies[kspec] = dx; - } - else if (m_speciesStatus[kspec] < VCS_SPECIES_MINOR) { - /********************************************************************/ - /********************** ZEROED OUT SPECIES **************************/ - /********************************************************************/ - bool resurrect = (m_deltaMolNumSpecies[kspec] > 0.0); -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 3) { - plogf(" --- %s currently zeroed (SpStatus=%-2d):", - m_speciesName[kspec].c_str(), m_speciesStatus[kspec]); - plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n", - irxn, m_deltaGRxn_new[irxn], m_molNumSpecies_new[kspec], - m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec]); + m_deltaMolNumSpecies[kspec] = dx; } + else if (m_speciesStatus[kspec] < VCS_SPECIES_MINOR) { + /********************************************************************/ + /********************** ZEROED OUT SPECIES **************************/ + /********************************************************************/ + bool resurrect = (m_deltaMolNumSpecies[kspec] > 0.0); +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 3) { + plogf(" --- %s currently zeroed (SpStatus=%-2d):", + m_speciesName[kspec].c_str(), m_speciesStatus[kspec]); + plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n", + irxn, m_deltaGRxn_new[irxn], m_molNumSpecies_new[kspec], + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec]); + } #endif - if (m_deltaGRxn_new[irxn] >= 0.0 || !resurrect) { - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; - m_deltaMolNumSpecies[kspec] = 0.0; - resurrect = false; + if (m_deltaGRxn_new[irxn] >= 0.0 || !resurrect) { + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; + m_deltaMolNumSpecies[kspec] = 0.0; + resurrect = false; #ifdef DEBUG_MODE - sprintf(ANOTE, "Species stays zeroed: DG = %11.4E", m_deltaGRxn_new[irxn]); - if (m_deltaGRxn_new[irxn] < 0.0) { - if (m_speciesStatus[kspec] == VCS_SPECIES_STOICHZERO) { - sprintf(ANOTE, "Species stays zeroed even though dg neg due to " - "STOICH/PHASEPOP constraint: DG = %11.4E", - m_deltaGRxn_new[irxn]); - } else { - sprintf(ANOTE, "Species stays zeroed even though dg neg: DG = %11.4E, ds zeroed", - m_deltaGRxn_new[irxn]); - } - } -#endif - } else { - for (int j = 0; j < m_numElemConstraints; ++j) { - int elType = m_elType[j]; - if (elType == VCS_ELEM_TYPE_ABSPOS) { - atomComp = m_formulaMatrix[j][kspec]; - if (atomComp > 0.0) { - double maxPermissible = m_elemAbundancesGoal[j] / atomComp; - if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) { -#ifdef DEBUG_MODE - sprintf(ANOTE, "Species stays zeroed even though dG " - "neg, because of %s elemAbund", - m_elementName[j].c_str()); -#endif - resurrect = false; - break; - } - } - } - } - } - /* - * Resurrect the species - */ - if (resurrect) { - bool phaseResurrected = false; - if (Vphase->exists() == VCS_PHASE_EXIST_NO) { - //Vphase->setExistence(1); - phaseResurrected = true; - } - - if (phaseResurrected) { -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - plogf(" --- Zeroed species changed to major: "); - plogf("%-12s\n", m_speciesName[kspec].c_str()); - } -#endif - m_speciesStatus[kspec] = VCS_SPECIES_MAJOR; - MajorSpeciesHaveConverged = false; - allMinorZeroedSpecies = false; - } else { -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - plogf(" --- Zeroed species changed to minor: "); - plogf("%-12s\n", m_speciesName[kspec].c_str()); - } -#endif - m_speciesStatus[kspec] = VCS_SPECIES_MINOR; - } - if (m_deltaMolNumSpecies[kspec] > 0.0) { - dx = m_deltaMolNumSpecies[kspec] * 0.01; - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; - } else { - m_molNumSpecies_new[kspec] = m_totalMolNum * VCS_DELETE_PHASE_CUTOFF * 10.; - dx = m_molNumSpecies_new[kspec] - m_molNumSpecies_old[kspec]; - } - m_deltaMolNumSpecies[kspec] = dx; -#ifdef DEBUG_MODE - sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", m_deltaGRxn_new[irxn]); -#endif - } else { - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; - m_deltaMolNumSpecies[kspec] = 0.0; - dx = 0.0; - } - } else if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR) { - /********************************************************************/ - /***************************** MINOR SPECIES ************************/ - /********************************************************************/ - /* - * Unless ITI isn't equal to zero we zero out changes - * to minor species. - */ - if (iti != 0) { - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; - m_deltaMolNumSpecies[kspec] = 0.0; - dx = 0.0; -#ifdef DEBUG_MODE - sprintf(ANOTE,"minor species not considered"); - if (m_debug_print_lvl >= 2) { - plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str()); - plogf("%3d%11.4E%11.4E%11.4E | %s", - m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec], - m_deltaMolNumSpecies[kspec], ANOTE); - plogendl(); - } -#endif - continue; - } - /* - * Minor species alternative calculation - * --------------------------------------- - * This is based upon the following approximation: - * The mole fraction changes due to these reactions don't affect - * the mole numbers of the component species. Therefore the - * following approximation is valid for an ideal solution - * 0 = DG(I) + log(WT(I)/W(I)) - * (DG contains the contribution from FF(I) + log(W(I)/TL) ) - * Thus, - * WT(I) = W(I) EXP(-DG(I)) - * If soldel is true on return, then we branch to the section - * that deletes a species from the current set of active species. - */ -#ifdef DEBUG_MODE - dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE); -#else - dx = vcs_minor_alt_calc(kspec, irxn, &soldel); -#endif - m_deltaMolNumSpecies[kspec] = dx; - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; - - if (soldel) { - /*******************************************************************/ - /***** DELETE MINOR SPECIES LESS THAN VCS_DELETE_SPECIES_CUTOFF */ - /***** MOLE NUMBER */ - /*******************************************************************/ -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - plogf(" --- Delete minor species in multispec phase: %-12s", - m_speciesName[kspec].c_str()); - plogendl(); - } -#endif - m_deltaMolNumSpecies[kspec] = 0.0; - /* - * Delete species, kspec. The alternate return is for the case - * where all species become deleted. Then, we need to - * branch to the code where we reevaluate the deletion - * of all species. - */ - lnospec = vcs_delete_species(kspec); - if (lnospec) goto L_RECHECK_DELETED; - /* - * Go back to consider the next species in the list. - * Note, however, that the next species in the list is now - * in slot l. In deleting the previous species L, We have - * exchanged slot MR with slot l, and then have - * decremented MR. - * Therefore, we will decrement the species counter, here. - */ - --irxn; -#ifdef DEBUG_MODE - goto L_MAIN_LOOP_END_NO_PRINT; -#else - goto L_MAIN_LOOP_END; -#endif - } - } else { - /********************************************************************/ - /*********************** MAJOR SPECIES ******************************/ - /********************************************************************/ -#ifdef DEBUG_MODE - sprintf(ANOTE, "Normal Major Calc"); -#endif - /* - * Check for superconvergence of the formation reaction. Do - * nothing if it is superconverged. Skip to the end of the - * irxn loop if it is superconverged. - */ - if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) { - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; - m_deltaMolNumSpecies[kspec] = 0.0; - dx = 0.0; -#ifdef DEBUG_MODE - sprintf(ANOTE, "major species is converged"); - if (m_debug_print_lvl >= 2) { - plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str()); - plogf("%3d%11.4E%11.4E%11.4E | %s", - m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec], - m_deltaMolNumSpecies[kspec], ANOTE); - plogendl(); - } -#endif - continue; - } - /* - * Set the initial step size, dx, equal to the value produced - * by the routine, vcs_RxnStepSize(). - * - * Note the multiplition logic is to make sure that - * dg[] didn't change sign due to w[] changing in the - * middle of the iteration. (it can if a single species - * phase goes out of existence). - */ - if ((m_deltaGRxn_new[irxn] * m_deltaMolNumSpecies[kspec]) <= 0.0) { - dx = m_deltaMolNumSpecies[kspec]; - } else { - dx = 0.0; - m_deltaMolNumSpecies[kspec] = 0.0; -#ifdef DEBUG_MODE - sprintf(ANOTE, "dx set to 0, DG flipped sign due to " - "changed initial point"); -#endif - } - /* - * Form a tentative value of the new species moles - */ - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; - - /* - * Check for non-positive mole fraction of major species. - * If we find one, we branch to a section below. Then, - * depending upon the outcome, we branch to sections below, - * or we restart the entire iteration. - */ - if (m_molNumSpecies_new[kspec] <= 0.0) { -#ifdef DEBUG_MODE - sprintf(ANOTE, "initial nonpos kmoles= %11.3E", - m_molNumSpecies_new[kspec]); -#endif - /* ************************************************* */ - /* *** NON-POSITIVE MOLES OF MAJOR SPECIES ********* */ - /* ************************************************* */ - /* - * We are here when a tentative value of a mole fraction - * created by a tentative value of M_DELTAMOLNUMSPECIES(*) is negative. - * We branch from here depending upon whether this - * species is in a single species phase or in - * a multispecies phase. - */ - if (! (m_SSPhase[kspec])) { - /* - * Section for multispecies phases: - * - Cut reaction adjustment for positive kmoles of - * major species in multispecies phases. - * Decrease its concentration by a factor of 10. - */ - dx = -0.9 * m_molNumSpecies_old[kspec]; - m_deltaMolNumSpecies[kspec] = dx; - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; - } else { - /* - * Section for single species phases: - * Calculate a dx that will wipe out the - * moles in the phase. - */ - dx = -m_molNumSpecies_old[kspec]; - /* - * Calculate an update that doesn't create a negative mole - * number for a component species. Actually, restrict this - * a little more so that the component values can only be - * reduced by two 99%, - */ - for (j = 0; j < m_numComponents; ++j) { - if (sc_irxn[j] != 0.0) { - wx[j] = m_molNumSpecies_old[j] + sc_irxn[j] * dx; - if (wx[j] <= m_molNumSpecies_old[j] * 0.01 - 1.0E-150) { - dx = MAX(dx, m_molNumSpecies_old[j] * -0.99 / sc_irxn[j]); - } + sprintf(ANOTE, "Species stays zeroed: DG = %11.4E", m_deltaGRxn_new[irxn]); + if (m_deltaGRxn_new[irxn] < 0.0) { + if (m_speciesStatus[kspec] == VCS_SPECIES_STOICHZERO) { + sprintf(ANOTE, "Species stays zeroed even though dg neg due to " + "STOICH/PHASEPOP constraint: DG = %11.4E", + m_deltaGRxn_new[irxn]); } else { - wx[j] = m_molNumSpecies_old[j]; + sprintf(ANOTE, "Species stays zeroed even though dg neg: DG = %11.4E, ds zeroed", + m_deltaGRxn_new[irxn]); } } - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; - if (m_molNumSpecies_new[kspec] > 0.0) { - m_deltaMolNumSpecies[kspec] = dx; -#ifdef DEBUG_MODE - sprintf(ANOTE, - "zeroing SS phase created a neg component species " - "-> reducing step size instead"); -#endif - } else { - /* - * We are going to zero the single species phase. - * Set the existence flag - */ - iph = m_phaseID[kspec]; - Vphase = m_VolPhaseList[iph]; - //Vphase->setExistence(0); -#ifdef DEBUG_MODE - sprintf(ANOTE, "zeroing out SS phase: "); #endif - /* - * Change the base mole numbers for the iteration. - * We need to do this here, because we have decided - * to eliminate the phase in this special section - * outside the main loop. - */ - m_molNumSpecies_new[kspec] = 0.0; - doPhaseDeleteIph = iph; - doPhaseDeleteKspec = kspec; + } else { + for (int j = 0; j < m_numElemConstraints; ++j) { + int elType = m_elType[j]; + if (elType == VCS_ELEM_TYPE_ABSPOS) { + atomComp = m_formulaMatrix[j][kspec]; + if (atomComp > 0.0) { + double maxPermissible = m_elemAbundancesGoal[j] / atomComp; + if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) { +#ifdef DEBUG_MODE + sprintf(ANOTE, "Species stays zeroed even though dG " + "neg, because of %s elemAbund", + m_elementName[j].c_str()); +#endif + resurrect = false; + break; + } + } + } + } + } + /* + * Resurrect the species + */ + if (resurrect) { + bool phaseResurrected = false; + if (Vphase->exists() == VCS_PHASE_EXIST_NO) { + //Vphase->setExistence(1); + phaseResurrected = true; + } + if (phaseResurrected) { #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { - if (m_speciesStatus[kspec] >= 0) { - plogf(" --- SS species changed to zeroedss: "); - plogf("%-12s", m_speciesName[kspec].c_str()); - plogendl(); + plogf(" --- Zeroed species changed to major: "); + plogf("%-12s\n", m_speciesName[kspec].c_str()); + } +#endif + m_speciesStatus[kspec] = VCS_SPECIES_MAJOR; + MajorSpeciesHaveConverged = false; + allMinorZeroedSpecies = false; + } else { +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- Zeroed species changed to minor: "); + plogf("%-12s\n", m_speciesName[kspec].c_str()); + } +#endif + m_speciesStatus[kspec] = VCS_SPECIES_MINOR; + } + if (m_deltaMolNumSpecies[kspec] > 0.0) { + dx = m_deltaMolNumSpecies[kspec] * 0.01; + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; + } else { + m_molNumSpecies_new[kspec] = m_totalMolNum * VCS_DELETE_PHASE_CUTOFF * 10.; + dx = m_molNumSpecies_new[kspec] - m_molNumSpecies_old[kspec]; + } + m_deltaMolNumSpecies[kspec] = dx; +#ifdef DEBUG_MODE + sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", m_deltaGRxn_new[irxn]); +#endif + } else { + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; + m_deltaMolNumSpecies[kspec] = 0.0; + dx = 0.0; + } + } else if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR) { + /********************************************************************/ + /***************************** MINOR SPECIES ************************/ + /********************************************************************/ + /* + * Unless ITI isn't equal to zero we zero out changes + * to minor species. + */ + if (iti != 0) { + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; + m_deltaMolNumSpecies[kspec] = 0.0; + dx = 0.0; +#ifdef DEBUG_MODE + sprintf(ANOTE,"minor species not considered"); + if (m_debug_print_lvl >= 2) { + plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str()); + plogf("%3d%11.4E%11.4E%11.4E | %s", + m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec], + m_deltaMolNumSpecies[kspec], ANOTE); + plogendl(); + } +#endif + continue; + } + /* + * Minor species alternative calculation + * --------------------------------------- + * This is based upon the following approximation: + * The mole fraction changes due to these reactions don't affect + * the mole numbers of the component species. Therefore the + * following approximation is valid for an ideal solution + * 0 = DG(I) + log(WT(I)/W(I)) + * (DG contains the contribution from FF(I) + log(W(I)/TL) ) + * Thus, + * WT(I) = W(I) EXP(-DG(I)) + * If soldel is true on return, then we branch to the section + * that deletes a species from the current set of active species. + */ +#ifdef DEBUG_MODE + dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE); +#else + dx = vcs_minor_alt_calc(kspec, irxn, &soldel); +#endif + m_deltaMolNumSpecies[kspec] = dx; + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; + + if (soldel) { + /*******************************************************************/ + /***** DELETE MINOR SPECIES LESS THAN VCS_DELETE_SPECIES_CUTOFF */ + /***** MOLE NUMBER */ + /*******************************************************************/ +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- Delete minor species in multispec phase: %-12s", + m_speciesName[kspec].c_str()); + plogendl(); + } +#endif + m_deltaMolNumSpecies[kspec] = 0.0; + /* + * Delete species, kspec. The alternate return is for the case + * where all species become deleted. Then, we need to + * branch to the code where we reevaluate the deletion + * of all species. + */ + lnospec = vcs_delete_species(kspec); + if (lnospec) goto L_RECHECK_DELETED; + /* + * Go back to consider the next species in the list. + * Note, however, that the next species in the list is now + * in slot l. In deleting the previous species L, We have + * exchanged slot MR with slot l, and then have + * decremented MR. + * Therefore, we will decrement the species counter, here. + */ + --irxn; +#ifdef DEBUG_MODE + goto L_MAIN_LOOP_END_NO_PRINT; +#else + goto L_MAIN_LOOP_END; +#endif + } + } else { + /********************************************************************/ + /*********************** MAJOR SPECIES ******************************/ + /********************************************************************/ +#ifdef DEBUG_MODE + sprintf(ANOTE, "Normal Major Calc"); +#endif + /* + * Check for superconvergence of the formation reaction. Do + * nothing if it is superconverged. Skip to the end of the + * irxn loop if it is superconverged. + */ + if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) { + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec]; + m_deltaMolNumSpecies[kspec] = 0.0; + dx = 0.0; +#ifdef DEBUG_MODE + sprintf(ANOTE, "major species is converged"); + if (m_debug_print_lvl >= 2) { + plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str()); + plogf("%3d%11.4E%11.4E%11.4E | %s", + m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec], + m_deltaMolNumSpecies[kspec], ANOTE); + plogendl(); + } +#endif + continue; + } + /* + * Set the initial step size, dx, equal to the value produced + * by the routine, vcs_RxnStepSize(). + * + * Note the multiplition logic is to make sure that + * dg[] didn't change sign due to w[] changing in the + * middle of the iteration. (it can if a single species + * phase goes out of existence). + */ + if ((m_deltaGRxn_new[irxn] * m_deltaMolNumSpecies[kspec]) <= 0.0) { + dx = m_deltaMolNumSpecies[kspec]; + } else { + dx = 0.0; + m_deltaMolNumSpecies[kspec] = 0.0; +#ifdef DEBUG_MODE + sprintf(ANOTE, "dx set to 0, DG flipped sign due to " + "changed initial point"); +#endif + } + /* + * Form a tentative value of the new species moles + */ + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; + + /* + * Check for non-positive mole fraction of major species. + * If we find one, we branch to a section below. Then, + * depending upon the outcome, we branch to sections below, + * or we restart the entire iteration. + */ + if (m_molNumSpecies_new[kspec] <= 0.0) { +#ifdef DEBUG_MODE + sprintf(ANOTE, "initial nonpos kmoles= %11.3E", + m_molNumSpecies_new[kspec]); +#endif + /* ************************************************* */ + /* *** NON-POSITIVE MOLES OF MAJOR SPECIES ********* */ + /* ************************************************* */ + /* + * We are here when a tentative value of a mole fraction + * created by a tentative value of M_DELTAMOLNUMSPECIES(*) is negative. + * We branch from here depending upon whether this + * species is in a single species phase or in + * a multispecies phase. + */ + if (! (m_SSPhase[kspec])) { + /* + * Section for multispecies phases: + * - Cut reaction adjustment for positive kmoles of + * major species in multispecies phases. + * Decrease its concentration by a factor of 10. + */ + dx = -0.9 * m_molNumSpecies_old[kspec]; + m_deltaMolNumSpecies[kspec] = dx; + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; + } else { + /* + * Section for single species phases: + * Calculate a dx that will wipe out the + * moles in the phase. + */ + dx = -m_molNumSpecies_old[kspec]; + /* + * Calculate an update that doesn't create a negative mole + * number for a component species. Actually, restrict this + * a little more so that the component values can only be + * reduced by two 99%, + */ + for (j = 0; j < m_numComponents; ++j) { + if (sc_irxn[j] != 0.0) { + wx[j] = m_molNumSpecies_old[j] + sc_irxn[j] * dx; + if (wx[j] <= m_molNumSpecies_old[j] * 0.01 - 1.0E-150) { + dx = MAX(dx, m_molNumSpecies_old[j] * -0.99 / sc_irxn[j]); + } + } else { + wx[j] = m_molNumSpecies_old[j]; } } + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx; + if (m_molNumSpecies_new[kspec] > 0.0) { + m_deltaMolNumSpecies[kspec] = dx; +#ifdef DEBUG_MODE + sprintf(ANOTE, + "zeroing SS phase created a neg component species " + "-> reducing step size instead"); +#endif + } else { + /* + * We are going to zero the single species phase. + * Set the existence flag + */ + iph = m_phaseID[kspec]; + Vphase = m_VolPhaseList[iph]; + //Vphase->setExistence(0); +#ifdef DEBUG_MODE + sprintf(ANOTE, "zeroing out SS phase: "); #endif - m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS; - ++m_numRxnMinorZeroed; - allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc); + /* + * Change the base mole numbers for the iteration. + * We need to do this here, because we have decided + * to eliminate the phase in this special section + * outside the main loop. + */ + m_molNumSpecies_new[kspec] = 0.0; + doPhaseDeleteIph = iph; + doPhaseDeleteKspec = kspec; - for (int kk = 0; kk < m_numSpeciesTot; kk++) { - m_deltaMolNumSpecies[kk] = 0.0; - m_molNumSpecies_new[kk] = m_molNumSpecies_old[kk]; - } - m_deltaMolNumSpecies[kspec] = dx; - m_molNumSpecies_new[kspec] = 0.0; +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + if (m_speciesStatus[kspec] >= 0) { + plogf(" --- SS species changed to zeroedss: "); + plogf("%-12s", m_speciesName[kspec].c_str()); + plogendl(); + } + } +#endif + m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS; + ++m_numRxnMinorZeroed; + allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc); - for (k = 0; k < m_numComponents; ++k) { - m_deltaMolNumSpecies[k] = 0.0; - } - for (iph = 0; iph < m_numPhases; iph++) { - m_deltaPhaseMoles[iph] = 0.0; - } + for (int kk = 0; kk < m_numSpeciesTot; kk++) { + m_deltaMolNumSpecies[kk] = 0.0; + m_molNumSpecies_new[kk] = m_molNumSpecies_old[kk]; + } + m_deltaMolNumSpecies[kspec] = dx; + m_molNumSpecies_new[kspec] = 0.0; + for (k = 0; k < m_numComponents; ++k) { + m_deltaMolNumSpecies[k] = 0.0; + } + for (iph = 0; iph < m_numPhases; iph++) { + m_deltaPhaseMoles[iph] = 0.0; + } + + } } - } - } + } #ifdef VCS_LINE_SEARCH - /*********************************************************************/ - /*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/ - /*********************************************************************/ - /* - * Skip the line search if we are birthing a species - */ - if ((dx != 0.0) && - (m_molNumSpecies_old[kspec] > 0.0) && - (doPhaseDeleteIph == -1) && - (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { - double dx_old = dx; + /*********************************************************************/ + /*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/ + /*********************************************************************/ + /* + * Skip the line search if we are birthing a species + */ + if ((dx != 0.0) && + (m_molNumSpecies_old[kspec] > 0.0) && + (doPhaseDeleteIph == -1) && + (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { + double dx_old = dx; #ifdef DEBUG_MODE - dx = vcs_line_search(irxn, dx_old, ANOTE); + dx = vcs_line_search(irxn, dx_old, ANOTE); #else - dx = vcs_line_search(irxn, dx_old); + dx = vcs_line_search(irxn, dx_old); #endif - vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW); - } - m_deltaMolNumSpecies[kspec] = dx; + vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW); + } + m_deltaMolNumSpecies[kspec] = dx; #endif - }/* End of Loop on ic[irxn] -> the type of species */ - } - /***********************************************************************/ - /****** CALCULATE KMOLE NUMBER CHANGE FOR THE COMPONENT BASIS **********/ - /***********************************************************************/ - if (dx != 0.0 && (m_speciesUnknownType[kspec] != - VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { - /* - * Change the amount of the component compounds according - * to the reaction delta that we just computed. - * This should keep the amount of material constant. - */ + }/* End of Loop on ic[irxn] -> the type of species */ + } + /***********************************************************************/ + /****** CALCULATE KMOLE NUMBER CHANGE FOR THE COMPONENT BASIS **********/ + /***********************************************************************/ + if (dx != 0.0 && (m_speciesUnknownType[kspec] != + VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { + /* + * Change the amount of the component compounds according + * to the reaction delta that we just computed. + * This should keep the amount of material constant. + */ #ifdef DEBUG_MODE - if (fabs(m_deltaMolNumSpecies[kspec] -dx) > - 1.0E-14*(fabs(m_deltaMolNumSpecies[kspec]) + fabs(dx) + 1.0E-32)) { - plogf(" ds[kspec] = %20.16g dx = %20.16g , kspec = %d\n", - m_deltaMolNumSpecies[kspec], dx, kspec); - plogf("we have a problem!"); + if (fabs(m_deltaMolNumSpecies[kspec] -dx) > + 1.0E-14*(fabs(m_deltaMolNumSpecies[kspec]) + fabs(dx) + 1.0E-32)) { + plogf(" ds[kspec] = %20.16g dx = %20.16g , kspec = %d\n", + m_deltaMolNumSpecies[kspec], dx, kspec); + plogf("we have a problem!"); + plogendl(); + exit(EXIT_FAILURE); + } +#endif + for (k = 0; k < m_numComponents; ++k) { + m_deltaMolNumSpecies[k] += sc_irxn[k] * dx; + } + /* + * Calculate the tentative change in the total number of + * moles in all of the phases + */ + dnPhase_irxn = m_deltaMolNumPhase[irxn]; + for (iph = 0; iph < m_numPhases; iph++) { + m_deltaPhaseMoles[iph] += dx * dnPhase_irxn[iph]; + } + } + +#ifdef DEBUG_MODE + checkDelta1(VCS_DATA_PTR(m_deltaMolNumSpecies), + VCS_DATA_PTR(m_deltaPhaseMoles), kspec+1); +#endif + /* + * Branch point for returning - + */ +#ifndef DEBUG_MODE + L_MAIN_LOOP_END: ; +#endif +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec]; + plogf(" --- "); plogf("%-12.12s", m_speciesName[kspec].c_str()); + plogf("%3d%11.4E%11.4E%11.4E | %s", + m_speciesStatus[kspec], m_molNumSpecies_old[kspec], + m_molNumSpecies_new[kspec], + m_deltaMolNumSpecies[kspec], ANOTE); + plogendl(); + } + L_MAIN_LOOP_END_NO_PRINT: ; +#endif + if (doPhaseDeleteIph != -1) { +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- "); + plogf("%-12.12s Main Loop Special Case deleting phase with species: ", + m_speciesName[doPhaseDeleteKspec].c_str()); + plogendl(); + } +#endif + break; + } + } /**************** END OF MAIN LOOP OVER FORMATION REACTIONS ************/ + +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + for (k = 0; k < m_numComponents; k++) { + plogf(" --- "); plogf("%-12.12s", m_speciesName[k].c_str()); + plogf(" c%11.4E%11.4E%11.4E |\n", + m_molNumSpecies_old[k], + m_molNumSpecies_old[k]+m_deltaMolNumSpecies[k], m_deltaMolNumSpecies[k]); + } + plogf(" "); vcs_print_line("-", 80); + plogf(" --- Finished Main Loop"); + plogendl(); + } +#endif + + /*************************************************************************/ + /*********** LIMIT REDUCTION OF BASIS SPECIES TO 99% *********************/ + /*************************************************************************/ + /* + * We have a tentative m_deltaMolNumSpecies[]. Now apply other criteria + * to limit it's magnitude. + * + * + */ + par = 0.5; + for (k = 0; k < m_numComponents; ++k) { + if (m_molNumSpecies_old[k] > 0.0) { + xx = -m_deltaMolNumSpecies[k] / m_molNumSpecies_old[k]; + if (par < xx) { + par = xx; +#ifdef DEBUG_MODE + ll = k; +#endif + } + } else { + if (m_deltaMolNumSpecies[k] < 0.0) { + /* + * If we are here, we then do a step which violates element + * conservation. + */ + iph = m_phaseID[k]; + m_deltaPhaseMoles[iph] -= m_deltaMolNumSpecies[k]; + m_deltaMolNumSpecies[k] = 0.0; + } + } + } + par = 1.0 / par; + if (par <= 1.01 && par > 0.0) { + /* Reduce the size of the step by the multiplicative factor, par */ + par *= 0.99; +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- Reduction in step size due to component "); + plogf("%s", m_speciesName[ll].c_str()); + plogf(" going negative = %11.3E", par); + plogendl(); + } +#endif + for (i = 0; i < m_numSpeciesTot; ++i) { + m_deltaMolNumSpecies[i] *= par; + } + for (iph = 0; iph < m_numPhases; iph++) { + m_deltaPhaseMoles[iph] *= par; + } + } else { + par = 1.0; + } +#ifdef DEBUG_MODE + checkDelta1(VCS_DATA_PTR(m_deltaMolNumSpecies), + VCS_DATA_PTR(m_deltaPhaseMoles), m_numSpeciesTot); +#endif + + /* + * Now adjust the wt[kspec]'s so that the reflect the decrease in + * the overall length of m_deltaMolNumSpecies[kspec] just calculated. At the end + * of this section wt[], m_deltaMolNumSpecies[], tPhMoles, and tPhMoles1 should all be + * consistent with a new estimate of the state of the system. + */ + for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { + m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec]; + if (m_molNumSpecies_new[kspec] < 0.0 && (m_speciesUnknownType[kspec] + != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { + plogf("vcs_solve_TP: ERROR on step change wt[%d:%s]: %g < 0.0", + kspec, m_speciesName[kspec].c_str(), m_molNumSpecies_new[kspec]); plogendl(); exit(EXIT_FAILURE); } -#endif - for (k = 0; k < m_numComponents; ++k) { - m_deltaMolNumSpecies[k] += sc_irxn[k] * dx; - } - /* - * Calculate the tentative change in the total number of - * moles in all of the phases - */ - dnPhase_irxn = m_deltaMolNumPhase[irxn]; - for (iph = 0; iph < m_numPhases; iph++) { - m_deltaPhaseMoles[iph] += dx * dnPhase_irxn[iph]; - } } - -#ifdef DEBUG_MODE - checkDelta1(VCS_DATA_PTR(m_deltaMolNumSpecies), - VCS_DATA_PTR(m_deltaPhaseMoles), kspec+1); -#endif + /* - * Branch point for returning - + * Calculate the tentative total mole numbers for each phase */ -#ifndef DEBUG_MODE - L_MAIN_LOOP_END: ; -#endif -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec]; - plogf(" --- "); plogf("%-12.12s", m_speciesName[kspec].c_str()); - plogf("%3d%11.4E%11.4E%11.4E | %s", - m_speciesStatus[kspec], m_molNumSpecies_old[kspec], - m_molNumSpecies_new[kspec], - m_deltaMolNumSpecies[kspec], ANOTE); - plogendl(); - } - L_MAIN_LOOP_END_NO_PRINT: ; -#endif - if (doPhaseDeleteIph != -1) { -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - plogf(" --- "); - plogf("%-12.12s Main Loop Special Case deleting phase with species: ", - m_speciesName[doPhaseDeleteKspec].c_str()); - plogendl(); - } -#endif - break; - } - } /**************** END OF MAIN LOOP OVER FORMATION REACTIONS ************/ - -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - for (k = 0; k < m_numComponents; k++) { - plogf(" --- "); plogf("%-12.12s", m_speciesName[k].c_str()); - plogf(" c%11.4E%11.4E%11.4E |\n", - m_molNumSpecies_old[k], - m_molNumSpecies_old[k]+m_deltaMolNumSpecies[k], m_deltaMolNumSpecies[k]); - } - plogf(" "); vcs_print_line("-", 80); - plogf(" --- Finished Main Loop"); - plogendl(); - } -#endif - - /*************************************************************************/ - /*********** LIMIT REDUCTION OF BASIS SPECIES TO 99% *********************/ - /*************************************************************************/ - /* - * We have a tentative m_deltaMolNumSpecies[]. Now apply other criteria - * to limit it's magnitude. - * - * - */ - par = 0.5; - for (k = 0; k < m_numComponents; ++k) { - if (m_molNumSpecies_old[k] > 0.0) { - xx = -m_deltaMolNumSpecies[k] / m_molNumSpecies_old[k]; - if (par < xx) { - par = xx; -#ifdef DEBUG_MODE - ll = k; -#endif - } - } else { - if (m_deltaMolNumSpecies[k] < 0.0) { - /* - * If we are here, we then do a step which violates element - * conservation. - */ - iph = m_phaseID[k]; - m_deltaPhaseMoles[iph] -= m_deltaMolNumSpecies[k]; - m_deltaMolNumSpecies[k] = 0.0; - } - } - } - par = 1.0 / par; - if (par <= 1.01 && par > 0.0) { - /* Reduce the size of the step by the multiplicative factor, par */ - par *= 0.99; -#ifdef DEBUG_MODE - if (m_debug_print_lvl >= 2) { - plogf(" --- Reduction in step size due to component "); - plogf("%s", m_speciesName[ll].c_str()); - plogf(" going negative = %11.3E", par); - plogendl(); - } -#endif - for (i = 0; i < m_numSpeciesTot; ++i) { - m_deltaMolNumSpecies[i] *= par; - } for (iph = 0; iph < m_numPhases; iph++) { - m_deltaPhaseMoles[iph] *= par; + m_tPhaseMoles_new[iph] = m_tPhaseMoles_old[iph] + m_deltaPhaseMoles[iph]; } - } else { - par = 1.0; - } -#ifdef DEBUG_MODE - checkDelta1(VCS_DATA_PTR(m_deltaMolNumSpecies), - VCS_DATA_PTR(m_deltaPhaseMoles), m_numSpeciesTot); -#endif - - /* - * Now adjust the wt[kspec]'s so that the reflect the decrease in - * the overall length of m_deltaMolNumSpecies[kspec] just calculated. At the end - * of this section wt[], m_deltaMolNumSpecies[], tPhMoles, and tPhMoles1 should all be - * consistent with a new estimate of the state of the system. - */ - for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { - m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec]; - if (m_molNumSpecies_new[kspec] < 0.0 && (m_speciesUnknownType[kspec] - != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { - plogf("vcs_solve_TP: ERROR on step change wt[%d:%s]: %g < 0.0", - kspec, m_speciesName[kspec].c_str(), m_molNumSpecies_new[kspec]); + + /* + * Set the flags indicating the mole numbers in the vcs_VolPhase + * objects are out of date. + */ + vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW); + + /* + * Calculate the new chemical potentials using the tentative + * solution values. We only calculate a subset of these, because + * we have only updated a subset of the W(). + */ + vcs_dfe(VCS_STATECALC_NEW, 0, 0, m_numSpeciesTot); + + /* + * Evaluate DeltaG for all components if ITI=0, and for + * major components only if ITI NE 0 + */ + vcs_deltag(0, false, VCS_STATECALC_NEW); + + /* *************************************************************** */ + /* **** CONVERGENCE FORCER SECTION ******************************* */ + /* *************************************************************** */ + if (printDetails) { + plogf(" --- Total Old Dimensionless Gibbs Free Energy = %20.13E\n", + vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_old), + VCS_DATA_PTR(m_tPhaseMoles_old))); + plogf(" --- Total tentative Dimensionless Gibbs Free Energy = %20.13E", + vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new), + VCS_DATA_PTR(m_tPhaseMoles_new))); plogendl(); - exit(EXIT_FAILURE); } - } - - /* - * Calculate the tentative total mole numbers for each phase - */ - for (iph = 0; iph < m_numPhases; iph++) { - m_tPhaseMoles_new[iph] = m_tPhaseMoles_old[iph] + m_deltaPhaseMoles[iph]; - } - /* - * Set the flags indicating the mole numbers in the vcs_VolPhase - * objects are out of date. - */ - vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW); + forced = vcs_globStepDamp(); - /* - * Calculate the new chemical potentials using the tentative - * solution values. We only calculate a subset of these, because - * we have only updated a subset of the W(). - */ - vcs_dfe(VCS_STATECALC_NEW, 0, 0, m_numSpeciesTot); - - /* - * Evaluate DeltaG for all components if ITI=0, and for - * major components only if ITI NE 0 - */ - vcs_deltag(0, false, VCS_STATECALC_NEW); - - /* *************************************************************** */ - /* **** CONVERGENCE FORCER SECTION ******************************* */ - /* *************************************************************** */ - if (printDetails) { - plogf(" --- Total Old Dimensionless Gibbs Free Energy = %20.13E\n", - vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_old), - VCS_DATA_PTR(m_tPhaseMoles_old))); - plogf(" --- Total tentative Dimensionless Gibbs Free Energy = %20.13E", - vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new), - VCS_DATA_PTR(m_tPhaseMoles_new))); - plogendl(); - } - - forced = vcs_globStepDamp(); - - /* - * Print out the changes to the solution that FORCER produced - */ - if (printDetails && forced) { + /* + * Print out the changes to the solution that FORCER produced + */ + if (printDetails && forced) { - plogf(" -----------------------------------------------------\n"); - plogf(" --- FORCER SUBROUTINE changed the solution:\n"); - plogf(" --- SPECIES Status INIT MOLES TENT_MOLES"); - plogf(" FINAL KMOLES INIT_DEL_G/RT TENT_DEL_G/RT FINAL_DELTA_G/RT\n"); - for (i = 0; i < m_numComponents; ++i) { - plogf(" --- %-12.12s", m_speciesName[i].c_str()); - plogf(" %14.6E %14.6E %14.6E\n", m_molNumSpecies_old[i], - m_molNumSpecies_old[i] + m_deltaMolNumSpecies[i], m_molNumSpecies_new[i]); + plogf(" -----------------------------------------------------\n"); + plogf(" --- FORCER SUBROUTINE changed the solution:\n"); + plogf(" --- SPECIES Status INIT MOLES TENT_MOLES"); + plogf(" FINAL KMOLES INIT_DEL_G/RT TENT_DEL_G/RT FINAL_DELTA_G/RT\n"); + for (i = 0; i < m_numComponents; ++i) { + plogf(" --- %-12.12s", m_speciesName[i].c_str()); + plogf(" %14.6E %14.6E %14.6E\n", m_molNumSpecies_old[i], + m_molNumSpecies_old[i] + m_deltaMolNumSpecies[i], m_molNumSpecies_new[i]); + } + for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) { + irxn = kspec - m_numComponents; + plogf(" --- %-12.12s", m_speciesName[kspec].c_str()); + plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", m_speciesStatus[kspec], + m_molNumSpecies_old[kspec], + m_molNumSpecies_old[kspec]+m_deltaMolNumSpecies[kspec], + m_molNumSpecies_new[kspec], m_deltaGRxn_old[irxn], + m_deltaGRxn_tmp[irxn], m_deltaGRxn_new[irxn]); + } + print_space(26); + plogf("Norms of Delta G():%14.6E%14.6E\n", + l2normdg(VCS_DATA_PTR(m_deltaGRxn_old)), + l2normdg(VCS_DATA_PTR(m_deltaGRxn_new))); + plogf(" Total kmoles of gas = %15.7E\n", m_tPhaseMoles_old[0]); + if ((m_numPhases > 1) && (! (m_VolPhaseList[1])->m_singleSpecies)) { + plogf(" Total kmoles of liquid = %15.7E\n", m_tPhaseMoles_old[1]); + } else { + plogf(" Total kmoles of liquid = %15.7E\n", 0.0); + } + plogf(" Total New Dimensionless Gibbs Free Energy = %20.13E\n", + vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new), + VCS_DATA_PTR(m_tPhaseMoles_new))); + plogf(" -----------------------------------------------------"); + plogendl(); } - for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) { - irxn = kspec - m_numComponents; - plogf(" --- %-12.12s", m_speciesName[kspec].c_str()); - plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", m_speciesStatus[kspec], - m_molNumSpecies_old[kspec], - m_molNumSpecies_old[kspec]+m_deltaMolNumSpecies[kspec], - m_molNumSpecies_new[kspec], m_deltaGRxn_old[irxn], - m_deltaGRxn_tmp[irxn], m_deltaGRxn_new[irxn]); - } - print_space(26); - plogf("Norms of Delta G():%14.6E%14.6E\n", - l2normdg(VCS_DATA_PTR(m_deltaGRxn_old)), - l2normdg(VCS_DATA_PTR(m_deltaGRxn_new))); - plogf(" Total kmoles of gas = %15.7E\n", m_tPhaseMoles_old[0]); - if ((m_numPhases > 1) && (! (m_VolPhaseList[1])->m_singleSpecies)) { - plogf(" Total kmoles of liquid = %15.7E\n", m_tPhaseMoles_old[1]); - } else { - plogf(" Total kmoles of liquid = %15.7E\n", 0.0); - } - plogf(" Total New Dimensionless Gibbs Free Energy = %20.13E\n", - vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new), - VCS_DATA_PTR(m_tPhaseMoles_new))); - plogf(" -----------------------------------------------------"); - plogendl(); } - /* *************************************************************** */ /* **** ITERATION SUMMARY PRINTOUT SECTION *********************** */ /* *************************************************************** */ @@ -1186,11 +1243,12 @@ namespace VCSnonideal { vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new), VCS_DATA_PTR(m_tPhaseMoles_new))); plogendl(); +#ifdef DEBUG_MODE if (m_VCount->Its > 550) { plogf(" --- Troublesome solve"); plogendl(); } - +#endif } /*************************************************************************/ @@ -1593,7 +1651,10 @@ namespace VCSnonideal { MajorSpeciesHaveConverged = false; /* * Go back and do another iteration with variable ITI - */ + */ + if (forceComponentCalc) { + goto L_COMPONENT_CALC; + } goto L_MAINLOOP_MM4_SPECIES; } } @@ -1659,6 +1720,9 @@ namespace VCSnonideal { * to the main loop to do another iteration. */ iti = 0; + if (forceComponentCalc) { + goto L_COMPONENT_CALC; + } goto L_MAINLOOP_ALL_SPECIES; } } @@ -1952,16 +2016,16 @@ namespace VCSnonideal { * the mole numbers of the component species. Therefore the following * approximation is valid for a small component of an ideal phase: * - * 0 = m_deltaGrxn_old(I) + log(molNum_new(I)/molNum_old(I)) + * 0 = m_deltaGRxn_old(I) + log(molNum_new(I)/molNum_old(I)) * - * m_deltaGrxn_old contains the contribution from + * m_deltaGRxn_old contains the contribution from * * m_feSpecies_old(I) = * m_SSfeSpecies(I) + * log(ActCoeff[i] * molNum_old(I) / m_tPhaseMoles_old(iph)) * Thus, * - * molNum_new(I)= molNum_old(I) * EXP(-m_deltaGrxn_old(I)) + * molNum_new(I)= molNum_old(I) * EXP(-m_deltaGRxn_old(I)) * * Most of this section is mainly restricting the update to reasonable * values. @@ -1993,12 +2057,15 @@ namespace VCSnonideal { , char *ANOTE #endif ) const { - double dx = 0.0; + double dx = 0.0, a; double w_kspec = m_molNumSpecies_old[kspec]; double molNum_kspec_new; - double wTrial; - double dg_irxn = m_deltaGRxn_old[irxn]; + double wTrial, tmp; + double dg_irxn = m_deltaGRxn_old[irxn]; + doublereal s; + vcs_VolPhase * Vphase = 0; int iph = m_phaseID[kspec]; + *do_delete = FALSE; if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { if (w_kspec <= 0.0) { @@ -2023,8 +2090,42 @@ namespace VCSnonideal { return 0.0; } } - - wTrial = w_kspec * exp(-dg_irxn); + + /* + * get the diagonal of the activity coefficent jacobian + */ + Vphase = m_VolPhaseList[iph]; + s = m_dLnActCoeffdMolNum[kspec][kspec]; + // s *= (m_tPhaseMoles_old[iph]); + /* + * We fit it to a power law approximation of the activity coefficient + * + * gamma = gamma_0 * ( x / x0)**a + * + * where a is forced to be a little bit greater than -1. + * We do this so that the resulting expression is always nonnegative + * + * We then solve the resulting calculation: + * + * gamma * x = gamma_0 * x0 exp (-deltaG/RT); + * + * + */ + a = w_kspec * s; + if (a < (-1.0 + 1.0E-8)) { + a = -1.0 + 1.0E-8; + } else if (a > 100.0) { + a = 100.0; + } + tmp = -dg_irxn / (1.0 + a); + if (tmp < -200.) { + tmp = -200.; + } else if ( tmp > 200.) { + tmp = 200.; + } + wTrial = w_kspec * exp(tmp); + // wTrial = w_kspec * exp(-dg_irxn); + molNum_kspec_new = wTrial; if (wTrial > 100. * w_kspec) { @@ -2096,9 +2197,9 @@ namespace VCSnonideal { double delta = *delta_ptr; #ifdef DEBUG_MODE if (irxn < 0) { - plogf(" --- delete_species() ERROR: called for a component %d", kspec); - plogendl(); - exit(EXIT_FAILURE); + plogf(" --- delete_species() ERROR: called for a component %d", kspec); + plogendl(); + exit(EXIT_FAILURE); } #endif if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { @@ -2583,8 +2684,8 @@ namespace VCSnonideal { for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { iph = m_phaseID[kspec]; m_feSpecies_new[kspec] = (m_SSfeSpecies[kspec] + log(m_actCoeffSpecies_old[kspec]) - - m_lnMnaughtSpecies[kspec] - + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iph]); + - m_lnMnaughtSpecies[kspec] + + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iph]); } /* @@ -2722,10 +2823,8 @@ namespace VCSnonideal { } return false; } - /*************************************************************************************/ - - // Provide an estimate for the deleted species in phases that - // are not zeroed out + //==================================================================================================================== + // Provide an estimate for the deleted species in phases that are not zeroed out /* * Try to add back in all deleted species. An estimate of the kmol numbers * are obtained and the species is added back into the equation system, @@ -2735,39 +2834,54 @@ namespace VCSnonideal { int iph, kspec, retn; if (m_numSpeciesRdc == m_numSpeciesTot) return 0; /* - * Use the standard chemical potentials for the chemical potentials - * of deleted species. Then, calculate Delta G for + * Use the standard chemical potentials for the chemical potentials of deleted species. Then, calculate Delta G for * for formation reactions. * We are relying here on a old saved value of m_actCoeffSpecies_old[kspec] - * being sufficiently good. Note, we will recalculate everything at the - * end of the routine. + * being sufficiently good. Note, we will recalculate everything at the end of the routine. */ - for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { - iph = m_phaseID[kspec]; - m_feSpecies_new[kspec] = (m_SSfeSpecies[kspec] + log(m_actCoeffSpecies_old[kspec]) - - m_lnMnaughtSpecies[kspec] - + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iph]); + vcs_dcopy(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_molNumSpecies_old), m_numSpeciesTot); + + for (int cits = 0; cits < 3; cits++) { + for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { + iph = m_phaseID[kspec]; + vcs_VolPhase *Vphase = m_VolPhaseList[iph]; + if (m_molNumSpecies_new[kspec] == 0.0) { + m_molNumSpecies_new[kspec] = VCS_DELETE_MINORSPECIES_CUTOFF * 1.0E-10; + } + if (!Vphase->m_singleSpecies) { + Vphase->sendToVCS_ActCoeff(VCS_STATECALC_NEW, VCS_DATA_PTR(m_actCoeffSpecies_new)); + } + m_feSpecies_new[kspec] = (m_SSfeSpecies[kspec] + log(m_actCoeffSpecies_new[kspec]) - m_lnMnaughtSpecies[kspec] + + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iph]); + } + /* + * Recalculate the DeltaG's of the formation reactions for the deleted species in the mechanism + */ + vcs_deltag(0, true, VCS_STATECALC_NEW); + for (int irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) { + kspec = m_indexRxnToSpecies[irxn]; + iph = m_phaseID[kspec]; + if (m_tPhaseMoles_old[iph] > 0.0) { + double maxDG = MIN(m_deltaGRxn_new[irxn], 690.0); + double dx = m_tPhaseMoles_old[iph] * exp(- maxDG); + m_molNumSpecies_new[kspec] = dx; + if (m_molNumSpecies_new[kspec] > 2 *VCS_DELETE_MINORSPECIES_CUTOFF) { + m_molNumSpecies_new[kspec] = 2 * VCS_DELETE_MINORSPECIES_CUTOFF; + } + } + } } - /* - * Recalculate the DeltaG's of the formation reactions for the - * deleted species in the mechanism - */ - vcs_deltag(0, true, VCS_STATECALC_NEW); - for (int irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) { kspec = m_indexRxnToSpecies[irxn]; iph = m_phaseID[kspec]; if (m_tPhaseMoles_old[iph] > 0.0) { - double maxDG = MIN(m_deltaGRxn_new[irxn], 690.0); - - double dx = m_tPhaseMoles_old[iph] * exp(- maxDG); + double dx = m_molNumSpecies_new[kspec]; retn = delta_species(kspec, &dx); if (retn == 0) { #ifdef DEBUG_MODE if (m_debug_print_lvl) { - plogf(" --- add_deleted(): delta_species() failed for " - "species %s (%d) with mol number %g\n", - m_speciesName[kspec].c_str(), kspec, dx); + plogf(" --- add_deleted(): delta_species() failed for species %s (%d) with mol number %g\n", + m_speciesName[kspec].c_str(), kspec, dx); } #endif if (dx > 1.0E-50) { @@ -2776,8 +2890,7 @@ namespace VCSnonideal { #ifdef DEBUG_MODE if (retn == 0) { if (m_debug_print_lvl) { - plogf(" --- add_deleted(): delta_species() failed for " - "species %s (%d) with mol number %g\n", + plogf(" --- add_deleted(): delta_species() failed for species %s (%d) with mol number %g\n", m_speciesName[kspec].c_str(), kspec, dx); } } @@ -2814,8 +2927,7 @@ namespace VCSnonideal { retn++; #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { - plogf(" --- add_deleted(): species %s " - "with mol number %g not converged: DG = %g", + plogf(" --- add_deleted(): species %s with mol number %g not converged: DG = %g", m_speciesName[kspec].c_str(), m_molNumSpecies_old[kspec], m_deltaGRxn_old[irxn]); plogendl(); @@ -3405,7 +3517,11 @@ namespace VCSnonideal { * Use Gauss-Jordon block elimination to calculate * the reaction matrix, m_stoichCoeffRxnMatrix[][]. */ - j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, m_stoichCoeffRxnMatrix[0], m_numRxnTot); + + j = vcsUtil_gaussj(sm, m_numElemConstraints, ncTrial, m_stoichCoeffRxnMatrix[0], m_numRxnTot); + // j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, m_stoichCoeffRxnMatrix[0], m_numRxnTot); + + if (j == 1) { plogf("vcs_solve_TP ERROR: mlequ returned an error condition\n"); return VCS_FAILED_CONVERGENCE; @@ -3454,7 +3570,9 @@ namespace VCSnonideal { } } } - j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, aw, 1); + + j = vcsUtil_gaussj(sm, m_numElemConstraints, ncTrial, aw, 1); + // j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, aw, 1); if (j == 1) { plogf("vcs_solve_TP ERROR: mlequ returned an error condition\n"); return VCS_FAILED_CONVERGENCE; @@ -3483,31 +3601,81 @@ namespace VCSnonideal { if (m_debug_print_lvl >= 2) { plogf(" --- Components:"); for (j = 0; j < ncTrial; j++) { - plogf(" %3d ", j); + plogf(" %3d", j); } plogf("\n --- Components Moles:"); for (j = 0; j < ncTrial; j++) { - plogf("%10.3g", m_molNumSpecies_old[j]); + plogf(" % -10.3E", m_molNumSpecies_old[j]); } - plogf("\n --- NonComponent| Moles | "); + plogf("\n --- NonComponent| Moles |"); for (j = 0; j < ncTrial; j++) { - plogf("%-10.10s", m_speciesName[j].c_str()); + plogf(" %10.10s", m_speciesName[j].c_str()); } //plogf("| m_scSize"); plogf("\n"); for (i = 0; i < m_numRxnTot; i++) { plogf(" --- %3d ", m_indexRxnToSpecies[i]); plogf("%-10.10s", m_speciesName[m_indexRxnToSpecies[i]].c_str()); - plogf("|%10.3g|", m_molNumSpecies_old[m_indexRxnToSpecies[i]]); + plogf("|% -10.3E|", m_molNumSpecies_old[m_indexRxnToSpecies[i]]); for (j = 0; j < ncTrial; j++) { - plogf(" %6.2f", m_stoichCoeffRxnMatrix[i][j]); + plogf(" %+7.3f", m_stoichCoeffRxnMatrix[i][j]); } //plogf(" | %6.2f", m_scSize[i]); plogf("\n"); } + + + /* + * Manual check on the satisfaction of the reaction matrix's ability + * to conserve elements + */ + double sum; + double sumMax = -1.0; + int iMax = -1; + int jMax = -1; + int n; + for (i = 0; i < m_numRxnTot; ++i) { + k = m_indexRxnToSpecies[i]; + for (j = 0; j < ncTrial; ++j) { + if (j == jlose) { + sum = m_formulaMatrix[juse][k]; + for (n = 0; n < ncTrial; n++) { + double numElements = m_formulaMatrix[juse][n]; + double coeff = m_stoichCoeffRxnMatrix[i][n]; + sum += coeff * numElements; + } + } else { + sum = m_formulaMatrix[j][k]; + for (n = 0; n < ncTrial; n++) { + double numElements = m_formulaMatrix[j][n]; + double coeff = m_stoichCoeffRxnMatrix[i][n]; + sum += coeff * numElements; + } + } + if (fabs(sum) > sumMax) { + sumMax = fabs(sum); + iMax = i; + jMax = j; + if (j == jlose) { + jMax = juse; + } + } + if (fabs(sum) > 1.0E-6) { + printf("we have a prob\n"); + exit(-1); + } + } + } + plogf(" --- largest error in Stoich coeff = %g at rxn = %d ", sumMax, iMax); + plogf("%-10.10s", m_speciesName[m_indexRxnToSpecies[iMax]].c_str()); + plogf(" element = %d ", jMax); + plogf("%-5.5s", m_elementName[jMax].c_str()); + plogf("\n"); plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n"); } #endif + + /* **************************************************** */ /* **** EVALUATE DELTA N VALUES *********************** */ /* **************************************************** */ @@ -4308,10 +4476,10 @@ namespace VCSnonideal { feSpecies[kspec] = m_SSfeSpecies[kspec] + log(actCoeff_ptr[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec] - + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase]; ; + + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase]; } else { feSpecies[kspec] = m_SSfeSpecies[kspec] - m_lnMnaughtSpecies[kspec] - + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase]; ; + + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase]; } } else { feSpecies[kspec] = m_SSfeSpecies[kspec] @@ -4375,7 +4543,93 @@ namespace VCSnonideal { } } } + + } + //==================================================================================================================== + // Print out a table of chemical potentials + /* + * @param vcsState Determines where to get the mole numbers from. + * - VCS_STATECALC_OLD -> from m_molNumSpecies_old + * - VCS_STATECALC_NEW -> from m_molNumSpecies_new + */ + void VCS_SOLVE::vcs_printSpeciesChemPot(const int stateCalc) const { + double mfValue = 1.0; + bool zeroedPhase = false; + int kspec; + + const double * molNum = VCS_DATA_PTR(m_molNumSpecies_old); + const double * tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_old); + const double * actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_old); + if (stateCalc == VCS_STATECALC_NEW) { + tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_new); + actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_new); + molNum = VCS_DATA_PTR(m_molNumSpecies_new); + } + + double * tMoles = VCS_DATA_PTR(m_TmpPhase); + const double *tPhInertMoles = VCS_DATA_PTR(TPhInertMoles); + for (int iph = 0; iph < m_numPhases; iph++) { + tMoles[iph] = tPhInertMoles[iph]; + } + for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { + if(m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + int iph = m_phaseID[kspec]; + tMoles[iph] += molNum[kspec]; + } + } + + double RT = m_temperature * Cantera::GasConstant; + printf(" --- CHEMICAL POT TABLE (J/kmol) Name PhID MolFR ChemoSS " + " logMF Gamma Elect extra ElectrChem\n"); + printf(" "); + vcs_print_line("-", 132); + + for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { + mfValue = 1.0; + int iphase = m_phaseID[kspec]; + const vcs_VolPhase * Vphase = m_VolPhaseList[iphase]; + if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS) || + (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) || + (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDSS) ) { + zeroedPhase = true; + } else { + zeroedPhase = false; + } + if (tMoles[iphase] > 0.0) { + if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { + mfValue = VCS_DELETE_MINORSPECIES_CUTOFF / tMoles[iphase]; + } else { + mfValue = molNum[kspec]/tMoles[iphase]; + } + } else { + int klocal = m_speciesLocalPhaseIndex[kspec]; + mfValue = Vphase->moleFraction(klocal); + } + double volts = Vphase->electricPotential(); + double elect = m_chargeSpecies[kspec] * m_Faraday_dim * volts; + double comb = - m_lnMnaughtSpecies[kspec]; + double total = (m_SSfeSpecies[kspec] + log(mfValue) + elect + log(actCoeff_ptr[kspec]) + comb); + + if (zeroedPhase) { + printf(" --- ** zp *** "); + } else { + printf(" --- "); + } + printf("%-24.24s", m_speciesName[kspec].c_str()); + printf(" %-3d", iphase); + printf(" % -12.4e", mfValue); + printf(" % -12.4e", m_SSfeSpecies[kspec] * RT); + printf(" % -12.4e", log(mfValue) * RT); + printf(" % -12.4e", log(actCoeff_ptr[kspec]) * RT); + printf(" % -12.4e", elect * RT); + printf(" % -12.4e", comb * RT); + printf(" % -12.4e\n", total *RT); + } + printf(" "); + vcs_print_line("-", 132); + } + /*****************************************************************************/ #ifdef DEBUG_MODE @@ -4927,8 +5181,125 @@ namespace VCSnonideal { } #endif } - /*****************************************************************************/ + //==================================================================================================================== + void VCS_SOLVE::vcs_printDeltaG( const int stateCalc) { + int j; + double * deltaGRxn = VCS_DATA_PTR(m_deltaGRxn_old); + double * feSpecies = VCS_DATA_PTR(m_feSpecies_old); + double * molNumSpecies = VCS_DATA_PTR(m_molNumSpecies_old); + const double * tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_old); + const double * actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_old); + if (stateCalc == VCS_STATECALC_NEW) { + deltaGRxn = VCS_DATA_PTR(m_deltaGRxn_new); + feSpecies = VCS_DATA_PTR(m_feSpecies_new); + molNumSpecies = VCS_DATA_PTR(m_molNumSpecies_new); + actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_new); + tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_new); + } + double RT = m_temperature * Cantera::GasConstant; + bool zeroedPhase = false; + if (m_debug_print_lvl >= 2) { + plogf(" --- DELTA_G TABLE Components:"); + for (j = 0; j < m_numComponents; j++) { + plogf(" %3d ", j); + } + plogf("\n --- Components Moles:"); + for (j = 0; j < m_numComponents; j++) { + plogf("%10.3g", m_molNumSpecies_old[j]); + } + plogf("\n --- NonComponent| Moles | "); + for (j = 0; j < m_numComponents; j++) { + plogf("%-10.10s", m_speciesName[j].c_str()); + } + //plogf("| m_scSize"); + plogf("\n"); + for (int i = 0; i < m_numRxnTot; i++) { + plogf(" --- %3d ", m_indexRxnToSpecies[i]); + plogf("%-10.10s", m_speciesName[m_indexRxnToSpecies[i]].c_str()); + plogf("|%10.3g|", m_molNumSpecies_old[m_indexRxnToSpecies[i]]); + for (j = 0; j < m_numComponents; j++) { + plogf(" %6.2f", m_stoichCoeffRxnMatrix[i][j]); + } + //plogf(" | %6.2f", m_scSize[i]); + plogf("\n"); + } + plogf(" "); for(int i=0; i<77; i++) plogf("-"); plogf("\n"); + } + printf(" --- DeltaG Table (J/kmol) Name PhID MoleNum MolFR " + " ElectrChemStar ElectrChem DeltaGStar DeltaG(Pred) Stability\n"); + printf(" "); + vcs_print_line("-", 132); + + for (int kspec = 0; kspec < m_numSpeciesTot; kspec++) { + + int irxn = kspec - m_numComponents; + + double mfValue = 1.0; + int iphase = m_phaseID[kspec]; + const vcs_VolPhase * Vphase = m_VolPhaseList[iphase]; + if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS) || + (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) || + (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDSS) ) { + zeroedPhase = true; + } else { + zeroedPhase = false; + } + if (tPhMoles_ptr[iphase] > 0.0) { + if (molNumSpecies[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { + mfValue = VCS_DELETE_MINORSPECIES_CUTOFF / tPhMoles_ptr[iphase]; + } else { + mfValue = molNumSpecies[kspec] / tPhMoles_ptr[iphase]; + } + } else { + int klocal = m_speciesLocalPhaseIndex[kspec]; + mfValue = Vphase->moleFraction(klocal); + } + if (zeroedPhase) { + printf(" --- ** zp *** "); + } else { + printf(" --- "); + } + double feFull = feSpecies[kspec]; + if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS) || + (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) ) { + feFull += log(actCoeff_ptr[kspec]) + log(mfValue); + } + printf("%-24.24s", m_speciesName[kspec].c_str()); + printf(" %-3d", iphase); + printf(" % -12.4e", molNumSpecies[kspec]); + printf(" % -12.4e", mfValue); + printf(" % -12.4e", feSpecies[kspec] * RT); + printf(" % -12.4e", feFull * RT); + if (irxn >= 0) { + printf(" % -12.4e", deltaGRxn[irxn] * RT); + printf(" % -12.4e", (deltaGRxn[irxn] + feFull - feSpecies[kspec]) * RT); + + if (deltaGRxn[irxn] < 0.0) { + if ( molNumSpecies[kspec] > 0.0) { + printf(" growing"); + } else { + printf(" stable"); + } + } else if (deltaGRxn[irxn] > 0.0) { + if ( molNumSpecies[kspec] > 0.0) { + printf(" shrinking"); + } else { + printf(" unstable"); + } + } else { + printf(" balanced"); + } + } + + printf(" \n"); + } + + printf(" "); + vcs_print_line("-", 132); + + } + //==================================================================================================================== // Calculate deltag of formation for all species in a single phase. /* * Calculate deltag of formation for all species in a single diff --git a/Cantera/src/equil/vcs_solve_phaseStability.cpp b/Cantera/src/equil/vcs_solve_phaseStability.cpp new file mode 100644 index 000000000..73e851416 --- /dev/null +++ b/Cantera/src/equil/vcs_solve_phaseStability.cpp @@ -0,0 +1,249 @@ +/** + * @file vcs_solve_TP.cpp Implementation file that contains the + * main algorithm for finding an equilibrium + */ +/* + * $Id: vcs_solve_TP.cpp 626 2010-10-28 01:33:54Z hkmoffa $ + */ +/* + * 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 +#include +#include +#include + +#include "vcs_solve.h" +#include "vcs_internal.h" +#include "vcs_VolPhase.h" +#include "vcs_species_thermo.h" +#include "vcs_prob.h" + +#include "clockWC.h" + +#ifdef WIN32 +#pragma warning(disable:4996) +#endif + +using namespace std; + +namespace VCSnonideal { + + + int VCS_SOLVE::vcs_PS(VCS_PROB *vprob, int iphase, int printLvl, double &feStable) { + + /* + * ifunc determines the problem type + */ + int ifunc = 0; + int iStab = 0; + + /* + * This function is called to create the private data + * using the public data. + */ + int nspecies0 = vprob->nspecies + 10; + int nelements0 = vprob->ne; + int nphase0 = vprob->NPhase; + + vcs_initSizes(nspecies0, nelements0, nphase0); + + + if (ifunc < 0 || ifunc > 2) { + plogf("vcs: Unrecognized value of ifunc, %d: bailing!\n", + ifunc); + return VCS_PUB_BAD; + } + + /* + * This function is called to copy the public data + * and the current problem specification + * into the current object's data structure. + */ + int retn = vcs_prob_specifyFully(vprob); + if (retn != 0) { + plogf("vcs_pub_to_priv returned a bad status, %d: bailing!\n", + retn); + return retn; + } + /* + * Prep the problem data + * - adjust the identity of any phases + * - determine the number of components in the problem + */ + retn = vcs_prep_oneTime(printLvl); + if (retn != 0) { + plogf("vcs_prep_oneTime returned a bad status, %d: bailing!\n", + retn); + return retn; + } + + + /* + * This function is called to copy the current problem + * into the current object's data structure. + */ + retn = vcs_prob_specify(vprob); + if (retn != 0) { + plogf("vcs_prob_specify returned a bad status, %d: bailing!\n", + retn); + return retn; + } + + + /* + * Prep the problem data for this particular instantiation of + * the problem + */ + retn = vcs_prep(); + if (retn != VCS_SUCCESS) { + plogf("vcs_prep returned a bad status, %d: bailing!\n", retn); + return retn; + } + /* + * Check to see if the current problem is well posed. + */ + if (!vcs_wellPosed(vprob)) { + plogf("vcs has determined the problem is not well posed: Bailing\n"); + return VCS_PUB_BAD; + } + + + int iconv; + /* + * Store the temperature and pressure in the private global variables + */ + m_temperature = vprob->T; + m_pressurePA = vprob->PresPA; + /* + * Evaluate the standard state free energies + * at the current temperatures and pressures. + */ + iconv = vcs_evalSS_TP(printLvl, printLvl, m_temperature, m_pressurePA); + + /* + * Prepare the problem data: + * ->nondimensionalize the free energies using + * the divisor, R * T + */ + vcs_nondim_TP(); + /* + * Prep the fe field + */ + vcs_fePrep_TP(); + + /* + * 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.) + */ + iStab = vcs_solve_phaseStability(iphase, ifunc, feStable, printLvl); + + + /* + * Redimensionalize the free energies using + * the reverse of vcs_nondim to add back units. + */ + vcs_redim_TP(); + + /* + vcs_VolPhase *Vphase = m_VolPhaseList[iphase]; + + std::vector mfPop = Vphase->moleFractions(); + int nsp = Vphase->nSpecies(); + + vcs_VolPhase *VPphase = vprob->VPhaseList[iphase]; + int kstart = Vphase->spGlobalIndexVCS(0); + for (int k = 0; k < nsp; k++) { + vprob->mf[kstart + k] = mfPop[k]; + } + VPphase->setMoleFractionsState(Vphase->totalMoles(), + VCS_DATA_PTR(Vphase->moleFractions()), + VCS_STATECALC_TMP); + */ + vcs_prob_update(vprob); + /* + * Return the convergence success flag. + */ + return iStab; + + + } + //==================================================================================================================== + // Routine that independently determines whether a phase should be popped + // under the current conditions. + /* + * This is the main routine that solves for equilibrium at constant T and P + * using a variant of the VCS method. Nonideal phases can be accommodated + * as well. + * + * Any number of single-species phases and multi-species phases + * can be handled by the present version. + * + * Input + * ------------ + * @param print_lvl 1 -> Print results to standard output + * 0 -> don't report on anything + * + * @param printDetails 1 -> Print intermediate results. + * + * @param maxit Maximum number of iterations for the algorithm + * + * @return 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_SOLVE::vcs_solve_phaseStability(const int iph, const int ifunc, + double &funcVal, + int printLvl) { + int retn = 0; + double test = -1.0E-10; + int usedZeroedSpecies; + std::vector phasePopPhaseIDs(0); + int iphasePop; + int iStab = 0; + + std::vector sm(m_numElemConstraints*m_numElemConstraints, 0.0); + std::vector ss(m_numElemConstraints, 0.0); + std::vector sa(m_numElemConstraints, 0.0); + + std::vector aw(m_numSpeciesTot, 0.0); + std::vector wx(m_numElemConstraints, 0.0); + + + retn = vcs_basopt(FALSE, VCS_DATA_PTR(aw), VCS_DATA_PTR(sa), + VCS_DATA_PTR(sm), VCS_DATA_PTR(ss), + test, &usedZeroedSpecies); + vcs_evaluate_speciesType(); + + vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesRdc); + if (printLvl > 3) { + vcs_printSpeciesChemPot(VCS_STATECALC_OLD); + } + vcs_deltag(0, true, VCS_STATECALC_OLD); + + if (printLvl > 3) { + vcs_printDeltaG(VCS_STATECALC_OLD); + } + vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_Deficient), VCS_DATA_PTR(m_deltaGRxn_old), m_numRxnRdc); + phasePopPhaseIDs.clear(); + iphasePop = vcs_popPhaseID(phasePopPhaseIDs); + funcVal = vcs_phaseStabilityTest(iph); + if (funcVal > 0.0) { + iStab = 1; + } else { + iStab = 0; + } + + return iStab; + } + +} diff --git a/Cantera/src/equil/vcs_util.cpp b/Cantera/src/equil/vcs_util.cpp index ae34e3a12..61e79511e 100644 --- a/Cantera/src/equil/vcs_util.cpp +++ b/Cantera/src/equil/vcs_util.cpp @@ -61,7 +61,7 @@ namespace VCSnonideal { /***************************************************************************/ #ifndef USE_MEMSET - void vcs_dcopy(double *vec_to, double *vec_from, int length) + void vcs_dcopy(double *const vec_to, const double * const vec_from, int length) /************************************************************************** * @@ -233,10 +233,8 @@ namespace VCSnonideal { } return retn; } - /*****************************************************************************/ - /*****************************************************************************/ - /*****************************************************************************/ + //==================================================================================================================== // Swap values in a std vector string /* * Switches the value of vecStrings[i1] with vecStrings[i2] @@ -250,7 +248,7 @@ namespace VCSnonideal { vstr[i2] = vstr[i1]; vstr[i1] = tmp; } - + //==================================================================================================================== // Swap values in vector of doubles /* * Switches the value of x[i1] with x[i2] @@ -264,7 +262,7 @@ namespace VCSnonideal { x[i1] = x[i2]; x[i2] = t; } - + //==================================================================================================================== // Swap values in an integer array /* * Switches the value of x[i1] with x[i2] @@ -279,6 +277,148 @@ namespace VCSnonideal { x[i2] = t; } + //==================================================================================================================== +#ifdef DEBUG_HKM + static void mlequ_matrixDump(double *c, int idem, int n) { + int i, j; + printf("vcsUtil_mlequ() MATRIX DUMP --------------------------------------------------\n"); + printf(" "); + for (j = 0; j < n; ++j) { + printf(" % 3d ", j); + } + printf("\n"); + for (j = 0; j < n; ++j) { + printf("-----------"); + } + printf("\n"); + for (i = 0; i < n; ++i) { + printf(" %3d | ", i); + for (j = 0; j < n; ++j) { + printf("% 10.3e ", c[i + j * idem]); + } + printf("\n"); + } + for (j = 0; j < n; ++j) { + printf("-----------"); + } + printf("\n"); + printf("vcsUtil_mlequ() END MATRIX DUMP --------------------------------------------------\n"); + + } +#endif + //==================================================================================================================== + //! Swap rows in the c matrix and the b rhs matrix + /*! + * @param c Matrix of size nxn, row first + * @param idem C storage dimension for the number of rows + * @param n Size of the matrix + * @param b RHS of the Ax=b problem to solve + * @param m Number of rhs to solve + * @param irowa first row to swap + * @param irowb second row to swap + */ + static void vcsUtil_swapRows(double *c, int idem, int n, double *b, int m, int irowa, int irowb) { + double t1; + int j; + if (irowa == irowb) return; + for (j = 0; j < n; j++) { + SWAP(c[irowa + j * idem], c[irowb + j * idem], t1); + } + for (j = 0; j < m; j++) { + SWAP(b[irowa + j * idem], b[irowb + j * idem], t1); + } + } + //==================================================================================================================== + //! Swap rows in the c matrix and the b rhs matrix to lower the condition number of the matrix + /*! + * @param c Matrix of size nxn, row first + * @param idem C storage dimension for the number of rows + * @param n Size of the matrix + * @param b RHS of the Ax=b problem to solve + * @param m Number of rhs to solve + */ + static void vcsUtil_mlequ_preprocess(double *c, int idem, int n, double *b, int m) { + int j = 0; + std::vector irowUsed(n, 0); + + for (j = 0; j < n; j++) { + int numNonzero = 0; + int inonzero = -1; + for (int i = 0; i < n; i++) { + if (c[i + j * idem] != 0.0) { + numNonzero++; + inonzero = i; + } + } + if (numNonzero == 1 ) { + if (inonzero != j) { + if (irowUsed[inonzero] == 0) { + vcsUtil_swapRows(c, idem, n, b, m, j, inonzero); +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + } + } + irowUsed[j] = 1; + } + } + + for (j = 0; j < n; j++) { + if (c[j + j * idem] == 0.0) { + int numNonzero = 0; + int inonzero = -1; + for (int i = 0; i < n; i++) { + if (! irowUsed[i]) { + if (c[i + j * idem] != 0.0) { + if ((c[i + i * idem] == 0.0) || (c[j + i * idem] != 0.0)) { + numNonzero++; + inonzero = i; + } + } + } + } + if (numNonzero == 1) { + if (inonzero != j) { + if (irowUsed[inonzero] == 0) { + vcsUtil_swapRows(c, idem, n, b, m, j, inonzero); +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + } + } + irowUsed[j] = 1; + } + } + } + + for (j = 0; j < n; j++) { + if (c[j + j * idem] == 0.0) { + int numNonzero = 0; + int inonzero = -1; + for (int i = 0; i < n; i++) { + if (! irowUsed[i]) { + if (c[i + j * idem] != 0.0) { + if ((c[i + i * idem] == 0.0) || (c[j + i * idem] != 0.0)) { + numNonzero++; + inonzero = i; + } + } + } + } + if (inonzero != -1) { + if (inonzero != j) { + if (irowUsed[inonzero] == 0) { + vcsUtil_swapRows(c, idem, n, b, m, j, inonzero); +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + } + } + } + } + } + } + //==================================================================================================================== // Invert an n x n matrix and solve m rhs's /* * Solve a square matrix with multiple right hand sides @@ -310,13 +450,58 @@ namespace VCSnonideal { * @param m number of rhs's */ int vcsUtil_mlequ(double *c, int idem, int n, double *b, int m) { +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + vcsUtil_mlequ_preprocess(c, idem, n, b, m); +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + int dmatrix = 0; +#ifdef DEBUG_HKM + static int s_numCalls = 0; + s_numCalls++; +#endif + int i, j, k, l; double R; if (n > idem || n <= 0) { plogf("vcsUtil_mlequ ERROR: badly dimensioned matrix: %d %d\n", n, idem); return 1; } - + +#ifdef DEBUG_HKM + for (i = 0; i < n; ++i) { + bool notFound = true; + for (j = 0; j < n; ++j) { + if (c[i + j * idem] != 0.0) { + notFound = false; + } + } + if (notFound) { + printf(" vcsUtil_mlequ ERROR(): row %d is identically zero\n", i); + } + } + for (j = 0; j < n; ++j) { + bool notFound = true; + for (i = 0; i < n; ++i) { + if (c[i + j * idem] != 0.0) { + notFound = false; + } + } + if (notFound) { + printf(" vcsUtil_mlequ ERROR(): column %d is identically zero\n", j); + } + } + // if (s_numCalls >= 32) { + // printf("vcsUtil_mlequ: we are here\n"); + // dmatrix = 1; + // } + + if (dmatrix) { + mlequ_matrixDump(c, idem, n); + } +#endif /* * Loop over the rows * -> At the end of each loop, the only nonzero entry in the column @@ -332,6 +517,12 @@ namespace VCSnonideal { if (c[k + i * idem] != 0.0) goto FOUND_PIVOT; } plogf("vcsUtil_mlequ ERROR: Encountered a zero column: %d\n", i); +#ifdef DEBUG_HKM + plogf(" call # %d\n", s_numCalls); +#endif +#ifdef DEBUG_HKM + mlequ_matrixDump(c, idem, n); +#endif return 1; FOUND_PIVOT: ; for (j = 0; j < n; ++j) c[i + j * idem] += c[k + j * idem]; @@ -358,6 +549,135 @@ namespace VCSnonideal { } return 0; } + //==================================================================================================================== + // Linear equation solution by Gauss-Jordan elimination for multiple rhs vectors + /* + * Solve a square matrix with multiple right hand sides + * + * \f[ + * C X + B = 0; + * \f] + * + * This routine uses Gauss-Jordan elimination with full pivoting and is optimized for the solution + * of lots of rhs's. + * + * @return Routine returns an integer representing success: + * - 1 : Matrix is singluar + * - 0 : solution is OK + * The solution x[] is returned in the matrix b. + * + * @param c Matrix to be inverted. c is in fortran format, i.e., rows + * are the inner loop. Row numbers equal to idem. + * c[i+j*idem] = c_i_j = Matrix to be inverted: i = row number + * j = column number + * @param idem number of row dimensions in c + * @param n Number of rows and columns in c + * @param b Multiple RHS. Note, b is actually the negative of + * most formulations. Row numbers equal to idem. + * b[i+j*idem] = b_i_j = vectors of rhs's: i = row number + * j = column number + * (each column is a new rhs) + * @param m number of rhs's + */ + int vcsUtil_gaussj(double *c, int idem, int n, double *b, int m) { + + int i, j, k, l, ll; + int irow = -1; + int icol = -1; + bool needInverse = false; + double pivinv, dum; +#ifdef DEBUG_HKM + static int s_numCalls = 0; + s_numCalls++; +#endif +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + /* + * Preprocess the problem + */ + vcsUtil_mlequ_preprocess(c, idem, n, b, m); + +#ifdef DEBUG_HKM + // mlequ_matrixDump(c, idem, n); +#endif + + std::vector indxc(n); + std::vector indxr(n); + std::vector ipiv(n, 0); + doublereal big = 0.0; + /* + * This is the main loop over the columns to be reduced. + */ + for (i = 0; i < n; i++) { + big = 0.0; + for (j = 0; j < n; j++) { + if (ipiv[j] != 1) { + for (k = 0; k < n; k++) { + if (ipiv[k] == 0) { + if (fabs(c[j + idem * k]) >= big) { + big = fabs(c[j + idem * k]); + irow = j; + icol = k; + } + } + } + } + } + ++(ipiv[icol]); + if (irow != icol) { + vcsUtil_swapRows(c, idem, n, b, m, irow, icol); + } + indxr[i] = irow; + indxc[i] = icol; + if (c[icol + idem * icol] == 0.0) { + plogf("vcsUtil_gaussj ERROR: Encountered a zero column: %d\n", i); + return 1; + } + pivinv = 1.0 / c[icol + idem * icol]; + c[icol + idem * icol] = 1.0; + for (l = 0; l < n; l++) { + c[icol + idem * l] *= pivinv; + } + for (l = 0; l < m; l++) { + b[icol + idem * l] *= pivinv; + } + for (ll = 0; ll < n; ll++) { + if (ll != icol) { + dum = c[ll + idem * icol]; + c[ll + idem * icol] = 0; + for (l = 0; l < n; l++) { + c[ll + idem * l] -= c[icol + idem * l] * dum; + } + for (l = 0; l < m; l++) { + b[ll + idem * l] -= b[icol + idem * l] * dum; + } + } + } + } + if (needInverse) { + for (l = n-1; l >= 0; l--) { + if (indxr[l] != indxc[l]) { + for (k = 0; k < n; k++) { + SWAP(c[k + idem * indxr[l]], c[k + idem * indxr[l]], dum); + } + } + } + } + + + /* + * The negative in the last expression is due to the form of B upon + * input + */ + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + b[i + j * idem] = -b[i + j * idem]; + } + } + return 0; + } + //==================================================================================================================== // Returns the value of the gas constant in the units specified by a parameter /* @@ -550,3 +870,5 @@ namespace VCSnonideal { } } + + diff --git a/Cantera/src/equil/vcs_xerror.c b/Cantera/src/equil/vcs_xerror.c index 32b0dd269..a7d98d18a 100644 --- a/Cantera/src/equil/vcs_xerror.c +++ b/Cantera/src/equil/vcs_xerror.c @@ -21,9 +21,9 @@ static integer c__1 = 1; /* -------------------------------------------------- */ /* | CVS Head Information | */ /* -------------------------------------------------- */ -/* $Author: hkmoffa $ */ -/* $Date: 2008/01/03 21:38:25 $ */ -/* $Revision: 1.1 $ */ +/* $Author$ */ +/* $Date$ */ +/* $Revision$ */ /* ======================================================================= */ /* Subroutine */ int s88fmt_(integer *n, integer *ivalue, integer *ifmt) diff --git a/Cantera/src/kinetics/AqueousKinetics.cpp b/Cantera/src/kinetics/AqueousKinetics.cpp index 0559dec2b..6ab77b9f5 100644 --- a/Cantera/src/kinetics/AqueousKinetics.cpp +++ b/Cantera/src/kinetics/AqueousKinetics.cpp @@ -30,7 +30,50 @@ using namespace std; namespace Cantera { + //==================================================================================================================== + AqueousKineticsData::AqueousKineticsData() : + m_logp_ref(0.0), + m_logc_ref(0.0), + m_ROP_ok(false), + m_temp(0.0) + { + } + //==================================================================================================================== + AqueousKineticsData::~AqueousKineticsData() + { + } + //==================================================================================================================== + AqueousKineticsData::AqueousKineticsData(const AqueousKineticsData &right) : + m_logp_ref(0.0), + m_logc_ref(0.0), + m_ROP_ok(false), + m_temp(0.0) + { + *this=right; + } + //==================================================================================================================== + AqueousKineticsData& AqueousKineticsData::operator=(const AqueousKineticsData &right) + { + if (this != &right) { + m_logp_ref = right.m_logp_ref; + m_logc_ref = right.m_logc_ref; + m_ropf = right.m_ropf; + m_ropr = right.m_ropr; + m_ropnet = right.m_ropnet; + m_rfn_low = right.m_rfn_low; + m_rfn_high = right.m_rfn_high; + m_ROP_ok = right.m_ROP_ok; + m_temp = right.m_temp; + m_rfn = right.m_rfn; + m_rkcn = right.m_rkcn; + } + return *this; + } + //==================================================================================================================== + + + //==================================================================================================================== /** * Construct an empty reaction mechanism. */ @@ -47,12 +90,70 @@ namespace Cantera { m_kdata->m_temp = 0.0; m_rxnstoich = new ReactionStoichMgr; } - + //==================================================================================================================== + AqueousKinetics::AqueousKinetics(const AqueousKinetics &right) : + Kinetics(), + m_kk(0), + m_nfall(0), + m_nirrev(0), + m_nrev(0), + m_finalized(false) + { + *this = right; + } + //==================================================================================================================== AqueousKinetics::~AqueousKinetics() { delete m_kdata; delete m_rxnstoich; - } + } + //==================================================================================================================== + AqueousKinetics& AqueousKinetics::operator=(const AqueousKinetics &right) + { + if (this == &right) return *this; + Kinetics::operator=(right); + + m_kk = right.m_kk; + m_nfall = right.m_nfall; + m_rates = right.m_rates; + m_index = right.m_index; + m_irrev = right.m_irrev; + + *m_rxnstoich = *(right.m_rxnstoich); + + m_fwdOrder = right.m_fwdOrder; + m_nirrev = right.m_nirrev; + m_nrev = right.m_nrev; + m_rgroups = right.m_rgroups; + m_pgroups = right.m_pgroups; + m_rxntype = right.m_rxntype; + m_rrxn = right.m_rrxn; + m_prxn = right.m_prxn; + m_dn = right.m_dn; + m_revindex = right.m_revindex; + m_rxneqn = right.m_rxneqn; + + *m_kdata = *(right.m_kdata); + + m_conc = right.m_conc; + m_grt = right.m_grt; + m_finalized = right.m_finalized; + + throw CanteraError("GasKinetics::operator=()", + "Unfinished implementation"); + + return *this; + + } + //==================================================================================================================== + Kinetics *AqueousKinetics::duplMyselfAsKinetics(const std::vector & tpVector) const + { + AqueousKinetics* gK = new AqueousKinetics(*this); + gK->assignShallowPointers(tpVector); + return dynamic_cast(gK); + } + + //==================================================================================================================== /** * Update temperature-dependent portions of reaction rates and * falloff functions. diff --git a/Cantera/src/kinetics/AqueousKinetics.h b/Cantera/src/kinetics/AqueousKinetics.h index a23bc0626..7036714a9 100644 --- a/Cantera/src/kinetics/AqueousKinetics.h +++ b/Cantera/src/kinetics/AqueousKinetics.h @@ -46,18 +46,21 @@ namespace Cantera { */ class AqueousKineticsData { public: - AqueousKineticsData() : - m_logp_ref(0.0), - m_logc_ref(0.0), - m_ROP_ok(false), - m_temp(0.0) - {} - virtual ~AqueousKineticsData(){} + AqueousKineticsData(); - doublereal m_logp_ref, m_logc_ref; + ~AqueousKineticsData(); + + AqueousKineticsData(const AqueousKineticsData &right); + + AqueousKineticsData& operator=(const AqueousKineticsData &right); + + doublereal m_logp_ref; + doublereal m_logc_ref; array_fp m_ropf; - array_fp m_ropr, m_ropnet; - array_fp m_rfn_low, m_rfn_high; + array_fp m_ropr; + array_fp m_ropnet; + array_fp m_rfn_low; + array_fp m_rfn_high; bool m_ROP_ok; doublereal m_temp; @@ -88,9 +91,27 @@ namespace Cantera { /// Constructor. AqueousKinetics(thermo_t* thermo = 0); + AqueousKinetics(const AqueousKinetics &right); + + AqueousKinetics& operator=(const AqueousKinetics &right); + /// Destructor. virtual ~AqueousKinetics(); + + //! Duplication routine for objects which inherit from Kinetics + /*! + * This virtual routine can be used to duplicate %Kinetics objects + * inherited from %Kinetics even if the application only has + * a pointer to %Kinetics to work with. + * + * These routines are basically wrappers around the derived copy constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object + */ + virtual Kinetics *duplMyselfAsKinetics(const std::vector & tpVector) const; + virtual int ID() const { return cAqueousKinetics; } virtual int type() const { return cAqueousKinetics; } diff --git a/Cantera/src/kinetics/EdgeKinetics.h b/Cantera/src/kinetics/EdgeKinetics.h index b19e7b3e6..6f1b5528b 100644 --- a/Cantera/src/kinetics/EdgeKinetics.h +++ b/Cantera/src/kinetics/EdgeKinetics.h @@ -37,6 +37,38 @@ namespace Cantera { /// Destructor. virtual ~EdgeKinetics() {} + EdgeKinetics(const EdgeKinetics &right) : + InterfaceKinetics(right) + { + *this=right; + } + + EdgeKinetics & operator=(const EdgeKinetics &right) + { + if (this != &right) { + InterfaceKinetics::operator=(right); + } + return *this; + } + + //! Duplication routine for objects which inherit from Kinetics + /*! + * This virtual routine can be used to duplicate %Kinetics objects + * inherited from %Kinetics even if the application only has + * a pointer to %Kinetics to work with. + * + * These routines are basically wrappers around the derived copy constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object + */ + virtual Kinetics *duplMyselfAsKinetics(const std::vector & tpVector) const + { + EdgeKinetics* iK = new EdgeKinetics(*this); + iK->assignShallowPointers(tpVector); + return dynamic_cast(iK); + } + /** * Identifies the subclass of the Kinetics manager type. * These are listed in mix_defs.h. diff --git a/Cantera/src/kinetics/GasKinetics.cpp b/Cantera/src/kinetics/GasKinetics.cpp index 4633a08ee..8e976f096 100644 --- a/Cantera/src/kinetics/GasKinetics.cpp +++ b/Cantera/src/kinetics/GasKinetics.cpp @@ -29,636 +29,812 @@ using namespace std; namespace Cantera { + //==================================================================================================================== + GasKineticsData::GasKineticsData() : + m_logp_ref(0.0), + m_logc_ref(0.0), + m_logStandConc(0.0), + m_ROP_ok(false), + m_temp(0.0) + { + } + //==================================================================================================================== + GasKineticsData::GasKineticsData(const GasKineticsData &right) : + m_logp_ref(0.0), + m_logc_ref(0.0), + m_logStandConc(0.0), + m_ROP_ok(false), + m_temp(0.0) + { + *this = right; + } + //==================================================================================================================== + GasKineticsData::~GasKineticsData() + { + } + //==================================================================================================================== + GasKineticsData& GasKineticsData::operator=(const GasKineticsData &right) + { + if (this == &right) return *this; - /** - * Construct an empty reaction mechanism. - */ - GasKinetics:: - GasKinetics(thermo_t* thermo) : - Kinetics(), - m_kk(0), - m_nfall(0), - m_nirrev(0), - m_nrev(0), - m_finalized(false) - { - if (thermo != 0) addPhase(*thermo); - m_kdata = new GasKineticsData; - m_kdata->m_temp = 0.0; - m_rxnstoich = new ReactionStoichMgr; - } - - GasKinetics:: - ~GasKinetics() {delete m_kdata; delete m_rxnstoich;} - - /** - * Update temperature-dependent portions of reaction rates and - * falloff functions. - */ - void GasKinetics:: - update_T() {} - - void GasKinetics:: - update_C() {} - - void GasKinetics:: - _update_rates_T() { - doublereal T = thermo().temperature(); - m_kdata->m_logStandConc = log(thermo().standardConcentration()); - //if (fabs(T - m_kdata->m_temp) > 0.0) { - doublereal logT = log(T); - m_rates.update(T, logT, &m_kdata->m_rfn[0]); - m_falloff_low_rates.update(T, logT, &m_kdata->m_rfn_low[0]); - m_falloff_high_rates.update(T, logT, &m_kdata->m_rfn_high[0]); - m_falloffn.updateTemp(T, &m_kdata->falloff_work[0]); - m_kdata->m_temp = T; - updateKc(); - m_kdata->m_ROP_ok = false; - //} - }; - - - /** - * Update properties that depend on concentrations. Currently only - * the enhanced collision partner concentrations are updated here. - */ - void GasKinetics:: - _update_rates_C() { - thermo().getActivityConcentrations(&m_conc[0]); - doublereal ctot = thermo().molarDensity(); - m_3b_concm.update(m_conc, ctot, &m_kdata->concm_3b_values[0]); - m_falloff_concm.update(m_conc, ctot, - &m_kdata->concm_falloff_values[0]); - m_kdata->m_ROP_ok = false; - } - - /** - * Update the equilibrium constants in molar units. - */ - void GasKinetics::updateKc() { - int i, irxn; - vector_fp& m_rkc = m_kdata->m_rkcn; - - thermo().getStandardChemPotentials(&m_grt[0]); - fill(m_rkc.begin(), m_rkc.end(), 0.0); - - // compute Delta G^0 for all reversible reactions - m_rxnstoich->getRevReactionDelta(m_ii, &m_grt[0], &m_rkc[0]); - - doublereal logStandConc = m_kdata->m_logStandConc; - doublereal rrt = 1.0/(GasConstant * thermo().temperature()); - for (i = 0; i < m_nrev; i++) { - irxn = m_revindex[i]; - m_rkc[irxn] = exp(m_rkc[irxn]*rrt - m_dn[irxn]*logStandConc); - } - - for(i = 0; i != m_nirrev; ++i) { - m_rkc[ m_irrev[i] ] = 0.0; - } - } - - /** - * Get the equilibrium constants of all reactions, whether - * reversible or not. - */ - void GasKinetics::getEquilibriumConstants(doublereal* kc) { - int i; - _update_rates_T(); - vector_fp& rkc = m_kdata->m_rkcn; - //thermo().getGibbs_RT(m_grt.begin()); - thermo().getStandardChemPotentials(&m_grt[0]); - fill(rkc.begin(), rkc.end(), 0.0); - - // compute Delta G^0 for all reactions - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], &rkc[0]); - - doublereal logStandConc = m_kdata->m_logStandConc; - doublereal rrt = 1.0/(GasConstant * thermo().temperature()); - for (i = 0; i < m_ii; i++) { - kc[i] = exp(-rkc[i]*rrt + m_dn[i]*logStandConc); - } - - // force an update of T-dependent properties, so that m_rkcn will - // be updated before it is used next. - m_kdata->m_temp = 0.0; - } - - /** - * - * getDeltaGibbs(): - * - * Return the vector of values for the reaction gibbs free energy - * change - * These values depend upon the concentration - * of the ideal gas. - * - * units = J kmol-1 - */ - void GasKinetics::getDeltaGibbs(doublereal* deltaG) { - /* - * Get the chemical potentials of the species in the - * ideal gas solution. - */ - thermo().getChemPotentials(&m_grt[0]); - /* - * Use the stoichiometric manager to find deltaG for each - * reaction. - */ - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaG); - } + m_logp_ref = right.m_logp_ref; + m_logc_ref = right.m_logc_ref; + m_logStandConc = right.m_logStandConc; + m_ropf = right.m_ropf; + m_ropr = right.m_ropr; + m_ropnet = right.m_ropnet; + m_rfn_low = right.m_rfn_low; + m_rfn_high = right.m_rfn_high; + m_ROP_ok = right.m_ROP_ok; + m_temp = right.m_temp; + m_rfn = right.m_rfn; + falloff_work = right.falloff_work; + concm_3b_values = right.concm_3b_values; + concm_falloff_values = right.concm_falloff_values; + m_rkcn = right.m_rkcn; - /** - * - * getDeltaEnthalpy(): - * - * Return the vector of values for the reactions change in - * enthalpy. - * These values depend upon the concentration - * of the solution. - * - * units = J kmol-1 - */ - void GasKinetics::getDeltaEnthalpy(doublereal* deltaH) { - /* - * Get the partial molar enthalpy of all species in the - * ideal gas. - */ - thermo().getPartialMolarEnthalpies(&m_grt[0]); - /* - * Use the stoichiometric manager to find deltaG for each - * reaction. - */ - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaH); - } + return *this; + } + //==================================================================================================================== + /* + * Construct an empty reaction mechanism. + */ + GasKinetics:: + GasKinetics(thermo_t* thermo) : + Kinetics(), + m_kk(0), + m_nfall(0), + m_nirrev(0), + m_nrev(0), + m_finalized(false) + { + if (thermo != 0) addPhase(*thermo); + m_kdata = new GasKineticsData(); + m_kdata->m_temp = 0.0; + m_rxnstoich = new ReactionStoichMgr(); + } - /************************************************************************ - * - * getDeltaEntropy(): - * - * Return the vector of values for the reactions change in - * entropy. - * These values depend upon the concentration - * of the solution. - * - * units = J kmol-1 Kelvin-1 - */ - void GasKinetics::getDeltaEntropy( doublereal* deltaS) { - /* - * Get the partial molar entropy of all species in the - * solid solution. - */ - thermo().getPartialMolarEntropies(&m_grt[0]); - /* - * Use the stoichiometric manager to find deltaS for each - * reaction. - */ - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaS); - } + //==================================================================================================================== + GasKinetics::GasKinetics(const GasKinetics &right) : + Kinetics(), + m_kk(0), + m_nfall(0), + m_nirrev(0), + m_nrev(0), + m_finalized(false) + { + m_kdata = new GasKineticsData(); + m_kdata->m_temp = 0.0; + m_rxnstoich = new ReactionStoichMgr(); + *this = right; + } + //==================================================================================================================== + GasKinetics::~GasKinetics() + { + delete m_kdata; + delete m_rxnstoich; + } + //==================================================================================================================== + GasKinetics& GasKinetics::operator=(const GasKinetics &right) + { + if (this == &right) return *this; - /** - * - * getDeltaSSGibbs(): - * - * Return the vector of values for the reaction - * standard state gibbs free energy change. - * These values don't depend upon the concentration - * of the solution. - * - * units = J kmol-1 - */ - void GasKinetics::getDeltaSSGibbs(doublereal* deltaG) { - /* - * Get the standard state chemical potentials of the species. - * This is the array of chemical potentials at unit activity - * We define these here as the chemical potentials of the pure - * species at the temperature and pressure of the solution. - */ - thermo().getStandardChemPotentials(&m_grt[0]); - /* - * Use the stoichiometric manager to find deltaG for each - * reaction. - */ - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaG); - } + Kinetics::operator=(right); + + m_kk = right.m_kk; + m_nfall = right.m_nfall; + m_fallindx = right.m_fallindx; + m_falloff_low_rates = right.m_falloff_low_rates; + m_falloff_high_rates = right.m_falloff_high_rates; + m_rates = right.m_rates; + m_index = right.m_index; + m_falloffn = right.m_falloffn; + m_3b_concm = right.m_3b_concm; + m_falloff_concm = right.m_falloff_concm; + m_irrev = right.m_irrev; - /** - * - * getDeltaSSEnthalpy(): - * - * Return the vector of values for the change in the - * standard state enthalpies of reaction. - * These values don't depend upon the concentration - * of the solution. - * - * units = J kmol-1 - */ - void GasKinetics::getDeltaSSEnthalpy(doublereal* deltaH) { - /* - * Get the standard state enthalpies of the species. - * This is the array of chemical potentials at unit activity - * We define these here as the enthalpies of the pure - * species at the temperature and pressure of the solution. - */ - thermo().getEnthalpy_RT(&m_grt[0]); - doublereal RT = thermo().temperature() * GasConstant; - for (int k = 0; k < m_kk; k++) { - m_grt[k] *= RT; - } - /* - * Use the stoichiometric manager to find deltaG for each - * reaction. - */ - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaH); - } + *m_rxnstoich = *(right.m_rxnstoich); - /********************************************************************* - * - * getDeltaSSEntropy(): - * - * Return the vector of values for the change in the - * standard state entropies for each reaction. - * These values don't depend upon the concentration - * of the solution. - * - * units = J kmol-1 Kelvin-1 - */ - void GasKinetics::getDeltaSSEntropy(doublereal* deltaS) { - /* - * Get the standard state entropy of the species. - * We define these here as the entropies of the pure - * species at the temperature and pressure of the solution. - */ - thermo().getEntropy_R(&m_grt[0]); - doublereal R = GasConstant; - for (int k = 0; k < m_kk; k++) { - m_grt[k] *= R; - } - /* - * Use the stoichiometric manager to find deltaS for each - * reaction. - */ - m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaS); - } + m_fwdOrder = right.m_fwdOrder; + m_nirrev = right.m_nirrev; + m_nrev = right.m_nrev; + m_rgroups = right.m_rgroups; + m_pgroups = right.m_pgroups; + m_rxntype = right.m_rxntype; + m_rrxn = right.m_rrxn; + m_prxn = right.m_prxn; + m_dn = right.m_dn; + m_revindex = right.m_revindex; + m_rxneqn = right.m_rxneqn; - void GasKinetics::processFalloffReactions() { + *m_kdata = *(right.m_kdata); - int i; - const vector_fp& fc = m_kdata->concm_falloff_values; - const array_fp& m_rf_low = m_kdata->m_rfn_low; - const array_fp& m_rf_high = m_kdata->m_rfn_high; + m_conc = right.m_conc; + m_grt = right.m_grt; + m_finalized = right.m_finalized; - // use m_ropr for temporary storage of reduced pressure - array_fp& pr = m_kdata->m_ropr; + throw CanteraError("GasKinetics::operator=()", + "Unfinished implementation"); - array_fp& ropf = m_kdata->m_ropf; + return *this; + } + //==================================================================================================================== + // Duplication routine for objects which inherit from Kinetics + /* + * This virtual routine can be used to duplicate %Kinetics objects + * inherited from %Kinetics even if the application only has + * a pointer to %Kinetics to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object + */ + Kinetics *GasKinetics::duplMyselfAsKinetics(const std::vector & tpVector) const { + GasKinetics* gK = new GasKinetics(*this); + gK->assignShallowPointers(tpVector); + return dynamic_cast(gK); + } + //==================================================================================================================== + /** + * Update temperature-dependent portions of reaction rates and + * falloff functions. + */ + void GasKinetics::update_T() + { + } + //==================================================================================================================== + void GasKinetics:: + update_C() {} + //==================================================================================================================== + void GasKinetics:: + _update_rates_T() { + doublereal T = thermo().temperature(); + m_kdata->m_logStandConc = log(thermo().standardConcentration()); + //if (fabs(T - m_kdata->m_temp) > 0.0) { + doublereal logT = log(T); + m_rates.update(T, logT, &m_kdata->m_rfn[0]); + m_falloff_low_rates.update(T, logT, &m_kdata->m_rfn_low[0]); + m_falloff_high_rates.update(T, logT, &m_kdata->m_rfn_high[0]); + m_falloffn.updateTemp(T, &m_kdata->falloff_work[0]); + m_kdata->m_temp = T; + updateKc(); + m_kdata->m_ROP_ok = false; + //} + }; - for (i = 0; i < m_nfall; i++) { - pr[i] = fc[i] * m_rf_low[i] / m_rf_high[i]; - } - - m_falloffn.pr_to_falloff( &pr[0], &m_kdata->falloff_work[0] ); + //==================================================================================================================== + /** + * Update properties that depend on concentrations. Currently only + * the enhanced collision partner concentrations are updated here. + */ + void GasKinetics:: + _update_rates_C() { + thermo().getActivityConcentrations(&m_conc[0]); + doublereal ctot = thermo().molarDensity(); + m_3b_concm.update(m_conc, ctot, &m_kdata->concm_3b_values[0]); + m_falloff_concm.update(m_conc, ctot, + &m_kdata->concm_falloff_values[0]); + m_kdata->m_ROP_ok = false; + } + //==================================================================================================================== + /** + * Update the equilibrium constants in molar units. + */ + void GasKinetics::updateKc() { + int i, irxn; + vector_fp& m_rkc = m_kdata->m_rkcn; - for (i = 0; i < m_nfall; i++) { - pr[i] *= m_rf_high[i]; - } + thermo().getStandardChemPotentials(&m_grt[0]); + fill(m_rkc.begin(), m_rkc.end(), 0.0); - scatter_copy(pr.begin(), pr.begin() + m_nfall, - ropf.begin(), m_fallindx.begin()); + // compute Delta G^0 for all reversible reactions + m_rxnstoich->getRevReactionDelta(m_ii, &m_grt[0], &m_rkc[0]); + + doublereal logStandConc = m_kdata->m_logStandConc; + doublereal rrt = 1.0/(GasConstant * thermo().temperature()); + for (i = 0; i < m_nrev; i++) { + irxn = m_revindex[i]; + m_rkc[irxn] = exp(m_rkc[irxn]*rrt - m_dn[irxn]*logStandConc); } + for(i = 0; i != m_nirrev; ++i) { + m_rkc[ m_irrev[i] ] = 0.0; + } + } + //==================================================================================================================== + /** + * Get the equilibrium constants of all reactions, whether + * reversible or not. + */ + void GasKinetics::getEquilibriumConstants(doublereal* kc) { + int i; + _update_rates_T(); + vector_fp& rkc = m_kdata->m_rkcn; + //thermo().getGibbs_RT(m_grt.begin()); + thermo().getStandardChemPotentials(&m_grt[0]); + fill(rkc.begin(), rkc.end(), 0.0); + + // compute Delta G^0 for all reactions + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], &rkc[0]); + + doublereal logStandConc = m_kdata->m_logStandConc; + doublereal rrt = 1.0/(GasConstant * thermo().temperature()); + for (i = 0; i < m_ii; i++) { + kc[i] = exp(-rkc[i]*rrt + m_dn[i]*logStandConc); + } - void GasKinetics::updateROP() { + // force an update of T-dependent properties, so that m_rkcn will + // be updated before it is used next. + m_kdata->m_temp = 0.0; + } + //==================================================================================================================== + /** + * + * getDeltaGibbs(): + * + * Return the vector of values for the reaction gibbs free energy + * change + * These values depend upon the concentration + * of the ideal gas. + * + * units = J kmol-1 + */ + void GasKinetics::getDeltaGibbs(doublereal* deltaG) { + /* + * Get the chemical potentials of the species in the + * ideal gas solution. + */ + thermo().getChemPotentials(&m_grt[0]); + /* + * Use the stoichiometric manager to find deltaG for each + * reaction. + */ + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaG); + } + //==================================================================================================================== + /** + * + * getDeltaEnthalpy(): + * + * Return the vector of values for the reactions change in + * enthalpy. + * These values depend upon the concentration + * of the solution. + * + * units = J kmol-1 + */ + void GasKinetics::getDeltaEnthalpy(doublereal* deltaH) { + /* + * Get the partial molar enthalpy of all species in the + * ideal gas. + */ + thermo().getPartialMolarEnthalpies(&m_grt[0]); + /* + * Use the stoichiometric manager to find deltaG for each + * reaction. + */ + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaH); + } + //==================================================================================================================== + /* + * + * getDeltaEntropy(): + * + * Return the vector of values for the reactions change in + * entropy. + * These values depend upon the concentration + * of the solution. + * + * units = J kmol-1 Kelvin-1 + */ + void GasKinetics::getDeltaEntropy( doublereal* deltaS) { + /* + * Get the partial molar entropy of all species in the + * solid solution. + */ + thermo().getPartialMolarEntropies(&m_grt[0]); + /* + * Use the stoichiometric manager to find deltaS for each + * reaction. + */ + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaS); + } + //==================================================================================================================== + /** + * + * getDeltaSSGibbs(): + * + * Return the vector of values for the reaction + * standard state gibbs free energy change. + * These values don't depend upon the concentration + * of the solution. + * + * units = J kmol-1 + */ + void GasKinetics::getDeltaSSGibbs(doublereal* deltaG) { + /* + * Get the standard state chemical potentials of the species. + * This is the array of chemical potentials at unit activity + * We define these here as the chemical potentials of the pure + * species at the temperature and pressure of the solution. + */ + thermo().getStandardChemPotentials(&m_grt[0]); + /* + * Use the stoichiometric manager to find deltaG for each + * reaction. + */ + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaG); + } + //==================================================================================================================== + /** + * + * getDeltaSSEnthalpy(): + * + * Return the vector of values for the change in the + * standard state enthalpies of reaction. + * These values don't depend upon the concentration + * of the solution. + * + * units = J kmol-1 + */ + void GasKinetics::getDeltaSSEnthalpy(doublereal* deltaH) { + /* + * Get the standard state enthalpies of the species. + * This is the array of chemical potentials at unit activity + * We define these here as the enthalpies of the pure + * species at the temperature and pressure of the solution. + */ + thermo().getEnthalpy_RT(&m_grt[0]); + doublereal RT = thermo().temperature() * GasConstant; + for (int k = 0; k < m_kk; k++) { + m_grt[k] *= RT; + } + /* + * Use the stoichiometric manager to find deltaG for each + * reaction. + */ + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaH); + } + //==================================================================================================================== + /********************************************************************* + * + * getDeltaSSEntropy(): + * + * Return the vector of values for the change in the + * standard state entropies for each reaction. + * These values don't depend upon the concentration + * of the solution. + * + * units = J kmol-1 Kelvin-1 + */ + void GasKinetics::getDeltaSSEntropy(doublereal* deltaS) { + /* + * Get the standard state entropy of the species. + * We define these here as the entropies of the pure + * species at the temperature and pressure of the solution. + */ + thermo().getEntropy_R(&m_grt[0]); + doublereal R = GasConstant; + for (int k = 0; k < m_kk; k++) { + m_grt[k] *= R; + } + /* + * Use the stoichiometric manager to find deltaS for each + * reaction. + */ + m_rxnstoich->getReactionDelta(m_ii, &m_grt[0], deltaS); + } - _update_rates_T(); - _update_rates_C(); + //==================================================================================================================== + // Return the species net production rates + /* + * Species net production rates [kmol/m^3/s]. Return the species + * net production rates (creation - destruction) in array + * wdot, which must be dimensioned at least as large as the + * total number of species. + * + * @param net Array of species production rates. + * units kmol m-3 s-1 + */ + void GasKinetics::getNetProductionRates(doublereal* net) { + updateROP(); + m_rxnstoich->getNetProductionRates(m_kk, &m_kdata->m_ropnet[0], net); + } + //==================================================================================================================== + // Return the species creation rates + /* + * Species creation rates [kmol/m^3]. Return the species + * creation rates in array cdot, which must be + * dimensioned at least as large as the total number of + * species. + * + * @param cdot Array of species production rates. + * units kmol m-3 s-1 + */ + void GasKinetics::getCreationRates(doublereal* cdot) { + updateROP(); + m_rxnstoich->getCreationRates(m_kk, &m_kdata->m_ropf[0], &m_kdata->m_ropr[0], cdot); + } + //==================================================================================================================== + // Return a vector of the species destruction rates + /* + * Species destruction rates [kmol/m^3]. Return the species + * destruction rates in array ddot, which must be + * dimensioned at least as large as the total number of + * species. + * + * + * @param ddot Array of species destruction rates. + * units kmol m-3 s-1 + * + */ + void GasKinetics::getDestructionRates(doublereal* ddot) { + updateROP(); + m_rxnstoich->getDestructionRates(m_kk, &m_kdata->m_ropf[0], &m_kdata->m_ropr[0], ddot); + } + //==================================================================================================================== + void GasKinetics::processFalloffReactions() { - if (m_kdata->m_ROP_ok) return; + int i; + const vector_fp& fc = m_kdata->concm_falloff_values; + const array_fp& m_rf_low = m_kdata->m_rfn_low; + const array_fp& m_rf_high = m_kdata->m_rfn_high; - const vector_fp& rf = m_kdata->m_rfn; - const vector_fp& m_rkc = m_kdata->m_rkcn; - array_fp& ropf = m_kdata->m_ropf; - array_fp& ropr = m_kdata->m_ropr; - array_fp& ropnet = m_kdata->m_ropnet; + // use m_ropr for temporary storage of reduced pressure + array_fp& pr = m_kdata->m_ropr; - // copy rate coefficients into ropf - copy(rf.begin(), rf.end(), ropf.begin()); + array_fp& ropf = m_kdata->m_ropf; - // multiply ropf by enhanced 3b conc for all 3b rxns - m_3b_concm.multiply( &ropf[0], &m_kdata->concm_3b_values[0] ); + for (i = 0; i < m_nfall; i++) { + pr[i] = fc[i] * m_rf_low[i] / m_rf_high[i]; + } - processFalloffReactions(); + m_falloffn.pr_to_falloff( &pr[0], &m_kdata->falloff_work[0] ); + + for (i = 0; i < m_nfall; i++) { + pr[i] *= m_rf_high[i]; + } - // multiply by perturbation factor - multiply_each(ropf.begin(), ropf.end(), m_perturb.begin()); + scatter_copy(pr.begin(), pr.begin() + m_nfall, + ropf.begin(), m_fallindx.begin()); + } + + //==================================================================================================================== + void GasKinetics::updateROP() { + + _update_rates_T(); + _update_rates_C(); + + if (m_kdata->m_ROP_ok) return; + + const vector_fp& rf = m_kdata->m_rfn; + const vector_fp& m_rkc = m_kdata->m_rkcn; + array_fp& ropf = m_kdata->m_ropf; + array_fp& ropr = m_kdata->m_ropr; + array_fp& ropnet = m_kdata->m_ropnet; + + // copy rate coefficients into ropf + copy(rf.begin(), rf.end(), ropf.begin()); + + // multiply ropf by enhanced 3b conc for all 3b rxns + m_3b_concm.multiply( &ropf[0], &m_kdata->concm_3b_values[0] ); + + processFalloffReactions(); + + // multiply by perturbation factor + multiply_each(ropf.begin(), ropf.end(), m_perturb.begin()); - // copy the forward rates to the reverse rates - copy(ropf.begin(), ropf.end(), ropr.begin()); + // copy the forward rates to the reverse rates + copy(ropf.begin(), ropf.end(), ropr.begin()); - // for reverse rates computed from thermochemistry, multiply - // the forward rates copied into m_ropr by the reciprocals of - // the equilibrium constants - multiply_each(ropr.begin(), ropr.end(), m_rkc.begin()); + // for reverse rates computed from thermochemistry, multiply + // the forward rates copied into m_ropr by the reciprocals of + // the equilibrium constants + multiply_each(ropr.begin(), ropr.end(), m_rkc.begin()); - // multiply ropf by concentration products - m_rxnstoich->multiplyReactants(&m_conc[0], &ropf[0]); - //m_reactantStoich.multiply(m_conc.begin(), ropf.begin()); + // multiply ropf by concentration products + m_rxnstoich->multiplyReactants(&m_conc[0], &ropf[0]); + //m_reactantStoich.multiply(m_conc.begin(), ropf.begin()); - // for reversible reactions, multiply ropr by concentration - // products - m_rxnstoich->multiplyRevProducts(&m_conc[0], &ropr[0]); - //m_revProductStoich.multiply(m_conc.begin(), ropr.begin()); + // for reversible reactions, multiply ropr by concentration + // products + m_rxnstoich->multiplyRevProducts(&m_conc[0], &ropr[0]); + //m_revProductStoich.multiply(m_conc.begin(), ropr.begin()); - for (int j = 0; j != m_ii; ++j) { - ropnet[j] = ropf[j] - ropr[j]; - } - - m_kdata->m_ROP_ok = true; + for (int j = 0; j != m_ii; ++j) { + ropnet[j] = ropf[j] - ropr[j]; } - /** - * - * getFwdRateConstants(): - * - * Update the rate of progress for the reactions. - * This key routine makes sure that the rate of progress vectors - * located in the solid kinetics data class are up to date. + m_kdata->m_ROP_ok = true; + } + //==================================================================================================================== + /** + * + * getFwdRateConstants(): + * + * Update the rate of progress for the reactions. + * This key routine makes sure that the rate of progress vectors + * located in the solid kinetics data class are up to date. + */ + void GasKinetics:: + getFwdRateConstants(doublereal *kfwd) { + _update_rates_T(); + _update_rates_C(); + + // copy rate coefficients into ropf + const vector_fp& rf = m_kdata->m_rfn; + array_fp& ropf = m_kdata->m_ropf; + copy(rf.begin(), rf.end(), ropf.begin()); + + // multiply ropf by enhanced 3b conc for all 3b rxns + m_3b_concm.multiply(&ropf[0], &m_kdata->concm_3b_values[0] ); + + /* + * This routine is hardcoded to replace some of the values + * of the ropf vector. */ - void GasKinetics:: - getFwdRateConstants(doublereal *kfwd) { - _update_rates_T(); - _update_rates_C(); + processFalloffReactions(); - // copy rate coefficients into ropf - const vector_fp& rf = m_kdata->m_rfn; - array_fp& ropf = m_kdata->m_ropf; - copy(rf.begin(), rf.end(), ropf.begin()); - - // multiply ropf by enhanced 3b conc for all 3b rxns - m_3b_concm.multiply(&ropf[0], &m_kdata->concm_3b_values[0] ); - - /* - * This routine is hardcoded to replace some of the values - * of the ropf vector. - */ - processFalloffReactions(); - - // multiply by perturbation factor - multiply_each(ropf.begin(), ropf.end(), m_perturb.begin()); + // multiply by perturbation factor + multiply_each(ropf.begin(), ropf.end(), m_perturb.begin()); - for (int i = 0; i < m_ii; i++) { - kfwd[i] = ropf[i]; - } + for (int i = 0; i < m_ii; i++) { + kfwd[i] = ropf[i]; } - - /** - * - * getRevRateConstants(): - * - * Return a vector of the reverse reaction rate constants - * - * Length is the number of reactions. units depends - * on many issues. Note, this routine will return rate constants - * for irreversible reactions if the default for - * doIrreversible is overridden. + } + //==================================================================================================================== + /** + * + * getRevRateConstants(): + * + * Return a vector of the reverse reaction rate constants + * + * Length is the number of reactions. units depends + * on many issues. Note, this routine will return rate constants + * for irreversible reactions if the default for + * doIrreversible is overridden. + */ + void GasKinetics:: + getRevRateConstants(doublereal *krev, bool doIrreversible) { + /* + * go get the forward rate constants. -> note, we don't + * really care about speed or redundancy in these + * informational routines. */ - void GasKinetics:: - getRevRateConstants(doublereal *krev, bool doIrreversible) { - /* - * go get the forward rate constants. -> note, we don't - * really care about speed or redundancy in these - * informational routines. - */ - getFwdRateConstants(krev); + getFwdRateConstants(krev); - if (doIrreversible) { - doublereal *tmpKc = &m_kdata->m_ropnet[0]; - getEquilibriumConstants(tmpKc); - for (int i = 0; i < m_ii; i++) { - krev[i] /= tmpKc[i]; - } - } else { - /* - * m_rkc[] is zero for irreversibly reactions - */ - const vector_fp& m_rkc = m_kdata->m_rkcn; - for (int i = 0; i < m_ii; i++) { - krev[i] *= m_rkc[i]; - } - } + if (doIrreversible) { + doublereal *tmpKc = &m_kdata->m_ropnet[0]; + getEquilibriumConstants(tmpKc); + for (int i = 0; i < m_ii; i++) { + krev[i] /= tmpKc[i]; + } + } else { + /* + * m_rkc[] is zero for irreversibly reactions + */ + const vector_fp& m_rkc = m_kdata->m_rkcn; + for (int i = 0; i < m_ii; i++) { + krev[i] *= m_rkc[i]; + } } + } + //==================================================================================================================== + void GasKinetics:: + addReaction(const ReactionData& r) { - void GasKinetics:: - addReaction(const ReactionData& r) { + if (r.reactionType == ELEMENTARY_RXN) addElementaryReaction(r); + else if (r.reactionType == THREE_BODY_RXN) addThreeBodyReaction(r); + else if (r.reactionType == FALLOFF_RXN) addFalloffReaction(r); - if (r.reactionType == ELEMENTARY_RXN) addElementaryReaction(r); - else if (r.reactionType == THREE_BODY_RXN) addThreeBodyReaction(r); - else if (r.reactionType == FALLOFF_RXN) addFalloffReaction(r); + // operations common to all reaction types + installReagents( r ); + installGroups(reactionNumber(), r.rgroups, r.pgroups); + incrementRxnCount(); + m_rxneqn.push_back(r.equation); + } - // operations common to all reaction types - installReagents( r ); - installGroups(reactionNumber(), r.rgroups, r.pgroups); - incrementRxnCount(); - m_rxneqn.push_back(r.equation); - } + //==================================================================================================================== + void GasKinetics:: + addFalloffReaction(const ReactionData& r) { + // install high and low rate coeff calculators - void GasKinetics:: - addFalloffReaction(const ReactionData& r) { - - // install high and low rate coeff calculators - - int iloc = m_falloff_high_rates.install(m_nfall, - r.rateCoeffType, - r.rateCoeffParameters.size(), - &r.rateCoeffParameters[0] ); + int iloc = m_falloff_high_rates.install(m_nfall, + r.rateCoeffType, + r.rateCoeffParameters.size(), + &r.rateCoeffParameters[0] ); - m_falloff_low_rates.install( m_nfall, - r.rateCoeffType, r.auxRateCoeffParameters.size(), - DATA_PTR(r.auxRateCoeffParameters) ); + m_falloff_low_rates.install( m_nfall, + r.rateCoeffType, r.auxRateCoeffParameters.size(), + DATA_PTR(r.auxRateCoeffParameters) ); - // add constant terms to high and low rate - // coeff value vectors - m_kdata->m_rfn_high.push_back(r.rateCoeffParameters[0]); - m_kdata->m_rfn_low.push_back(r.auxRateCoeffParameters[0]); + // add constant terms to high and low rate + // coeff value vectors + m_kdata->m_rfn_high.push_back(r.rateCoeffParameters[0]); + m_kdata->m_rfn_low.push_back(r.auxRateCoeffParameters[0]); - // add a dummy entry in m_rf, where computed falloff - // rate coeff will be put - m_kdata->m_rfn.push_back(0.0); + // add a dummy entry in m_rf, where computed falloff + // rate coeff will be put + m_kdata->m_rfn.push_back(0.0); - // add this reaction number to the list of - // falloff reactions - m_fallindx.push_back( reactionNumber() ); + // add this reaction number to the list of + // falloff reactions + m_fallindx.push_back( reactionNumber() ); - // install the enhanced third-body concentration - // calculator for this reaction - m_falloff_concm.install( m_nfall, r.thirdBodyEfficiencies, - r.default_3b_eff); + // install the enhanced third-body concentration + // calculator for this reaction + m_falloff_concm.install( m_nfall, r.thirdBodyEfficiencies, + r.default_3b_eff); - // install the falloff function calculator for - // this reaction - m_falloffn.install( m_nfall, r.falloffType, r.falloffParameters ); + // install the falloff function calculator for + // this reaction + m_falloffn.install( m_nfall, r.falloffType, r.falloffParameters ); - // forward rxn order equals number of reactants, since rate - // coeff is defined in terms of the high-pressure limit - m_fwdOrder.push_back(r.reactants.size()); + // forward rxn order equals number of reactants, since rate + // coeff is defined in terms of the high-pressure limit + m_fwdOrder.push_back(r.reactants.size()); - // increment the falloff reaction counter - ++m_nfall; - registerReaction( reactionNumber(), FALLOFF_RXN, iloc); - } + // increment the falloff reaction counter + ++m_nfall; + registerReaction( reactionNumber(), FALLOFF_RXN, iloc); + } + //==================================================================================================================== + void GasKinetics:: + addElementaryReaction(const ReactionData& r) { + int iloc; - void GasKinetics:: - addElementaryReaction(const ReactionData& r) { - int iloc; + // install rate coeff calculator + iloc = m_rates.install( reactionNumber(), + r.rateCoeffType, r.rateCoeffParameters.size(), + DATA_PTR(r.rateCoeffParameters) ); - // install rate coeff calculator - iloc = m_rates.install( reactionNumber(), - r.rateCoeffType, r.rateCoeffParameters.size(), - DATA_PTR(r.rateCoeffParameters) ); + // add constant term to rate coeff value vector + m_kdata->m_rfn.push_back(r.rateCoeffParameters[0]); - // add constant term to rate coeff value vector - m_kdata->m_rfn.push_back(r.rateCoeffParameters[0]); + // forward rxn order equals number of reactants + m_fwdOrder.push_back(r.reactants.size()); + registerReaction( reactionNumber(), ELEMENTARY_RXN, iloc); + } - // forward rxn order equals number of reactants - m_fwdOrder.push_back(r.reactants.size()); - registerReaction( reactionNumber(), ELEMENTARY_RXN, iloc); - } - - - void GasKinetics:: - addThreeBodyReaction(const ReactionData& r) { + //==================================================================================================================== + void GasKinetics:: + addThreeBodyReaction(const ReactionData& r) { - int iloc; - // install rate coeff calculator - iloc = m_rates.install( reactionNumber(), - r.rateCoeffType, r.rateCoeffParameters.size(), - DATA_PTR(r.rateCoeffParameters) ); + int iloc; + // install rate coeff calculator + iloc = m_rates.install( reactionNumber(), + r.rateCoeffType, r.rateCoeffParameters.size(), + DATA_PTR(r.rateCoeffParameters) ); - // add constant term to rate coeff value vector - m_kdata->m_rfn.push_back(r.rateCoeffParameters[0]); + // add constant term to rate coeff value vector + m_kdata->m_rfn.push_back(r.rateCoeffParameters[0]); - // forward rxn order equals number of reactants + 1 - m_fwdOrder.push_back(r.reactants.size() + 1); - - m_3b_concm.install( reactionNumber(), r.thirdBodyEfficiencies, - r.default_3b_eff ); - registerReaction( reactionNumber(), THREE_BODY_RXN, iloc); - } + // forward rxn order equals number of reactants + 1 + m_fwdOrder.push_back(r.reactants.size() + 1); + m_3b_concm.install( reactionNumber(), r.thirdBodyEfficiencies, + r.default_3b_eff ); + registerReaction( reactionNumber(), THREE_BODY_RXN, iloc); + } + //==================================================================================================================== - void GasKinetics::installReagents(const ReactionData& r) { + void GasKinetics::installReagents(const ReactionData& r) { - m_kdata->m_ropf.push_back(0.0); // extend by one for new rxn - m_kdata->m_ropr.push_back(0.0); - m_kdata->m_ropnet.push_back(0.0); - int n, ns, m; - doublereal nsFlt; - doublereal reactantGlobalOrder = 0.0; - doublereal productGlobalOrder = 0.0; - int rnum = reactionNumber(); + m_kdata->m_ropf.push_back(0.0); // extend by one for new rxn + m_kdata->m_ropr.push_back(0.0); + m_kdata->m_ropnet.push_back(0.0); + int n, ns, m; + doublereal nsFlt; + doublereal reactantGlobalOrder = 0.0; + doublereal productGlobalOrder = 0.0; + int rnum = reactionNumber(); - vector_int rk; - int nr = r.reactants.size(); - for (n = 0; n < nr; n++) { - nsFlt = r.rstoich[n]; - reactantGlobalOrder += nsFlt; - ns = (int) nsFlt; - if ((doublereal) ns != nsFlt) { - if (ns < 1) { - ns = 1; - } - } - if (r.rstoich[n] != 0.0) - m_rrxn[r.reactants[n]][rnum] += r.rstoich[n]; - for (m = 0; m < ns; m++) { - rk.push_back(r.reactants[n]); - } - } - m_reactants.push_back(rk); - - vector_int pk; - int np = r.products.size(); - for (n = 0; n < np; n++) { - nsFlt = r.pstoich[n]; - productGlobalOrder += nsFlt; - ns = (int) nsFlt; - if ((double) ns != nsFlt) { - if (ns < 1) { - ns = 1; - } - } - if (r.pstoich[n] != 0.0) - m_prxn[r.products[n]][rnum] += r.pstoich[n]; - for (m = 0; m < ns; m++) { - pk.push_back(r.products[n]); - } - } - m_products.push_back(pk); - - m_kdata->m_rkcn.push_back(0.0); - - m_rxnstoich->add(reactionNumber(), r); - - if (r.reversible) { - m_dn.push_back(productGlobalOrder - reactantGlobalOrder); - m_revindex.push_back(reactionNumber()); - m_nrev++; - } - else { - m_dn.push_back(productGlobalOrder - reactantGlobalOrder); - m_irrev.push_back( reactionNumber() ); - m_nirrev++; - } + vector_int rk; + int nr = r.reactants.size(); + for (n = 0; n < nr; n++) { + nsFlt = r.rstoich[n]; + reactantGlobalOrder += nsFlt; + ns = (int) nsFlt; + if ((doublereal) ns != nsFlt) { + if (ns < 1) { + ns = 1; + } + } + if (r.rstoich[n] != 0.0) + m_rrxn[r.reactants[n]][rnum] += r.rstoich[n]; + for (m = 0; m < ns; m++) { + rk.push_back(r.reactants[n]); + } } + m_reactants.push_back(rk); - - void GasKinetics::installGroups(int irxn, - const vector& r, const vector& p) { - if (!r.empty()) { - writelog("installing groups for reaction "+int2str(reactionNumber())); - m_rgroups[reactionNumber()] = r; - m_pgroups[reactionNumber()] = p; - } + vector_int pk; + int np = r.products.size(); + for (n = 0; n < np; n++) { + nsFlt = r.pstoich[n]; + productGlobalOrder += nsFlt; + ns = (int) nsFlt; + if ((double) ns != nsFlt) { + if (ns < 1) { + ns = 1; + } + } + if (r.pstoich[n] != 0.0) + m_prxn[r.products[n]][rnum] += r.pstoich[n]; + for (m = 0; m < ns; m++) { + pk.push_back(r.products[n]); + } } + m_products.push_back(pk); + m_kdata->m_rkcn.push_back(0.0); - void GasKinetics::init() { - m_kk = thermo().nSpecies(); - m_rrxn.resize(m_kk); - m_prxn.resize(m_kk); - m_conc.resize(m_kk); - m_grt.resize(m_kk); - m_kdata->m_logp_ref = log(thermo().refPressure()) - log(GasConstant); + m_rxnstoich->add(reactionNumber(), r); + + if (r.reversible) { + m_dn.push_back(productGlobalOrder - reactantGlobalOrder); + m_revindex.push_back(reactionNumber()); + m_nrev++; } + else { + m_dn.push_back(productGlobalOrder - reactantGlobalOrder); + m_irrev.push_back( reactionNumber() ); + m_nirrev++; + } + } + //==================================================================================================================== - void GasKinetics::finalize() { - if (!m_finalized) { - // int i, j, nr, np; - m_kdata->falloff_work.resize( - static_cast(m_falloffn.workSize())); - m_kdata->concm_3b_values.resize( - static_cast(m_3b_concm.workSize())); - m_kdata->concm_falloff_values.resize( - static_cast(m_falloff_concm.workSize())); - -// for (i = 0; i < m_ii; i++) { -// nr = m_reactants[i].size(); -// for (j = 0; j < nr; j++) { -// m_rstoich[i][m_reactants[i][j]]++; -// } -// np = m_products[i].size(); -// for (j = 0; j < np; j++) { -// m_pstoich[i][m_products[i][j]]++; -// } -// } - //m_rxnstoich->write("c.cpp"); - m_finalized = true; - } + void GasKinetics::installGroups(int irxn, + const vector& r, const vector& p) { + if (!r.empty()) { + writelog("installing groups for reaction "+int2str(reactionNumber())); + m_rgroups[reactionNumber()] = r; + m_pgroups[reactionNumber()] = p; } + } - bool GasKinetics::ready() const { - return (m_finalized); + //==================================================================================================================== + void GasKinetics::init() { + m_kk = thermo().nSpecies(); + m_rrxn.resize(m_kk); + m_prxn.resize(m_kk); + m_conc.resize(m_kk); + m_grt.resize(m_kk); + m_kdata->m_logp_ref = log(thermo().refPressure()) - log(GasConstant); + } + //==================================================================================================================== + void GasKinetics::finalize() { + if (!m_finalized) { + // int i, j, nr, np; + m_kdata->falloff_work.resize( + static_cast(m_falloffn.workSize())); + m_kdata->concm_3b_values.resize( + static_cast(m_3b_concm.workSize())); + m_kdata->concm_falloff_values.resize( + static_cast(m_falloff_concm.workSize())); + + // for (i = 0; i < m_ii; i++) { + // nr = m_reactants[i].size(); + // for (j = 0; j < nr; j++) { + // m_rstoich[i][m_reactants[i][j]]++; + // } + // np = m_products[i].size(); + // for (j = 0; j < np; j++) { + // m_pstoich[i][m_products[i][j]]++; + // } + // } + //m_rxnstoich->write("c.cpp"); + m_finalized = true; } - + } + //==================================================================================================================== + bool GasKinetics::ready() const { + return (m_finalized); + } + //==================================================================================================================== } +//====================================================================================================================== diff --git a/Cantera/src/kinetics/GasKinetics.h b/Cantera/src/kinetics/GasKinetics.h index 7dee80dcd..ce81edd0f 100644 --- a/Cantera/src/kinetics/GasKinetics.h +++ b/Cantera/src/kinetics/GasKinetics.h @@ -34,385 +34,427 @@ void get_wdot(const doublereal* rop, doublereal* wdot); namespace Cantera { - // forward references + // forward references - class Enhanced3BConc; - class ReactionData; - class GasKineticsData; - class Thermo; + class Enhanced3BConc; + class ReactionData; + class GasKineticsData; + class Thermo; + + /** + * Holds mechanism-specific data. + */ + class GasKineticsData { + public: + + GasKineticsData(); + + GasKineticsData(const GasKineticsData &right); + + virtual ~GasKineticsData(); + + GasKineticsData& operator=(const GasKineticsData &right); + + doublereal m_logp_ref; + doublereal m_logc_ref; + doublereal m_logStandConc; + array_fp m_ropf; + array_fp m_ropr; + array_fp m_ropnet; + array_fp m_rfn_low; + array_fp m_rfn_high; + bool m_ROP_ok; + + doublereal m_temp; + array_fp m_rfn; + array_fp falloff_work; + array_fp concm_3b_values; + array_fp concm_falloff_values; + array_fp m_rkcn; + }; + + + /** + * Kinetics manager for elementary gas-phase chemistry. This + * kinetics manager implements standard mass-action reaction rate + * expressions for low-density gases. + * @ingroup kinetics + */ + class GasKinetics : public Kinetics { + + public: /** - * Holds mechanism-specific data. + * @name Constructors and General Information */ - class GasKineticsData { - public: - GasKineticsData() : - m_logp_ref(0.0), - m_logc_ref(0.0), - m_logStandConc(0.0), - m_ROP_ok(false), - m_temp(0.0) - {} - virtual ~GasKineticsData(){} + //@{ - doublereal m_logp_ref, m_logc_ref, m_logStandConc; - array_fp m_ropf, m_ropr, m_ropnet; - array_fp m_rfn_low, m_rfn_high; - bool m_ROP_ok; + //! Constructor. + /*! + * @param thermo Pointer to the gas ThermoPhase (optional) + */ + GasKinetics(thermo_t* thermo = 0); - doublereal m_temp; - array_fp m_rfn; - array_fp falloff_work; - array_fp concm_3b_values; - array_fp concm_falloff_values; - array_fp m_rkcn; - }; + + //!Copy Constructor for the %GasKinetics object. + /*! + * Currently, this is not fully implemented. If called it will + * throw an exception. + * + * @param right object to be copied + */ + GasKinetics(const GasKinetics &right); + + //! Destructor. + virtual ~GasKinetics(); + + //! Assignment operator + /*! + * This is NOT a virtual function. + * + * @param right Reference to %GasKinetics object to be copied into the + * current one. + */ + GasKinetics& operator=(const GasKinetics &right); + + //! Duplication routine for objects which inherit from Kinetics + /*! + * This virtual routine can be used to duplicate %Kinetics objects + * inherited from %Kinetics even if the application only has + * a pointer to %Kinetics to work with. + * + * These routines are basically wrappers around the derived copy constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object + */ + virtual Kinetics *duplMyselfAsKinetics(const std::vector & tpVector) const; + + + //! Identifies the subclass of the Kinetics manager type. + /*! + * These are listed in mix_defs.h. + */ + virtual int ID() const { return cGasKinetics; } + + //! Identifies the kinetics manager type. + /*! + * Each class derived from Kinetics should overload this method to + * return a unique integer. Standard values are defined in file + * mix_defs.h. + */ + virtual int type() const { return cGasKinetics; } + + virtual doublereal reactantStoichCoeff(int k, int i) const { + return m_rrxn[k][i]; + } + + virtual doublereal productStoichCoeff(int k, int i) const { + return m_prxn[k][i]; + } + + //@} + /** + * @name Reaction Rates Of Progress + */ + //@{ + /** + * Forward rates of progress. + * Return the forward rates of progress in array fwdROP, which + * must be dimensioned at least as large as the total number + * of reactions. + */ + virtual void getFwdRatesOfProgress(doublereal* fwdROP) { + updateROP(); + std::copy(m_kdata->m_ropf.begin(), m_kdata->m_ropf.end(), fwdROP); + } + + /** + * Reverse rates of progress. + * Return the reverse rates of progress in array revROP, which + * must be dimensioned at least as large as the total number + * of reactions. + */ + virtual void getRevRatesOfProgress(doublereal* revROP) { + updateROP(); + std::copy(m_kdata->m_ropr.begin(), m_kdata->m_ropr.end(), revROP); + } + + /** + * Net rates of progress. Return the net (forward - reverse) + * rates of progress in array netROP, which must be + * dimensioned at least as large as the total number of + * reactions. + */ + virtual void getNetRatesOfProgress(doublereal* netROP) { + updateROP(); + std::copy(m_kdata->m_ropnet.begin(), m_kdata->m_ropnet.end(), netROP); + } /** - * Kinetics manager for elementary gas-phase chemistry. This - * kinetics manager implements standard mass-action reaction rate - * expressions for low-density gases. - * @ingroup kinetics + * Equilibrium constants. Return the equilibrium constants of + * the reactions in concentration units in array kc, which + * must be dimensioned at least as large as the total number + * of reactions. */ - class GasKinetics : public Kinetics { + virtual void getEquilibriumConstants(doublereal* kc); - public: + /** + * Return the array of values for the reaction gibbs free energy + * change. + * These values depend on the species concentrations. + * + * units = J kmol-1 + */ + virtual void getDeltaGibbs( doublereal* deltaG); - /** - * @name Constructors and General Information - */ - //@{ - /// Constructor. - GasKinetics(thermo_t* thermo = 0); + /** + * Return the array of values for the reaction enthalpy change. + * These values depend upon the species concentrations. + * + * units = J kmol-1 + */ + virtual void getDeltaEnthalpy( doublereal* deltaH); - /// Destructor. - virtual ~GasKinetics(); + /** + * Return the array of values for the reactions change in + * entropy. + * These values depend upon the concentration + * of the solution. + * + * units = J kmol-1 Kelvin-1 + */ + virtual void getDeltaEntropy(doublereal* deltaS); - virtual int ID() const { return cGasKinetics; } - virtual int type() const { return cGasKinetics; } + /** + * Return the array of values for the reaction + * standard state Gibbs free energy change. + * These values do not depend on the species + * concentrations. + * + * units = J kmol-1 + */ + virtual void getDeltaSSGibbs(doublereal* deltaG); - virtual doublereal reactantStoichCoeff(int k, int i) const { - return m_rrxn[k][i]; - } + /** + * Return the array of values for the change in the + * standard state enthalpies of reaction. + * These values do not depend upon the concentration + * of the solution. + * + * units = J kmol-1 + */ + virtual void getDeltaSSEnthalpy(doublereal* deltaH); - virtual doublereal productStoichCoeff(int k, int i) const { - return m_prxn[k][i]; - } + /** + * Return the array of values for the change in the + * standard state entropies for each reaction. + * These values do not depend upon the concentration + * of the solution. + * + * units = J kmol-1 Kelvin-1 + */ + virtual void getDeltaSSEntropy(doublereal* deltaS); - //@} - /** - * @name Reaction Rates Of Progress - */ - //@{ - /** - * Forward rates of progress. - * Return the forward rates of progress in array fwdROP, which - * must be dimensioned at least as large as the total number - * of reactions. - */ - virtual void getFwdRatesOfProgress(doublereal* fwdROP) { - updateROP(); - std::copy(m_kdata->m_ropf.begin(), m_kdata->m_ropf.end(), fwdROP); - } + //@} + /** + * @name Species Production Rates + */ + //@{ - /** - * Reverse rates of progress. - * Return the reverse rates of progress in array revROP, which - * must be dimensioned at least as large as the total number - * of reactions. - */ - virtual void getRevRatesOfProgress(doublereal* revROP) { - updateROP(); - std::copy(m_kdata->m_ropr.begin(), m_kdata->m_ropr.end(), revROP); - } + //! Return the species net production rates + /*! + * Species net production rates [kmol/m^3/s]. Return the species + * net production rates (creation - destruction) in array + * wdot, which must be dimensioned at least as large as the + * total number of species. + * + * @param net Array of species production rates. + * units kmol m-3 s-1 + */ + virtual void getNetProductionRates(doublereal* net); - /** - * Net rates of progress. Return the net (forward - reverse) - * rates of progress in array netROP, which must be - * dimensioned at least as large as the total number of - * reactions. - */ - virtual void getNetRatesOfProgress(doublereal* netROP) { - updateROP(); - std::copy(m_kdata->m_ropnet.begin(), m_kdata->m_ropnet.end(), netROP); - } + //! Return the species creation rates + /*! + * Species creation rates [kmol/m^3]. Return the species + * creation rates in array cdot, which must be + * dimensioned at least as large as the total number of + * species. + * + * @param cdot Array of species creation rates. + * units kmol m-3 s-1 + */ + virtual void getCreationRates(doublereal* cdot); + + //! Return a vector of the species destruction rates + /*! + * Species destruction rates [kmol/m^3]. Return the species + * destruction rates in array ddot, which must be + * dimensioned at least as large as the total number of + * species. + * + * + * @param ddot Array of species destruction rates. + * units kmol m-3 s-1 + * + */ + virtual void getDestructionRates(doublereal* ddot); + + //@} + /** + * @name Reaction Mechanism Informational Query Routines + */ + //@{ + + /** + * Flag specifying the type of reaction. The legal values and + * their meaning are specific to the particular kinetics + * manager. + */ + virtual int reactionType(int i) const { + return m_index[i].first; + } + + virtual std::string reactionString(int i) const { + return m_rxneqn[i]; + } + + /** + * True if reaction i has been declared to be reversible. If + * isReversible(i) is false, then the reverse rate of progress + * for reaction i is always zero. + */ + virtual bool isReversible(int i) { + if (std::find(m_revindex.begin(), m_revindex.end(), i) + < m_revindex.end()) return true; + else return false; + } + + /** + * Return the forward rate constants + * + * length is the number of reactions. units depends + * on many issues. + */ + virtual void getFwdRateConstants(doublereal *kfwd); + + /** + * Return the reverse rate constants. + * + * length is the number of reactions. units depends + * on many issues. Note, this routine will return rate constants + * for irreversible reactions if the default for + * doIrreversible is overridden. + */ + virtual void getRevRateConstants(doublereal *krev, + bool doIrreversible = false); + + //@} + /** + * @name Reaction Mechanism Setup Routines + */ + //@{ + + virtual void init(); + + /// Add a reaction to the mechanism. + virtual void addReaction(const ReactionData& r); + + virtual void finalize(); + virtual bool ready() const; + + virtual void update_T(); + virtual void update_C(); + + void updateROP(); - /** - * Equilibrium constants. Return the equilibrium constants of - * the reactions in concentration units in array kc, which - * must be dimensioned at least as large as the total number - * of reactions. - */ - virtual void getEquilibriumConstants(doublereal* kc); - - /** - * Return the array of values for the reaction gibbs free energy - * change. - * These values depend on the species concentrations. - * - * units = J kmol-1 - */ - virtual void getDeltaGibbs( doublereal* deltaG); - - /** - * Return the array of values for the reaction enthalpy change. - * These values depend upon the species concentrations. - * - * units = J kmol-1 - */ - virtual void getDeltaEnthalpy( doublereal* deltaH); - - /** - * Return the array of values for the reactions change in - * entropy. - * These values depend upon the concentration - * of the solution. - * - * units = J kmol-1 Kelvin-1 - */ - virtual void getDeltaEntropy(doublereal* deltaS); - - /** - * Return the array of values for the reaction - * standard state Gibbs free energy change. - * These values do not depend on the species - * concentrations. - * - * units = J kmol-1 - */ - virtual void getDeltaSSGibbs(doublereal* deltaG); - - /** - * Return the array of values for the change in the - * standard state enthalpies of reaction. - * These values do not depend upon the concentration - * of the solution. - * - * units = J kmol-1 - */ - virtual void getDeltaSSEnthalpy(doublereal* deltaH); - - /** - * Return the array of values for the change in the - * standard state entropies for each reaction. - * These values do not depend upon the concentration - * of the solution. - * - * units = J kmol-1 Kelvin-1 - */ - virtual void getDeltaSSEntropy(doublereal* deltaS); - - //@} - /** - * @name Species Production Rates - */ - //@{ - - //! Return the species net production rates - /*! - * Species net production rates [kmol/m^3/s]. Return the species - * net production rates (creation - destruction) in array - * wdot, which must be dimensioned at least as large as the - * total number of species. - * - * @param net Array of species production rates. - * units kmol m-3 s-1 - */ - virtual void getNetProductionRates(doublereal* net) { - updateROP(); - //#ifdef HWMECH - //get_wdot(&m_kdata->m_ropnet[0], net); - //#else - m_rxnstoich->getNetProductionRates(m_kk, - &m_kdata->m_ropnet[0], net); - //#endif - } - - /** - * Species creation rates [kmol/m^3]. Return the species - * creation rates in array cdot, which must be - * dimensioned at least as large as the total number of - * species. - * - */ - virtual void getCreationRates(doublereal* cdot) { - updateROP(); - m_rxnstoich->getCreationRates(m_kk, &m_kdata->m_ropf[0], - &m_kdata->m_ropr[0], cdot); - } - - /** - * Species destruction rates [kmol/m^3]. Return the species - * destruction rates in array ddot, which must be - * dimensioned at least as large as the total number of - * species. - * - */ - virtual void getDestructionRates(doublereal* ddot) { - updateROP(); - m_rxnstoich->getDestructionRates(m_kk, &m_kdata->m_ropf[0], - &m_kdata->m_ropr[0], ddot); - // fill(ddot, ddot + m_kk, 0.0); - //m_revProductStoich.incrementSpecies( - // m_kdata->m_ropr.begin(), ddot); - //m_reactantStoich.incrementSpecies( - // m_kdata->m_ropf.begin(), ddot); - } - - //@} - /** - * @name Reaction Mechanism Informational Query Routines - */ - //@{ - - /** - * Flag specifying the type of reaction. The legal values and - * their meaning are specific to the particular kinetics - * manager. - */ - virtual int reactionType(int i) const { - return m_index[i].first; - } - - virtual std::string reactionString(int i) const { - return m_rxneqn[i]; - } - - /** - * True if reaction i has been declared to be reversible. If - * isReversible(i) is false, then the reverse rate of progress - * for reaction i is always zero. - */ - virtual bool isReversible(int i) { - if (std::find(m_revindex.begin(), m_revindex.end(), i) - < m_revindex.end()) return true; - else return false; - } - - /** - * Return the forward rate constants - * - * length is the number of reactions. units depends - * on many issues. - */ - virtual void getFwdRateConstants(doublereal *kfwd); - - /** - * Return the reverse rate constants. - * - * length is the number of reactions. units depends - * on many issues. Note, this routine will return rate constants - * for irreversible reactions if the default for - * doIrreversible is overridden. - */ - virtual void getRevRateConstants(doublereal *krev, - bool doIrreversible = false); - - //@} - /** - * @name Reaction Mechanism Setup Routines - */ - //@{ - - virtual void init(); - - /// Add a reaction to the mechanism. - virtual void addReaction(const ReactionData& r); - - virtual void finalize(); - virtual bool ready() const; - - virtual void update_T(); - virtual void update_C(); - - void updateROP(); + const std::vector& reactantGroups(int i) + { return m_rgroups[i]; } + const std::vector& productGroups(int i) + { return m_pgroups[i]; } - const std::vector& reactantGroups(int i) - { return m_rgroups[i]; } - const std::vector& productGroups(int i) - { return m_pgroups[i]; } + void _update_rates_T(); + void _update_rates_C(); + + //@} + + protected: + + int m_kk; + + int m_nfall; + + array_int m_fallindx; + + Rate1 m_falloff_low_rates; + Rate1 m_falloff_high_rates; + Rate1 m_rates; + + mutable std::map > m_index; + + FalloffMgr m_falloffn; + + ThirdBodyMgr m_3b_concm; + ThirdBodyMgr m_falloff_concm; + + std::vector m_irrev; + + ReactionStoichMgr* m_rxnstoich; + + std::vector m_fwdOrder; + + int m_nirrev; + int m_nrev; + + std::map > m_rgroups; + std::map > m_pgroups; + + std::vector m_rxntype; + + mutable std::vector > m_rrxn; + mutable std::vector > m_prxn; + + /** + * Difference between the input global reactants order + * and the input global products order. Changed to a double + * to account for the fact that we can have real-valued + * stoichiometries. + */ + array_fp m_dn; + array_int m_revindex; + + std::vector m_rxneqn; + + GasKineticsData* m_kdata; + + array_fp m_conc; + void processFalloffReactions(); + array_fp m_grt; - void _update_rates_T(); - void _update_rates_C(); + private: - //@} + int reactionNumber(){ return m_ii;} + std::vector > m_stoich; - protected: + void addElementaryReaction(const ReactionData& r); + void addThreeBodyReaction(const ReactionData& r); + void addFalloffReaction(const ReactionData& r); - int m_kk, m_nfall; + void installReagents(const ReactionData& r); - array_int m_fallindx; + void installGroups(int irxn, const std::vector& r, + const std::vector& p); + void updateKc(); - Rate1 m_falloff_low_rates; - Rate1 m_falloff_high_rates; - Rate1 m_rates; - - mutable std::map > m_index; - - FalloffMgr m_falloffn; - - ThirdBodyMgr m_3b_concm; - ThirdBodyMgr m_falloff_concm; - - std::vector m_irrev; - - ReactionStoichMgr* m_rxnstoich; - - std::vector m_fwdOrder; - - int m_nirrev; - int m_nrev; - - std::map > m_rgroups; - std::map > m_pgroups; - - std::vector m_rxntype; - - mutable std::vector > m_rrxn; - mutable std::vector > m_prxn; - - /** - * Difference between the input global reactants order - * and the input global products order. Changed to a double - * to account for the fact that we can have real-valued - * stoichiometries. - */ - array_fp m_dn; - array_int m_revindex; - - std::vector m_rxneqn; - - GasKineticsData* m_kdata; - - array_fp m_conc; - void processFalloffReactions(); - array_fp m_grt; - - - private: - - int reactionNumber(){ return m_ii;} - std::vector > m_stoich; - - void addElementaryReaction(const ReactionData& r); - void addThreeBodyReaction(const ReactionData& r); - void addFalloffReaction(const ReactionData& r); - - void installReagents(const ReactionData& r); - - void installGroups(int irxn, const std::vector& r, - const std::vector& p); - void updateKc(); - - void registerReaction(int rxnNumber, int type, int loc) { - m_index[rxnNumber] = std::pair(type, loc); - } - bool m_finalized; - }; + void registerReaction(int rxnNumber, int type, int loc) { + m_index[rxnNumber] = std::pair(type, loc); + } + bool m_finalized; + }; } #endif diff --git a/Cantera/src/kinetics/Group.h b/Cantera/src/kinetics/Group.h index 82e13b74f..cf44e475c 100644 --- a/Cantera/src/kinetics/Group.h +++ b/Cantera/src/kinetics/Group.h @@ -14,7 +14,6 @@ #include "ct_defs.h" -//using namespace std; namespace Cantera { /** diff --git a/Cantera/src/kinetics/InterfaceKinetics.cpp b/Cantera/src/kinetics/InterfaceKinetics.cpp index 2f5cd0cd7..63325fae7 100644 --- a/Cantera/src/kinetics/InterfaceKinetics.cpp +++ b/Cantera/src/kinetics/InterfaceKinetics.cpp @@ -24,7 +24,45 @@ using namespace std; namespace Cantera { - + //==================================================================================================================== + InterfaceKineticsData::InterfaceKineticsData() : + m_logp0(0.0), + m_logc0(0.0), + m_ROP_ok(false), + m_temp(0.0), + m_logtemp(0.0) + { + } + //==================================================================================================================== + InterfaceKineticsData:: InterfaceKineticsData(const InterfaceKineticsData &right) : + m_logp0(0.0), + m_logc0(0.0), + m_ROP_ok(false), + m_temp(0.0), + m_logtemp(0.0) + { + *this = right; + } + //==================================================================================================================== + InterfaceKineticsData::~InterfaceKineticsData() + { + } + //==================================================================================================================== + InterfaceKineticsData & InterfaceKineticsData::operator=(const InterfaceKineticsData &right) + { + if (this == &right) return *this; + m_logp0 = right.m_logp0; + m_logc0 = right.m_logc0; + m_ropf = right.m_ropf; + m_ropr = right.m_ropr; + m_ropnet = right.m_ropnet; + m_ROP_ok = right.m_ROP_ok; + m_temp = right.m_temp; + m_logtemp = right.m_logtemp; + m_rfn = right.m_rfn; + m_rkcn = right.m_rkcn; + return *this; + } //==================================================================================================================== /* * Construct an empty InterfaceKinetics reaction mechanism. @@ -54,6 +92,7 @@ namespace Cantera { m_has_exchange_current_density_formulation(false), m_phaseExistsCheck(false), m_phaseExists(0), + m_phaseIsStable(0), m_rxnPhaseIsReactant(0), m_rxnPhaseIsProduct(0), m_ioFlag(0) @@ -72,8 +111,8 @@ namespace Cantera { delete m_integrator; } for (int i = 0; i < m_ii; i++) { - delete m_rxnPhaseIsReactant[i]; - delete m_rxnPhaseIsProduct[i]; + delete [] m_rxnPhaseIsReactant[i]; + delete [] m_rxnPhaseIsProduct[i]; } } //==================================================================================================================== @@ -102,6 +141,7 @@ namespace Cantera { m_has_exchange_current_density_formulation(false), m_phaseExistsCheck(false), m_phaseExists(0), + m_phaseIsStable(0), m_rxnPhaseIsReactant(0), m_rxnPhaseIsProduct(0), m_ioFlag(0) @@ -130,14 +170,13 @@ namespace Cantera { if (this == &right) return *this; for (i = 0; i < m_ii; i++) { - delete (m_rxnPhaseIsReactant[i]); - delete (m_rxnPhaseIsProduct[i]); + delete [] m_rxnPhaseIsReactant[i]; + delete [] m_rxnPhaseIsProduct[i]; } Kinetics::operator=(right); - - + m_grt = right.m_grt; m_kk = right.m_kk; m_revindex = right.m_revindex; m_rates = right.m_rates; @@ -150,7 +189,8 @@ namespace Cantera { m_rrxn = right.m_rrxn; m_prxn = right.m_prxn; m_rxneqn = right.m_rxneqn; - *m_kdata = *right.m_kdata; // needs to be developed + *m_kdata = *right.m_kdata; + m_conc = right.m_conc; m_mu0 = right.m_mu0; m_phi = right.m_phi; m_pot = right.m_pot; @@ -170,7 +210,7 @@ namespace Cantera { m_has_exchange_current_density_formulation = right.m_has_exchange_current_density_formulation; m_phaseExistsCheck = right.m_phaseExistsCheck; m_phaseExists = right.m_phaseExists; - + m_phaseIsStable = right.m_phaseIsStable; m_rxnPhaseIsReactant.resize(m_ii, 0); m_rxnPhaseIsProduct.resize(m_ii, 0); @@ -184,8 +224,6 @@ namespace Cantera { } } - m_rxnPhaseIsProduct = right.m_rxnPhaseIsProduct; - m_ioFlag = right.m_ioFlag; return *this; @@ -199,17 +237,6 @@ namespace Cantera { int InterfaceKinetics::type() const { return cInterfaceKinetics; } - //==================================================================================================================== - // Set the electric potential in the nth phase - /* - * @param n phase Index in this kinetics object. - * @param V Electric potential (volts) - */ - void InterfaceKinetics::setElectricPotential(int n, doublereal V) { - thermo(n).setElectricPotential(V); - m_redo_rates = true; - } - //==================================================================================================================== // Duplication routine for objects which inherit from Kinetics /* @@ -219,10 +246,24 @@ namespace Cantera { * * These routines are basically wrappers around the derived copy * constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object */ - Kinetics *InterfaceKinetics::duplMyselfAsKinetics() const { - InterfaceKinetics* tp = new InterfaceKinetics(*this); - return dynamic_cast(tp); + Kinetics *InterfaceKinetics::duplMyselfAsKinetics(const std::vector & tpVector) const { + InterfaceKinetics* iK = new InterfaceKinetics(*this); + iK->assignShallowPointers(tpVector); + return dynamic_cast(iK); + } + //==================================================================================================================== + // Set the electric potential in the nth phase + /* + * @param n phase Index in this kinetics object. + * @param V Electric potential (volts) + */ + void InterfaceKinetics::setElectricPotential(int n, doublereal V) { + thermo(n).setElectricPotential(V); + m_redo_rates = true; } //==================================================================================================================== // Update properties that depend on temperature @@ -298,6 +339,17 @@ namespace Cantera { } + // Get the vector of activity concentrations used in the kinetics object + /* + * @param conc (output) Vector of activity concentrations. Length is + * equal to the number of species in the kinetics object + */ + void InterfaceKinetics::getActivityConcentrations(doublereal * const conc) { + _update_rates_C(); + copy(m_conc.begin(), m_conc.end(), conc); + } + + /** * Update the equilibrium constants in molar units for all * reversible reactions. Irreversible reactions have their @@ -704,6 +756,12 @@ namespace Cantera { } } } + if (m_rxnPhaseIsReactant[j][p]) { + if (! m_phaseIsStable[p]) { + ropnet[j] = 0.0; + ropr[j] = ropf[j]; + } + } } } else if ((ropf[j] > ropr[j]) && (ropf[j] > 0.0)) { for (int p = 0; p < nPhases(); p++) { @@ -723,6 +781,12 @@ namespace Cantera { } } } + if (m_rxnPhaseIsProduct[j][p]) { + if (! m_phaseIsStable[p]) { + ropnet[j] = 0.0; + ropf[j] = ropr[j]; + } + } } } } @@ -731,8 +795,38 @@ namespace Cantera { m_kdata->m_ROP_ok = true; } +#ifdef KINETICS_WITH_INTERMEDIATE_ZEROED_PHASES + //================================================================================================= + InterfaceKinetics::adjustRatesForIntermediatePhases() { + doublereal sFac = 1.0; - /** + array_fp& ropf = m_kdata->m_ropf; + array_fp& ropr = m_kdata->m_ropr; + array_fp& ropnet = m_kdata->m_ropnet; + + getCreatingRates(DATA_PTR(m_speciestmpP)); + getDestructionRates(DATA_PTR(m_speciestmpD)); + + for (iphase = 0; iphase < nphases; iphase++) { + if (m_intermediatePhases(iphase)) { + for (isp = 0; isp < nspecies; isp++) { + if (m_speciesTmpD[ispI] > m_speciesTmpP[I]) { + sFac = m_speciesTmpD[ispI]/ m_speciesTmpP[I]; + } + // Loop over reactions that are reactants for the species in the phase + // reducing their rates. + + + } + } + + } + + } +#endif + //================================================================================================= + //================================================================================================= + /* * * getDeltaGibbs(): * @@ -763,8 +857,35 @@ namespace Cantera { */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaG); } - - /** + //================================================================================================= + // Return the vector of values for the reaction electrochemical free energy change. + /* + * These values depend upon the concentration of the solution and + * the voltage of the phases + * + * units = J kmol-1 + * + * @param deltaM Output vector of deltaM's for reactions + * Length: m_ii. + */ + void InterfaceKinetics::getDeltaElectrochemPotentials(doublereal* deltaM) { + /* + * Get the chemical potentials of the species in the + * ideal gas solution. + */ + int np = nPhases(); + int n; + for (n = 0; n < np; n++) { + thermo(n).getElectrochemPotentials(DATA_PTR(m_grt) + m_start[n]); + } + /* + * Use the stoichiometric manager to find deltaG for each + * reaction. + */ + m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaM); + } + //================================================================================================= + /* * * getDeltaEnthalpy(): * @@ -935,11 +1056,27 @@ namespace Cantera { */ void InterfaceKinetics::addReaction(const ReactionData& r) { + /* + * Install the rate coefficient for the current reaction + * in the appropriate data structure. + */ addElementaryReaction(r); - - // operations common to all reaction types + /* + * Add the reactants and products for m_ropnet;the current reaction + * to the various stoichiometric coefficient arrays. + */ installReagents(r); + /* + * Save the reaction and product groups, which are + * part of the ReactionData class, in this class. + * They aren't used for anything but reaction path + * analysis. + */ //installGroups(reactionNumber(), r.rgroups, r.pgroups); + /* + * Increase the internal number of reactions, m_ii, by one. + * increase the size of m_perturb by one as well. + */ incrementRxnCount(); m_rxneqn.push_back(r.equation); @@ -1137,6 +1274,7 @@ namespace Cantera { void InterfaceKinetics::addPhase(thermo_t &thermo) { Kinetics::addPhase(thermo); m_phaseExists.push_back(true); + m_phaseIsStable.push_back(true); } //================================================================================================ /** @@ -1195,7 +1333,7 @@ namespace Cantera { m_finalized = true; } - + //================================================================================================ doublereal InterfaceKinetics::electrochem_beta(int irxn) const{ int n = m_ctrxn.size(); for (int i = 0; i < n; i++) { @@ -1206,7 +1344,7 @@ namespace Cantera { return 0.0; } - + //================================================================================================ bool InterfaceKinetics::ready() const { return (m_finalized); } @@ -1241,8 +1379,7 @@ namespace Cantera { * reduce the computational cost of repeated calls. */ void InterfaceKinetics:: - solvePseudoSteadyStateProblem(int ifuncOverride, - doublereal timeScaleOverride) { + solvePseudoSteadyStateProblem(int ifuncOverride, doublereal timeScaleOverride) { // create our own solver object if (m_integrator == 0) { vector k; @@ -1258,7 +1395,7 @@ namespace Cantera { } //================================================================================================ - void InterfaceKinetics::setPhaseExistence(const int iphase, const bool exists) { + void InterfaceKinetics::setPhaseExistence(const int iphase, const int exists) { if (iphase < 0 || iphase >= (int) m_thermo.size()) { throw CanteraError("InterfaceKinetics:setPhaseExistence", "out of bounds"); } @@ -1267,13 +1404,58 @@ namespace Cantera { m_phaseExistsCheck--; m_phaseExists[iphase] = true; } + m_phaseIsStable[iphase] = true; } else { if (m_phaseExists[iphase]) { m_phaseExistsCheck++; m_phaseExists[iphase] = false; } + m_phaseIsStable[iphase] = false; } } + //================================================================================================ + // Gets the phase existence int for the ith phase + /* + * @param iphase Phase Id + * + * @return Returns the int specifying whether the kinetics object thinks the phase exists + * or not. If it exists, then species in that phase can be a reactant in reactions. + */ + int InterfaceKinetics::phaseExistence(const int iphase) const { + if (iphase < 0 || iphase >= (int) m_thermo.size()) { + throw CanteraError("InterfaceKinetics:phaseExistence()", "out of bounds"); + } + return m_phaseExists[iphase]; + } + //================================================================================================ + // Gets the phase stability int for the ith phase + /* + * @param iphase Phase Id + * + * @return Returns the int specifying whether the kinetics object thinks the phase is stable + * with nonzero mole numbers. + * If it stable, then the kinetics object will allow for rates of production of + * of species in that phase that are positive. + */ + int InterfaceKinetics::phaseStability(const int iphase) const { + if (iphase < 0 || iphase >= (int) m_thermo.size()) { + throw CanteraError("InterfaceKinetics:phaseStability()", "out of bounds"); + } + return m_phaseIsStable[iphase]; + } + //================================================================================================ + + void InterfaceKinetics::setPhaseStability(const int iphase, const int isStable) { + if (iphase < 0 || iphase >= (int) m_thermo.size()) { + throw CanteraError("InterfaceKinetics:setPhaseStability", "out of bounds"); + } + if (isStable) { + m_phaseIsStable[iphase] = true; + } else { + m_phaseIsStable[iphase] = false; + } + } + //================================================================================================ void EdgeKinetics::finalize() { m_rwork.resize(nReactions()); diff --git a/Cantera/src/kinetics/InterfaceKinetics.h b/Cantera/src/kinetics/InterfaceKinetics.h index 50ca5dc59..a7011237c 100644 --- a/Cantera/src/kinetics/InterfaceKinetics.h +++ b/Cantera/src/kinetics/InterfaceKinetics.h @@ -44,17 +44,17 @@ namespace Cantera { */ class InterfaceKineticsData { public: - InterfaceKineticsData() : - m_logp0(0.0), - m_logc0(0.0), - m_ROP_ok(false), - m_temp(0.0), - m_logtemp(0.0) - {} - + InterfaceKineticsData(); + + InterfaceKineticsData(const InterfaceKineticsData &right); + + InterfaceKineticsData &operator=(const InterfaceKineticsData &right); + //! Virtual destructor - virtual ~InterfaceKineticsData() { - } + /*! + * todo - why is this virtual + */ + virtual ~InterfaceKineticsData(); doublereal m_logp0; doublereal m_logc0; @@ -73,12 +73,38 @@ namespace Cantera { }; - /// - /// A kinetics manager for heterogeneous reaction mechanisms. The - /// reactions are assumed to occur at a 2D interface between two - /// 3D phases. - /// - /// @ingroup chemkinetics + + //! A kinetics manager for heterogeneous reaction mechanisms. The + //! reactions are assumed to occur at a 2D interface between two 3D phases. + /*! + * + * There are some important additions to the behavior of the kinetics class due to the + * presence of multiple phases and a heterogeneous interface. If a reactant phase + * doesn't exists, i.e., has a mole number of zero, a heterogeneous reaction can not + * proceed from reactants to products. Note it could perhaps proceed from products to + * reactants if all of the product phases exist. + * + * In order to make the determination of whether a phase exists or not actually involves + * the specification of additional information to the kinetics object., which heretofore + * has only had access to intrinsic field information about the phases (i.e., temperature + * pressure, and mole fraction). + * + * The extrinsic specification of whether a phase exists or not must be specified on top of the + * intrinsic calculation of the reaction rate. This routine carries a set of + * booleans indicating whether a phase in the heterogeneous mechanism exists or not. + * + * Additionally, the routine carries a set of booleans around indicating whether a product + * phase is stable or not. If a phase is not thermodynamically stable, it may be the case that + * a particular reaction in a heterogeneous mechanism will create a product species in the + * unstable phase. However, other reactions in the mechanism will destruct that species. + * This may cause oscillations in the formation of the unstable phase from time step to time + * step within a ODE solver, in practice. In order to avoid this situation, a set of + * booleans is tracked which sets the stability of a phase. If a phase is deemed to be unstable, + * then species in that phase will not be allowed to be birthed by the kinetics operator. + * Nonexistent phases are deemed to be unstable by default, but this can be changed. + * + * @ingroup chemkinetics + */ class InterfaceKinetics : public Kinetics { public: @@ -116,17 +142,19 @@ namespace Cantera { InterfaceKinetics& operator=(const InterfaceKinetics &right); - //! Duplication routine for objects which inherit from - //! Kinetics + + //! Duplication routine for objects which inherit from Kinetics /*! - * This virtual routine can be used to duplicate %InterfaceKinetics objects + * This virtual routine can be used to duplicate %Kinetics objects * inherited from %Kinetics even if the application only has * a pointer to %Kinetics to work with. * - * These routines are basically wrappers around the derived copy - * constructor. + * These routines are basically wrappers around the derived copy constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object */ - virtual Kinetics *duplMyselfAsKinetics() const; + virtual Kinetics *duplMyselfAsKinetics(const std::vector & tpVector) const; //! Return the ID of the kinetics object virtual int ID() const; @@ -188,8 +216,28 @@ namespace Cantera { void getExchangeCurrentQuantities(); + //! Return the vector of values for the reaction gibbs free energy change. + /*! + * These values depend upon the concentration of the solution. + * + * units = J kmol-1 + * + * @param deltaG Output vector of deltaG's for reactions + * Length: m_ii. + */ + virtual void getDeltaGibbs(doublereal* deltaG); - virtual void getDeltaGibbs( doublereal* deltaG); + //! Return the vector of values for the reaction electrochemical free energy change. + /*! + * These values depend upon the concentration of the solution and + * the voltage of the phases + * + * units = J kmol-1 + * + * @param deltaM Output vector of deltaM's for reactions + * Length: m_ii. + */ + virtual void getDeltaElectrochemPotentials(doublereal* deltaM); /** * Return the vector of values for the reactions change in @@ -199,7 +247,7 @@ namespace Cantera { * * units = J kmol-1 */ - virtual void getDeltaEnthalpy( doublereal* deltaH); + virtual void getDeltaEnthalpy(doublereal* deltaH); //! Return the vector of values for the change in //! entropy due to each reaction @@ -325,6 +373,13 @@ namespace Cantera { return m_index[i].first; } + //! Get the vector of activity concentrations used in the kinetics object + /*! + * @param conc (output) Vector of activity concentrations. Length is + * equal to the number of species in the kinetics object + */ + virtual void getActivityConcentrations(doublereal * const conc); + //! Return the charge transfer rxn Beta parameter for the ith reaction /*! * Returns the beta parameter for a charge transfer reaction. This @@ -437,7 +492,16 @@ namespace Cantera { */ void _update_rates_T(); + //! Update properties that depend on the electric potential + /*! + * This is called to update all of the properties that depend on potential + */ void _update_rates_phi(); + + //! Update properties that depend on the species mole fractions and/or concentration + /*! + * This is called to update all of the properties that depend on concentration + */ void _update_rates_C(); //! Advance the surface coverages in time @@ -528,13 +592,52 @@ namespace Cantera { /*! * Tell the kinetics object whether a phase in the object exists. * This is actually an extrinsic specification that must be carried out on top of the - * intrinsic calculation of the reaction rate + * intrinsic calculation of the reaction rate. + * The routine will also flip the IsStable boolean within the kinetics object as well. * * @param iphase Index of the phase. This is the order within the internal thermo vector object * @param exists Boolean indicating whether the phase exists or not */ - void setPhaseExistence(const int iphase, const bool exists); + void setPhaseExistence(const int iphase, const int exists); + + //! Set the stability of a phase in the reaction object + /*! + * Tell the kinetics object whether a phase in the object is stable. Species in an unstable phase + * will not be allowed to have a positive rate of formation from this kinetics object. + * This is actually an extrinsic specification that must be carried out on top of the + * intrinsic calculation of the reaction rate. + * + * While conceptually not needed since kinetics is consistent with thermo when taken as a whole, + * in practice it has found to be very useful to turn off the creation of phases which shouldn't + * be forming. Typically thais can reduce the oscillations in phase formation and destruction + * which are observed. + * + * @param iphase Index of the phase. This is the order within the internal thermo vector object + * @param exists Boolean indicating whether the phase exists or not + */ + void setPhaseStability(const int iphase, const int isStable); + //! Gets the phase existence int for the ith phase + /*! + * @param iphase Phase Id + * + * @return Returns the int specifying whether the kinetics object thinks the phase exists + * or not. If it exists, then species in that phase can be a reactant in reactions. + */ + int phaseExistence(const int iphase) const; + + //! Gets the phase stability int for the ith phase + /*! + * @param iphase Phase Id + * + * @return Returns the int specifying whether the kinetics object thinks the phase is stable + * with nonzero mole numbers. + * If it stable, then the kinetics object will allow for rates of production of + * of species in that phase that are positive. + */ + int phaseStability(const int iphase) const; + + protected: //! Temporary work vector of length m_kk @@ -680,6 +783,7 @@ namespace Cantera { //! Vector of raw activation energies for the reactions /*! * units are in Kelvin + * Length is number of reactions. */ vector_fp m_E; @@ -731,7 +835,7 @@ namespace Cantera { //! Boolean flag indicating whether any reaction in the mechanism //! has a beta electrochemical parameter. /*! - * If this is true, the the Butler-Volmer correction is applied + * If this is true, the Butler-Volmer correction is applied * to the forward reaction rate for those reactions. * * fac = exp ( - beta * (delta_phi)) @@ -764,11 +868,65 @@ namespace Cantera { * length = number of phases in the object * By default all phases exist. */ - std::vector m_phaseExists; + std::vector m_phaseExists; + //! Vector of int indicating whether phases are stable or not + /*! + * Vector of booleans indicating whether a phase is stable or not + * under the current conditions. + * We use this to set the ROP's so that unphysical things don't happen + * + * length = number of phases in the object + * By default all phases are stable + */ + std::vector m_phaseIsStable; + + //! Vector of vector of booleans indicating whether a phase participates in a + //! reaction as a reactant + /*! + * m_rxnPhaseIsReactant[j][p] indicates whether a species in phase p + * participates in reaction j as a reactant. + */ std::vector m_rxnPhaseIsReactant; + + //! Vector of vector of booleans indicating whether a phase participates in a + //! reaction as a product + /*! + * m_rxnPhaseIsReactant[j][p] indicates whether a species in phase p + * participates in reaction j as a product. + */ std::vector m_rxnPhaseIsProduct; +#ifdef KINETICS_WITH_INTERMEDIATE_ZEROED_PHASES + //! Vector of ints indicating whether zeroed phase is an intermediate for + //! the formation of another phase + /*! + * If a phase is zeroed out but it is an intermediate, then the phase + * can be formed whether it is stable or not, but the destruction rate of + * species in that phase can't exceed the formation rate for species in that + * phase. + * + * length = number of phases in the object + * By default all phases are not intermediates + */ + std::vector m_phaseIsIntermediate; + int m_numIntermediatePhases; + + //! Reaction rate reduction factor for intermediates + /*! + * Individual reaction rates are reduced to accommodate the requirements of intermediate + * zero phases. + * + * length = number of reactions in the object + * By default all phases are not intermediates + */ + std::vector m_rxnRateFactorPhaseIntermediates; + + //! Work vector having length number of species + std::vector m_speciesTmpP; + std::vector m_speciesTmpD; +#endif + int m_ioFlag; private: diff --git a/Cantera/src/kinetics/Kinetics.cpp b/Cantera/src/kinetics/Kinetics.cpp index c2338e1e1..989f3d2b7 100644 --- a/Cantera/src/kinetics/Kinetics.cpp +++ b/Cantera/src/kinetics/Kinetics.cpp @@ -32,11 +32,17 @@ namespace Cantera { Kinetics::Kinetics() : m_ii(0), m_nTotalSpecies(0), + m_perturb(0), + m_reactants(0), + m_products(0), m_thermo(0), + m_start(0), + m_phaseindex(), m_index(-1), m_surfphase(-1), m_rxnphase(-1), - m_mindim(4) + m_mindim(4), + m_dummygroups(0) { } @@ -51,16 +57,22 @@ namespace Cantera { Kinetics::Kinetics(const Kinetics &right) : m_ii(0), m_nTotalSpecies(0), + m_perturb(0), + m_reactants(0), + m_products(0), m_thermo(0), + m_start(0), + m_phaseindex(), m_index(-1), m_surfphase(-1), m_rxnphase(-1), - m_mindim(4) + m_mindim(4), + m_dummygroups(0) { /* * Call the assignment operator */ - *this = operator=(right); + *this = right; } // Assignment operator @@ -96,7 +108,7 @@ namespace Cantera { return *this; } - + //==================================================================================================================== // Duplication routine for objects which inherit from // Kinetics /* @@ -107,22 +119,48 @@ namespace Cantera { * These routines are basically wrappers around the derived copy * constructor. */ - Kinetics *Kinetics::duplMyselfAsKinetics() const { - Kinetics* tp = new Kinetics(*this); - return tp; + Kinetics *Kinetics::duplMyselfAsKinetics(const std::vector & tpVector) const { + Kinetics* ko = new Kinetics(*this); + + ko->assignShallowPointers(tpVector); + return ko; } - - - + //==================================================================================================================== int Kinetics::ID() const { return 0; } - + //==================================================================================================================== int Kinetics::type() const { return 0; } + //==================================================================================================================== + void Kinetics::assignShallowPointers(const std::vector & tpVector) { + size_t ns = tpVector.size(); + if (ns != m_thermo.size()) { + throw CanteraError(" Kinetics::assignShallowPointers", + " Number of ThermoPhase objects arent't the same"); + } + for (size_t i = 0; i < ns; i++) { + ThermoPhase *ntp = tpVector[i]; + ThermoPhase *otp = m_thermo[i]; + if (ntp->id() != otp->id()) { + throw CanteraError(" Kinetics::assignShallowPointers", + " id() of the ThermoPhase objects isn't the same"); + } + if (ntp->eosType() != otp->eosType()) { + throw CanteraError(" Kinetics::assignShallowPointers", + " eosType() of the ThermoPhase objects isn't the same"); + } + if (ntp->nSpecies() != otp->nSpecies()) { + throw CanteraError(" Kinetics::assignShallowPointers", + " Number of ThermoPhase objects isn't the same"); + } + m_thermo[i] = tpVector[i]; + } + } + //==================================================================================================================== /** * Takes as input an array of properties for all species in the * mechanism and copies those values beloning to a particular @@ -285,17 +323,13 @@ namespace Cantera { if (type() == cEdgeKinetics) ptype = cEdge; else if (type() == cInterfaceKinetics) ptype = cSurf; if (thermo.eosType() == ptype) { - // if (m_surfphase >= 0) { - // throw CanteraError("Kinetics::addPhase", - // "cannot add more than one surface phase"); - // } m_surfphase = nPhases(); m_rxnphase = nPhases(); } m_thermo.push_back(&thermo); m_phaseindex[m_thermo.back()->id()] = nPhases(); } - + void Kinetics::finalize() { m_nTotalSpecies = 0; int np = nPhases(); @@ -305,10 +339,9 @@ namespace Cantera { } } - - //! Private function of the class Kinetics, indicating that a function - //! inherited from the base class hasn't had a definition assigned to it - /*! + // Private function of the class Kinetics, indicating that a function + // inherited from the base class hasn't had a definition assigned to it + /* * @param m String message */ void Kinetics::err(std::string m) const { diff --git a/Cantera/src/kinetics/Kinetics.h b/Cantera/src/kinetics/Kinetics.h index 33b63263b..ea8bc6ab2 100644 --- a/Cantera/src/kinetics/Kinetics.h +++ b/Cantera/src/kinetics/Kinetics.h @@ -169,18 +169,35 @@ namespace Cantera { Kinetics& operator=(const Kinetics &right); - //! Duplication routine for objects which inherit from - //! Kinetics + //! Duplication routine for objects which inherit from Kinetics /*! * This virtual routine can be used to duplicate %Kinetics objects * inherited from %Kinetics even if the application only has * a pointer to %Kinetics to work with. * - * These routines are basically wrappers around the derived copy - * constructor. + * These routines are basically wrappers around the derived copy constructor. + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object */ - virtual Kinetics *duplMyselfAsKinetics() const; + virtual Kinetics *duplMyselfAsKinetics(const std::vector & tpVector) const; + //! Reassign the shallow pointers within the %FKinetics object + /*! + * This type or routine is absolute necessary because the Kinetics object doesn't + * own the ThermoPhase objects. After a duplication, we need to point to different + * ThermoPhase objects. + * + * We check that the ThermoPhase objects are alligned in the same order and have + * the following identical properties to the ones that they are replacing. + * id() + * eosType() + * nSpecies() + * + * @param tpVector Vector of shallow pointers to ThermoPhase objects. this is the + * m_thermo vector within this object + */ + virtual void assignShallowPointers(const std::vector & tpVector); //! Identifies the subclass of the Kinetics manager type. /*! @@ -492,20 +509,33 @@ namespace Cantera { err("getReactionDelta"); } - /** - * Return the vector of values for the reaction gibbs free - * energy change. These values depend upon the concentration - * of the solution. + //! Return the vector of values for the reaction gibbs free energy change. + /*! + * These values depend upon the concentration of the solution. * * units = J kmol-1 * * @param deltaG Output vector of deltaG's for reactions * Length: m_ii. */ - virtual void getDeltaGibbs( doublereal* deltaG) { + virtual void getDeltaGibbs(doublereal* deltaG) { err("getDeltaGibbs"); } + //! Return the vector of values for the reaction electrochemical free energy change. + /*! + * These values depend upon the concentration of the solution and + * the voltage of the phases + * + * units = J kmol-1 + * + * @param deltaM Output vector of deltaM's for reactions + * Length: m_ii. + */ + virtual void getDeltaElectrochemPotentials(doublereal* deltaM) { + err("getDeltaElectrochemPotentials"); + } + /** * Return the vector of values for the reactions change in * enthalpy. These values depend upon the concentration of @@ -516,7 +546,7 @@ namespace Cantera { * @param deltaH Output vector of deltaH's for reactions * Length: m_ii. */ - virtual void getDeltaEnthalpy( doublereal* deltaH) { + virtual void getDeltaEnthalpy(doublereal* deltaH) { err("getDeltaEnthalpy"); } @@ -530,7 +560,7 @@ namespace Cantera { * @param deltaS Output vector of deltaS's for reactions * Length: m_ii. */ - virtual void getDeltaEntropy( doublereal* deltaS) { + virtual void getDeltaEntropy(doublereal* deltaS) { err("getDeltaEntropy"); } @@ -544,7 +574,7 @@ namespace Cantera { * @param deltaG Output vector of ss deltaG's for reactions * Length: m_ii. */ - virtual void getDeltaSSGibbs( doublereal* deltaG) { + virtual void getDeltaSSGibbs(doublereal* deltaG) { err("getDeltaSSGibbs"); } @@ -558,7 +588,7 @@ namespace Cantera { * @param deltaH Output vector of ss deltaH's for reactions * Length: m_ii. */ - virtual void getDeltaSSEnthalpy( doublereal* deltaH) { + virtual void getDeltaSSEnthalpy(doublereal* deltaH) { err("getDeltaSSEnthalpy"); } @@ -572,7 +602,7 @@ namespace Cantera { * @param deltaS Output vector of ss deltaS's for reactions * Length: m_ii. */ - virtual void getDeltaSSEntropy( doublereal* deltaS) { + virtual void getDeltaSSEntropy(doublereal* deltaS) { err("getDeltaSSEntropy"); } @@ -654,8 +684,10 @@ namespace Cantera { return -1.0; } - /** - * reactant Order of species k in reaction i. + //! Reactant order of species k in reaction i. + /*! + * This is the nominal order of the activity concentration in + * determining the forward rate of progress of the reaction * * @param k kinetic species index * @param i reaction index @@ -665,6 +697,30 @@ namespace Cantera { return -1.0; } + //! product Order of species k in reaction i. + /*! + * This is the nominal order of the activity concentration of species k in + * determining the reverse rate of progress of the reaction i + * + * For irreversible reactions, this will all be zero. + * + * @param k kinetic species index + * @param i reaction index + */ + virtual doublereal productOrder(int k, int i) const { + err("productOrder"); + return -1.0; + } + + //! Get the vector of activity concentrations used in the kinetics object + /*! + * @param conc (output) Vector of activity concentrations. Length is + * equal to the number of species in the kinetics object + */ + virtual void getActivityConcentrations(doublereal * const conc) { + err("getActivityConcentrations"); + } + /** * Returns a read-only reference to the vector of reactant * index numbers for reaction i. @@ -849,13 +905,13 @@ namespace Cantera { */ //@{ - /// The current value of the multiplier for reaction i. + //! The current value of the multiplier for reaction i. /*! * @param i index of the reaction */ doublereal multiplier(int i) const {return m_perturb[i];} - /// Set the multiplier for reaction i to f. + //! Set the multiplier for reaction i to f. /*! * @param i index of the reaction * @param f value of the multiplier. @@ -939,8 +995,7 @@ namespace Cantera { */ std::vector m_products; - //! m_thermo is a vector of pointers to ThermoPhase - //! objects. + //! m_thermo is a vector of pointers to ThermoPhase objects that are involved with this kinetics operator /*! * For homogeneous kinetics applications, this vector * will only have one entry. For interfacial reactions, this @@ -973,21 +1028,27 @@ namespace Cantera { * -1. */ std::map m_phaseindex; + //! Index of the Kinetics Manager int m_index; - /** - * Index in the list of phases of the one surface phase. - */ + + //! Index in the list of phases of the one surface phase. + /*! + * + */ int m_surfphase; - /** - * Index in the list of phases of the one phase where the reactions - * occur. + + //! Phase Index where reactions are assumed to be taking place + /*! + * We calculate this by assuming that the phase with the lowest dimensionality is the phase where reactions + * are taking place + * @deprecated */ int m_rxnphase; - /// number of spatial dimensions of lowest-dimensional phase. + //! number of spatial dimensions of lowest-dimensional phase. int m_mindim; private: @@ -995,9 +1056,11 @@ namespace Cantera { //! Vector of group lists std::vector m_dummygroups; - //! Function for unhandled situations + + //! Private function of the class Kinetics, indicating that a function + //! inherited from the base class hasn't had a definition assigned to it /*! - * @param m String error message + * @param m String message */ void err(std::string m) const; diff --git a/Cantera/src/kinetics/ReactionStoichMgr.cpp b/Cantera/src/kinetics/ReactionStoichMgr.cpp index 6009a1164..13ff8ece9 100644 --- a/Cantera/src/kinetics/ReactionStoichMgr.cpp +++ b/Cantera/src/kinetics/ReactionStoichMgr.cpp @@ -24,12 +24,18 @@ using namespace std; namespace Cantera { - + //==================================================================================================================== // create stoichiometry managers for the reactants of all reactions, // for the products of the reversible reactions, and for the // products of the irreversible reactions. - ReactionStoichMgr:: - ReactionStoichMgr() { + ReactionStoichMgr::ReactionStoichMgr() : + m_reactants(0), + m_revproducts(0), + m_irrevproducts(0) +#ifdef INCL_STOICH_WRITER + , m_rwriter(0) +#endif + { m_reactants = new StoichManagerN; m_revproducts = new StoichManagerN; m_irrevproducts = new StoichManagerN; @@ -38,19 +44,54 @@ namespace Cantera { #endif m_dummy.resize(10,1.0); } - + //==================================================================================================================== // delete the three stoichiometry managers - ReactionStoichMgr::~ReactionStoichMgr() { + ReactionStoichMgr::~ReactionStoichMgr() + { delete m_reactants; delete m_revproducts; delete m_irrevproducts; - // delete m_global; #ifdef INCL_STOICH_WRITER delete m_rwriter; #endif } + //==================================================================================================================== + ReactionStoichMgr::ReactionStoichMgr(const ReactionStoichMgr &right) : + m_reactants(0), + m_revproducts(0), + m_irrevproducts(0) +#ifdef INCL_STOICH_WRITER + , m_rwriter(0) +#endif + { + m_reactants = new StoichManagerN(*right.m_reactants); + m_revproducts = new StoichManagerN(*right.m_revproducts); + m_irrevproducts = new StoichManagerN(*right.m_irrevproducts); + m_dummy = right.m_dummy; +#ifdef INCL_STOICH_WRITER + m_rwriter = new StoichManagerN(right.m_writer); +#endif + } + //==================================================================================================================== + ReactionStoichMgr & ReactionStoichMgr::operator=(const ReactionStoichMgr &right) + { + if (this != &right) { + if (m_reactants) delete(m_reactants); + if (m_revproducts) delete(m_revproducts); + if (m_irrevproducts) delete(m_irrevproducts); - + m_reactants = new StoichManagerN(*right.m_reactants); + m_revproducts = new StoichManagerN(*right.m_revproducts); + m_irrevproducts = new StoichManagerN(*right.m_irrevproducts); + m_dummy = right.m_dummy; +#ifdef INCL_STOICH_WRITER + if(m_writer) delete (m_writer); + m_rwriter = new StoichManagerN(right.m_writer); +#endif + } + return *this; + } + //==================================================================================================================== void ReactionStoichMgr:: add(int rxn, const vector_int& reactants, const vector_int& products, bool reversible) { diff --git a/Cantera/src/kinetics/ReactionStoichMgr.h b/Cantera/src/kinetics/ReactionStoichMgr.h index eba12e5d5..7824d3916 100644 --- a/Cantera/src/kinetics/ReactionStoichMgr.h +++ b/Cantera/src/kinetics/ReactionStoichMgr.h @@ -26,8 +26,8 @@ namespace Cantera { * user programs. * * Class ReactionStoichMgr handles the calculation of quantities involving - * the stoichiometry of a set of reactions. The reactions must have integer - * stoichiometric coefficients. Specifically, its methods compute + * the stoichiometry of a set of reactions. The reactions may have integer + * or non-integer stoichiometric coefficients. Specifically, its methods compute * - species creation rates * - species destruction rates * - species net production rates @@ -70,6 +70,10 @@ namespace Cantera { /// Destructor. virtual ~ReactionStoichMgr(); + ReactionStoichMgr(const ReactionStoichMgr &right); + + ReactionStoichMgr & operator=(const ReactionStoichMgr &right); + /** * Add a reaction with mass-action kinetics. Vectors * 'reactants' and 'products' contain the integer species @@ -97,7 +101,7 @@ namespace Cantera { * @param reversible true if the reaction is reversible, false otherwise */ virtual void add(int rxn, const vector_int& reactants, const vector_int& products, - bool reversible); + bool reversible); /** * Add a reaction with specified, possibly non-integral, reaction orders. @@ -112,11 +116,7 @@ namespace Cantera { * species with index in the corresponding location in 'reactants.' * */ - // void add(int rxn, const vector_int& reactants, const vector_int& products, - // bool reversible, const vector_fp& fwdOrder); - - - virtual void add(int rxn, const ReactionData& r); + virtual void add(int rxn, const ReactionData& r); /** * Species creation rates. @@ -144,7 +144,7 @@ namespace Cantera { * Note that the stoichiometric coefficient matrices are very sparse, integer * matrices. */ - virtual void getDestructionRates(int nSpecies, + virtual void getDestructionRates(int nSpecies, const doublereal* fwdRatesOfProgress, const doublereal* revRatesOfProgress, doublereal* destructionRates); @@ -164,7 +164,7 @@ namespace Cantera { * W = (N_r - N_p) Q_{\rm net}, * \f] */ - virtual void getNetProductionRates(int nsp, const doublereal* ropnet, doublereal* w); + virtual void getNetProductionRates(int nsp, const doublereal* ropnet, doublereal* w); @@ -205,7 +205,7 @@ namespace Cantera { * calculating reveerse rate coefficients from thermochemistry * for reversible reactions. */ - virtual void getRevReactionDelta(int nr, const doublereal* g, doublereal* dg); + virtual void getRevReactionDelta(int nr, const doublereal* g, doublereal* dg); /** @@ -217,7 +217,7 @@ namespace Cantera { * * Here \f$ o_{k,i} \f$ is the reaction order of species k in reaction i. */ - virtual void multiplyReactants(const doublereal* C, doublereal* R); + virtual void multiplyReactants(const doublereal* C, doublereal* R); /** @@ -229,7 +229,7 @@ namespace Cantera { * Here \f$ \nu^{(p)}_{k,i} \f$ is the product stoichiometric coefficient * of species k in reaction i. */ - virtual void multiplyRevProducts(const doublereal* c, doublereal* r); + virtual void multiplyRevProducts(const doublereal* c, doublereal* r); virtual void write(std::string filename); @@ -240,6 +240,9 @@ namespace Cantera { void writeNetProductionRates(std::ostream& f); void writeMultiplyReactants(std::ostream& f); void writeMultiplyRevProducts(std::ostream& f); + + protected: + StoichManagerN* m_reactants; StoichManagerN* m_revproducts; StoichManagerN* m_irrevproducts; diff --git a/Cantera/src/kinetics/RxnRates.h b/Cantera/src/kinetics/RxnRates.h index e8b0b5284..ce2cf2fc3 100644 --- a/Cantera/src/kinetics/RxnRates.h +++ b/Cantera/src/kinetics/RxnRates.h @@ -18,7 +18,7 @@ #include "ctexceptions.h" namespace Cantera { - + //! Arrhenius reaction rate type depends only on temperature /** * A reaction rate coefficient of the following form. @@ -29,20 +29,21 @@ namespace Cantera { * */ class Arrhenius { - public: - /// return the rate coefficient type. - static int type(){ return ARRHENIUS_REACTION_RATECOEFF_TYPE ; } + //! return the rate coefficient type. + static int type() { + return ARRHENIUS_REACTION_RATECOEFF_TYPE; + } - /// Default constructor. + //! Default constructor. Arrhenius() : m_logA(-1.0E300), m_b (0.0), m_E (0.0), m_A(0.0) {} - /// Constructor with Arrhenius parameters specified with an array. + //! Constructor with Arrhenius parameters specified with an array. Arrhenius(int csize, const doublereal* c) : m_b (c[1]), m_E (c[2]), @@ -126,7 +127,10 @@ namespace Cantera { class ArrheniusSum { public: - static int type(){ return ARRHENIUS_SUM_REACTION_RATECOEFF_TYPE; } + + static int type() { + return ARRHENIUS_SUM_REACTION_RATECOEFF_TYPE; + } ArrheniusSum() : m_nterms(0) {} void addArrheniusTerm(doublereal A, doublereal b, doublereal E) { @@ -193,7 +197,10 @@ namespace Cantera { class SurfaceArrhenius { public: - static int type(){ return ARRHENIUS_REACTION_RATECOEFF_TYPE ; } + static int type() { + return ARRHENIUS_REACTION_RATECOEFF_TYPE; + } + SurfaceArrhenius() : m_logA(-1.0E300), m_b (0.0), @@ -353,12 +360,11 @@ namespace Cantera { * */ class ExchangeCurrent { - public: - + //! return the rate coefficient type. static int type() { - return EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE ; + return EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE; } //! Default constructor. @@ -429,7 +435,6 @@ namespace Cantera { doublereal updateRC(doublereal logT, doublereal recipT) const { return m_A * exp(m_b*logT - m_E*recipT); } - void writeUpdateRHS(std::ostream& s) const { s << " exp(" << m_logA; diff --git a/Cantera/src/kinetics/StoichManager.h b/Cantera/src/kinetics/StoichManager.h index 56327d85a..97a9ff4ce 100644 --- a/Cantera/src/kinetics/StoichManager.h +++ b/Cantera/src/kinetics/StoichManager.h @@ -164,8 +164,26 @@ namespace Cantera { public: - C1( int rxn = 0, int ic0 = 0) - : m_rxn (rxn), m_ic0 (ic0) {} + C1(int rxn = 0, int ic0 = 0) : + m_rxn (rxn), + m_ic0 (ic0) + { + } + + C1(const C1 &right) : + m_rxn (right.m_rxn), + m_ic0 (right.m_ic0) + { + } + + C1& operator=(const C1 &right) + { + if (this != &right) { + m_rxn = right.m_rxn; + m_ic0 = right.m_ic0; + } + return *this; + } int data(std::vector& ic) { ic.resize(1); @@ -216,7 +234,9 @@ namespace Cantera { } private: + //! Reaction number int m_rxn; + //! Species number int m_ic0; }; @@ -231,6 +251,23 @@ namespace Cantera { C2( int rxn = 0, int ic0 = 0, int ic1 = 0) : m_rxn (rxn), m_ic0 (ic0), m_ic1 (ic1) {} + C2(const C2 &right) : + m_rxn(right.m_rxn), + m_ic0(right.m_ic0), + m_ic1(right.m_ic1) + { + } + + C2& operator=(const C2 &right) + { + if (this != &right) { + m_rxn = right.m_rxn; + m_ic0 = right.m_ic0; + m_ic1 = right.m_ic1; + } + return *this; + } + int data(std::vector& ic) { ic.resize(2); ic[0] = m_ic0; @@ -296,7 +333,8 @@ namespace Cantera { * Species indecise -> index into the species vector for the * two species. */ - int m_ic0, m_ic1; + int m_ic0; + int m_ic1; }; @@ -309,6 +347,25 @@ namespace Cantera { C3( int rxn = 0, int ic0 = 0, int ic1 = 0, int ic2 = 0) : m_rxn (rxn), m_ic0 (ic0), m_ic1 (ic1), m_ic2 (ic2) {} + C3(const C3 &right) : + m_rxn(right.m_rxn), + m_ic0(right.m_ic0), + m_ic1(right.m_ic1), + m_ic2(right.m_ic2) + { + } + + C3& operator=(const C3 &right) + { + if (this != &right) { + m_rxn = right.m_rxn; + m_ic0 = right.m_ic0; + m_ic1 = right.m_ic1; + m_ic2 = right.m_ic2; + } + return *this; + } + int data(std::vector& ic) { ic.resize(3); ic[0] = m_ic0; @@ -367,7 +424,10 @@ namespace Cantera { out[m_ic2] += s; } private: - int m_rxn, m_ic0, m_ic1, m_ic2; + int m_rxn; + int m_ic0; + int m_ic1; + int m_ic2; }; @@ -378,11 +438,17 @@ namespace Cantera { */ class C_AnyN { public: - C_AnyN() : m_rxn (-1) {} - C_AnyN( int rxn, const vector_int& ic, const vector_fp& order, - const vector_fp& stoich) - : m_rxn (rxn) { + C_AnyN() : + m_n(0), + m_rxn(-1) + { + } + + C_AnyN(int rxn, const vector_int& ic, const vector_fp& order, const vector_fp& stoich) : + m_n(0), + m_rxn(rxn) + { m_n = ic.size(); m_ic.resize(m_n); m_order.resize(m_n); @@ -394,6 +460,27 @@ namespace Cantera { } } + C_AnyN(const C_AnyN &right) : + m_n(right.m_n), + m_rxn(right.m_rxn), + m_ic(right.m_ic), + m_order(right.m_order), + m_stoich(right.m_stoich) + { + } + + C_AnyN& operator=(const C_AnyN &right) + { + if (this != &right) { + m_n = right.m_n; + m_rxn = right.m_rxn; + m_ic = right.m_ic; + m_order = right.m_order; + m_stoich = right.m_stoich; + } + return *this; + } + int data(std::vector& ic) { ic.resize(m_n); int n; @@ -627,7 +714,34 @@ namespace Cantera { * DGG - the problem is that the number of reactions and species * are not known initially. */ - StoichManagerN() {} + StoichManagerN() + { + } + + StoichManagerN(const StoichManagerN &right) : + m_c1_list(right.m_c1_list), + m_c2_list(right.m_c2_list), + m_c3_list(right.m_c3_list), + m_cn_list(right.m_cn_list), + m_n(right.m_n), + m_loc(right.m_loc) + { + + + } + + StoichManagerN& operator=(const StoichManagerN &right) + { + if (this != &right) { + m_c1_list = right.m_c1_list; + m_c2_list = right.m_c2_list; + m_c3_list = right.m_c3_list; + m_cn_list = right.m_cn_list; + m_n = right.m_n; + m_loc = right.m_loc; + } + return *this; + } /** * Add a single reaction to the list of reactions that this @@ -795,7 +909,31 @@ namespace Cantera { class StoichWriter { public: - StoichWriter() {} + StoichWriter() + { + } + + StoichWriter(const StoichWriter &right) : + m_mult(right.m_mult), + m_ir(right.m_ir), + m_dr(right.m_dr), + m_is(right.m_is), + m_ds(right.m_ds) + { + } + + StoichWriter& operator=(const StoichWriter &right) + { + if (this != &right) { + m_mult = right.m_mult; + m_ir = right.m_ir; + m_dr = right.m_dr; + m_is = right.m_is; + m_ds = right.m_ds; + } + return *this; + } + void add(int rxn, const vector_int& k) { int n, nn = k.size(); @@ -841,7 +979,11 @@ namespace Cantera { std::string decrRxn(int rxn) { return m_dr[rxn]; } private: - std::map m_mult, m_ir, m_dr, m_is, m_ds; + std::map m_mult; + std::map m_ir; + std::map m_dr; + std::map m_is; + std::map m_ds; }; #endif diff --git a/Cantera/src/numerics/ArrayViewer.h b/Cantera/src/numerics/ArrayViewer.h old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/BEulerInt.cpp b/Cantera/src/numerics/BEulerInt.cpp new file mode 100644 index 000000000..a2abc55fb --- /dev/null +++ b/Cantera/src/numerics/BEulerInt.cpp @@ -0,0 +1,2330 @@ +/** + * @file BEulerInt.cpp + * + */ + +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#include "BEulerInt.h" + + +#include "mdp_allo.h" +#include + +using namespace std; +using namespace mdp; + +#define SAFE_DELETE(a) if (a) { delete (a); a = 0; } + + +/* + * Blas routines + */ +extern "C" { + extern void dcopy_(int *, double *, int *, double *, int *); +} +namespace Cantera { + + //================================================================================================ + /* + * Exception thrown when a BEuler error is encountered. We just call the + * Cantera Error handler in the initialization list + */ + BEulerErr::BEulerErr(std::string msg) : + CanteraError("BEulerInt", msg) + { + } + + //================================================================================================ + /* + * Constructor. Default settings: dense jacobian, no user-supplied + * Jacobian function, Newton iteration. + */ + BEulerInt::BEulerInt() : + m_iter(Newton_Iter), + m_method(BEulerVarStep), + m_jacFormMethod(BEULER_JAC_NUM), + m_rowScaling(true), + m_colScaling(false), + m_matrixConditioning(false), + m_itol(0), + m_reltol(1.e-4), + m_abstols(1.e-10), + m_abstol(0), + m_ewt(0), + m_hmax(0.0), + m_maxord(0), + m_time_step_num(0), + m_time_step_attempts(0), + m_max_time_step_attempts(11000000), + m_numInitialConstantDeltaTSteps(0), + m_failure_counter(0), + m_min_newt_its(0), + m_printSolnStepInterval(1), + m_printSolnNumberToTout(1), + m_printSolnFirstSteps(0), + m_dumpJacobians(false), + m_neq(0), + m_y_n(0), + m_y_nm1(0), + m_y_pred_n(0), + m_ydot_n(0), + m_ydot_nm1(0), + m_t0(0.0), + m_time_final(0.0), + time_n(0.0), + time_nm1(0.0), + time_nm2(0.0), + delta_t_n(0.0), + delta_t_nm1(0.0), + delta_t_nm2(0.0), + delta_t_np1(1.0E-8), + delta_t_max(1.0E300), + m_resid(0), + m_residWts(0), + m_wksp(0), + m_func(0), + m_rowScales(0), + m_colScales(0), + tdjac_ptr(0), + m_print_flag(3), + m_nfe(0), + m_nJacEval(0), + m_numTotalNewtIts(0), + m_numTotalLinearSolves(0), + m_numTotalConvFails(0), + m_numTotalTruncFails(0), + num_failures(0) + { + + } + //================================================================================================ + /* + * Destructor + */ + BEulerInt::~BEulerInt() + { + mdp::mdp_safe_free((void **) &m_y_n); + mdp::mdp_safe_free((void **) &m_y_nm1); + mdp::mdp_safe_free((void **) &m_y_pred_n); + mdp::mdp_safe_free((void **) &m_ydot_n); + mdp::mdp_safe_free((void **) &m_ydot_nm1); + mdp::mdp_safe_free((void **) &m_resid); + mdp::mdp_safe_free((void **) &m_residWts); + mdp::mdp_safe_free((void **) &m_wksp); + mdp::mdp_safe_free((void **) &m_ewt); + mdp::mdp_safe_free((void **) &m_abstol); + mdp::mdp_safe_free((void **) &m_rowScales); + mdp::mdp_safe_free((void **) &m_colScales); + SAFE_DELETE(tdjac_ptr); + } + //================================================================================================ + void BEulerInt::setTolerances(double reltol, int n, double* abstol) { + m_itol = 1; + if (!m_abstol) { + m_abstol = mdp_alloc_dbl_1(m_neq, MDP_DBL_NOINIT); + } + if (n != m_neq) { + printf("ERROR n is wrong\n"); + exit(-1); + } + for (int i = 0; i < m_neq; i++) { + m_abstol[i] = abstol[i]; + } + m_reltol = reltol; + } + //================================================================================================ + void BEulerInt::setTolerances(double reltol, double abstol) { + m_itol = 0; + m_reltol = reltol; + m_abstols = abstol; + } + //================================================================================================ + void BEulerInt::setProblemType(int jacFormMethod) { + m_jacFormMethod = jacFormMethod; + } + //================================================================================================ + void BEulerInt::setMethodBEMT(BEulerMethodType t) { + m_method = t; + } + //================================================================================================ + void BEulerInt::setMaxStep(doublereal hmax) { + m_hmax = hmax; + } + //================================================================================================ + void BEulerInt::setMaxNumTimeSteps(int maxNumTimeSteps) { + m_max_time_step_attempts = maxNumTimeSteps; + } + //================================================================================================ + void BEulerInt::setNumInitialConstantDeltaTSteps(int num) { + m_numInitialConstantDeltaTSteps = num; + } + //================================================================================================ + /* + * + * setPrintSolnOptins(): + * + * This routine controls when the solution is printed + * + * @param printStepInterval If greater than 0, then the + * soln is printed every printStepInterval + * steps. + * + * @param printNumberToTout The solution is printed at + * regular invervals a total of + * "printNumberToTout" times. + * + * @param printSolnFirstSteps The solution is printed out + * the first "printSolnFirstSteps" + * steps. After these steps the other + * parameters determine the printing. + * default = 0 + * + * @param dumpJacobians Dump jacobians to disk. + * + * default = false + * + */ + void BEulerInt::setPrintSolnOptions(int printSolnStepInterval, + int printSolnNumberToTout, + int printSolnFirstSteps, + bool dumpJacobians) + { + m_printSolnStepInterval = printSolnStepInterval; + m_printSolnNumberToTout = printSolnNumberToTout; + m_printSolnFirstSteps = printSolnFirstSteps; + m_dumpJacobians = dumpJacobians; + } + //================================================================================================ + void BEulerInt::setIterator(IterType t) { + m_iter = t; + } + //================================================================================================ + /* + * + * setNonLinOptions() + * + * Set the options for the nonlinear method + * + * Defaults are set in the .h file. These are the defaults: + * min_newt_its = 0 + * matrixConditioning = false + * colScaling = false + * rowScaling = true + */ + void BEulerInt::setNonLinOptions(int min_newt_its, bool matrixConditioning, + bool colScaling, bool rowScaling) + { + m_min_newt_its = min_newt_its; + m_matrixConditioning = matrixConditioning; + m_colScaling = colScaling; + m_rowScaling = rowScaling; + if (m_colScaling) { + if (!m_colScales) { + m_colScales = mdp_alloc_dbl_1(m_neq, 1.0); + } + } + if (m_rowScaling) { + if (!m_rowScales) { + m_rowScales = mdp_alloc_dbl_1(m_neq, 1.0); + } + } + } + //================================================================================================ + /* + * + * setInitialTimeStep(): + * + * Set the initial time step. Right now, we set the + * time step by setting delta_t_np1. + */ + void BEulerInt::setInitialTimeStep(double deltaT) + { + delta_t_np1 = deltaT; + } + //================================================================================================ + /* + * setPrintFlag(): + * + */ + void BEulerInt::setPrintFlag(int print_flag) + { + m_print_flag = print_flag; + } + //================================================================================================ + /* + * + * initialize(): + * + * Find the initial conditions for y and ydot. + */ + void BEulerInt::initializeRJE(double t0, ResidJacEval &func) + { + m_neq = func.nEquations(); + m_t0 = t0; + internalMalloc(); + + /* + * Get the initial conditions. + */ + func.getInitialConditions(m_t0, m_y_n, m_ydot_n); + + // Store a pointer to the residual routine in the object + m_func = &func; + + /* + * Initialize the various time counters in the object + */ + time_n = t0; + time_nm1 = time_n; + time_nm2 = time_nm1; + delta_t_n = 0.0; + delta_t_nm1 = 0.0; + } + //================================================================================================ + /* + * + * reinitialize(): + * + */ + void BEulerInt::reinitializeRJE(double t0, ResidJacEval& func) + { + m_neq = func.nEquations(); + m_t0 = t0; + internalMalloc(); + /* + * At the initial time, get the initial conditions and time and store + * them into internal storage in the object, my[]. + */ + m_t0 = t0; + func.getInitialConditions(m_t0, m_y_n, m_ydot_n); + /** + * Set up the internal weights that are used for testing convergence + */ + setSolnWeights(); + + // Store a pointer to the function + m_func = &func; + + } + //================================================================================================ + /* + * + * getPrintTime(): + * + */ + double BEulerInt::getPrintTime(double time_current) + { + double tnext; + if (m_printSolnNumberToTout > 0) { + double dt = (m_time_final - m_t0) / m_printSolnNumberToTout; + for (int i = 0; i <= m_printSolnNumberToTout; i++) { + tnext = m_t0 + dt * i; + if (tnext >= time_current) return tnext; + } + } + return 1.0E300; + } + //================================================================================================ + /* + * nEvals(): + * + * Return the total number of function evaluations + */ + int BEulerInt::nEvals() const + { + return m_nfe; + } + //================================================================================================ + /* + * + * internalMalloc(): + * + * Internal routine that sets up the fixed length storage based on + * the size of the problem to solve. + */ + void BEulerInt::internalMalloc() + { + mdp_realloc_dbl_1(&m_ewt, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_y_n, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_y_nm1, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_y_pred_n, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_ydot_n, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_ydot_nm1, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_resid, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_residWts, m_neq, 0, 0.0); + mdp_realloc_dbl_1(&m_wksp, m_neq, 0, 0.0); + if (m_rowScaling) { + mdp_realloc_dbl_1(&m_rowScales, m_neq, 0, 1.0); + } + if (m_colScaling) { + mdp_realloc_dbl_1(&m_colScales, m_neq, 0, 1.0); + } + tdjac_ptr = new SquareMatrix(m_neq); + } + //================================================================================================ + /* + * setSolnWeights(): + * + * Set the solution weights + * This is a very important routine as it affects quite a few + * operations involving convergence. + * + */ + void BEulerInt::setSolnWeights() + { + int i; + if (m_itol == 1) { + /* + * Adjust the atol vector if we are using vector + * atol conditions. + */ + // m_func->adjustAtol(m_abstol); + + for (i = 0; i < m_neq; i++) { + m_ewt[i] = m_abstol[i] + m_reltol * 0.5 * + (fabs(m_y_n[i]) + fabs(m_y_pred_n[i])); + } + } else { + for (i = 0; i < m_neq; i++) { + m_ewt[i] = m_abstols + m_reltol * 0.5 * + (fabs(m_y_n[i]) + fabs(m_y_pred_n[i])); + } + } + } + //================================================================================================ + /* + * + * setColumnScales(): + * + * Set the column scaling vector at the current time + */ + void BEulerInt::setColumnScales() + { + m_func->calcSolnScales(time_n, m_y_n, m_y_nm1, m_colScales); + } + //================================================================================================ + /* + * computeResidWts(): + * + * We compute residual weights here, which we define as the L_0 norm + * of the Jacobian Matrix, weighted by the solution weights. + * This is the proper way to guage the magnitude of residuals. However, + * it does need the evaluation of the jacobian, and the implementation + * below is slow, but doesn't take up much memory. + * + * Here a small weighting indicates that the change in solution is + * very sensitive to that equation. + */ + void BEulerInt::computeResidWts(GeneralMatrix &jac) + { + int i, j; + double *data = &(*(jac.begin())); + double value; + for (i = 0; i < m_neq; i++) { + m_residWts[i] = fabs(data[i] * m_ewt[0]); + for (j = 1; j < m_neq; j++) { + value = fabs(data[j*m_neq + i] * m_ewt[j]); + m_residWts[i] = MAX(m_residWts[i], value); + } + } + } + //================================================================================================ + /* + * filterNewStep(): + * + * void BEulerInt:: + * + */ + double BEulerInt::filterNewStep(double timeCurrent, double *y_current, double *ydot_current) { + return 0.0; + } + //================================================================================================== + static void print_line(const char *str, int n) + { + for (int i = 0; i < n; i++) { + printf("%s", str); + } + printf("\n"); + } + //================================================================================================== + /* + * Print out for relevant time step information + */ + static void print_time_step1(int order, int n_time_step, double time, + double delta_t_n, double delta_t_nm1, + bool step_failed, int num_failures) + { + const char *string = 0; + if (order == 0) string = "Backward Euler"; + else if (order == 1) string = "Forward/Backward Euler"; + else if (order == 2) string = "Adams-Bashforth/TR"; + printf("\n"); print_line("=", 80); + printf("\nStart of Time Step: %5d Time_n = %9.5g Time_nm1 = %9.5g\n", + n_time_step, time, time - delta_t_n); + printf("\tIntegration method = %s\n", string); + if (step_failed) + printf("\tPreviously attempted step was a failure\n"); + if (delta_t_n > delta_t_nm1) + string = "(Increased from previous iteration)"; + else if (delta_t_n < delta_t_nm1) + string = "(Decreased from previous iteration)"; + else { + string = "(same as previous iteration)"; + } + printf("\tdelta_t_n = %8.5e %s", delta_t_n, string); + if (num_failures > 0) + printf("\t(Bad_History Failure Counter = %d)", num_failures); + printf("\n\tdelta_t_nm1 = %8.5e\n", delta_t_nm1); + } + //================================================================================================ + /* + * Print out for relevant time step information + */ + static void print_time_step2(int time_step_num, int order, + double time, double time_error_factor, + double delta_t_n, double delta_t_np1) + { + printf("\tTime Step Number %5d was a success: time = %10g\n", time_step_num, + time); + printf("\t\tEstimated Error\n"); + printf("\t\t-------------------- = %8.5e\n", time_error_factor); + printf("\t\tTolerated Error\n\n"); + printf("\t- Recommended next delta_t (not counting history) = %g\n", + delta_t_np1); + printf("\n"); print_line("=", 80); printf("\n"); + } + //================================================================================================ + /* + * Print Out descriptive information on why the current step failed + */ + static void print_time_fail(bool convFailure, int time_step_num, + double time, double delta_t_n, + double delta_t_np1, double time_error_factor) + { + printf("\n"); print_line("=", 80); + if (convFailure) { + printf("\tTime Step Number %5d experienced a convergence " + "failure\n", time_step_num); + printf("\tin the non-linear or linear solver\n"); + printf("\t\tValue of time at failed step = %g\n", time); + printf("\t\tdelta_t of the failed step = %g\n", + delta_t_n); + printf("\t\tSuggested value of delta_t to try next = %g\n", + delta_t_np1); + } else { + printf("\tTime Step Number %5d experienced a truncation error " + "failure!\n", time_step_num); + printf("\t\tValue of time at failed step = %g\n", time); + printf("\t\tdelta_t of the failed step = %g\n", + delta_t_n); + printf("\t\tSuggested value of delta_t to try next = %g\n", + delta_t_np1); + printf("\t\tCalculated truncation error factor = %g\n", + time_error_factor); + } + printf("\n"); print_line("=", 80); + } + //================================================================================================ + /* + * Print out the final results and counters + */ + static void print_final(double time, int step_failed, + int time_step_num, int num_newt_its, + int total_linear_solves, int numConvFails, + int numTruncFails, int nfe, int nJacEval) + { + printf("\n"); print_line("=", 80); + printf("TIME INTEGRATION ROUTINE HAS FINISHED: "); + if (step_failed) + printf(" IT WAS A FAILURE\n"); + else + printf(" IT WAS A SUCCESS\n"); + printf("\tEnding time = %g\n", time); + printf("\tNumber of time steps = %d\n", time_step_num); + printf("\tNumber of newt its = %d\n", num_newt_its); + printf("\tNumber of linear solves = %d\n", total_linear_solves); + printf("\tNumber of convergence failures= %d\n", numConvFails); + printf("\tNumber of TimeTruncErr fails = %d\n", numTruncFails); + printf("\tNumber of Function evals = %d\n", nfe); + printf("\tNumber of Jacobian evals/solvs= %d\n", nJacEval); + printf("\n"); print_line("=", 80); + } + //================================================================================================ + /* + * Header info for one line comment about a time step + */ + static void print_lvl1_Header(int nTimes) { + printf("\n"); + if (nTimes) { + print_line("-", 80); + } + printf("time Time Time Time "); + if (nTimes == 0) { + printf(" START"); + } else { + printf(" (continued)"); + } + printf("\n"); + + printf("step (sec) step Newt Aztc bktr trunc "); + printf("\n"); + + printf(" No. Rslt size Its Its stps error |"); + printf(" comment"); + printf("\n"); + print_line("-", 80); + } + //================================================================================================ + /* + * One line entry about time step + * rslt -> 4 letter code + */ + static void print_lvl1_summary( + int time_step_num, double time, const char *rslt, double delta_t_n, + int newt_its, int aztec_its, int bktr_stps, double time_error_factor, + const char *comment) { + printf("%6d %11.6g %4s %10.4g %4d %4d %4d %11.4g", + time_step_num, time, rslt, delta_t_n, newt_its, aztec_its, + bktr_stps, time_error_factor); + if (comment) printf(" | %s", comment); + printf("\n"); + } + //================================================================================================ + /* + * subtractRD(): + * This routine subtracts 2 numbers. If the difference is less + * than 1.0E-14 times the magnitude of the smallest number, + * then diff returns an exact zero. + * It also returns an exact zero if the difference is less than + * 1.0E-300. + * + * returns: a - b + * + * This routine is used in numerical differencing schemes in order + * to avoid roundoff errors resulting in creating Jacobian terms. + * Note: This is a slow routine. However, jacobian errors may cause + * loss of convergence. Therefore, in practice this routine + * has proved cost-effective. + */ + double subtractRD(double a, double b) { + double diff = a - b; + double d = MIN(fabs(a), fabs(b)); + d *= 1.0E-14; + double ad = fabs(diff); + if (ad < 1.0E-300) { + diff = 0.0; + } + if (ad < d) { + diff = 0.0; + } + return diff; + } + //================================================================================================ + /* + * + * Function called by BEuler to evaluate the Jacobian matrix and the + * current residual at the current time step. + * @param N = The size of the equation system + * @param J = Jacobian matrix to be filled in + * @param f = Right hand side. This routine returns the current + * value of the rhs (output), so that it does + * not have to be computed again. + * + */ + void BEulerInt::beuler_jac(GeneralMatrix &J, double * const f, + double time_curr, double CJ, + double * const y, + double * const ydot, + int num_newt_its) + { + int i, j; + double* col_j; + double ysave, ydotsave, dy; + /** + * Clear the factor flag + */ + J.clearFactorFlag(); + + + if (m_jacFormMethod & BEULER_JAC_ANAL) { + /******************************************************************** + * Call the function to get a jacobian. + */ + m_func->evalJacobian(time_curr, delta_t_n, CJ, y, ydot, J, f); +#ifdef DEBUG_HKM + //double dddd = J(89, 89); + //checkFinite(dddd); +#endif + m_nJacEval++; + m_nfe++; + } else { + /******************************************************************* + * Generic algorithm to calculate a numerical Jacobian + */ + /* + * Calculate the current value of the rhs given the + * current conditions. + */ + + m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); + m_nfe++; + m_nJacEval++; + + + /* + * Malloc a vector and call the function object to return a set of + * deltaY's that are appropriate for calculating the numerical + * derivative. + */ + double *dyVector = mdp::mdp_alloc_dbl_1(m_neq, MDP_DBL_NOINIT); + m_func->calcDeltaSolnVariables(time_curr, y, m_y_nm1, dyVector, + m_ewt); +#ifdef DEBUG_HKM + bool print_NumJac = false; + if (print_NumJac) { + FILE *idy = fopen("NumJac.csv", "w"); + fprintf(idy, "Unk m_ewt y " + "dyVector ResN\n"); + for (int iii = 0; iii < m_neq; iii++){ + fprintf(idy, " %4d %16.8e %16.8e %16.8e %16.8e \n", + iii, m_ewt[iii], y[iii], dyVector[iii], f[iii]); + } + fclose(idy); + } +#endif + /* + * Loop over the variables, formulating a numerical derivative + * of the dense matrix. + * For the delta in the variable, we will use a variety of approaches + * The original approach was to use the error tolerance amount. + * This may not be the best approach, as it could be overly large in + * some instances and overly small in others. + * We will first protect from being overly small, by using the usual + * sqrt of machine precision approach, i.e., 1.0E-7, + * to bound the lower limit of the delta. + */ + for (j = 0; j < m_neq; j++) { + + + /* + * Get a pointer into the column of the matrix + */ + + + col_j = (double *) J.ptrColumn(j); + ysave = y[j]; + dy = dyVector[j]; + //dy = fmaxx(1.0E-6 * m_ewt[j], fabs(ysave)*1.0E-7); + + y[j] = ysave + dy; + dy = y[j] - ysave; + ydotsave = ydot[j]; + ydot[j] += dy * CJ; + /* + * Call the functon + */ + + + m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, m_wksp, + JacDelta_ResidEval, j, dy); + m_nfe++; + double diff; + for (i = 0; i < m_neq; i++) { + diff = subtractRD(m_wksp[i], f[i]); + col_j[i] = diff / dy; + //col_j[i] = (m_wksp[i] - f[i])/dy; + } + + y[j] = ysave; + ydot[j] = ydotsave; + + } + /* + * Release memory + */ + mdp::mdp_safe_free((void **) &dyVector); + } + + + } + + + /* + * Function to calculate the predicted solution vector, m_y_pred_n for the + * (n+1)th time step. This routine can be used by a first order - forward + * Euler / backward Euler predictor / corrector method or for a second order + * Adams-Bashforth / Trapezoidal Rule predictor / corrector method. See Nachos + * documentation Sand86-1816 and Gresho, Lee, Sani LLNL report UCRL - 83282 for + * more information. + * + * variables: + * + * on input: + * + * N - number of unknowns + * order - indicates order of method + * = 1 -> first order forward Euler/backward Euler + * predictor/corrector + * = 2 -> second order Adams-Bashforth/Trapezoidal Rule + * predictor/corrector + * + * delta_t_n - magnitude of time step at time n (i.e., = t_n+1 - t_n) + * delta_t_nm1 - magnitude of time step at time n - 1 (i.e., = t_n - t_n-1) + * y_n[] - solution vector at time n + * y_dot_n[] - acceleration vector from the predictor at time n + * y_dot_nm1[] - acceleration vector from the predictor at time n - 1 + * + * on output: + * + * m_y_pred_n[] - predicted solution vector at time n + 1 + */ + void BEulerInt::calc_y_pred(int order) + { + int i; + double c1, c2; + switch (order) { + case 0: + case 1: + c1 = delta_t_n; + for (i = 0; i < m_neq; i++) { + m_y_pred_n[i] = m_y_n[i] + c1 * m_ydot_n[i]; + } + break; + case 2: + c1 = delta_t_n * (2.0 + delta_t_n / delta_t_nm1) / 2.0; + c2 = (delta_t_n * delta_t_n) / (delta_t_nm1 * 2.0); + for (i = 0; i < m_neq; i++) { + m_y_pred_n[i] = m_y_n[i] + c1 * m_ydot_n[i] - c2 * m_ydot_nm1[i]; + } + break; + } + + /* + * Filter the predictions. + */ + m_func->filterSolnPrediction(time_n, m_y_pred_n); + + } /* calc_y_pred */ + + + /* Function to calculate the acceleration vector ydot for the first or + * second order predictor/corrector time integrator. This routine can be + * called by a first order - forward Euler / backward Euler predictor / + * corrector or for a second order Adams - Bashforth / Trapezoidal Rule + * predictor / corrector. See Nachos documentation Sand86-1816 and Gresho, + * Lee, Sani LLNL report UCRL - 83282 for more information. + * + * variables: + * + * on input: + * + * N - number of local unknowns on the processor + * This is equal to internal plus border unknowns. + * order - indicates order of method + * = 1 -> first order forward Euler/backward Euler + * predictor/corrector + * = 2 -> second order Adams-Bashforth/Trapezoidal Rule + * predictor/corrector + * + * delta_t_n - Magnitude of the current time step at time n + * (i.e., = t_n - t_n-1) + * y_curr[] - Current Solution vector at time n + * y_nm1[] - Solution vector at time n-1 + * ydot_nm1[] - Acceleration vector at time n-1 + * + * on output: + * + * ydot_curr[] - Current acceleration vector at time n + * + * Note we use the current attribute to denote the possibility that + * y_curr[] may not be equal to m_y_n[] during the nonlinear solve + * because we may be using a look-ahead scheme. + */ + void BEulerInt:: + calc_ydot(int order, double *y_curr, double *ydot_curr) + { + int i; + double c1; + switch (order) { + case 0: + case 1: /* First order forward Euler/backward Euler */ + c1 = 1.0 / delta_t_n; + for (i = 0; i < m_neq; i++) { + ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]); + } + return; + case 2: /* Second order Adams-Bashforth / Trapezoidal Rule */ + c1 = 2.0 / delta_t_n; + for (i = 0; i < m_neq; i++) { + ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]) - m_ydot_nm1[i]; + } + return; + } + } /************* END calc_ydot () ****************************************/ + + /* This function calculates the time step truncation error estimate + * from a very simple formula based on Gresho et al. This routine can be + * called for a + * first order - forward Euler/backward Euler predictor/ corrector and + * for a + * second order Adams- Bashforth/Trapezoidal Rule predictor/corrector. See + * Nachos documentation Sand86-1816 and Gresho, Lee, LLNL report + * UCRL - 83282 + * for more information. + * + * variables: + * + * on input: + * + * abs_error - Generic absolute error tolerance + * rel_error - Generic realtive error tolerance + * x_coor[] - Solution vector from the implicit corrector + * x_pred_n[] - Solution vector from the explicit predictor + * + * on output: + * + * delta_t_n - Magnitude of next time step at time t_n+1 + * delta_t_nm1 - Magnitude of previous time step at time t_n + */ + double BEulerInt::time_error_norm() + { + int i; + double rel_norm, error; +#ifdef DEBUG_HKM +#define NUM_ENTRIES 5 + if (m_print_flag > 2) { + int imax[NUM_ENTRIES], j, jnum; + double dmax; + bool used; + printf("\t\ttime step truncation error contributors:\n"); + printf("\t\t I entry actual predicted " + " weight ydot\n"); + printf("\t\t"); print_line("-", 70); + for (j = 0; j < NUM_ENTRIES; j++) imax[j] = -1; + for (jnum = 0; jnum < NUM_ENTRIES; jnum++) { + dmax = -1.0; + for (i = 0; i < m_neq; i++) { + used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = (m_y_n[i] - m_y_pred_n[i]) / m_ewt[i]; + rel_norm = sqrt(error * error); + if (rel_norm > dmax) { + imax[jnum] = i; + dmax = rel_norm; + } + } + } + if (imax[jnum] >= 0) { + i = imax[jnum]; + printf("\t\t%4d %12.4e %12.4e %12.4e %12.4e %12.4e\n", + i, dmax, m_y_n[i], m_y_pred_n[i], m_ewt[i], m_ydot_n[i]); + } + } + printf("\t\t"); print_line("-", 70); + } +#endif + rel_norm = 0.0; + for (i = 0; i < m_neq; i++) { + error = (m_y_n[i] - m_y_pred_n[i]) / m_ewt[i]; + rel_norm += (error * error); + } + rel_norm = sqrt(rel_norm / m_neq); + return rel_norm; + } + + /************************************************************************* + * Time step control function for the selection of the time step size based on + * a desired accuracy of time integration and on an estimate of the relative + * error of the time integration process. This routine can be called for a + * first order - forward Euler/backward Euler predictor/ corrector and for a + * second order Adams- Bashforth/Trapezoidal Rule predictor/corrector. See + * Nachos documentation Sand86-1816 and Gresho, Lee, Sani LLNL report UCRL - + * 83282 for more information. + * + * variables: + * + * on input: + * + * order - indicates order of method + * = 1 -> first order forward Euler/backward Euler + * predictor/corrector + * = 2 -> second order forward Adams-Bashforth/Trapezoidal + * rule predictor/corrector + * + * delta_t_n - Magnitude of time step at time t_n + * delta_t_nm1 - Magnitude of time step at time t_n-1 + * rel_error - Generic realtive error tolerance + * time_error_factor - Estimated value of the time step truncation error + * factor. This value is a ratio of the computed + * error norms. The premultiplying constants + * and the power are not yet applied to normalize the + * predictor/corrector ratio. (see output value) + * + * on output: + * + * return - delta_t for the next time step + * If delta_t is negative, then the current time step is + * rejected because the time-step truncation error is + * too large. The return value will contain the negative + * of the recommended next time step. + * + * time_error_factor - This output value is normalized so that + * values greater than one indicate the current time + * integration error is greater than the user + * specified magnitude. + */ + double BEulerInt::time_step_control(int order, double time_error_factor) + { + double factor = 0.0, power = 0.0, delta_t; + const char *yo = "time_step_control"; + + /* + * Special case time_error_factor so that zeroes don't cause a problem. + */ + time_error_factor = MAX(1.0E-50, time_error_factor); + + /* + * Calculate the factor for the change in magnitude of time step. + */ + switch (order) { + case 1: + factor = 1.0/(2.0 *(time_error_factor)); + power = 0.5; + break; + case 2: + factor = 1.0/(3.0 * (1.0 + delta_t_nm1 / delta_t_n) + * (time_error_factor)); + power = 0.3333333333333333; + } + factor = pow(factor, power); + if (factor < 0.5) { + if (m_print_flag > 1) { + printf("\t%s: WARNING - Current time step will be chucked\n", yo); + printf("\t\tdue to a time step truncation error failure.\n"); + } + delta_t = - 0.5 * delta_t_n; + } else { + factor = MIN(factor, 1.5); + delta_t = factor * delta_t_n; + } + return delta_t; + } /************ END of time_step_control()********************************/ + //================================================================================================ + /************************************************************************** + * + * integrate(): + * + * defaults are located in the .h file. They are as follows: + * time_init = 0.0 + */ + double BEulerInt::integrateRJE(double tout, double time_init) + { + double time_current; + bool weAreNotFinished = true; + m_time_final = tout; + int flag = SUCCESS; + /** + * Initialize the time step number to zero. step will increment so that + * the first time step is number 1 + */ + m_time_step_num = 0; + + + /* + * Do the integration a step at a time + */ + int istep = 0; + int printStep = 0; + bool doPrintSoln = false; + time_current = time_init; + time_n = time_init; + time_nm1 = time_init; + time_nm2 = time_init; + m_func->evalTimeTrackingEqns(time_current, 0.0, m_y_n, m_ydot_n); + double print_time = getPrintTime(time_current); + if (print_time == time_current) { + m_func->writeSolution(4, time_current, delta_t_n, + istep, m_y_n, m_ydot_n); + } + /* + * We print out column headers here for the case of + */ + if (m_print_flag == 1) { + print_lvl1_Header(0); + } + /* + * Call a different user routine at the end of each step, + * that will probably print to a file. + */ + m_func->user_out2(0, time_current, 0.0, m_y_n, m_ydot_n); + + do { + + print_time = getPrintTime(time_current); + if (print_time >= tout) print_time = tout; + + /************************************************************ + * Step the solution + */ + time_current = step(tout); + istep++; + printStep++; + /***********************************************************/ + if (time_current < 0.0) { + if (time_current == -1234.) { + time_current = 0.0; + } else { + time_current = -time_current; + } + flag = FAILURE; + } + + if (flag != FAILURE) { + bool retn = + m_func->evalStoppingCritera(time_current, delta_t_n, + m_y_n, m_ydot_n); + if (retn) { + weAreNotFinished = false; + doPrintSoln = true; + } + } + + /* + * determine conditional printing of soln + */ + if (time_current >= print_time) { + doPrintSoln = true; + } + if (m_printSolnStepInterval == printStep) { + doPrintSoln = true; + } + if (m_printSolnFirstSteps > istep) { + doPrintSoln = true; + } + + /* + * Evaluate time integrated quantities that are calculated at the + * end of every successful time step. + */ + if (flag != FAILURE) { + m_func->evalTimeTrackingEqns(time_current, delta_t_n, + m_y_n, m_ydot_n); + } + + /* + * Call the printout routine. + */ + if (doPrintSoln) { + m_func->writeSolution(1, time_current, delta_t_n, + istep, m_y_n, m_ydot_n); + printStep = 0; + doPrintSoln = false; + if (m_print_flag == 1) { + print_lvl1_Header(1); + } + } + /* + * Call a different user routine at the end of each step, + * that will probably print to a file. + */ + if (flag == FAILURE) { + m_func->user_out2(-1, time_current, delta_t_n, m_y_n, m_ydot_n); + } else { + m_func->user_out2(1, time_current, delta_t_n, m_y_n, m_ydot_n); + } + + } while (time_current < tout && + m_time_step_attempts < m_max_time_step_attempts && + flag == SUCCESS && weAreNotFinished); + + /* + * Check current time against the max solution time. + */ + if (time_current >= tout) { + printf("Simulation completed time integration in %d time steps\n", + m_time_step_num); + printf("Final Time: %e\n\n", time_current); + } else if (m_time_step_attempts >= m_max_time_step_attempts) { + printf("Simulation ran into time step attempt limit in" + "%d time steps\n", + m_time_step_num); + printf("Final Time: %e\n\n", time_current); + } else if (flag == FAILURE) { + printf("ERROR: time stepper failed at time = %g\n", time_current); + } + + /* + * Print out the final results and counters. + */ + print_final(time_n, flag, m_time_step_num, m_numTotalNewtIts, + m_numTotalLinearSolves, m_numTotalConvFails, + m_numTotalTruncFails, m_nfe, m_nJacEval); + + /* + * Call a different user routine at the end of each step, + * that will probably print to a file. + */ + m_func->user_out2(2, time_current, delta_t_n, m_y_n, m_ydot_n); + + + if (flag != SUCCESS) + throw BEulerErr(" BEuler error encountered."); + return time_current; + } + + /************************************************************************** + * + * step(): + * + * This routine advances the calculations one step using a predictor + * corrector approach. We use an implicit algorithm here. + * + */ + double BEulerInt::step(double t_max) + { + double CJ; + int one = 1; + bool step_failed = false; + bool giveUp = false; + bool convFailure = false; + const char *rslt; + double time_error_factor = 0.0; + double normFilter = 0.0; + int numTSFailures = 0; + int bktr_stps = 0; + int nonlinearloglevel = m_print_flag; + int num_newt_its = 0; + int aztec_its = 0; + string comment; + /* + * Increment the time counter - May have to be taken back, + * if time step is found to be faulty. + */ + m_time_step_num++; + + /** + * Loop here until we achieve a successful step or we set the giveUp + * flag indicating that repeated errors have occurred. + */ + do { + m_time_step_attempts++; + comment.clear(); + + /* + * Possibly adjust the delta_t_n value for this time step from the + * recommended delta_t_np1 value determined in the previous step + * due to maximum time step constraints or other occurences, + * known to happen at a given time. + */ + if ((time_n + delta_t_np1) >= t_max) { + delta_t_np1 =t_max - time_n; + } + + if (delta_t_np1 >= delta_t_max) { + delta_t_np1 = delta_t_max; + } + + /* + * Increment the delta_t counters and the time for the current + * time step. + */ + + delta_t_nm2 = delta_t_nm1; + delta_t_nm1 = delta_t_n; + delta_t_n = delta_t_np1; + time_n += delta_t_n; + + /* + * Determine the integration order of the current step. + * + * Special case for start-up of time integration procedure + * First time step = Do a predictor step as we + * have recently added an initial + * ydot input option. And, setting ydot=0 + * is equivalent to not doing a + * predictor step. + * Second step = If 2nd order method, do a first order + * step for this time-step, only. + * + * If 2nd order method with a constant time step, the + * first and second steps are 1/10 the specified step, and + * the third step is 8/10 the specified step. This reduces + * the error asociated with using lower order + * integration on the first two steps. (RCS 11-6-97) + * + * If the previous time step failed for one reason or another, + * do a linear step. It's more robust. + */ + if (m_time_step_num == 1) { + m_order = 1; /* Backward Euler */ + } + else if (m_time_step_num == 2) { + m_order = 1; /* Forward/Backward Euler */ + } + else if (step_failed) { + m_order = 1; /* Forward/Backward Euler */ + } + else if (m_time_step_num > 2) { + m_order = 1; /* Specified + Predictor/Corrector + - not implemented */ + } + + /* + * Print out an initial statement about the step. + */ + if (m_print_flag > 1) { + print_time_step1(m_order, m_time_step_num, time_n, delta_t_n, + delta_t_nm1, step_failed, m_failure_counter); + } + + /* + * Calculate the predicted solution, m_y_pred_n, for the current + * time step. + */ + calc_y_pred(m_order); + + /* + * HKM - Commented this out. I may need it for particles later. + * If Solution bounds checking is turned on, we need to crop the + * predicted solution to make sure bounds are enforced + * + * + * cropNorm = 0.0; + * if (Cur_Realm->Realm_Nonlinear.Constraint_Backtracking_Flag == + * Constraint_Backtrack_Enable) { + * cropNorm = cropPredictor(mesh, x_pred_n, abs_time_error, + * m_reltol); + */ + + /* + * Save the old solution, before overwriting with the new solution + * - use + */ + mdp_copy_dbl_1(m_y_nm1, m_y_n, m_neq); + + /* + * Use the predicted value as the initial guess for the corrector + * loop, for + * every step other than the first step. + */ + if (m_order > 0) { + mdp_copy_dbl_1(m_y_n, m_y_pred_n, m_neq); + } + + /* + * Save the old time derivative, if necessary, before it is + * overwritten. + * This overwrites ydot_nm1, losing information from the previous time + * step. + */ + mdp_copy_dbl_1(m_ydot_nm1, m_ydot_n, m_neq); + + /* + * Calculate the new time derivative, ydot_n, that is consistent + * with the + * initial guess for the corrected solution vector. + * + */ + calc_ydot(m_order, m_y_n, m_ydot_n); + + /* + * Calculate CJ, the coefficient for the jacobian corresponding to the + * derivative of the residual wrt to the acceleration vector. + */ + if (m_order < 2) CJ = 1.0 / delta_t_n; + else CJ = 2.0 / delta_t_n; + + /* + * Calculate a new Solution Error Weighting vector + */ + setSolnWeights(); + + /* + * Solve the system of equations at the current time step. + * Note - x_corr_n and x_dot_n are considered to be updated, + * on return from this solution. + */ + int ierror = solve_nonlinear_problem(m_y_n, m_ydot_n, + CJ, time_n, *tdjac_ptr, num_newt_its, + aztec_its, bktr_stps, + nonlinearloglevel); + /* + * Set the appropriate flags if a convergence failure is detected. + */ + if (ierror < 0) { /* Step failed */ + convFailure = true; + step_failed = true; + rslt = "fail"; + m_numTotalConvFails++; + m_failure_counter +=3; + if (m_print_flag > 1) { + printf("\tStep is Rejected, nonlinear problem didn't converge," + "ierror = %d\n", ierror); + } + } + else { /* Step succeeded */ + convFailure = false; + step_failed = false; + rslt = "done"; + + /* + * Apply a filter to a new successful step + */ + normFilter = filterNewStep(time_n, m_y_n, m_ydot_n); + if (normFilter > 1.0) { + convFailure = true; + step_failed = true; + rslt = "filt"; + if (m_print_flag > 1) { + printf("\tStep is Rejected, too large filter adjustment = %g\n", + normFilter); + } + } else if (normFilter > 0.0) { + if (normFilter > 0.3) { + if (m_print_flag > 1) { + printf("\tStep was filtered, norm = %g, next " + "time step adjusted\n", normFilter); + } + } else { + if (m_print_flag > 1) { + printf("\tStep was filtered, norm = %g\n", normFilter); + } + } + } + } + + /* + * Calculate the time step truncation error for the current step. + */ + if (!step_failed) { + time_error_factor = time_error_norm(); + } else { + time_error_factor = 1000.; + } + + /* + * Dynamic time step control- delta_t_n, delta_t_nm1 are set here. + */ + if (step_failed) { + /* + * For convergence failures, decrease the step-size by a factor of + * 4 and try again. + */ + delta_t_np1 = 0.25 * delta_t_n; + } + else if (m_method == BEulerVarStep) { + + /* + * If we are doing a predictor/corrector method, and we are + * past a certain number of time steps given by the input file + * then either correct the DeltaT for the next time step or + * + */ + if ((m_order > 0) && + (m_time_step_num > m_numInitialConstantDeltaTSteps) ) { + delta_t_np1 = time_step_control(m_order, time_error_factor); + if (normFilter > 0.1) { + if (delta_t_np1 > delta_t_n) delta_t_np1 = delta_t_n; + } + + /* + * Check for Current time step failing due to violation of + * time step + * truncation bounds. + */ + if (delta_t_np1 < 0.0) { + m_numTotalTruncFails++; + step_failed = true; + delta_t_np1 = -delta_t_np1; + m_failure_counter += 2; + comment += "TIME TRUNC FAILURE"; + rslt = "TRNC"; + } + + /* + * Prevent churning of the time step by not increasing the + * time step, + * if the recent "History" of the time step behavior is still bad + */ + else if (m_failure_counter > 0) { + delta_t_np1 = MIN(delta_t_np1, delta_t_n); + } + } else { + delta_t_np1 = delta_t_n; + } + + /* Decrease time step if a lot of Newton Iterations are + * taken. + * The idea being if more or less Newton iteration are taken + * than the target number of iterations, then adjust the time + * step downwards so that the target number of iterations or lower + * is achieved. This + * should prevent step failure by too many Newton iterations because + * the time step becomes too large. CCO + * hkm -> put in num_new_its min of 3 because the time step + * was being altered even when num_newt_its == 1 + */ + int max_Newton_steps = 10000; + int target_num_iter = 5; + if (num_newt_its > 3000 && !step_failed) { + if (max_Newton_steps != target_num_iter){ + double iter_diff = num_newt_its - target_num_iter; + double iter_adjust_zone = max_Newton_steps - target_num_iter; + double target_time_step = delta_t_n + *(1.0 - iter_diff*fabs(iter_diff)/ + ((2.0*iter_adjust_zone*iter_adjust_zone))); + target_time_step = MAX(0.5*delta_t_n, target_time_step); + if (target_time_step < delta_t_np1) { + printf("\tNext time step will be decreased from %g to %g" + " because of new its restraint\n", + delta_t_np1, target_time_step); + delta_t_np1 = target_time_step; + } + } + } + + + } + + /* + * The final loop in the time stepping algorithm depends on whether the + * current step was a success or not. + */ + if (step_failed) { + /* + * Increment the counter indicating the number of consecutive + * failures + */ + numTSFailures++; + /* + * Print out a statement about the failure of the time step. + */ + if (m_print_flag > 1) { + print_time_fail(convFailure, m_time_step_num, time_n, delta_t_n, + delta_t_np1, time_error_factor); + } else if (m_print_flag == 1) { + print_lvl1_summary(m_time_step_num, time_n, rslt, delta_t_n, + num_newt_its, aztec_its, bktr_stps, + time_error_factor, + comment.c_str()); + } + + /* + * Change time step counters back to the previous step before + * the failed + * time step occurred. + */ + time_n -= delta_t_n; + delta_t_n = delta_t_nm1; + delta_t_nm1 = delta_t_nm2; + + /* + * Replace old solution vector and time derivative solution vector. + */ + dcopy_(&m_neq, m_y_nm1, &one, m_y_n, &one); + dcopy_(&m_neq, m_ydot_nm1, &one, m_ydot_n, &one); + /* + * Decide whether to bail on the whole loop + */ + if (numTSFailures > 35) giveUp = true; + } + + /* + * Do processing for a successful step. + */ + else { + + /* + * Decrement the number of consequative failure counter. + */ + m_failure_counter = MAX(0, m_failure_counter-1); + + /* + * Print out final results of a successfull time step. + */ + if (m_print_flag > 1) { + print_time_step2(m_time_step_num, m_order, time_n, time_error_factor, + delta_t_n, delta_t_np1); + } + else if (m_print_flag == 1) { + print_lvl1_summary(m_time_step_num, time_n, " ", delta_t_n, + num_newt_its, aztec_its, bktr_stps, time_error_factor, + comment.c_str()); + } + + /* + * Output information at the end of every successful time step, if + * requested. + * + * fill in + */ + + + } + } while (step_failed && !giveUp); + + /* + * Send back the overall result of the time step. + */ + if (step_failed) { + if (time_n == 0.0) return -1234.0; + return -time_n; + } + return time_n; + } + + + + //----------------------------------------------------------- + // Constants + //----------------------------------------------------------- + + const double DampFactor = 4; + const int NDAMP = 10; + + + //----------------------------------------------------------- + // MultiNewton methods + //----------------------------------------------------------- + /** + * L2 Norm of a delta in the solution + * + * The second argument has a default of false. However, + * if true, then a table of the largest values is printed + * out to standard output. + */ + double BEulerInt::soln_error_norm(const double * const delta_y, + bool printLargest) + { + int i; + double sum_norm = 0.0, error; + for (i = 0; i < m_neq; i++) { + error = delta_y[i] / m_ewt[i]; + sum_norm += (error * error); + } + sum_norm = sqrt(sum_norm / m_neq); + if (printLargest) { + const int num_entries = 8; + double dmax1, normContrib; + int j; + int *imax = mdp_alloc_int_1(num_entries, -1); + printf("\t\tPrintout of Largest Contributors to norm " + "of value (%g)\n", sum_norm); + printf("\t\t I ysoln deltaY weightY " + "Error_Norm**2\n"); + printf("\t\t "); print_line("-", 80); + for (int jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < m_neq; i++) { + bool used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = delta_y[i] / m_ewt[i]; + normContrib = sqrt(error * error); + if (normContrib > dmax1) { + imax[jnum] = i; + dmax1 = normContrib; + } + } + } + i = imax[jnum]; + if (i >= 0) { + printf("\t\t %4d %12.4e %12.4e %12.4e %12.4e\n", + i, m_y_n[i], delta_y[i], m_ewt[i], dmax1); + } + } + printf("\t\t "); print_line("-", 80); + mdp_safe_free((void **) &imax); + } + return sum_norm; + } +#ifdef DEBUG_HKM_JAC + SquareMatrix jacBack(); +#endif + /************************************************************************** + * + * doNewtonSolve(): + * + * Compute the undamped Newton step. The residual function is + * evaluated at the current time, t_n, at the current values of the + * solution vector, m_y_n, and the solution time derivative, m_ydot_n, + * but the Jacobian is not recomputed. + */ + void BEulerInt::doNewtonSolve(double time_curr, double *y_curr, + double *ydot_curr, double* delta_y, + GeneralMatrix& jac, int loglevel) + { + int irow, jcol; + + m_func->evalResidNJ(time_curr, delta_t_n, y_curr, + ydot_curr, delta_y, Base_ResidEval); + m_nfe++; + int sz = m_func->nEquations(); + for (int n = 0; n < sz; n++) { + delta_y[n] = -delta_y[n]; + } + + + /* + * Column scaling -> We scale the columns of the Jacobian + * by the nominal important change in the solution vector + */ + if (m_colScaling) { + if (!jac.factored()) { + /* + * Go get new scales + */ + setColumnScales(); + + /* + * Scale the new Jacobian + */ + double *jptr = &(*(jac.begin())); + for (jcol = 0; jcol < m_neq; jcol++) { + for (irow = 0; irow < m_neq; irow++) { + *jptr *= m_colScales[jcol]; + jptr++; + } + } + } + } + + if (m_matrixConditioning) { + if (jac.factored()) { + m_func->matrixConditioning(0, sz, delta_y); + } else { + double *jptr = &(*(jac.begin())); + m_func->matrixConditioning(jptr, sz, delta_y); + } + } + + /* + * row sum scaling -> Note, this is an unequivical success + * at keeping the small numbers well balanced and + * nonnegative. + */ + if (m_rowScaling) { + if (! jac.factored()) { + /* + * Ok, this is ugly. jac.begin() returns an vector iterator + * to the first data location. + * Then &(*()) reverts it to a double *. + */ + double *jptr = &(*(jac.begin())); + for (irow = 0; irow < m_neq; irow++) { + m_rowScales[irow] = 0.0; + } + for (jcol = 0; jcol < m_neq; jcol++) { + for (irow = 0; irow < m_neq; irow++) { + m_rowScales[irow] += fabs(*jptr); + jptr++; + } + } + + jptr = &(*(jac.begin())); + for (jcol = 0; jcol < m_neq; jcol++) { + for (irow = 0; irow < m_neq; irow++) { + *jptr /= m_rowScales[irow]; + jptr++; + } + } + } + for (irow = 0; irow < m_neq; irow++) { + delta_y[irow] /= m_rowScales[irow]; + } + } + +#ifdef DEBUG_HKM_JAC + bool printJacContributions = false; + if (m_time_step_num > 304) { + printJacContributions = false; + } + int focusRow = 10; + int numRows = 2; + double RRow[2]; + bool freshJac = true; + RRow[0] = delta_y[focusRow]; + RRow[1] = delta_y[focusRow+1]; + double Pcutoff = 1.0E-70; + if (!jac.m_factored) { + jacBack = jac; + } else { + freshJac = false; + } +#endif + /* + * Solve the system -> This also involves inverting the + * matrix + */ + (void) jac.solve(delta_y); + + + /* + * reverse the column scaling if there was any. + */ + if (m_colScaling) { + for (irow = 0; irow < m_neq; irow++) { + delta_y[irow] *= m_colScales[irow]; + } + } + +#ifdef DEBUG_HKM_JAC + if (printJacContributions) { + for (int iNum = 0; iNum < numRows; iNum++) { + if (iNum > 0) focusRow++; + double dsum = 0.0; + vector_fp& Jdata = jacBack.data(); + double dRow = Jdata[m_neq * focusRow + focusRow]; + printf("\n Details on delta_Y for row %d \n", focusRow); + printf(" Value before = %15.5e, delta = %15.5e," + "value after = %15.5e\n", y_curr[focusRow], + delta_y[focusRow], + y_curr[focusRow] + delta_y[focusRow]); + if (!freshJac) { + printf(" Old Jacobian\n"); + } + printf(" col delta_y aij " + "contrib \n"); + printf("--------------------------------------------------" + "---------------------------------------------\n"); + printf(" Res(%d) %15.5e %15.5e %15.5e (Res = %g)\n", + focusRow, delta_y[focusRow], + dRow, RRow[iNum] / dRow, RRow[iNum]); + dsum += RRow[iNum] / dRow; + for (int ii = 0; ii < m_neq; ii++) { + if (ii != focusRow) { + double aij = Jdata[m_neq * ii + focusRow]; + double contrib = aij * delta_y[ii] * (-1.0) / dRow; + dsum += contrib; + if (fabs(contrib) > Pcutoff) { + printf("%6d %15.5e %15.5e %15.5e\n", ii, + delta_y[ii] , aij, contrib); + } + } + } + printf("--------------------------------------------------" + "---------------------------------------------\n"); + printf(" %15.5e %15.5e\n", + delta_y[focusRow], dsum); + } + } + +#endif + + m_numTotalLinearSolves++; + } + + //================================================================================================ + // Bound the Newton step while relaxing the solution + /* + * Return the factor by which the undamped Newton step 'step0' + * must be multiplied in order to keep all solution components in + * all domains between their specified lower and upper bounds. + * Other bounds may be applied here as well. + * + * Currently the bounds are hard coded into this routine: + * + * Minimum value for all variables: - 0.01 * m_ewt[i] + * Maximum value = none. + * + * Thus, this means that all solution components are expected + * to be numerical greater than zero in the limit of time step + * truncation errors going to zero. + * + * Delta bounds: The idea behind these is that the Jacobian + * couldn't possibly be representative if the + * variable is changed by a lot. (true for + * nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: + * factor of 2 + * Maximum decrease in variable in any one newton iteration: + * factor of 5 + * + * @param y Current value of the solution + * @param step0 Current raw step change in y[] + * @param loglevel Log level. This routine produces output if loglevel + * is greater than one + * + * @return Returns the damping coefficient + */ + double BEulerInt::boundStep(const double * const y, + const double * const step0, int loglevel) { + int i, i_lower = -1, i_fbounds, ifbd = 0, i_fbd = 0; + double fbound = 1.0, f_lowbounds = 1.0, f_delta_bounds = 1.0; + double ff, y_new, ff_alt; + for (i = 0; i < m_neq; i++) { + y_new = y[i] + step0[i]; + if ((y_new < (-0.01 * m_ewt[i])) && y[i] >= 0.0) { + ff = 0.9 * (y[i] / (y[i] - y_new)); + if (ff < f_lowbounds) { + f_lowbounds = ff; + i_lower = i; + } + } + /* + * Now do a delta bounds + * Increase variables by a factor of 2 only + * decrease variables by a factor of 5 only + */ + ff = 1.0; + if ((fabs(y_new) > 2.0 * fabs(y[i])) && + (fabs(y_new-y[i]) > m_ewt[i])) { + ff = fabs(y[i]/(y_new - y[i])); + ff_alt = fabs(m_ewt[i] / (y_new - y[i])); + ff = MAX(ff, ff_alt); + ifbd = 1; + } + if ((fabs(5.0 * y_new) < fabs(y[i])) && + (fabs(y_new - y[i]) > m_ewt[i])) { + ff = y[i]/(y_new-y[i]) * (1.0 - 5.0)/5.0; + ff_alt = fabs(m_ewt[i] / (y_new - y[i])); + ff = MAX(ff, ff_alt); + ifbd = 0; + } + if (ff < f_delta_bounds) { + f_delta_bounds = ff; + i_fbounds = i; + i_fbd = ifbd; + } + f_delta_bounds = MIN(f_delta_bounds, ff); + } + fbound = MIN(f_lowbounds, f_delta_bounds); + /* + * Report on any corrections + */ + if (loglevel > 1) { + if (fbound != 1.0) { + if (f_lowbounds < f_delta_bounds) { + printf("\t\tboundStep: Variable %d causing lower bounds " + "damping of %g\n", + i_lower, f_lowbounds); + } else { + if (ifbd) { + printf("\t\tboundStep: Decrease of Variable %d causing " + "delta damping of %g\n", + i_fbd, f_delta_bounds); + } else { + printf("\t\tboundStep: Increase of variable %d causing" + "delta damping of %g\n", + i_fbd, f_delta_bounds); + } + } + } + } + return fbound; + } + //================================================================================================ + /************************************************************************** + * + * dampStep(): + * + * On entry, step0 must contain an undamped Newton step for the + * solution x0. This method attempts to find a damping coefficient + * such that the next undamped step would have a norm smaller than + * that of step0. If successful, the new solution after taking the + * damped step is returned in y1, and the undamped step at y1 is + * returned in step1. + */ + int BEulerInt::dampStep(double time_curr, const double * y0, + const double *ydot0, const double* step0, + double* y1, double* ydot1, double* step1, + double& s1, GeneralMatrix & jac, + int& loglevel, bool writetitle, + int& num_backtracks) { + + + // Compute the weighted norm of the undamped step size step0 + double s0 = soln_error_norm(step0); + + // Compute the multiplier to keep all components in bounds + // A value of one indicates that there is no limitation + // on the current step size in the nonlinear method due to + // bounds constraints (either negative values of delta + // bounds constraints. + double fbound = boundStep(y0, step0, loglevel); + + // if fbound is very small, then y0 is already close to the + // boundary and step0 points out of the allowed domain. In + // this case, the Newton algorithm fails, so return an error + // condition. + if (fbound < 1.e-10) { + if (loglevel > 1) printf("\t\t\tdampStep: At limits.\n"); + return -3; + } + + //-------------------------------------------- + // Attempt damped step + //-------------------------------------------- + + // damping coefficient starts at 1.0 + double damp = 1.0; + int j, m; + double ff; + num_backtracks = 0; + for (m = 0; m < NDAMP; m++) { + + ff = fbound*damp; + + // step the solution by the damped step size + /* + * Whenever we update the solution, we must also always + * update the time derivative. + */ + for (j = 0; j < m_neq; j++) { + y1[j] = y0[j] + ff*step0[j]; + // HKM setting intermediate y's to zero was a tossup. + // slightly different, equivalent results + //#ifdef DEBUG_HKM + // y1[j] = MAX(0.0, y1[j]); + //#endif + } + calc_ydot(m_order, y1, ydot1); + + // compute the next undamped step, step1[], that would result + // if y1[] were accepted. + + doNewtonSolve(time_curr, y1, ydot1, step1, jac, loglevel); + +#ifdef DEBUG_HKM + for (j = 0; j < m_neq; j++) { + checkFinite(step1[j]); + checkFinite(y1[j]); + } +#endif + // compute the weighted norm of step1 + s1 = soln_error_norm(step1); + + // write log information + if (loglevel > 3) { + print_solnDelta_norm_contrib((const double *) step0, + "DeltaSolnTrial", + (const double *) step1, + "DeltaSolnTrialTest", + "dampNewt: Important Entries for " + "Weighted Soln Updates:", + y0, y1, ff, 5); + } + if (loglevel > 1) { + printf("\t\t\tdampNewt: s0 = %g, s1 = %g, fbound = %g," + "damp = %g\n", s0, s1, fbound, damp); + } +#ifdef DEBUG_HKM + if (loglevel > 2) { + if (s1 > 1.00000001 * s0 && s1 > 1.0E-5) { + printf("WARNING: Possible Jacobian Problem " + "-> turning on more debugging for this step!!!\n"); + print_solnDelta_norm_contrib((const double *) step0, + "DeltaSolnTrial", + (const double *) step1, + "DeltaSolnTrialTest", + "dampNewt: Important Entries for " + "Weighted Soln Updates:", + y0, y1, ff, 5); + loglevel = 4; + } + } +#endif + + // if the norm of s1 is less than the norm of s0, then + // accept this damping coefficient. Also accept it if this + // step would result in a converged solution. Otherwise, + // decrease the damping coefficient and try again. + + if (s1 < 1.0E-5 || s1 < s0) { + if (loglevel > 2) { + if (s1 > s0) { + if (s1 > 1.0) { + printf("\t\t\tdampStep: current trial step and damping" + " coefficient accepted because test step < 1\n"); + printf("\t\t\t s1 = %g, s0 = %g\n", s1, s0); + } + } + } + break; + } else { + if (loglevel > 1) { + printf("\t\t\tdampStep: current step rejected: (s1 = %g > " + "s0 = %g)", s1, s0); + if (m < (NDAMP-1)) { + printf(" Decreasing damping factor and retrying"); + } else { + printf(" Giving up!!!"); + } + printf("\n"); + } + } + num_backtracks++; + damp /= DampFactor; + } + + // If a damping coefficient was found, return 1 if the + // solution after stepping by the damped step would represent + // a converged solution, and return 0 otherwise. If no damping + // coefficient could be found, return -2. + if (m < NDAMP) { + if (s1 > 1.0) return 0; + else return 1; + } else { + if (s1 < 0.5 && (s0 < 0.5)) return 1; + if (s1 < 1.0) return 0; + return -2; + } + } + //================================================================================================ + // Solve a nonlinear system + /* + * Find the solution to F(X, xprime) = 0 by damped Newton iteration. On + * entry, y_comm[] contains an initial estimate of the solution and + * ydot_comm[] contains an estimate of the derivative. + * On successful return, y_comm[] contains the converged solution + * and ydot_comm[] contains the derivative + * + * + * @param y_comm[] Contains the input solution. On output y_comm[] contains + * the converged solution + * @param ydot_comm Contains the input derivative solution. On output y_comm[] contains + * the converged derivative solution + * @param CJ Inverse of the time step + * @param time_curr Current value of the time + * @param jac Jacobian + * @param num_newt_its number of newton iterations + * @param num_linear_solves number of linear solves + * @param num_backtracks number of backtracs + * @param loglevel Log level + */ + int BEulerInt::solve_nonlinear_problem(double * const y_comm, + double * const ydot_comm, double CJ, + double time_curr, + GeneralMatrix & jac, + int &num_newt_its, + int &num_linear_solves, + int &num_backtracks, + int loglevel) + { + bool m_residCurrent = false; + int m = 0; + bool forceNewJac = false; + double s1=1.e30; + + double * y_curr = mdp_alloc_dbl_1(m_neq, 0.0); + double * ydot_curr = mdp_alloc_dbl_1(m_neq, 0.0); + double * stp = mdp_alloc_dbl_1(m_neq, 0.0); + double * stp1 = mdp_alloc_dbl_1(m_neq, 0.0); + double * y_new = mdp_alloc_dbl_1(m_neq, 0.0); + double * ydot_new = mdp_alloc_dbl_1(m_neq, 0.0); + + mdp_copy_dbl_1(y_curr, y_comm, m_neq); + mdp_copy_dbl_1(ydot_curr, ydot_comm, m_neq); + + bool frst = true; + num_newt_its = 0; + num_linear_solves = - m_numTotalLinearSolves; + num_backtracks = 0; + int i_backtracks; + + while (1 > 0) { + + /* + * Increment Newton Solve counter + */ + m_numTotalNewtIts++; + num_newt_its++; + + + if (loglevel > 1) { + printf("\t\tSolve_Nonlinear_Problem: iteration %d:\n", + num_newt_its); + } + + // Check whether the Jacobian should be re-evaluated. + + forceNewJac = true; + + if (forceNewJac) { + if (loglevel > 1) { + printf("\t\t\tGetting a new Jacobian and solving system\n"); + } + beuler_jac(jac, m_resid, time_curr, CJ, y_curr, ydot_curr, + num_newt_its); + m_residCurrent = true; + } else { + if (loglevel > 1) { + printf("\t\t\tSolving system with old jacobian\n"); + } + m_residCurrent = false; + } + + // compute the undamped Newton step + doNewtonSolve(time_curr, y_curr, ydot_curr, stp, jac, loglevel); + + // damp the Newton step + m = dampStep(time_curr, y_curr, ydot_curr, stp, y_new, ydot_new, + stp1, s1, jac, loglevel, frst, i_backtracks); + frst = false; + num_backtracks += i_backtracks; + + /* + * Impose the minimum number of newton iterations critera + */ + if (num_newt_its < m_min_newt_its) { + if (m == 1) m = 0; + } + /* + * Impose max newton iteration + */ + if (num_newt_its > 20) { + m = -1; + if (loglevel > 1) { + printf("\t\t\tDampnewton unsuccessful (max newts exceeded) sfinal = %g\n", s1); + } + } + + if (loglevel > 1) { + if (m == 1) { + printf("\t\t\tDampNewton iteration successful, nonlin " + "converged sfinal = %g\n", s1); + } else if (m == 0) { + printf("\t\t\tDampNewton iteration successful, get new" + "direction, sfinal = %g\n", s1); + } else { + printf("\t\t\tDampnewton unsuccessful sfinal = %g\n", s1); + } + } + + // If we are converged, then let's use the best solution possible + // for an end result. We did a resolve in dampStep(). Let's update + // the solution to reflect that. + // HKM 5/16 -> Took this out, since if the last step was a + // damped step, then adding stp1[j] is undamped, and + // may lead to oscillations. It kind of defeats the + // purpose of dampStep() anyway. + // if (m == 1) { + // for (int j = 0; j < m_neq; j++) { + // y_new[j] += stp1[j]; + // HKM setting intermediate y's to zero was a tossup. + // slightly different, equivalent results + // #ifdef DEBUG_HKM + // y_new[j] = MAX(0.0, y_new[j]); + // #endif + // } + // } + + bool m_filterIntermediate = false; + if (m_filterIntermediate) { + if (m == 0) { + (void) filterNewStep(time_n, y_new, ydot_new); + } + } + // Exchange new for curr solutions + if (m == 0 || m == 1) { + mdp_copy_dbl_1(y_curr, y_new, m_neq); + calc_ydot(m_order, y_curr, ydot_curr); + } + + // convergence + if (m == 1) goto done; + + // If dampStep fails, first try a new Jacobian if an old + // one was being used. If it was a new Jacobian, then + // return -1 to signify failure. + else if (m < 0) { + goto done; + } + } + + done: + // Copy into the return vectors + mdp_copy_dbl_1(y_comm, y_curr, m_neq); + mdp_copy_dbl_1(ydot_comm, ydot_curr, m_neq); + // Increment counters + num_linear_solves += m_numTotalLinearSolves; + // Free memory + mdp_safe_free((void **) &y_curr); + mdp_safe_free((void **) &ydot_curr); + mdp_safe_free((void **) &stp); + mdp_safe_free((void **) &stp1); + mdp_safe_free((void **) &y_new); + mdp_safe_free((void **) &ydot_new); + + double time_elapsed = 0.0; + if (loglevel > 1) { + if (m == 1) { + printf("\t\tNonlinear problem solved successfully in " + "%d its, time elapsed = %g sec\n", + num_newt_its, time_elapsed); + } + } + return m; + } + //================================================================================================ + /* + * + * + */ + void BEulerInt:: + print_solnDelta_norm_contrib(const double * const solnDelta0, + const char * const s0, + const double * const solnDelta1, + const char * const s1, + const char * const title, + const double * const y0, + const double * const y1, + double damp, + int num_entries) { + int i, j, jnum; + bool used; + double dmax0, dmax1, error, rel_norm; + printf("\t\t%s currentDamp = %g\n", title, damp); + printf("\t\t I ysoln %10s ysolnTrial " + "%10s weight relSoln0 relSoln1\n", s0, s1); + int *imax = mdp_alloc_int_1(num_entries, -1); + printf("\t\t "); print_line("-", 90); + for (jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < m_neq; i++) { + used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = solnDelta0[i] / m_ewt[i]; + rel_norm = sqrt(error * error); + error = solnDelta1[i] / m_ewt[i]; + rel_norm += sqrt(error * error); + if (rel_norm > dmax1) { + imax[jnum] = i; + dmax1 = rel_norm; + } + } + } + if (imax[jnum] >= 0) { + i = imax[jnum]; + error = solnDelta0[i] / m_ewt[i]; + dmax0 = sqrt(error * error); + error = solnDelta1[i] / m_ewt[i]; + dmax1 = sqrt(error * error); + printf("\t\t %4d %12.4e %12.4e %12.4e %12.4e " + "%12.4e %12.4e %12.4e\n", + i, y0[i], solnDelta0[i], y1[i], + solnDelta1[i], m_ewt[i], dmax0, dmax1); + } + } + printf("\t\t "); print_line("-", 90); + mdp_safe_free((void **) &imax); + } + //=============================================================================================== + +} // End of namespace Cantera + diff --git a/Cantera/src/numerics/BEulerInt.h b/Cantera/src/numerics/BEulerInt.h new file mode 100644 index 000000000..3a02a1368 --- /dev/null +++ b/Cantera/src/numerics/BEulerInt.h @@ -0,0 +1,471 @@ +/** + * @file BEulerInt.h + */ + +/* $Author: hkmoffa $ + * $Date: 2009/01/27 16:50:53 $ + * $Revision: 1.19 $ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ +#ifndef CT_BEULERINT_H +#define CT_BEULERINT_H + +#include "ct_defs.h" +#include "ctlapack.h" +#include "utilities.h" +#include "ctexceptions.h" + + +#include "Integrator.h" +#include "ResidJacEval.h" + +#include "GeneralMatrix.h" +#include "NonlinearSolver.h" + +#include "mdp_allo.h" + +#ifndef MAX +# define MAX(x,y) (( (x) > (y) ) ? (x) : (y)) +#endif +#ifndef MIN +# define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) +#endif +#define OPT_SIZE 10 + +#define SUCCESS 0 +#define FAILURE 1 + +#define STEADY 0 +#define TRANSIENT 1 + +namespace Cantera { + + enum BEulerMethodType { + BEulerFixedStep, + BEulerVarStep + }; + + /** + * Exception class thrown when a BEuler error is encountered. + */ + class BEulerErr : public CanteraError { + public: + BEulerErr(std::string msg); + }; + + +#define BEULER_JAC_ANAL 2 +#define BEULER_JAC_NUM 1 + + /** + * Wrapper class for 'beuler' integrator + * We derive the class from the class Integrator + */ + class BEulerInt : public Integrator { + + public: + + //! The default constructor doesn't take an argument. + BEulerInt(); + //! Destructor + virtual ~BEulerInt(); + virtual void setTolerances(double reltol, int n, double* abstol); + virtual void setTolerances(double reltol, double abstol); + virtual void setProblemType(int probtype); + virtual void initializeRJE(double t0, ResidJacEval& func); + virtual void reinitializeRJE(double t0, ResidJacEval& func); + virtual double integrateRJE(double tout, double tinit = 0.0); + virtual doublereal step(double tout); + virtual void setSolnWeights(); + virtual double& solution(int k){ return m_y_n[k]; } + double* solution(){ return m_y_n; } + int nEquations() const { return m_neq;} + virtual int nEvals() const; + virtual void setMethodBEMT(BEulerMethodType t); + virtual void setIterator(IterType t); + virtual void setMaxStep(double hmax); + virtual void setMaxNumTimeSteps(int); + virtual void setNumInitialConstantDeltaTSteps(int); + + void print_solnDelta_norm_contrib(const double * const soln0, + const char * const s0, + const double * const soln1, + const char * const s1, + const char * const title, + const double * const y0, + const double * const y1, + double damp, + int num_entries); + + virtual void setPrintSolnOptions(int printSolnStepInterval, + int printSolnNumberToTout, + int printSolnFirstSteps = 0, + bool dumpJacobians = false); + void setNonLinOptions(int min_newt_its = 0, + bool matrixConditioning = false, + bool colScaling = false, + bool rowScaling = true); + virtual void setPrintFlag(int print_flag); + virtual void setColumnScales(); + /** + * calculate the solution error norm + */ + virtual double soln_error_norm(const double * const, + bool printLargest = false); + virtual void setInitialTimeStep(double delta_t); + + void beuler_jac(GeneralMatrix &, double * const, + double, double, double * const, double * const, int); + + + protected: + + //! Internal routine that sets up the fixed length storage based on + //! the size of the problem to solve. + void internalMalloc(); + /** + * Internal function to calculate the predicted solution + * at a time step. + */ + void calc_y_pred(int); + /** + * Internal function to calculate the time derivative at the + * new step + */ + void calc_ydot(int, double *, double *); + /** + * Internal function to calculate the time step truncation + * error for a predictor corrector time step + */ + double time_error_norm(); + /** + * Internal function to calculate the time step for the + * next step based on the time-truncation error on the + * current time step + */ + double time_step_control(int m_order, double time_error_factor); + + //! Solve a nonlinear system + /*! + * + * Find the solution to F(X, xprime) = 0 by damped Newton iteration. On + * entry, y_comm[] contains an initial estimate of the solution and + * ydot_comm[] contains an estimate of the derivative. + * On successful return, y_comm[] contains the converged solution + * and ydot_comm[] contains the derivative + * + * + * @param y_comm[] Contains the input solution. On output y_comm[] contains + * the converged solution + * @param ydot_comm Contains the input derivative solution. On output y_comm[] contains + * the converged derivative solution + * @param CJ Inverse of the time step + * @param time_curr Current value of the time + * @param jac Jacobian + * @param num_newt_its number of newton iterations + * @param num_linear_solves number of linear solves + * @param num_backtracks number of backtracs + * @param loglevel Log level + */ + int solve_nonlinear_problem(double * const y_comm, + double * const ydot_comm, double CJ, + double time_curr, + GeneralMatrix& jac, + int &num_newt_its, + int &num_linear_solves, + int &num_backtracks, + int loglevel); + + /** + * Compute the undamped Newton step. The residual function is + * evaluated at x, but the Jacobian is not recomputed. + */ + void doNewtonSolve(double, double *, double*, double *, + GeneralMatrix&, int); + + + //! Bound the Newton step while relaxing the solution + /*! + * Return the factor by which the undamped Newton step 'step0' + * must be multiplied in order to keep all solution components in + * all domains between their specified lower and upper bounds. + * Other bounds may be applied here as well. + * + * Currently the bounds are hard coded into this routine: + * + * Minimum value for all variables: - 0.01 * m_ewt[i] + * Maximum value = none. + * + * Thus, this means that all solution components are expected + * to be numerical greater than zero in the limit of time step + * truncation errors going to zero. + * + * Delta bounds: The idea behind these is that the Jacobian + * couldn't possibly be representative if the + * variable is changed by a lot. (true for + * nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: + * factor of 2 + * Maximum decrease in variable in any one newton iteration: + * factor of 5 + * + * @param y Current value of the solution + * @param step0 Current raw step change in y[] + * @param loglevel Log level. This routine produces output if loglevel + * is greater than one + * + * @return Returns the damping coefficient + */ + double boundStep(const double * const y, const double * const step0, int loglevel); + + /* + * Damp step + */ + int dampStep(double, const double*, const double*, + const double *, double*, double*, + double*, double&, GeneralMatrix&, int&, bool, int&); + + /* + * Compute Residual Weights + */ + void computeResidWts(GeneralMatrix &jac); + + /* + * Filter a new step + */ + double filterNewStep(double, double *, double *); + + /* + * get the next time to print out + */ + double getPrintTime(double time_current); + + /********************** Member data ***************************/ + /********************* + * METHOD FLAGS + *********************/ + + //! IterType is used to specify how the nonlinear equations are + //! to be relaxed at each time step. + IterType m_iter; + /** + * MethodType is used to specify how the time step is to be + * chosen. Currently, there are two choices, one is a fixed + * step method while the other is based on a predictor-corrector + * algorithm and a time-step truncation error tolerance. + */ + BEulerMethodType m_method; + /** + * m_jacFormMethod determines how a matrix is formed. + */ + int m_jacFormMethod; + /** + * m_rowScaling is a boolean. If true then row sum scaling + * of the Jacobian matrix is carried out when solving the + * linear systems. + */ + bool m_rowScaling; + /** + * m_colScaling is a boolean. If true, then column scaling + * is performed on each solution of the linear system. + */ + bool m_colScaling; + /** + * m_matrixConditioning is a boolean. If true, then the + * Jacobian and every rhs is multiplied by the inverse + * of a matrix that is suppose to reduce the condition + * number of the matrix. This is done before row scaling. + */ + bool m_matrixConditioning; + /** + * If m_itol =1 then each component has an individual + * value of atol. If m_itol = 0, the all atols are equal. + */ + int m_itol; + /** + * Relative time truncation error tolerances + */ + double m_reltol; + /** + * Absolute time truncation error tolerances, when uniform + * for all variables. + */ + double m_abstols; + /** + * Vector of absolute time truncation error tolerance + * when not uniform for all variables. + */ + double *m_abstol; + /** + * Error Weights. This is a surprisingly important quantity. + */ + double *m_ewt; + + //! Maximum step size + double m_hmax; + /** + * Maximum integration order + */ + int m_maxord; + /** + * Current integration order + */ + int m_order; + /** + * Time step number + */ + int m_time_step_num; + int m_time_step_attempts; + /** + * Max time steps allowed + */ + int m_max_time_step_attempts; + /** + * Number of initial time steps to take where the + * time truncation error tolerances are not checked. Instead + * the delta T is uniform + */ + int m_numInitialConstantDeltaTSteps; + /** + * Failure Counter -> keeps track of the number + * of consequetive failures + */ + int m_failure_counter; + /** + * Minimum Number of Newton Iterations per nonlinear step + * default = 0 + */ + int m_min_newt_its; + /************************ + * PRINTING OPTIONS + ************************/ + /** + * Step Interval at which to print out the solution + * default = 1; + * If set to zero, there is no printout + */ + int m_printSolnStepInterval; + /** + * Number of evenly spaced printouts of the solution + * If zero, there is no printout from this option + * default 1 + * If set to zero there is no printout. + */ + int m_printSolnNumberToTout; + + /** + * Number of initial steps that the solution is + * printed out. + * default = 0 + */ + int m_printSolnFirstSteps; + + /** + * Dump Jacobians to disk + * default false + */ + bool m_dumpJacobians; + + /********************* + * INTERNAL SOLUTION VALUES + *********************/ + /** + * Number of equations in the ode integrator + */ + int m_neq; + double *m_y_n; + double *m_y_nm1; + double *m_y_pred_n; + double *m_ydot_n; + double *m_ydot_nm1; + /************************ + * TIME VARIABLES + ************************/ + /** + * Initial time at the start of the integration + */ + double m_t0; + /** + * Final time + */ + double m_time_final; + /** + * + */ + double time_n; + double time_nm1; + double time_nm2; + double delta_t_n; + double delta_t_nm1; + double delta_t_nm2; + double delta_t_np1; + /** + * Maximum permissible time step + */ + double delta_t_max; + + + double *m_resid; + double *m_residWts; + double *m_wksp; + ResidJacEval *m_func; + double *m_rowScales; + double *m_colScales; + + /** + * Pointer to the jacobian representing the + * time dependent problem + */ + GeneralMatrix *tdjac_ptr; + /** + * Determines the level of printing for each time + * step. + * 0 -> absolutely nothing is printed for + * a single time step. + * 1 -> One line summary per time step + * 2 -> short description, points of interest + * 3 -> Lots printed per time step (default) + */ + int m_print_flag; + /*************************************************************************** + * COUNTERS OF VARIOUS KINDS + ***************************************************************************/ + /** + * Number of function evaluations + */ + int m_nfe; + /** + * Number of Jacobian Evaluations and + * factorization steps (they are the same) + */ + int m_nJacEval; + /** + * Number of total newton iterations + */ + int m_numTotalNewtIts; + /** + * Total number of linear iterations + */ + int m_numTotalLinearSolves; + /** + * Total number of convergence failures. + */ + int m_numTotalConvFails; + /** + * Total Number of time truncation error failures + */ + int m_numTotalTruncFails; + /* + * + */ + int num_failures; + }; + +} // namespace + +#endif // CT_BEULER diff --git a/Cantera/src/numerics/BandMatrix.cpp b/Cantera/src/numerics/BandMatrix.cpp old mode 100755 new mode 100644 index b643fe1b2..44a045dfb --- a/Cantera/src/numerics/BandMatrix.cpp +++ b/Cantera/src/numerics/BandMatrix.cpp @@ -17,165 +17,483 @@ #include "ctexceptions.h" #include "stringUtils.h" #include "global.h" +#include using namespace std; namespace Cantera { + //==================================================================================================================== + BandMatrix::BandMatrix() : + GeneralMatrix(1), + m_factored(false), + m_n(0), + m_kl(0), + m_ku(0), + m_zero(0.0) + { + data.clear(); + ludata.clear(); + } + //==================================================================================================================== + BandMatrix::BandMatrix(int n, int kl, int ku, doublereal v) : + GeneralMatrix(1), + m_factored(false), + m_n(n), + m_kl(kl), + m_ku(ku), + m_zero(0.0) + { + data.resize(n*(2*kl + ku + 1)); + ludata.resize(n*(2*kl + ku + 1)); + fill(data.begin(), data.end(), v); + fill(ludata.begin(), ludata.end(), 0.0); + m_ipiv.resize(m_n); + m_colPtrs.resize(n); + int ldab = (2*kl + ku + 1); + for (int j = 0; j < n; j++) { + m_colPtrs[j] = &(data[ldab * j]); + } + } + //==================================================================================================================== + BandMatrix::BandMatrix(const BandMatrix& y) : + GeneralMatrix(1), + m_factored(false), + m_n(0), + m_kl(0), + m_ku(0), + m_zero(0.0) + { + m_n = y.m_n; + m_kl = y.m_kl; + m_ku = y.m_ku; + data = y.data; + ludata = y.ludata; + m_factored = y.m_factored; + m_ipiv = y.m_ipiv; + m_colPtrs.resize(m_n); + int ldab = (2 *m_kl + m_ku + 1); + for (int j = 0; j < m_n; j++) { + m_colPtrs[j] = &(data[ldab * j]); + } + } + //==================================================================================================================== + BandMatrix::~BandMatrix() { - /// Default constructor. - BandMatrix::BandMatrix() : m_factored(false), m_n(0), - m_kl(0), m_ku(0), m_zero(0.0) { - data.clear(); ludata.clear(); + } + //==================================================================================================================== + BandMatrix& BandMatrix::operator=(const BandMatrix & y) { + if (&y == this) return *this; + GeneralMatrix::operator=(y); + m_n = y.m_n; + m_kl = y.m_kl; + m_ku = y.m_ku; + m_ipiv = y.m_ipiv; + data = y.data; + ludata = y.ludata; + m_factored = y.m_factored; + m_colPtrs.resize(m_n); + int ldab = (2 * m_kl + m_ku + 1); + for (int j = 0; j < m_n; j++) { + m_colPtrs[j] = &(data[ldab * j]); + } + return *this; + } + //==================================================================================================================== + void BandMatrix::resize(int n, int kl, int ku, doublereal v) { + m_n = n; + m_kl = kl; + m_ku = ku; + data.resize(n*(2*kl + ku + 1)); + ludata.resize(n*(2*kl + ku + 1)); + m_ipiv.resize(m_n); + fill(data.begin(), data.end(), v); + m_colPtrs.resize(m_n); + int ldab = (2 * m_kl + m_ku + 1); + for (int j = 0; j < n; j++) { + m_colPtrs[j] = &(data[ldab * j]); + } + m_factored = false; + } + //==================================================================================================================== + void BandMatrix::bfill(doublereal v) { + std::fill(data.begin(), data.end(), v); + m_factored = false; + } + //==================================================================================================================== + void BandMatrix::zero() { + std::fill(data.begin(), data.end(), 0.0); + m_factored = false; + } + //==================================================================================================================== + doublereal& BandMatrix::operator()(int i, int j) { + return value(i,j); + } + //==================================================================================================================== + doublereal BandMatrix::operator()(int i, int j) const { + return value(i,j); + } + //==================================================================================================================== + doublereal& BandMatrix::value(int i, int j) { + m_factored = false; + if (i < j - m_ku || i > j + m_kl) { + return m_zero; + } + return data[index(i,j)]; + } + //==================================================================================================================== + doublereal BandMatrix::value( int i, int j) const { + if (i < j - m_ku || i > j + m_kl) return 0.0; + return data[index(i,j)]; + } + //==================================================================================================================== + int BandMatrix::index(int i, int j) const { + int rw = m_kl + m_ku + i - j; + return (2*m_kl + m_ku + 1)*j + rw; + } + //==================================================================================================================== + doublereal BandMatrix::_value(int i, int j) const { + return data[index(i,j)]; + } + //==================================================================================================================== + // Number of rows + size_t BandMatrix::nRows() const { + return m_n; + } + //==================================================================================================================== + // Number of rows + size_t BandMatrix::nRowsAndStruct(int * const iStruct) const { + if (iStruct) { + iStruct[0] = m_kl; + iStruct[1] = m_ku; + } + return m_n; + } + //==================================================================================================================== + // Number of columns + int BandMatrix::nColumns() const { + return m_n; + } + //==================================================================================================================== + // Number of subdiagonals + int BandMatrix::nSubDiagonals() const { + return m_kl; + } + //==================================================================================================================== + // Number of superdiagonals + int BandMatrix::nSuperDiagonals() const { + return m_ku; + } + //==================================================================================================================== + int BandMatrix::ldim() const { + return 2*m_kl + m_ku + 1; + } + //==================================================================================================================== + vector_int & BandMatrix::ipiv() { + return m_ipiv; + } + //==================================================================================================================== + /* + * Multiply A*b and write result to \c prod. + */ + void BandMatrix::mult(const doublereal * const b, doublereal * const prod) const { + int nr = nRows(); + doublereal sum = 0.0; + for (int m = 0; m < nr; m++) { + sum = 0.0; + for (int j = m - m_kl; j <= m + m_ku; j++) { + if (j >= 0 && j < m_n) + sum += _value(m,j) * b[j]; + } + prod[m] = sum; + } + } + //==================================================================================================================== + /* + * Multiply b*A and write result to \c prod. + */ + void BandMatrix::leftMult(const doublereal * const b, doublereal * const prod) const { + int nc = nColumns(); + doublereal sum = 0.0; + for (int n = 0; n < nc; n++) { + sum = 0.0; + for (int i = n - m_ku; i <= n + m_kl; i++) { + if (i >= 0 && i < m_n) + sum += _value(i,n) * b[i]; + } + prod[n] = sum; + } + } + //==================================================================================================================== + /* + * Perform an LU decomposition. LAPACK routine DGBTRF is used. + * The factorization is saved in ludata. + */ + int BandMatrix::factor() { + int info=0; + copy(data.begin(), data.end(), ludata.begin()); + ct_dgbtrf(nRows(), nColumns(), nSubDiagonals(), nSuperDiagonals(), + DATA_PTR(ludata), ldim(), DATA_PTR(ipiv()), info); + + // if info = 0, LU decomp succeeded. + if (info == 0) { + m_factored = true; + } else { + m_factored = false; + ofstream fout("bandmatrix.csv"); + fout << *this << endl; + fout.close(); + } + return info; + } + //==================================================================================================================== + int BandMatrix::solve(const doublereal * const b, doublereal * const x) { + copy(b, b + m_n, x); + return solve(x); + } + //==================================================================================================================== + int BandMatrix::solve(doublereal* b) { + int info = 0; + if (!m_factored) info = factor(); + if (info == 0) + ct_dgbtrs(ctlapack::NoTranspose, nColumns(), nSubDiagonals(), + nSuperDiagonals(), 1, DATA_PTR(ludata), ldim(), + DATA_PTR(ipiv()), b, nColumns(), info); + + // error handling + if (info != 0) { + ofstream fout("bandmatrix.csv"); + fout << *this << endl; + fout.close(); + } + return info; + } + //==================================================================================================================== + vector_fp::iterator BandMatrix::begin() { + m_factored = false; + return data.begin(); + } + //==================================================================================================================== + vector_fp::iterator BandMatrix::end() { + m_factored = false; + return data.end(); + } + //==================================================================================================================== + vector_fp::const_iterator BandMatrix::begin() const { + return data.begin(); + } + //==================================================================================================================== + vector_fp::const_iterator BandMatrix::end() const { + return data.end(); + } + //==================================================================================================================== + ostream& operator<<(ostream& s, const BandMatrix& m) { + int nr = m.nRows(); + int nc = m.nColumns(); + for (int i = 0; i < nr; i++) { + for (int j = 0; j < nc; j++) { + s << m(i,j) << ", "; + } + s << endl; + } + return s; + } + //==================================================================================================================== + void BandMatrix::err(std::string msg) const { + throw CanteraError("BandMatrix() unimplemented function", msg); + } + //==================================================================================================================== + // Factors the A matrix using the QR algorithm, overwriting A + /* + * we set m_factored to 2 to indicate the matrix is now QR factored + * + * @return Returns the info variable from lapack + */ + int BandMatrix::factorQR() { + factor(); + return 0; + } + //==================================================================================================================== + // Factors the A matrix using the QR algorithm, overwriting A + // Returns an estimate of the inverse of the condition number for the matrix + /* + * The matrix must have been previously factored using the QR algorithm + * + * @return returns the inverse of the condition number + */ + doublereal BandMatrix::rcondQR() { + double a1norm = oneNorm(); + return rcond(a1norm); + } + //==================================================================================================================== + // Returns an estimate of the inverse of the condition number for the matrix + /* + * The matrix must have been previously factored using the LU algorithm + * + * @param a1norm Norm of the matrix + * + * @return returns the inverse of the condition number + */ + doublereal BandMatrix::rcond(doublereal a1norm) { + int printLevel = 0; + int useReturnErrorCode = 0; + if ((int) iwork_.size() < m_n) { + iwork_.resize(m_n); + } + if ((int) work_.size() < 3 * m_n) { + work_.resize(3 * m_n); + } + doublereal rcond = 0.0; + if (m_factored != 1) { + throw CanteraError("BandMatrix::rcond()", "matrix isn't factored correctly"); } - - /** - * Constructor. Create an n by n banded matrix. - * @param n number of rows and columns - * @param kl number of subdiagonals - * @param ku number of superdiagonals - * @param v initial value (default = 0.0) - */ - BandMatrix::BandMatrix(int n, int kl, int ku, doublereal v) - : m_factored(false), m_n(n), m_kl(kl), m_ku(ku) { - data.resize(n*(2*kl + ku + 1)); - ludata.resize(n*(2*kl + ku + 1)); - fill(data.begin(), data.end(), v); - fill(ludata.begin(), ludata.end(), 0.0); - m_ipiv.resize(m_n); + // doublereal anorm = oneNorm(); + int ldab = (2 *m_kl + m_ku + 1); + int rinfo; + rcond = ct_dgbcon('1', m_n, m_kl, m_ku, DATA_PTR(ludata), ldab, DATA_PTR(m_ipiv), a1norm, DATA_PTR(work_), + DATA_PTR(iwork_), rinfo); + if (rinfo != 0) { + if (printLevel) { + writelogf("BandMatrix::rcond(): DGBCON returned INFO = %d\n", rinfo); + } + if (! useReturnErrorCode) { + throw CanteraError("BandMatrix::rcond()", "DGBCON returned INFO = " + int2str(rinfo)); + } } - - /// copy constructor - BandMatrix::BandMatrix(const BandMatrix& y) { - m_n = y.m_n; - m_kl = y.m_kl; - m_ku = y.m_ku; - data = y.data; - ludata = y.ludata; - m_factored = y.m_factored; - m_ipiv = y.m_ipiv; - } - - BandMatrix& BandMatrix::operator=(const BandMatrix& y) { - if (&y == this) return *this; - m_n = y.m_n; - m_kl = y.m_kl; - m_ku = y.m_ku; - m_ipiv = y.m_ipiv; - data = y.data; - ludata = y.ludata; - m_factored = y.m_factored; - return *this; - } - - void BandMatrix::resize(int n, int kl, int ku, doublereal v) { - m_n = n; - m_kl = kl; - m_ku = ku; - data.resize(n*(2*kl + ku + 1)); - ludata.resize(n*(2*kl + ku + 1)); - m_ipiv.resize(m_n); - fill(data.begin(), data.end(), v); - fill(data.begin(), data.end(), 0.0); - m_factored = false; - } - - - /** - * Multiply A*b and write result to \c prod. - */ - void BandMatrix::mult(const double* b, double* prod) const { - int nr = rows(); - int m, j; - double sum = 0.0; - for (m = 0; m < nr; m++) { - sum = 0.0; - for (j = m - m_kl; j <= m + m_ku; j++) { - if (j >= 0 && j < m_n) - sum += _value(m,j)*b[j]; - } - prod[m] = sum; - } - } - - - /** - * Multiply b*A and write result to \c prod. - */ - void BandMatrix::leftMult(const double* b, double* prod) const { - int nc = columns(); - int n, i; - double sum = 0.0; - for (n = 0; n < nc; n++) { - sum = 0.0; - for (i = n - m_ku; i <= n + m_kl; i++) { - if (i >= 0 && i < m_n) - sum += _value(i,n)*b[i]; - } - prod[n] = sum; - } - } - - - /** - * Perform an LU decomposition. LAPACK routine DGBTRF is used. - * The factorization is saved in ludata. - */ - int BandMatrix::factor() { - int info=0; - copy(data.begin(), data.end(), ludata.begin()); - ct_dgbtrf(rows(), columns(), nSubDiagonals(), nSuperDiagonals(), - DATA_PTR(ludata), ldim(), DATA_PTR(ipiv()), info); - - // if info = 0, LU decomp succeeded. - if (info == 0) { - m_factored = true; - } - else { - m_factored = false; - ofstream fout("bandmatrix.csv"); - fout << *this << endl; - fout.close(); - } - return info; - } - - - - int BandMatrix::solve(int n, const doublereal* b, doublereal* x) { - copy(b, b+n, x); - return solve(n, x); - } - - int BandMatrix::solve(int n, doublereal* b) { - int info = 0; - if (!m_factored) info = factor(); - if (info == 0) - ct_dgbtrs(ctlapack::NoTranspose, columns(), nSubDiagonals(), - nSuperDiagonals(), 1, DATA_PTR(ludata), ldim(), - DATA_PTR(ipiv()), b, columns(), info); - - // error handling - if (info != 0) { - ofstream fout("bandmatrix.csv"); - fout << *this << endl; - fout.close(); - } - return info; - } - - ostream& operator<<(ostream& s, const BandMatrix& m) { - int nr = m.rows(); - int nc = m.columns(); - int i,j; - for (i = 0; i < nr; i++) { - for (j = 0; j < nc; j++) { - s << m(i,j) << ", "; - } - s << endl; - } - return s; + return rcond; + } + //==================================================================================================================== + // Change the way the matrix is factored + /* + * @param fAlgorithm integer + * 0 LU factorization + * 1 QR factorization + */ + void BandMatrix::useFactorAlgorithm(int fAlgorithm) { + // QR algorithm isn't implemented for banded matrix. + } + //==================================================================================================================== + int BandMatrix::factorAlgorithm() const { + return 0; + } + //==================================================================================================================== + // Returns the one norm of the matrix + doublereal BandMatrix::oneNorm() const { + doublereal value = 0.0; + for (int j = 0; j < m_n; j++) { + doublereal sum = 0.0; + doublereal *colP = m_colPtrs[j]; + for (int i = j - m_ku; i <= j + m_kl; i++) { + sum += fabs(colP[m_kl + m_ku + i - j]); + } + if (sum > value) { + value = sum; + } } + return value; + } + //==================================================================================================================== + int BandMatrix::checkRows(doublereal &valueSmall) const { + valueSmall = 1.0E300; + int iSmall = -1; + double vv; + for (int i = 0; i < m_n; i++) { + double valueS = 0.0; + for (int j = i - m_kl; j <= i + m_ku; j++) { + if (j >= 0 && (j < m_n)) { + vv = fabs(value(i,j)); + if (vv > valueS) { + valueS = vv; + } + } + } + if (valueS < valueSmall) { + iSmall = i; + valueSmall = valueS; + if (valueSmall == 0.0) { + return iSmall; + } + } + } + return iSmall; + } + //==================================================================================================================== + int BandMatrix::checkColumns(doublereal &valueSmall) const { + valueSmall = 1.0E300; + int jSmall = -1; + double vv; + for (int j = 0; j < m_n; j++) { + double valueS = 0.0; + for (int i = j - m_ku; i <= j + m_kl; i++) { + if (i >= 0 && (i < m_n)) { + vv = fabs(value(i,j)); + if (vv > valueS) { + valueS = vv; + } + } + } + if (valueS < valueSmall) { + jSmall = j; + valueSmall = valueS; + if (valueSmall == 0.0) { + return jSmall; + } + } + } + return jSmall; + } + //==================================================================================================================== + GeneralMatrix * BandMatrix::duplMyselfAsGeneralMatrix() const { + BandMatrix *dd = new BandMatrix(*this); + return static_cast(dd); + } + //==================================================================================================================== + bool BandMatrix::factored() const { + return m_factored; + } + //==================================================================================================================== + // Return a pointer to the top of column j, columns are assumed to be contiguous in memory + /* + * @param j Value of the column + * + * @return Returns a pointer to the top of the column + */ + doublereal * BandMatrix::ptrColumn(int j) { + return m_colPtrs[j]; + } + //==================================================================================================================== + // Return a vector of const pointers to the columns + /* + * Note the value of the pointers are protected by their being const. + * However, the value of the matrix is open to being changed. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + doublereal * const * BandMatrix::colPts() { + return &(m_colPtrs[0]); + } + //==================================================================================================================== + // Copy the data from one array into another without doing any checking + /* + * This differs from the assignment operator as no resizing is done and memcpy() is used. + * @param y Array to be copied + */ + void BandMatrix::copyData(const GeneralMatrix& y) { + m_factored = false; + size_t n = sizeof(doublereal) * m_n * (2 *m_kl + m_ku + 1); + GeneralMatrix * yyPtr = const_cast(&y); + (void) memcpy(DATA_PTR(data), yyPtr->ptrColumn(0), n); + } + //==================================================================================================================== + /* + * clear the factored flag + */ + void BandMatrix::clearFactorFlag() { + m_factored = 0; + } + //==================================================================================================================== + //==================================================================================================================== } diff --git a/Cantera/src/numerics/BandMatrix.h b/Cantera/src/numerics/BandMatrix.h old mode 100755 new mode 100644 index d3f7fdd3e..6a756172e --- a/Cantera/src/numerics/BandMatrix.h +++ b/Cantera/src/numerics/BandMatrix.h @@ -1,7 +1,8 @@ /** * @file BandMatrix.h - * - * Banded matrices. + * Declarations for the class BandMatrix + * which is a child class of GeneralMatrix for banded matrices handled by solvers + * (see class \ref numerics and \link Cantera::BandMatrix BandMatrix\endlink). */ /* @@ -20,133 +21,425 @@ #include "ctlapack.h" #include "utilities.h" #include "ctexceptions.h" +#include "GeneralMatrix.h" namespace Cantera { - /** - * A class for banded matrices. + //! A class for banded matrices, involving matrix inversion processes. + //! The class is based upon the LAPACK banded storage matrix format. + /*! + * An important issue with this class is that it stores both the original data + * and the LU factorization of the data. This means that the banded matrix typically + * will take up twice the room that it is expected to take. + * + * QR factorizations of banded matrices are not included in the original LAPACK work. + * Add-ons are available. However, they are not included here. Instead we just use the + * stock LU decompositions. + * + * This class is a derived class of the base class GeneralMatrix. However, withinin + * the oneD directory, the class is used as is, without reference to the GeneralMatrix + * base type. + */ + class BandMatrix : public GeneralMatrix { + + public: + + //! Base Constructor + /*! + * * Create an \c 0 by \c 0 matrix, and initialize all elements to \c 0. */ - class BandMatrix { + BandMatrix(); - public: + //! Creates a banded matrix and sets all elements to zero + /*! + * Create an \c n by \c n banded matrix, and initialize all elements to \c v. + * + * @param n size of the square matrix + * @param kl band size on the lower portion of the matrix + * @param ku band size on the upper portion of the matrix + * @param v intial value of all matrix components. + */ + BandMatrix(int n, int kl, int ku, doublereal v = 0.0); - BandMatrix(); - BandMatrix(int n, int kl, int ku, doublereal v = 0.0); + //! Copy constructor + /*! + * @param y Matrix to be copied + */ + BandMatrix(const BandMatrix& y); - /// copy constructor - BandMatrix(const BandMatrix& y); + //! Destructor. Does nothing. + virtual ~BandMatrix(); - /// Destructor. Does nothing. - virtual ~BandMatrix(){} + //! assignment operator + /*! + * @param y reference to the matrix to be copied + */ + BandMatrix& operator=(const BandMatrix& y); - /// assignment. - BandMatrix& operator=(const BandMatrix& y); + //! Resize the matrix problem + /*! + * All data is lost + * + * @param n size of the square matrix + * @param kl band size on the lower portion of the matrix + * @param ku band size on the upper portion of the matrix + * @param v intial value of all matrix components. + */ + void resize(int n, int kl, int ku, doublereal v = 0.0); - void resize(int n, int kl, int ku, doublereal v = 0.0); + //! Fill or zero the matrix + /*! + * @param v Fill value, defaults to zero. + */ + void bfill(doublereal v = 0.0); - void bfill(doublereal v) { - std::fill(data.begin(), data.end(), v); - m_factored = false; - } - - doublereal& operator()( int i, int j) { - return value(i,j); - } - - doublereal operator() ( int i, int j) const { - return value(i,j); - } - - /// Return a reference to element (i,j). Since this method may - /// alter the element value, it may need to be refactored, so - /// the flag m_factored is set to false. - doublereal& value( int i, int j) { - m_factored = false; - if (i < j - m_ku || i > j + m_kl) { - m_zero = 0.0; - return m_zero; - } - return data[index(i,j)]; - } - - /// Return the value of element (i,j). This method does not - /// alter the array. - doublereal value( int i, int j) const { - if (i < j - m_ku || i > j + m_kl) return 0.0; - return data[index(i,j)]; - } - - /// Return the location in the internal 1D array corresponding to - /// the (i,j) element in the banded array. - int index(int i, int j) const { - int rw = m_kl + m_ku + i - j; - return (2*m_kl + m_ku + 1)*j + rw; - } - - /// Return the value of the (i,j) element for (i,j) within the - /// bandwidth. For efficiency, this method does not check that - /// (i,j) are within the bandwidth; it is up to the calling - /// program to insure that this is true. - doublereal _value(int i, int j) const { - return data[index(i,j)]; - } - - /// Number of rows - int nRows() const { return m_n; } - /// @deprecated Redundant. - int rows() const { return m_n; } - - /// Number of columns - int nColumns() const { return m_n; } - /// @deprecated Redundant. - int columns() const { return m_n; } - - /// Number of subdiagonals - int nSubDiagonals() const { return m_kl; } - - /// Number of superdiagonals - int nSuperDiagonals() const { return m_ku; } - - int ldim() const { return 2*m_kl + m_ku + 1; } - vector_int& ipiv() { return m_ipiv; } - - /// Multiply A*b and write result to prod. - void mult(const double* b, double* prod) const; - - /// Multiply b*A and write result to prod. - void leftMult(const double* b, double* prod) const; - - int factor(); - - //void solve(const vector_fp& b, vector_fp& x); - - int solve(int n, const doublereal* b, doublereal* x); - int solve(int n, doublereal* b); - - vector_fp::iterator begin() { - m_factored = false; - return data.begin(); - } - vector_fp::iterator end() { - m_factored = false; - return data.end(); - } - vector_fp::const_iterator begin() const { return data.begin(); } - vector_fp::const_iterator end() const { return data.end(); } - - protected: - vector_fp data; - vector_fp ludata; - bool m_factored; + //! Index into the (i,j) element + /*! + * @param i row + * @param j column + * + * Returns a changeable reference to the matrix entry + */ + doublereal& operator()(int i, int j); - int m_n, m_kl, m_ku; - doublereal m_zero; - vector_int m_ipiv; + //! Constant index into the (i,j) element + /*! + * @param i row + * @param j column + * + * Returns an unchangeable reference to the matrix entry + */ + doublereal operator() (int i, int j) const; - }; + //! Return a changeable reference to element (i,j). + /*! + * Since this method may alter the element value, it may need to be refactored, so + * the flag m_factored is set to false. + * + * @param i row + * @param j column + * + * @return Returns a reference to the value of the matrix entry + */ + doublereal& value( int i, int j); - std::ostream& operator<<(std::ostream& s, const BandMatrix& m); + + //! Return the value of element (i,j). + /*! + * This method does not alter the array. + * @param i row + * @param j column + * + * @return Returns the value of the matrix entry + */ + doublereal value( int i, int j) const; + + //! Returns the location in the internal 1D array corresponding to the (i,j) element in the banded array + /*! + * @param i row + * @param j column + * + * @return Returns the index of the matrix entry + */ + int index(int i, int j) const; + + //! Return the value of the (i,j) element for (i,j) within the bandwidth. + /*! + * For efficiency, this method does not check that (i,j) are within the bandwidth; it is up to the calling + * program to insure that this is true. + * + * @param i row + * @param j column + * + * @return Returns the value of the matrix entry + */ + doublereal _value(int i, int j) const; + + //! Returns the number of rows + virtual size_t nRows() const; + + //! Return the size and structure of the matrix + /*! + * This is inherited from GeneralMatrix + * + * @param iStruct OUTPUT Pointer to a vector of ints that describe the structure of the matrix. + * istruct[0] = kl + * istruct[1] = ku + * + * @return returns the number of rows and columns in the matrix. + */ + virtual size_t nRowsAndStruct(int * const iStruct = 0) const; + + //! Number of columns + int nColumns() const; + + //! Number of subdiagonals + int nSubDiagonals() const; + + //! Number of superdiagonals + int nSuperDiagonals() const; + + //! Return the number of rows of storage needed for the band storage + int ldim() const; + + //! Return a reference to the pivot vector + /*! + * @return return a reference to the pivot vector + */ + vector_int& ipiv(); + + //! Multiply A*b and write result to prod. + /*! + * @param b Vector to do the rh multiplcation + * @param prod OUTPUT vector to receive the result + */ + virtual void mult(const doublereal * const b, doublereal * const prod) const; + + //! Multiply b*A and write result to prod. + /*! + * @param b Vector to do the lh multiplcation + * @param prod OUTPUT vector to receive the result + */ + virtual void leftMult(const doublereal * const b, doublereal * const prod) const; + + //! Perform an LU decomposition, the LAPACK routine DGBTRF is used. + /*! + * + * The factorization is saved in ludata. + * + * @return Return a success flag. + * 0 indicates a success + * ~0 Some error occurred, see the LAPACK documentation + */ + int factor(); + + + //! Solve the matrix problem Ax = b + /*! + * @param b INPUT rhs of the problem + * @param x OUTPUT solution to the problem + * + * @return Return a success flag + * 0 indicates a success + * ~0 Some error occurred, see the LAPACK documentation + */ + int solve(const doublereal * const b, doublereal * const x); + + //! Solve the matrix problem Ax = b + /*! + * @param b INPUT rhs of the problem + * OUTPUT solution to the problem + * + * @return Return a success flag + * 0 indicates a success + * ~0 Some error occurred, see the LAPACK documentation + */ + int solve(doublereal * const b); + + + //! Returns an iterator for the start of the band storage data + /*! + * Iterator points to the beginning of the data, and it is changeable. + */ + virtual vector_fp::iterator begin(); + + //! Returns an iterator for the end of the band storage data + /*! + * Iterator points to the end of the data, and it is changeable. + */ + vector_fp::iterator end(); + + //! Returns a const iterator for the start of the band storage data + /*! + * Iterator points to the beginning of the data, and it is not changeable. + */ + vector_fp::const_iterator begin() const; + + //! Returns a const iterator for the end of the band storage data + /*! + * Iterator points to the end of the data, and it is not changeable. + */ + vector_fp::const_iterator end() const; + + /** + * Zero the matrix + */ + virtual void zero(); + + //! Factors the A matrix using the QR algorithm, overwriting A + /*! + * we set m_factored to 2 to indicate the matrix is now QR factored + * + * @return Returns the info variable from lapack + */ + virtual int factorQR(); + + //! Returns an estimate of the inverse of the condition number for the matrix + /*! + * The matrix must have been previously factored using the QR algorithm + * + * @return returns the inverse of the condition number + */ + virtual doublereal rcondQR(); + + //! Returns an estimate of the inverse of the condition number for the matrix + /*! + * The matrix must have been previously factored using the LU algorithm + * + * @param a1norm Norm of the matrix + * + * @return returns the inverse of the condition number + */ + virtual doublereal rcond(doublereal a1norm); + + //! Change the way the matrix is factored + /*! + * @param fAlgorithm integer + * 0 LU factorization + * 1 QR factorization + */ + virtual void useFactorAlgorithm(int fAlgorithm); + + //! Returns the factor algorithm used + /*! + * 0 LU decomposition + * 1 QR decomposition + * + * This routine will always return 0 + */ + virtual int factorAlgorithm() const; + + //! Returns the one norm of the matrix + virtual doublereal oneNorm() const; + + //! Duplicate this object as a GeneralMatrix pointer + virtual GeneralMatrix * duplMyselfAsGeneralMatrix() const; + + //! Report whether the current matrix has been factored. + virtual bool factored() const; + + //! Return a pointer to the top of column j, column values are assumed to be contiguous in memory + /*! + * The LAPACK bandstructure has column values which are contiguous in memory: + * + * On entry, the matrix A in band storage, in rows KL+1 to + * 2*KL+KU+1; rows 1 to KL of the array need not be set. + * The j-th column of A is stored in the j-th column of the + * array AB as follows: + * AB(KL + KU + 1 + i - j,j) = A(i,j) for max(1, j - KU) <= i <= min(m, j + KL) + * + * This routine returns the position of AB(1,j) (fortran-1 indexing) in the above format + * + * So to address the (i,j) position, you use the following indexing: + * + * double *colP_j = matrix.ptrColumn(j); + * double a_i_j = colP_j[kl + ku + i - j]; + * + * + * @param j Value of the column + * + * @return Returns a pointer to the top of the column + */ + virtual doublereal * ptrColumn(int j); + + //! Return a vector of const pointers to the columns + /*! + * Note the value of the pointers are protected by their being const. + * However, the value of the matrix is open to being changed. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + virtual doublereal * const * colPts(); + + //! Copy the data from one array into another without doing any checking + /*! + * This differs from the assignment operator as no resizing is done and memcpy() is used. + * @param y Array to be copied + */ + virtual void copyData(const GeneralMatrix& y); + + + //! Clear the factored flag + virtual void clearFactorFlag(); + + //! Check to see if we have any zero rows in the jacobian + /*! + * This utility routine checks to see if any rows are zero. + * The smallest row is returned along with the largest coefficient in that row + * + * @param valueSmall OUTPUT value of the largest coefficient in the smallest row + * + * @return index of the row that is most nearly zero + */ + virtual int checkRows(doublereal & valueSmall) const; + + //! Check to see if we have any zero columns in the jacobian + /*! + * This utility routine checks to see if any columns are zero. + * The smallest column is returned along with the largest coefficient in that column + * + * @param valueSmall OUTPUT value of the largest coefficient in the smallest column + * + * @return index of the column that is most nearly zero + */ + virtual int checkColumns(doublereal & valueSmall) const; + + protected: + + //! Matrix data + vector_fp data; + + //! Factorized data + vector_fp ludata; + + //! Boolean indicating whether the matrix is factored + bool m_factored; + + //! Number of rows and columns of the matrix + int m_n; + + //! Number of subdiagonals of the matrix + int m_kl; + + //! Number of super diagonals of the matrix + int m_ku; + + //! value of zero + doublereal m_zero; + + //! Pivot vector + vector_int m_ipiv; + + //! Vector of column pointers + std::vector m_colPtrs; + + //! Extra work array needed - size = n + vector_int iwork_; + + //! Extra dp work array needed - size = 3n + vector_fp work_; + + private: + + //! Error function that gets called for unhandled cases + /*! + * @param msg String containing the message. + */ + void err(std::string msg) const; + + + }; + + //! Utility routine to print out the matrix + /*! + * @param s ostream to print the matrix out to + * @param m Matrix to be printed + * + * @return Returns a reference to the ostream + */ + std::ostream& operator<<(std::ostream& s, const BandMatrix& m); } diff --git a/Cantera/src/numerics/DAE_Solver.h b/Cantera/src/numerics/DAE_Solver.h index 4d570cca7..cbc4d4b03 100644 --- a/Cantera/src/numerics/DAE_Solver.h +++ b/Cantera/src/numerics/DAE_Solver.h @@ -12,212 +12,236 @@ * Copyright 2006 California Institute of Technology * */ - -#undef DAE_DEVEL - #ifndef CT_DAE_Solver_H #define CT_DAE_Solver_H #include #include "ct_defs.h" -#include "ResidEval.h" +#include "ResidJacEval.h" #include "global.h" namespace Cantera { +#define DAE_DEVEL #ifdef DAE_DEVEL - /** - * @defgroup numerics Numerical Utilities within Cantera - * - * + + class Jacobian { + public: + Jacobian(){} + virtual ~Jacobian(){} + virtual bool supplied() { return false; } + virtual bool isBanded() { return false; } + virtual int lowerBandWidth() { return 0; } + virtual int upperBandWidth() { return 0; } + }; + + class BandedJacobian : public Jacobian { + public: + BandedJacobian(int ml, int mu) { + m_ml = ml; m_mu = mu; + } + virtual bool supplied() { return false; } + virtual bool isBanded() { return true; } + virtual int lowerBandWidth() { return m_ml; } + virtual int upperBandWidth() { return m_mu; } + protected: + int m_ml, m_mu; + }; + + const int cDirect = 0; + const int cKrylov = 1; + + + + /** + * Wrapper for DAE solvers + */ + class DAE_Solver { + public: + + DAE_Solver(ResidJacEval& f) : + m_resid(f), + m_neq(f.nEquations()), + m_time(0.0) + { + } + + virtual ~DAE_Solver(){} + + /** + * Set error tolerances. This version specifies a scalar + * relative tolerance, and a vector absolute tolerance. */ + virtual void setTolerances(doublereal reltol, + doublereal* abstol) { + warn("setTolerances"); + } - class Jacobian { - public: - Jacobian(){} - virtual ~Jacobian(){} - virtual bool supplied() { return false; } - virtual bool isBanded() { return false; } - virtual int lowerBandWidth() { return 0; } - virtual int upperBandWidth() { return 0; } - }; + /** + * Set error tolerances. This version specifies a scalar + * relative tolerance, and a scalar absolute tolerance. + */ + virtual void setTolerances(doublereal reltol, doublereal abstol) { + warn("setTolerances"); + } - class BandedJacobian : public Jacobian { - public: - BandedJacobian(int ml, int mu) { - m_ml = ml; m_mu = mu; - } - virtual bool supplied() { return false; } - virtual bool isBanded() { return true; } - virtual int lowerBandWidth() { return m_ml; } - virtual int upperBandWidth() { return m_mu; } - protected: - int m_ml, m_mu; - }; + /** + * Specify a Jacobian evaluator. If this method is not called, + * the Jacobian will be computed by finite difference. + */ + void setJacobian(Jacobian& jac) { + warn("setJacobian"); + } - const int cDirect = 0; - const int cKrylov = 1; + virtual void setLinearSolverType(int solverType) { + warn("setLinearSolverType"); + } + virtual void setDenseLinearSolver() { + warn("setDenseLinearSolver"); + } + virtual void setBandedLinearSolver(int m_upper, int m_lower) { + warn("setBandedLinearSolver"); + } + virtual void setMaxStepSize(doublereal dtmax) { + warn("setMaxStepSize"); + } + virtual void setMaxOrder(int n) { + warn("setMaxOrder"); + } + virtual void setMaxNumSteps(int n) { + warn("setMaxNumSteps"); + } + virtual void setInitialStepSize(doublereal h0) { + warn("setInitialStepSize"); + } + virtual void setStopTime(doublereal tstop) { + warn("setStopTime"); + } + virtual void setMaxErrTestFailures(int n) { + warn("setMaxErrTestFailures"); + } + virtual void setMaxNonlinIterations(int n) { + warn("setMaxNonlinIterations"); + } + virtual void setMaxNonlinConvFailures(int n) { + warn("setMaxNonlinConvFailures"); + } + virtual void inclAlgebraicInErrorTest(bool yesno) { + warn("inclAlgebraicInErrorTest"); + } /** - * Wrapper for DAE solvers + * This method may be called if the initial conditions do not + * satisfy the residual equation F = 0. Given the derivatives + * of all variables, this method computes the initial y + * values. */ - class DAE_Solver { - public: + virtual void correctInitial_Y_given_Yp(doublereal* y, doublereal* yp, + doublereal tout) { + warn("correctInitial_Y_given_Yp"); + } + + /** + * This method may be called if the initial conditions do not + * satisfy the residual equation F = 0. Given the initial + * values of all differential variables, it computes the + * initial values of all algebraic variables and the initial + * derivatives of all differential variables. + */ + virtual void correctInitial_YaYp_given_Yd(doublereal* y, doublereal* yp, + doublereal tout) + { + warn("correctInitial_YaYp_given_Yd"); + } - DAE_Solver(ResidEval& f) : m_resid(f), - m_neq(f.nEquations()), - m_time(0.0) {} + /** + * Solve the system of equations up to time tout. + */ + virtual int solve(doublereal tout) { + warn("solve"); return 0; + } - virtual ~DAE_Solver(){} + /** + * Take one internal step. + */ + virtual doublereal step(doublereal tout) { + warn("step"); return 0; + } - /** - * Set error tolerances. This version specifies a scalar - * relative tolerance, and a vector absolute tolerance. - */ - virtual void setTolerances(doublereal reltol, - doublereal* abstol) { - warn("setTolerances"); - } + /// Number of equations. + int nEquations() const { + return m_resid.nEquations(); + } - /** - * Set error tolerances. This version specifies a scalar - * relative tolerance, and a scalar absolute tolerance. - */ - virtual void setTolerances(doublereal reltol, doublereal abstol) { - warn("setTolerances"); - } + /** + * initialize. Base class method does nothing. + */ + virtual void init(doublereal t0) {} - /** - * Specify a Jacobian evaluator. If this method is not called, - * the Jacobian will be computed by finite difference. - */ - void setJacobian(Jacobian& jac) { - warn("setJacobian"); - } + /** + * Set a solver-specific input parameter. + */ + virtual void setInputParameter(int flag, doublereal value) { + warn("setInputParameter"); + } - virtual void setLinearSolverType(int solverType) { - warn("setLinearSolverType"); - } + /** + * Get the value of a solver-specific output parameter. + */ + virtual doublereal getOutputParameter(int flag) const { + warn("getOutputParameter"); return 0.0; + } - virtual void setDenseLinearSolver() { - warn("setDenseLinearSolver"); - } + /// the current value of solution component k. + virtual doublereal solution(int k) const { + warn("solution"); return 0.0; + } - virtual void setBandedLinearSolver(int m_upper, int m_lower) { - warn("setBandedLinearSolver"); - } - virtual void setMaxTime(doublereal tmax) { - warn("setMaxTime"); - } - virtual void setMaxStepSize(doublereal dtmax) { - warn("setMaxStepSize"); - } - virtual void setMaxOrder(int n) { - warn("setMaxOrder"); - } - virtual void setMaxNumSteps(int n) { - warn("setMaxNumSteps"); - } - virtual void setInitialStepSize(doublereal h0) { - warn("setInitialStepSize"); - } - virtual void setStopTime(doublereal tstop) { - warn("setStopTime"); - } - virtual void setMaxErrTestFailures(int n) { - warn("setMaxErrTestFailures"); - } - virtual void setMaxNonlinIterations(int n) { - warn("setMaxNonlinIterations"); - } - virtual void setMaxNonlinConvFailures(int n) { - warn("setMaxNonlinConvFailures"); - } - virtual void inclAlgebraicInErrorTest(bool yesno) { - warn("inclAlgebraicInErrorTest"); - } + virtual const doublereal* solutionVector() const { + warn("solutionVector"); return &m_dummy; + } - virtual void correctInitial_Y_given_Yp() { - warn("correctInitial_Y_given_Yp"); - } + /// the current value of the derivative of solution component k. + virtual doublereal derivative(int k) const { + warn("derivative"); return 0.0; + } - virtual void correctInitial_YaYp_given_Yd() { - warn("correctInitial_YaYp_given_Yd"); - } + virtual const doublereal* derivativeVector() const { + warn("derivativeVector"); return &m_dummy; + } - /** - * Solve the system of equations up to time tout. - */ - virtual int solve(doublereal tout) { - warn("solve"); return 0; - } + protected: - /** - * Take one internal step. - */ - virtual doublereal step(doublereal tout) { - warn("step"); return 0; - } + doublereal m_dummy; - /// Number of equations. - int nEquations() const { return m_resid.nEquations(); } + ResidJacEval& m_resid; - /** - * initialize. Base class method does nothing. - */ - virtual void init(doublereal t0) {} - - /** - * Set a solver-specific input parameter. - */ - virtual void setInputParameter(int flag, doublereal value) { - warn("setInputParameter"); - } - - /** - * Get the value of a solver-specific output parameter. - */ - virtual doublereal getOutputParameter(int flag) const { - warn("getOutputParameter"); return 0.0; - } - - /// the current value of solution component k. - virtual doublereal solution(int k) const { - warn("solution"); return 0.0; - } - - virtual const doublereal* solutionVector() const { - warn("solutionVector"); return &m_dummy; - } - - /// the current value of the derivative of solution component k. - virtual doublereal derivative(int k) const { - warn("derivative"); return 0.0; - } - - virtual const doublereal* derivativeVector() const { - warn("derivativeVector"); return &m_dummy; - } - - protected: - - doublereal m_dummy; - - ResidEval& m_resid; - - integer m_neq; - doublereal m_time; + //! Number of total equations in the system + integer m_neq; + doublereal m_time; - private: - void warn(std::string msg) const { - writelog(">>>> Warning: method "+msg+" of base class " - +"DAE_Solver called. Nothing done.\n"); - } - }; + private: + void warn(std::string msg) const { + writelog(">>>> Warning: method "+msg+" of base class " + +"DAE_Solver called. Nothing done.\n"); + } + }; + + + //! Factor method for choosing a DAE solver + /*! + * + * @param itype String identifying the type + * (IDA is the only option) + * @param f Residual function to be solved by the DAE algorithm + * + * @return Returns a point to the instantiated DAE_Solver object + */ + DAE_Solver* newDAE_Solver(std::string itype, ResidJacEval& f); #endif diff --git a/Cantera/src/numerics/DAE_solvers.cpp b/Cantera/src/numerics/DAE_solvers.cpp index 4e0c2d7c7..02b58c5fe 100644 --- a/Cantera/src/numerics/DAE_solvers.cpp +++ b/Cantera/src/numerics/DAE_solvers.cpp @@ -3,6 +3,7 @@ #include "DAE_Solver.h" // DAE_DEVEL is turned off at the current time +#define DAE_DEVEL #ifdef DAE_DEVEL #ifdef HAS_SUNDIALS @@ -11,18 +12,18 @@ namespace Cantera { - DAE_Solver* newDAE_Solver(string itype) { + DAE_Solver* newDAE_Solver(std::string itype, ResidJacEval& f) { if (itype == "IDA") { #ifdef HAS_SUNDIALS - return new IDA_Solver(); + return new IDA_Solver(f); #else - raise CanteraError("newDAE_Solver","IDA solver requires sundials" - " package, but Cantera was not built with sundials."); + throw CanteraError("newDAE_Solver","IDA solver requires sundials" + " package, but Cantera was not built with sundials."); #endif } else { throw CanteraError("newDAE_Solver", - "unknown DAE solver: "+itype); + "unknown DAE solver: "+itype); } } } diff --git a/Cantera/src/numerics/DASPK.cpp b/Cantera/src/numerics/DASPK.cpp old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/DASPK.h b/Cantera/src/numerics/DASPK.h old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/DenseMatrix.cpp b/Cantera/src/numerics/DenseMatrix.cpp old mode 100755 new mode 100644 index 762e4e393..134acfe72 --- a/Cantera/src/numerics/DenseMatrix.cpp +++ b/Cantera/src/numerics/DenseMatrix.cpp @@ -14,136 +14,294 @@ #include "utilities.h" #include "DenseMatrix.h" #include "stringUtils.h" +#include "global.h" namespace Cantera { - - /// assignment. - DenseMatrix& DenseMatrix::operator=(const DenseMatrix& y) { - if (&y == this) return *this; - Array2D::operator=(y); - m_ipiv = y.ipiv(); - return *this; - } - - void DenseMatrix::resize(int n, int m, doublereal v) { - Array2D::resize(n,m,v); - m_ipiv.resize( max(n,m) ); - } - - void DenseMatrix::mult(const double* b, double* prod) const { - ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, - static_cast(nRows()), - static_cast(nRows()), 1.0, ptrColumn(0), //begin(), - static_cast(nRows()), b, 1, 0.0, prod, 1); - } - - void DenseMatrix::leftMult(const double* b, double* prod) const { - int nc = static_cast(nColumns()); - int nr = static_cast(nRows()); - int n, i; - double sum = 0.0; - for (n = 0; n < nc; n++) { - sum = 0.0; - for (i = 0; i < nr; i++) { - sum += value(i,n)*b[i]; - } - prod[n] = sum; - } - } - - int solve(DenseMatrix& A, double* b) { - int info=0; - ct_dgetrf(static_cast(A.nRows()), - static_cast(A.nColumns()), A.ptrColumn(0), //begin(), - static_cast(A.nRows()), &A.ipiv()[0], info); - if (info != 0) - throw CanteraError("DenseMatrix::solve", - "DGETRF returned INFO = "+int2str(info)); - ct_dgetrs(ctlapack::NoTranspose, - static_cast(A.nRows()), 1, A.ptrColumn(0), //begin(), - static_cast(A.nRows()), - &A.ipiv()[0], b, - static_cast(A.nColumns()), info); - if (info != 0) - throw CanteraError("DenseMatrix::solve", - "DGETRS returned INFO = "+int2str(info)); - return 0; + //==================================================================================================================== + // Default Constructor + DenseMatrix::DenseMatrix() : + Array2D(0,0,0.0), + m_ipiv(0), + m_useReturnErrorCode(0), + m_printLevel(0) + { + } + //==================================================================================================================== + /* + * Constructor. Create an \c n by \c m matrix, and initialize + * all elements to \c v. + */ + DenseMatrix::DenseMatrix(int n, int m, doublereal v) : + Array2D(n, m, v), + m_ipiv(0), + m_useReturnErrorCode(0), + m_printLevel(0) + { + m_ipiv.resize(max(n, m)); + m_colPts.resize(m); + for (int j = 0; j < m; j++) { + m_colPts[j] = &(m_data[m_nrows*j]); } - - int solve(DenseMatrix& A, DenseMatrix& b) { - int info=0; - ct_dgetrf(static_cast(A.nRows()), - static_cast(A.nColumns()), A.ptrColumn(0), - static_cast(A.nRows()), &A.ipiv()[0], info); - if (info != 0) - throw CanteraError("DenseMatrix::solve", - "DGETRF returned INFO = "+int2str(info)); - ct_dgetrs(ctlapack::NoTranspose, static_cast(A.nRows()), - static_cast(b.nColumns()), - A.ptrColumn(0), static_cast(A.nRows()), - &A.ipiv()[0], b.ptrColumn(0), - static_cast(b.nRows()), info); - if (info != 0) - throw CanteraError("DenseMatrix::solve", - "DGETRS returned INFO = "+int2str(info)); - return 0; + } + //==================================================================================================================== + // Copy constructor + /* + * @param y Object to be copied + */ + DenseMatrix::DenseMatrix(const DenseMatrix& y) : + Array2D(y), + m_ipiv(0), + m_useReturnErrorCode(0), + m_printLevel(0) + { + m_ipiv = y.ipiv(); + m_colPts.resize(m_ncols); + for (int j = 0; j < m_ncols; j++) { + m_colPts[j] = &(m_data[m_nrows*j]); } - + } + //==================================================================================================================== + // assignment + DenseMatrix& DenseMatrix::operator=(const DenseMatrix& y) { + if (&y == this) return *this; + Array2D::operator=(y); + m_ipiv = y.ipiv(); + m_colPts.resize(m_ncols); + for (int j = 0; j < m_ncols; j++) { + m_colPts[j] = &(m_data[m_nrows*j]); + } + m_useReturnErrorCode = y.m_useReturnErrorCode; + m_printLevel = y.m_printLevel; + return *this; + } + //==================================================================================================================== + // Destructor. Does nothing. + DenseMatrix::~DenseMatrix() + { + } + //==================================================================================================================== + void DenseMatrix::resize(int n, int m, doublereal v) { + Array2D::resize(n,m,v); + m_ipiv.resize( max(n,m) ); + m_colPts.resize(m_ncols); + for (int j = 0; j < m_ncols; j++) { + m_colPts[j] = &(m_data[m_nrows*j]); + } + } + //==================================================================================================================== + doublereal * const * DenseMatrix::colPts() { + return &(m_colPts[0]); + } + //==================================================================================================================== + const doublereal * const * DenseMatrix::const_colPts() const { + return &(m_colPts[0]); + } + //==================================================================================================================== + void DenseMatrix::mult(const double* b, double* prod) const { + ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, + static_cast(nRows()), + static_cast(nRows()), 1.0, ptrColumn(0), //begin(), + static_cast(nRows()), b, 1, 0.0, prod, 1); + } + //==================================================================================================================== + void DenseMatrix::leftMult(const double* const b, double* const prod) const { + int nc = static_cast(nColumns()); + int nr = static_cast(nRows()); + int n, i; + double sum = 0.0; + for (n = 0; n < nc; n++) { + sum = 0.0; + for (i = 0; i < nr; i++) { + sum += value(i,n)*b[i]; + } + prod[n] = sum; + } + } + //==================================================================================================================== + vector_int& DenseMatrix::ipiv() { + return m_ipiv; + } + //==================================================================================================================== + int solve(DenseMatrix& A, double* b) { + int info = 0; + if (A.nColumns() != A.nRows()) { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, double* b): Can only solve a square matrix\n"); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, double* b)", "Can only solve a square matrix"); + } + return -1; + } + ct_dgetrf(static_cast(A.nRows()), + static_cast(A.nColumns()), A.ptrColumn(0), //begin(), + static_cast(A.nRows()), &A.ipiv()[0], info); + if (info != 0) { + if (info > 0) { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, double* b): DGETRF returned INFO = %d U(i,i) is exactly zero. The factorization has" + " been completed, but the factor U is exactly singular, and division by zero will occur if " + "it is used to solve a system of equations.\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, double* b)", + "DGETRF returned INFO = "+int2str(info) + ". U(i,i) is exactly zero. The factorization has" + " been completed, but the factor U is exactly singular, and division by zero will occur if " + "it is used to solve a system of equations."); + } + } else { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, double* b): DGETRF returned INFO = %d. The argument i has an illegal value\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, double* b)", + "DGETRF returned INFO = "+int2str(info) + ". The argument i has an illegal value"); + } + } + return info; + } + ct_dgetrs(ctlapack::NoTranspose, + static_cast(A.nRows()), 1, A.ptrColumn(0), //begin(), + static_cast(A.nRows()), + &A.ipiv()[0], b, + static_cast(A.nColumns()), info); + if (info != 0) { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, double* b): DGETRS returned INFO = %d\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, double* b)", "DGETRS returned INFO = "+int2str(info)); + } + } + return info; + } + //==================================================================================================================== + int solve(DenseMatrix& A, DenseMatrix& b) { + int info = 0; + if (A.nColumns() != A.nRows()) { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, DenseMatrix& b): Can only solve a square matrix\n"); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, DenseMatrix& b)", "Can only solve a square matrix"); + } + return -1; + } + ct_dgetrf(static_cast(A.nRows()), + static_cast(A.nColumns()), A.ptrColumn(0), + static_cast(A.nRows()), &A.ipiv()[0], info); + if (info != 0) { + if (info > 0) { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, DenseMatrix& b): DGETRF returned INFO = %d U(i,i) is exactly zero. The factorization has" + " been completed, but the factor U is exactly singular, and division by zero will occur if " + "it is used to solve a system of equations.\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, DenseMatrix& b)", + "DGETRF returned INFO = "+int2str(info) + ". U(i,i) is exactly zero. The factorization has" + " been completed, but the factor U is exactly singular, and division by zero will occur if " + "it is used to solve a system of equations."); + } + } else { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, DenseMatrix& b): DGETRF returned INFO = %d. The argument i has an illegal value\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, DenseMatrix& b)", + "DGETRF returned INFO = "+int2str(info) + ". The argument i has an illegal value"); + } + } + return info; + } + + ct_dgetrs(ctlapack::NoTranspose, static_cast(A.nRows()), + static_cast(b.nColumns()), + A.ptrColumn(0), static_cast(A.nRows()), + &A.ipiv()[0], b.ptrColumn(0), + static_cast(b.nRows()), info); + if (info != 0) { + if (A.m_printLevel) { + writelogf("solve(DenseMatrix& A, DenseMatrix& b): DGETRS returned INFO = %d\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("solve(DenseMatrix& A, DenseMatrix& b)", "DGETRS returned INFO = "+int2str(info)); + } + } + + return info; + } + //==================================================================================================================== #ifdef INCL_LEAST_SQUARES - /** @todo fix lwork */ - int leastSquares(DenseMatrix& A, double* b) { - int info = 0; - int rank = 0; - double rcond = -1.0; - // fix this! - int lwork = 6000; // 2*(3*min(m,n) + max(2*min(m,n), max(m,n))); - vector_fp work(lwork); - vector_fp s(min(static_cast(A.nRows()), - static_cast(A.nColumns()))); - ct_dgelss(static_cast(A.nRows()), - static_cast(A.nColumns()), 1, A.ptrColumn(0), - static_cast(A.nRows()), b, - static_cast(A.nColumns()), &s[0], //.begin(), - rcond, rank, &work[0], work.size(), info); - if (info != 0) - throw CanteraError("DenseMatrix::leaseSquares", - "DGELSS returned INFO = "+int2str(info)); - return 0; + /** @todo fix lwork */ + int leastSquares(DenseMatrix& A, double* b) { + int info = 0; + int rank = 0; + double rcond = -1.0; + // fix this! + int lwork = 6000; // 2*(3*min(m,n) + max(2*min(m,n), max(m,n))); + vector_fp work(lwork); + vector_fp s(min(static_cast(A.nRows()), + static_cast(A.nColumns()))); + ct_dgelss(static_cast(A.nRows()), + static_cast(A.nColumns()), 1, A.ptrColumn(0), + static_cast(A.nRows()), b, + static_cast(A.nColumns()), &s[0], //.begin(), + rcond, rank, &work[0], work.size(), info); + if (info != 0) { + if (A.m_printLevel) { + writelogf("leastSquares(): DGELSS returned INFO = %d\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("leastSquares()", "DGELSS returned INFO = " + int2str(info)); + } } + return info; + } #endif - - void multiply(const DenseMatrix& A, const double* b, double* prod) { - ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, - static_cast(A.nRows()), static_cast(A.nColumns()), 1.0, - A.ptrColumn(0), static_cast(A.nRows()), b, 1, 0.0, prod, 1); + //==================================================================================================================== + void multiply(const DenseMatrix& A, const double * const b, double * const prod) { + ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, + static_cast(A.nRows()), static_cast(A.nColumns()), 1.0, + A.ptrColumn(0), static_cast(A.nRows()), b, 1, 0.0, prod, 1); + } + //==================================================================================================================== + void increment(const DenseMatrix& A, const double* b, double* prod) { + ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, + static_cast(A.nRows()), static_cast(A.nRows()), 1.0, + A.ptrColumn(0), static_cast(A.nRows()), b, 1, 1.0, prod, 1); + } + //==================================================================================================================== + int invert(DenseMatrix& A, int nn) { + integer n = (nn > 0 ? nn : static_cast(A.nRows())); + int info=0; + ct_dgetrf(n, n, A.ptrColumn(0), static_cast(A.nRows()), + &A.ipiv()[0], info); + if (info != 0) { + if (A.m_printLevel) { + writelogf("invert(DenseMatrix& A, int nn): DGETRS returned INFO = %d\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("invert(DenseMatrix& A, int nn)", "DGETRS returned INFO = "+int2str(info)); + } + return info; } - void increment(const DenseMatrix& A, - const double* b, double* prod) { - ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, - static_cast(A.nRows()), static_cast(A.nRows()), 1.0, - A.ptrColumn(0), static_cast(A.nRows()), b, 1, 1.0, prod, 1); - } - - int invert(DenseMatrix& A, int nn) { - integer n = (nn > 0 ? nn : static_cast(A.nRows())); - int info=0; - ct_dgetrf(n, n, A.ptrColumn(0), static_cast(A.nRows()), - &A.ipiv()[0], info); - if (info != 0) - throw CanteraError("invert", - "DGETRF returned INFO="+int2str(info)); - - vector_fp work(n); - integer lwork = static_cast(work.size()); - ct_dgetri(n, A.ptrColumn(0), static_cast(A.nRows()), - &A.ipiv()[0], - &work[0], lwork, info); - if (info != 0) - throw CanteraError("invert", - "DGETRI returned INFO="+int2str(info)); - return 0; + vector_fp work(n); + integer lwork = static_cast(work.size()); + ct_dgetri(n, A.ptrColumn(0), static_cast(A.nRows()), + &A.ipiv()[0], &work[0], lwork, info); + if (info != 0) { + if (A.m_printLevel) { + writelogf("invert(DenseMatrix& A, int nn): DGETRS returned INFO = %d\n", info); + } + if (! A.m_useReturnErrorCode) { + throw CELapackError("invert(DenseMatrix& A, int nn)", "DGETRI returned INFO="+int2str(info)); + } } + return info; + } + //==================================================================================================================== } diff --git a/Cantera/src/numerics/DenseMatrix.h b/Cantera/src/numerics/DenseMatrix.h old mode 100755 new mode 100644 index 613bb948b..c43018d4a --- a/Cantera/src/numerics/DenseMatrix.h +++ b/Cantera/src/numerics/DenseMatrix.h @@ -1,7 +1,8 @@ /** * @file DenseMatrix.h - * - * Dense (not sparse) matrices. + * Headers for the %DenseMatrix object, which deals with dense rectangular matrices and + * description of the numerics groupings of objects + * (see \ref numerics and \link Cantera::DenseMatrix DenseMatrix \endlink) . */ /* @@ -20,85 +21,259 @@ #include "ct_defs.h" #include "Array.h" + namespace Cantera { + /** + * @defgroup numerics Numerical Utilities within Cantera + * + * Cantera contains some capabilities for solving nonlinear equations and + * integrating both ODE and DAE equation systems in time. This section describes these + * capabilities. + * + */ - /** - * A class for full (non-sparse) matrices with Fortran-compatible - * data storage. Adds matrix operations to class Array2D. + + //! Exception thrown when an LAPACK error is encountered associated with inverting or solving a matrix + /*! + * A named error condition is used so that the calling code may differentiate this type of error + * from other error conditions. + */ + class CELapackError : public CanteraError { + public: + + //! Constructor passes through to main Cantera error handler + /*! + * @param routine Name of calling routine + * @param msg Informative message */ - class DenseMatrix : public Array2D { + CELapackError(std::string routine, std::string msg) : + CanteraError(routine + " LAPACK ERROR", msg) + { + } - public: + }; + + //! A class for full (non-sparse) matrices with Fortran-compatible + //! data storage, which adds matrix operations to class Array2D. + /*! + * The dense matrix class adds matrix operations onto the Array2D class. + * These matrix operations are carried out by the appropriate BLAS and LAPACK routines + * + * Error handling from BLAS and LAPACK are handled via the following formulation. + * Depending on a variable, a singular matrix or other terminal error condition from + * LAPACK is handled by either throwing an exception of type, CELapackError, or by + * returning the error code condition to the calling routine. + * + * The int variable, m_useReturnErrorCode, determines which method is used. + * The default value of zero means that an exception is thrown. A value of 1 + * means that a return code is used. + * + * Reporting of these LAPACK error conditions is handled by the class variable + * m_printLevel. The default is for no reporting. If m_printLevel is nonzero, + * the error condition is reported to Cantera's log file. + * + * @ingroup numerics + */ + class DenseMatrix : public Array2D { - DenseMatrix(){} + public: - /** - * Constructor. Create an \c n by \c m matrix, and initialize - * all elements to \c v. - */ - DenseMatrix(int n, int m, doublereal v = 0.0) : Array2D(n,m,v) { - m_ipiv.resize( max(n, m) ); - } - - /// copy constructor - DenseMatrix(const DenseMatrix& y) : Array2D(y) { - m_ipiv = y.ipiv(); - } - - /// assignment. - DenseMatrix& operator=(const DenseMatrix& y); - - void resize(int n, int m, doublereal v = 0.0); - - /// Destructor. Does nothing. - virtual ~DenseMatrix(){} - - - /** - * Multiply A*b and write result to \c prod. - */ - virtual void mult(const double* b, double* prod) const; - - /** - * Left-multiply the matrix by transpose(b), and write the - * result to prod. - */ - virtual void leftMult(const double* b, double* prod) const; - - vector_int& ipiv() { return m_ipiv; } - const vector_int& ipiv() const { return m_ipiv; } - - protected: - - vector_int m_ipiv; - }; - - - /** - * Solve Ax = b. Array b is overwritten on exit with x. + //! Default Constructor + DenseMatrix(); + + //! Constructor. + /*! + * Create an \c n by \c m matrix, and initialize all elements to \c v. + * + * @param n New number of rows + * @param m New number of columns + * @param v Default fill value. defaults to zero. */ - int solve(DenseMatrix& A, double* b); + DenseMatrix(int n, int m, doublereal v = 0.0); - /** Solve Ax = b for multiple right-hand-side vectors. */ - int solve(DenseMatrix& A, DenseMatrix& b); + //! Copy constructor + /*! + * @param y Object to be copied + */ + DenseMatrix(const DenseMatrix& y); + + //! Assignment operator + /*! + * @param y Object to be copied + */ + DenseMatrix& operator=(const DenseMatrix& y); + + //! Destructor. Does nothing. + virtual ~DenseMatrix(); + + //! Resize the matrix + /*! + * Resize the matrix to n rows by m cols. + * + * @param n New number of rows + * @param m New number of columns + * @param v Default fill value. defaults to zero. + */ + void resize(int n, int m, doublereal v = 0.0); + + //! Return a vector of const pointers to the columns + /*! + * Note the value of the pointers are protected by their being const. + * However, the value of the matrix is open to being changed. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + virtual doublereal * const * colPts(); + + //! Return a const vector of const pointers to the columns + /*! + * Note, the jacobian can not be altered by this routine, and + * therefore the member function is const. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + const doublereal * const * const_colPts() const; + + //! Multiply A*b and write result to \c prod. + /*! + * + * @param b input vector b with length N + * @param prod output output vector prod length = M + */ + virtual void mult(const double* b, double* prod) const; + + //! Left-multiply the matrix by transpose(b), and write the result to prod. + /*! + * @param b left multiply by this vector. The length must be equal to n + * the number of rows in the matrix. + * + * @param prod Resulting vector. This is of length m, the number of columns + * in the matrix + */ + virtual void leftMult(const double * const b, double* const prod) const; + + //! Return a changeable value of the pivot vector + /*! + * @return Returns a reference to the pivot vector as a vector_int + */ + vector_int& ipiv(); + + //! Return a changeable value of the pivot vector + /*! + * @return Returns a reference to the pivot vector as a vector_int + */ + const vector_int& ipiv() const { return m_ipiv; } + + protected: + + //! Vector of pivots. Length is equal to the max of m and n. + vector_int m_ipiv; + + //! Vector of column pointers + std::vector m_colPts; + + public: + + //! Error Handling Flag + /*! + * The default is to set this to 0. In this case, if a factorization is requested and can't be achieved, + * a CESingularMatrix exception is triggered. No return code is used, because an exception is thrown. + * If this is set to 1, then an exception is not thrown. Routines return with an error code, that is up + * to the calling routine to handle correctly + */ + int m_useReturnErrorCode; + + //! Print Level + /*! + * Printing is done to the log file using the routine writelogf(). + * + * Level of printing that is carried out. Only error conditions are printed out, if this value is nonzero. + */ + int m_printLevel; + + + // Listing of friend functions which are defined below + + friend int solve(DenseMatrix& A, double* b); + friend int solve(DenseMatrix& A, DenseMatrix& b); + friend int invert(DenseMatrix& A, int nn); +#ifdef INCL_LEAST_SQUARES + friend int leastSquares(DenseMatrix& A, double* b); +#endif + + }; + + //================================================================================================================== + + + //! Solve Ax = b. Array b is overwritten on exit with x. + /*! + * The solve class uses the LAPACK routine dgetrf to invert the m xy n matrix. + * + * The factorization has the form + * A = P * L * U + * where P is a permutation matrix, L is lower triangular with unit + * diagonal elements (lower trapezoidal if m > n), and U is upper + * triangular (upper trapezoidal if m < n). + * + * The system is then solved using the LAPACK routine dgetrs + * + * @param A Dense matrix to be factored + * @param b rhs to be solved. + */ + int solve(DenseMatrix& A, double* b); + + //! Solve Ax = b for multiple right-hand-side vectors. + /*! + * @param A Dense matrix to be factored + * @param b Dense matrix of rhs's. Each column is a rhs + */ + int solve(DenseMatrix& A, DenseMatrix& b); #ifdef INCL_LEAST_SQUARES - /** @todo fix lwork */ - int leastSquares(DenseMatrix& A, double* b); + //! Solve Ax = b in the least squares sense + /*! + * @param A Matrix to be inverted in the least squares sense + * @param b Vector b to be solved for + * @todo fix lwork + */ + int leastSquares(DenseMatrix& A, double* b); #endif - /** - * Multiply \c A*b and return the result in \c prod. Uses BLAS - * routine DGEMV. - */ - void multiply(const DenseMatrix& A, const double* b, double* prod); + + //! Multiply \c A*b and return the result in \c prod. Uses BLAS routine DGEMV. + /*! + * \f[ + * prod_i = sum^N_{j = 1}{A_{ij} b_j} + * \f] + * + * @param A input Dense Matrix A with M rows and N columns + * @param b input vector b with length N + * @param prod output output vector prod length = M + */ + void multiply(const DenseMatrix& A, const double * const b, double * const prod); - void increment(const DenseMatrix& A, - const double* b, double* prod); + //! Multiply \c A*b and add it to the result in \c prod. Uses BLAS routine DGEMV. + /*! + * \f[ + * prod_i += sum^N_{j = 1}{A_{ij} b_j} + * \f] + * + * @param A input Dense Matrix A with M rows and N columns + * @param b input vector b with length N + * @param prod output output vector prod length = M + */ + void increment(const DenseMatrix& A, const double * const b, double * const prod); - /** - * invert A. A is overwritten with A^-1. - */ - int invert(DenseMatrix& A, int nn=-1); + //! invert A. A is overwritten with A^-1. + /*! + * @param A Invert the matrix A and store it back in place + * + * @param nn Size of A. This defaults to -1, which means that the number + * of rows is used as the default size of n + */ + int invert(DenseMatrix& A, int nn=-1); } diff --git a/Cantera/src/numerics/Func1.h b/Cantera/src/numerics/Func1.h index fa3e6b23f..e91263101 100644 --- a/Cantera/src/numerics/Func1.h +++ b/Cantera/src/numerics/Func1.h @@ -23,7 +23,6 @@ #include #include -using namespace std; namespace Cantera { diff --git a/Cantera/src/numerics/FuncEval.h b/Cantera/src/numerics/FuncEval.h old mode 100755 new mode 100644 index d88181533..e835eb9ab --- a/Cantera/src/numerics/FuncEval.h +++ b/Cantera/src/numerics/FuncEval.h @@ -55,7 +55,7 @@ namespace Cantera { */ virtual int neq()=0; - /// Number of parameters. + //! Number of parameters. virtual int nparams() { return 0; } protected: diff --git a/Cantera/src/numerics/GeneralMatrix.cpp b/Cantera/src/numerics/GeneralMatrix.cpp new file mode 100644 index 000000000..5a76c5e6b --- /dev/null +++ b/Cantera/src/numerics/GeneralMatrix.cpp @@ -0,0 +1,42 @@ +/** + * @file GeneralMatrix.cpp + * + */ +/* + * $Revision: 725 $ + * $Date: 2011-05-16 18:45:08 -0600 (Mon, 16 May 2011) $ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#include "GeneralMatrix.h" +using namespace std; + +namespace Cantera { + //==================================================================================================================== + GeneralMatrix::GeneralMatrix(int matType) : + matrixType_(matType) + { + } + //==================================================================================================================== + GeneralMatrix::GeneralMatrix(const GeneralMatrix &y) : + matrixType_(y.matrixType_) + { + } + //==================================================================================================================== + GeneralMatrix& GeneralMatrix::operator=(const GeneralMatrix &y) + { + if (&y == this) return *this; + matrixType_ = y.matrixType_; + return *this; + } + //==================================================================================================================== + GeneralMatrix::~GeneralMatrix() + { + } + //==================================================================================================================== +} diff --git a/Cantera/src/numerics/GeneralMatrix.h b/Cantera/src/numerics/GeneralMatrix.h new file mode 100644 index 000000000..8781ff524 --- /dev/null +++ b/Cantera/src/numerics/GeneralMatrix.h @@ -0,0 +1,245 @@ +/** + * @file GeneralMatrix.h + * Declarations for the class GeneralMatrix which is a virtual base class for matrices handled by solvers + * (see class \ref numerics and \link Cantera::GeneralMatrix GeneralMatrix\endlink). + */ + +/* + * $Date: 2011-10-13 15:16:06 -0600 (Thu, 13 Oct 2011) $ + * $Revision: 776 $ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#ifndef CT_GENERALMATRIX_H +#define CT_GENERALMATRIX_H + +#include "ct_defs.h" + +namespace Cantera { + + //! Generic matrix + class GeneralMatrix { + + + public: + + //! Base Constructor + /*! + * @param matType Matrix type + * 0 full + * 1 banded + */ + GeneralMatrix(int matType); + + //! Copy Constructor + /*! + * @param right Object to be copied + */ + GeneralMatrix(const GeneralMatrix& right); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + GeneralMatrix& operator=(const GeneralMatrix& right); + + //! Destructor. Does nothing. + virtual ~GeneralMatrix(); + + //! Duplicator member function + /*! + * This function will duplicate the matrix given a generic GeneralMatrix pointer + * + * @return Returns a pointer to the malloced object + */ + virtual GeneralMatrix * duplMyselfAsGeneralMatrix() const = 0; + + //! Zero the matrix elements + virtual void zero() = 0; + + //! Multiply A*b and write result to prod. + /*! + * @param b Vector to do the rh multiplcation + * @param prod OUTPUT vector to receive the result + */ + virtual void mult(const doublereal * const b, doublereal * const prod) const = 0; + + //! Multiply b*A and write result to prod. + /*! + * @param b Vector to do the lh multiplcation + * @param prod OUTPUT vector to receive the result + */ + virtual void leftMult(const doublereal * const b, doublereal * const prod) const = 0; + + //! Factors the A matrix, overwriting A. + /* + * We flip m_factored boolean to indicate that the matrix is now A-1. + */ + virtual int factor() = 0; + + //! Factors the A matrix using the QR algorithm, overwriting A + /*! + * we set m_factored to 2 to indicate the matrix is now QR factored + * + * @return Returns the info variable from lapack + */ + virtual int factorQR() = 0; + + //! Returns an estimate of the inverse of the condition number for the matrix + /*! + * The matrix must have been previously factored using the QR algorithm + * + * @return returns the inverse of the condition number + */ + virtual doublereal rcondQR() = 0; + + //! Returns an estimate of the inverse of the condition number for the matrix + /*! + * The matrix must have been previously factored using the LU algorithm + * + * @param a1norm Norm of the matrix + * + * @return returns the inverse of the condition number + */ + virtual doublereal rcond(doublereal a1norm) = 0; + + //! Change the way the matrix is factored + /*! + * @param fAlgorithm integer + * 0 LU factorization + * 1 QR factorization + */ + virtual void useFactorAlgorithm(int fAlgorithm) = 0; + + //! Return the factor algorithm used + /*! + * + */ + virtual int factorAlgorithm() const = 0; + + //! Calculate the one norm of the matrix + /*! + * Returns the one norm of the matrix + */ + virtual doublereal oneNorm() const = 0; + + + //! Return the number of rows in the matrix + virtual size_t nRows() const = 0; + + + //! Return the size and structure of the matrix + /*! + * This is inherited from GeneralMatrix + * + * @param iStruct OUTPUT Pointer to a vector of ints that describe the structure of the matrix. + * + * @return returns the number of rows and columns in the matrix. + */ + virtual size_t nRowsAndStruct(int * const iStruct = 0) const = 0; + + //! clear the factored flag + virtual void clearFactorFlag() = 0; + + //! Solves the Ax = b system returning x in the b spot. + /*! + * @param b Vector for the rhs of the equation system + */ + virtual int solve(doublereal *b) = 0; + + //! true if the current factorization is up to date with the matrix + virtual bool factored() const = 0; + + //! Return a pointer to the top of column j, columns are assumed to be contiguous in memory + /*! + * @param j Value of the column + * + * @return Returns a pointer to the top of the column + */ + virtual doublereal * ptrColumn(int j) = 0; + + //! Index into the (i,j) element + /*! + * @param i row + * @param j column + * + * Returns a changeable reference to the matrix entry + */ + virtual doublereal& operator()(int i, int j) = 0; + + + //! Constant Index into the (i,j) element + /*! + * @param i row + * @param j column + * + * Returns an unchangeable reference to the matrix entry + */ + virtual doublereal operator() (int i, int j) const = 0; + + //! Copy the data from one array into another without doing any checking + /*! + * This differs from the assignment operator as no resizing is done and memcpy() is used. + * @param y Array to be copied + */ + virtual void copyData(const GeneralMatrix& y) = 0; + + //! Return an iterator pointing to the first element + /*! + * We might drop this later + */ + virtual vector_fp::iterator begin() = 0; + + //! Return a const iterator pointing to the first element + /*! + * We might drop this later + */ + virtual vector_fp::const_iterator begin() const = 0; + + //! Return a vector of const pointers to the columns + /*! + * Note the value of the pointers are protected by their being const. + * However, the value of the matrix is open to being changed. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + virtual doublereal * const * colPts() = 0; + + //! Check to see if we have any zero rows in the jacobian + /*! + * This utility routine checks to see if any rows are zero. + * The smallest row is returned along with the largest coefficient in that row + * + * @param valueSmall OUTPUT value of the largest coefficient in the smallest row + * + * @return index of the row that is most nearly zero + */ + virtual int checkRows (doublereal & valueSmall) const = 0; + + //! Check to see if we have any zero columns in the jacobian + /*! + * This utility routine checks to see if any columns are zero. + * The smallest column is returned along with the largest coefficient in that column + * + * @param valueSmall OUTPUT value of the largest coefficient in the smallest column + * + * @return index of the column that is most nearly zero + */ + virtual int checkColumns (doublereal & valueSmall) const = 0; + + //! Matrix type + /*! + * 0 Square + * 1 Banded + */ + int matrixType_; + + }; +} +#endif diff --git a/Cantera/src/numerics/IDA_Solver.cpp b/Cantera/src/numerics/IDA_Solver.cpp index eec7f9226..0ff4eadce 100644 --- a/Cantera/src/numerics/IDA_Solver.cpp +++ b/Cantera/src/numerics/IDA_Solver.cpp @@ -1,4 +1,3 @@ - /** * @file IDA_Solver.cpp * @@ -10,8 +9,10 @@ #include "stringUtils.h" #include -using namespace std; +#ifdef HAS_SUNDIALS + +#ifdef SUNDIALS_VERSION_22 #include #include #include @@ -19,238 +20,633 @@ using namespace std; #include #include #include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + +using namespace std; + + inline static N_Vector nv(void* x) { - return reinterpret_cast(x); + return reinterpret_cast(x); } namespace Cantera { - /** - * A simple class to hold an array of parameter values and a pointer to - * an instance of a subclass of ResidEval. - */ - class ResidData { + /** + * A simple class to hold an array of parameter values and a pointer to + * an instance of a subclass of ResidEval. + */ + class ResidData { + + public: + ResidData(ResidJacEval* f, IDA_Solver *s, int npar = 0) { + m_func = f; + m_solver = s; + } + virtual ~ResidData() { + } - - public: - ResidData(ResidEval* f, int npar = 0) { - m_func = f; - } - virtual ~ResidData() {} - ResidEval* m_func; - }; + ResidJacEval* m_func; + IDA_Solver * m_solver; + }; } - +//====================================================================================================================== extern "C" { - - /** - * Function called by IDA to evaluate the residual, given y and - * ydot. IDA allows passing in a void* pointer to access - * external data. Instead of requiring the user to provide a - * residual function directly to IDA (which would require using - * the sundials data types N_Vector, etc.), we define this - * function as the single function that IDA always calls. The - * real evaluation of the residual is done by an instance of a - * subclass of ResidEval, passed in to this function as a pointer - * in the parameters. - */ - static int ida_resid(realtype t, N_Vector y, N_Vector ydot, - N_Vector r, void *f_data) { - double* ydata = NV_DATA_S(y); - double* ydotdata = NV_DATA_S(ydot); - double* rdata = NV_DATA_S(r); - Cantera::ResidData* d = (Cantera::ResidData*)f_data; - Cantera::ResidEval* f = d->m_func; - f->eval(t, ydata, ydotdata, rdata); - return 0; + //! Function called by IDA to evaluate the residual, given y and ydot. + /*! + * IDA allows passing in a void* pointer to access external data. Instead of requiring the user to provide a + * residual function directly to IDA (which would require using + * the sundials data types N_Vector, etc.), we define this function as the single function that IDA always calls. The + * real evaluation of the residual is done by an instance of a subclass of ResidEval, passed in to this + * function as a pointer in the parameters. + * + * FROM IDA WRITEUP -> What the IDA solver expects as a return flag from its residual routines ------ + * A IDAResFn res should return a value of 0 if successful, a positive + * value if a recoverable error occured (e.g. yy has an illegal value), + * or a negative value if a nonrecoverable error occured. In the latter + * case, the program halts. If a recoverable error occured, the integrator + * will attempt to correct and retry. + */ + static int ida_resid(realtype t, N_Vector y, N_Vector ydot, N_Vector r, void *f_data) { + double* ydata = NV_DATA_S(y); + double* ydotdata = NV_DATA_S(ydot); + double* rdata = NV_DATA_S(r); + Cantera::ResidData* d = (Cantera::ResidData*) f_data; + Cantera::ResidJacEval* f = d->m_func; + Cantera::IDA_Solver *s = d->m_solver; + double delta_t = s->getCurrentStepFromIDA(); + // TODO evaluate evalType. Assumed to be Base_ResidEval + int retn = 0; + int flag = f->evalResidNJ(t, delta_t, ydata, ydotdata, rdata); + if (flag < 0) { + // This signals to IDA that a nonrecoverable error has occurred. + retn = flag; } + return retn; + } + + //! Function called by by IDA to evaluate the Jacobian, given y and ydot. + /*! + * + * + * typedef int (*IDADlsDenseJacFn)(int N, realtype t, realtype c_j, + * N_Vector y, N_Vector yp, N_Vector r, + * DlsMat Jac, void *user_data, + * N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + * + * A IDADlsDenseJacFn should return + * 0 if successful, + * a positive int if a recoverable error occurred, or + * a negative int if a nonrecoverable error occurred. + * In the case of a recoverable error return, the integrator will + * attempt to recover by reducing the stepsize (which changes cj). + */ + static int ida_jacobian(int nrows, realtype t, realtype c_j, N_Vector y, N_Vector ydot, N_Vector r, + DlsMat Jac, void *f_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) { + doublereal * ydata = NV_DATA_S(y); + doublereal * ydotdata = NV_DATA_S(ydot); + doublereal * rdata = NV_DATA_S(r); + Cantera::ResidData* d = (Cantera::ResidData*) f_data; + Cantera::ResidJacEval* f = d->m_func; + doublereal * const * colPts = Jac->cols; + Cantera::IDA_Solver *s = d->m_solver; + double delta_t = s->getCurrentStepFromIDA(); + // printf(" delta_t = %g 1/cj = %g\n", delta_t, 1.0/c_j); + f->evalJacobianDP(t, delta_t, c_j, ydata, ydotdata, colPts, rdata); + return 0; + } + } namespace Cantera { - - /** - * Constructor. Default settings: dense jacobian, no user-supplied - * Jacobian function, Newton iteration. - */ - IDA_Solver::IDA_Solver(ResidEval& f) : DAE_Solver(f), - m_neq(0), - m_ida_mem(0), - m_t0(0.0), - m_y(0), - m_ydot(0), - m_abstol(0), - m_type(0), - m_itol(IDA_SS), - m_iter(0), - m_maxord(0), - m_reltol(1.e-9), - m_abstols(1.e-15), - m_nabs(0), - m_hmax(0.0), - m_maxsteps(20000), - m_mupper(0), - m_mlower(0) {} - - - /// Destructor. - IDA_Solver::~IDA_Solver() - { - if (m_ida_mem) { - IDAFree(&m_ida_mem); - } - if (m_y) N_VDestroy_Serial(nv(m_y)); - if (m_ydot) N_VDestroy_Serial(nv(m_ydot)); - if (m_abstol) N_VDestroy_Serial(nv(m_abstol)); - delete m_fdata; + //==================================================================================================================== + /* + * Constructor. Default settings: dense jacobian, no user-supplied + * Jacobian function, Newton iteration. + */ + IDA_Solver::IDA_Solver(ResidJacEval& f) : + DAE_Solver(f), + m_ida_mem(0), + m_t0(0.0), + m_y(0), + m_ydot(0), + m_id(0), + m_constraints(0), + m_abstol(0), + m_type(0), + m_itol(IDA_SS), + m_iter(0), + m_reltol(1.e-9), + m_abstols(1.e-15), + m_nabs(0), + m_hmax(0.0), + m_hmin(0.0), + m_h0(0.0), + m_maxsteps(20000), + m_maxord(0), + m_formJac(0), + m_tstop(0.0), + m_told_old(0.0), + m_told(0.0), + m_tcurrent(0.0), + m_deltat(0.0), + m_maxErrTestFails(-1), + m_maxNonlinIters(0), + m_maxNonlinConvFails(-1), + m_setSuppressAlg(0), + m_fdata(0), + m_mupper(0), + m_mlower(0) + { + } + //==================================================================================================================== + IDA_Solver::~IDA_Solver() + { + if (m_ida_mem) { + IDAFree(&m_ida_mem); } - - doublereal IDA_Solver::solution(int k) const { - return NV_Ith_S(nv(m_y),k); + if (m_y) N_VDestroy_Serial(nv(m_y)); + if (m_ydot) N_VDestroy_Serial(nv(m_ydot)); + if (m_abstol) N_VDestroy_Serial(nv(m_abstol)); + if (m_constraints) N_VDestroy_Serial(nv(m_constraints)); + delete m_fdata; + } + //==================================================================================================================== + doublereal IDA_Solver::solution(int k) const { + return NV_Ith_S(nv(m_y),k); + } + //==================================================================================================================== + const doublereal* IDA_Solver::solutionVector() const { + return NV_DATA_S(nv(m_y)); + } + //==================================================================================================================== + doublereal IDA_Solver::derivative(int k) const { + return NV_Ith_S(nv(m_ydot),k); + } + //==================================================================================================================== + const doublereal* IDA_Solver::derivativeVector() const { + return NV_DATA_S(nv(m_ydot)); + } + //==================================================================================================================== + + void IDA_Solver::setTolerances(double reltol, double* abstol) { + m_itol = IDA_SV; + if (!m_abstol) { + m_abstol = reinterpret_cast(N_VNew_Serial(m_neq)); } - - const doublereal* IDA_Solver::solutionVector() const { return NV_DATA_S(nv(m_y));} - - doublereal IDA_Solver::derivative(int k) const { - return NV_Ith_S(nv(m_ydot),k); + for (int i = 0; i < m_neq; i++) { + NV_Ith_S(nv(m_abstol), i) = abstol[i]; } - - const doublereal* IDA_Solver::derivativeVector() const { return NV_DATA_S(nv(m_ydot));} + m_reltol = reltol; + if (m_ida_mem) { + int flag = IDASVtolerances(m_ida_mem, m_reltol, nv(m_abstol)); + if (flag != IDA_SUCCESS) { + throw IDA_Err("Memory allocation failed."); + } + } + } + //==================================================================================================================== + void IDA_Solver::setTolerances(doublereal reltol, doublereal abstol) { + m_itol = IDA_SS; + m_reltol = reltol; + m_abstols = abstol; + if (m_ida_mem) { + int flag = IDASStolerances(m_ida_mem, m_reltol, m_abstols); + if (flag != IDA_SUCCESS) { + throw IDA_Err("Memory allocation failed."); + } + } + } + //==================================================================================================================== + void IDA_Solver::setLinearSolverType(int solverType) { + m_type = solverType; + } + //==================================================================================================================== + void IDA_Solver::setDenseLinearSolver() { + setLinearSolverType(0); + } + //==================================================================================================================== + void IDA_Solver::setBandedLinearSolver(int m_upper, int m_lower) { + m_type = 2; + m_upper = m_mupper; + m_mlower = m_lower; + } + //==================================================================================================================== + void IDA_Solver::setMaxOrder(int n) { + m_maxord = n; + } + //==================================================================================================================== + void IDA_Solver::setMaxNumSteps(int n) { + m_maxsteps = n; + } + //==================================================================================================================== + void IDA_Solver::setInitialStepSize(doublereal h0) { + m_h0 = h0; + } + //==================================================================================================================== + void IDA_Solver::setStopTime(doublereal tstop) { + m_tstop = tstop; + } + //==================================================================================================================== + doublereal IDA_Solver::getCurrentStepFromIDA() { + doublereal hcur; + IDAGetCurrentStep(m_ida_mem, &hcur); + return hcur; + } + //==================================================================================================================== + void IDA_Solver::setJacobianType(int formJac) { + m_formJac = formJac; + if (m_ida_mem) { + if (m_formJac == 1) { + int flag = IDADlsSetDenseJacFn(m_ida_mem, ida_jacobian); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDADlsSetDenseJacFn failed."); + } + } + } + } + //==================================================================================================================== + void IDA_Solver::setMaxErrTestFailures(int maxErrTestFails) { + m_maxErrTestFails = maxErrTestFails; + } + //==================================================================================================================== + void IDA_Solver::setMaxNonlinIterations(int n) { + m_maxNonlinIters = n; + } + //==================================================================================================================== + void IDA_Solver::setMaxNonlinConvFailures(int n) { + m_maxNonlinConvFails = n; + } + //==================================================================================================================== + void IDA_Solver::inclAlgebraicInErrorTest(bool yesno) { + if (yesno) { + m_setSuppressAlg = 0; + } else { + m_setSuppressAlg = 1; + } + } + //==================================================================================================================== + void IDA_Solver::init(doublereal t0) { - void IDA_Solver::setTolerances(double reltol, double* abstol) { - m_itol = IDA_SV; - if (m_abstol) N_VDestroy_Serial(nv(m_abstol)); - m_abstol = reinterpret_cast(N_VNew_Serial(m_neq)); - for (int i=0; i < m_neq; i++) { - NV_Ith_S(nv(m_abstol), i) = abstol[i]; - } - m_reltol = reltol; + m_t0 = t0; + m_told = t0; + m_told_old = t0; + m_tcurrent = t0; + if (m_y) { + N_VDestroy_Serial(nv(m_y)); + } + if (m_ydot) N_VDestroy_Serial(nv(m_ydot)); + if (m_id) N_VDestroy_Serial(nv(m_id)); + if (m_constraints) N_VDestroy_Serial(nv(m_constraints)); + + m_y = reinterpret_cast(N_VNew_Serial(m_neq)); + m_ydot = reinterpret_cast(N_VNew_Serial(m_neq)); + m_constraints = reinterpret_cast(N_VNew_Serial(m_neq)); + + for (int i=0; i(N_VNew_Serial(m_neq)); - m_ydot = reinterpret_cast(N_VNew_Serial(m_neq)); - m_constraints = reinterpret_cast(N_VNew_Serial(m_neq)); - - for (int i=0; i 0) - // flag = CVodeSetMaxOrd(m_cvode_mem, m_maxord); - //if (m_maxsteps > 0) - // flag = CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps); - //if (m_hmax > 0) - // flag = CVodeSetMaxStep(m_cvode_mem, m_hmax); - } - - void IDA_Solver::solve(double tout) - { - double t; - int flag; - flag = IDASolve(m_ida_mem, tout, &t, nv(m_y), nv(m_ydot), IDA_NORMAL); - if (flag != IDA_SUCCESS) - throw IDA_Err(" IDA error encountered."); - } - - double IDA_Solver::step(double tout) - { - double t; - int flag; - flag = IDASolve(m_ida_mem, tout, &t, nv(m_y), nv(m_ydot), IDA_ONE_STEP); - if (flag != IDA_SUCCESS) - throw IDA_Err(" IDA error encountered."); - return t; + /* Call IDACreate */ + m_ida_mem = IDACreate(); + + int flag = 0; + + + + if (m_itol == IDA_SV) { +#if defined(SUNDIALS_VERSION_22) || defined(SUNDIALS_VERSION_23) + // vector atol + flag = IDAMalloc(m_ida_mem, ida_resid, m_t0, nv(m_y), nv(m_ydot), + m_itol, m_reltol, nv(m_abstol)); + if (flag != IDA_SUCCESS) { + if (flag == IDA_MEM_FAIL) { + throw IDA_Err("Memory allocation failed."); + } else if (flag == IDA_ILL_INPUT) { + throw IDA_Err("Illegal value for IDAMalloc input argument."); + } else + throw IDA_Err("IDAMalloc failed."); } - doublereal IDA_Solver::getOutputParameter(int flag) { - switch (flag) { - case REAL_WORKSPACE_SIZE: - flag = IDAGetWorkSpace(m_ida_mem, &lenrw, &leniw); - return doublereal(lenrw); - } - +#elif defined(SUNDIALS_VERSION_24) + flag = IDAInit(m_ida_mem, ida_resid, m_t0, nv(m_y), nv(m_ydot)); + if (flag != IDA_SUCCESS) { + if (flag == IDA_MEM_FAIL) { + throw IDA_Err("Memory allocation failed."); + } else if (flag == IDA_ILL_INPUT) { + throw IDA_Err("Illegal value for IDAMalloc input argument."); + } + else + throw IDA_Err("IDAMalloc failed."); + } + flag = IDASVtolerances(m_ida_mem, m_reltol, nv(m_abstol)); + if (flag != IDA_SUCCESS) { + throw IDA_Err("Memory allocation failed."); + } +#endif + } + else { +#if defined(SUNDIALS_VERSION_22) || defined(SUNDIALS_VERSION_23) + // scalar atol + flag = IDAMalloc(m_ida_mem, ida_resid, m_t0, nv(m_y), nv(m_ydot), + m_itol, m_reltol, &m_abstols); + if (flag != IDA_SUCCESS) { + if (flag == IDA_MEM_FAIL) { + throw IDA_Err("Memory allocation failed."); } + else if (flag == IDA_ILL_INPUT) { + throw IDA_Err("Illegal value for IDAMalloc input argument."); + } + else + throw IDA_Err("IDAMalloc failed."); + } + +#elif defined(SUNDIALS_VERSION_24) + flag = IDAInit(m_ida_mem, ida_resid, m_t0, nv(m_y), nv(m_ydot)); + if (flag != IDA_SUCCESS) { + if (flag == IDA_MEM_FAIL) { + throw IDA_Err("Memory allocation failed."); } + else if (flag == IDA_ILL_INPUT) { + throw IDA_Err("Illegal value for IDAMalloc input argument."); + } + else + throw IDA_Err("IDAMalloc failed."); + } + flag = IDASStolerances(m_ida_mem, m_reltol, m_abstols); + if (flag != IDA_SUCCESS) { + throw IDA_Err("Memory allocation failed."); + } +#endif + } + + //----------------------------------- + // set the linear solver type + //----------------------------------- + + if (m_type == 1 || m_type == 0) { + long int N = m_neq; + flag = IDADense(m_ida_mem, N); + if (flag) { + throw IDA_Err("IDADense failed"); + } + } + else if (m_type == 2) { + long int N = m_neq; + long int nu = m_mupper; + long int nl = m_mlower; + IDABand(m_ida_mem, N, nu, nl); + } + else { + throw IDA_Err("unsupported linear solver type"); + } + + if (m_formJac == 1) { + flag = IDADlsSetDenseJacFn(m_ida_mem, ida_jacobian); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDADlsSetDenseJacFn failed."); + } + } + + // pass a pointer to func in m_data + m_fdata = new ResidData(&m_resid, this, m_resid.nparams()); +#if defined(SUNDIALS_VERSION_22) || defined(SUNDIALS_VERSION_23) + flag = IDASetRdata(m_ida_mem, (void*)m_fdata); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetRdata failed."); + } +#elif defined(SUNDIALS_VERSION_24) + flag = IDASetUserData(m_ida_mem, (void*)m_fdata); + if (flag != IDA_SUCCESS) + throw IDA_Err("IDASetUserData failed."); +#endif + + // set options + if (m_maxord > 0) { + flag = IDASetMaxOrd(m_ida_mem, m_maxord); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetMaxOrd failed."); + } + } + if (m_maxsteps > 0) { + flag = IDASetMaxNumSteps(m_ida_mem, m_maxsteps); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetMaxNumSteps failed."); + } + } + if (m_h0 > 0.0) { + flag = IDASetInitStep(m_ida_mem, m_h0); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetInitStep failed."); + } + } + if (m_tstop > 0.0) { + flag = IDASetStopTime(m_ida_mem, m_tstop); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetStopTime failed."); + } + } + if (m_maxErrTestFails >= 0) { + flag = IDASetMaxErrTestFails(m_ida_mem, m_maxErrTestFails); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetMaxErrTestFails failed."); + } + } + if (m_maxNonlinIters > 0) { + flag = IDASetMaxNonlinIters(m_ida_mem, m_maxNonlinIters); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetmaxNonlinIters failed."); + } + } + if (m_maxNonlinConvFails >= 0) { + flag = IDASetMaxConvFails(m_ida_mem, m_maxNonlinConvFails); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetMaxConvFails failed."); + } + } + if (m_setSuppressAlg != 0) { + flag = IDASetSuppressAlg(m_ida_mem, m_setSuppressAlg); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDASetSuppressAlg failed."); + } + } + + + + } + //==================================================================================================================== + // Calculate consistent value of the starting solution given the starting solution derivatives + /* + * This method may be called if the initial conditions do not + * satisfy the residual equation F = 0. Given the derivatives + * of all variables, this method computes the initial y + * values. + */ + void IDA_Solver::correctInitial_Y_given_Yp(doublereal* y, doublereal* yp, doublereal tout) { + int icopt = IDA_Y_INIT; + doublereal tout1 = tout; + if (tout == 0.0) { + double h0 = 1.0E-5; + if (m_h0 > 0.0) { + h0 = m_h0; + } + tout1 = m_t0 + h0; + } + + int flag = IDACalcIC(m_ida_mem, icopt, tout1); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDACalcIC failed: error = " + int2str(flag)); + } + + + flag = IDAGetSolution(m_ida_mem, tout1, nv(m_y), nv(m_ydot)); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDAGetSolution failed: error = " + int2str(flag)); + } + doublereal *yy = NV_DATA_S(nv(m_y)); + doublereal *yyp = NV_DATA_S(nv(m_ydot)); + + for (int i = 0; i < m_neq; i++) { + y[i] = yy[i]; + yp[i] = yyp[i]; + } + } + //==================================================================================================================== + /* + * This method may be called if the initial conditions do not + * satisfy the residual equation F = 0. Given the initial + * values of all differential variables, it computes the + * initial values of all algebraic variables and the initial + * derivatives of all differential variables. + * + * @param y Calculated value of the solution vector after the procedure ends + * @param yp Calculated value of the solution derivative after the procedure + * @param The first value of t at which a soluton will be + * requested (from IDASolve). (This is needed here to + * determine the direction of integration and rough scale + * in the independent variable t. + */ + void IDA_Solver::correctInitial_YaYp_given_Yd(doublereal* y, doublereal* yp, doublereal tout) { + + int icopt = IDA_YA_YDP_INIT; + doublereal tout1 = tout; + if (tout == 0.0) { + double h0 = 1.0E-5; + if (m_h0 > 0.0) { + h0 = m_h0; + } + tout1 = m_t0 + h0; + } + + int flag = IDACalcIC(m_ida_mem, icopt, tout1); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDACalcIC failed: error = " + int2str(flag)); + } + + + flag = IDAGetSolution(m_ida_mem, tout1, nv(m_y), nv(m_ydot)); + if (flag != IDA_SUCCESS) { + throw IDA_Err("IDAGetSolution failed: error = " + int2str(flag)); + } + doublereal *yy = NV_DATA_S(nv(m_y)); + doublereal *yyp = NV_DATA_S(nv(m_ydot)); + + for (int i = 0; i < m_neq; i++) { + y[i] = yy[i]; + yp[i] = yyp[i]; + } + } + //==================================================================================================================== + int IDA_Solver::solve(double tout) + { + double tretn; + int flag; + flag = IDASetStopTime(m_ida_mem, tout); + if (flag != IDA_SUCCESS) { + throw IDA_Err(" IDA error encountered."); + } + do { + if (tout <= m_tcurrent) { + throw IDA_Err(" tout <= tcurrent"); + } + m_told_old = m_told; + m_told = m_tcurrent; + flag = IDASolve(m_ida_mem, tout, &tretn, nv(m_y), nv(m_ydot), IDA_ONE_STEP); + if (flag < 0) { + throw IDA_Err(" IDA error encountered."); + } else if (flag == IDA_TSTOP_RETURN) { + // we've reached our goal, and have actually integrated past it + } else if (flag == IDA_ROOT_RETURN) { + // not sure what to do with this yet + } else if (flag == IDA_WARNING) { + throw IDA_Err(" IDA Warning encountered."); + } + m_tcurrent = tretn; + m_deltat = m_tcurrent - m_told; + } while (tretn < tout); + + if (flag != IDA_SUCCESS && flag != IDA_TSTOP_RETURN) { + throw IDA_Err(" IDA error encountered."); + } + return flag; + } + //==================================================================================================================== + double IDA_Solver::step(double tout) + { + double t; + int flag; + if (tout <= m_tcurrent) { + throw IDA_Err(" tout <= tcurrent"); + } + m_told_old = m_told; + m_told = m_tcurrent; + flag = IDASolve(m_ida_mem, tout, &t, nv(m_y), nv(m_ydot), IDA_ONE_STEP); + if (flag < 0) { + throw IDA_Err(" IDA error encountered."); + } else if (flag == IDA_TSTOP_RETURN) { + // we've reached our goal, and have actually integrated past it + } else if (flag == IDA_ROOT_RETURN) { + // not sure what to do with this yet + } else if (flag == IDA_WARNING) { + throw IDA_Err(" IDA Warning encountered."); + } + m_tcurrent = t; + m_deltat = m_tcurrent - m_told; + return t; + } + //==================================================================================================================== + doublereal IDA_Solver::getOutputParameter(int flag) const { + long int lenrw, leniw; + switch (flag) { + case REAL_WORKSPACE_SIZE: + flag = IDAGetWorkSpace(m_ida_mem, &lenrw, &leniw); + return doublereal(lenrw); + break; + } + return 0.0; + } + //==================================================================================================================== + } - - +#endif diff --git a/Cantera/src/numerics/IDA_Solver.h b/Cantera/src/numerics/IDA_Solver.h index 59546d991..7102c58ad 100644 --- a/Cantera/src/numerics/IDA_Solver.h +++ b/Cantera/src/numerics/IDA_Solver.h @@ -13,123 +13,346 @@ * */ -#ifndef CT_IDA_Solver_H -#define CT_IDA_Solver_H +#ifndef CT_IDA_SOLVER_H +#define CT_IDA_SOLVER_H #include #include "DAE_Solver.h" #include "ctexceptions.h" +#ifdef HAS_SUNDIALS + +#ifdef SUNDIALS_VERSION_22 +#include +#else +#include + +// These constants are defined internally in the ida package, ida.c +#define IDA_NN 0 +#define IDA_SS 1 +#define IDA_SV 2 +#define IDA_WF 3 + +#endif +#if defined(SUNDIALS_VERSION_24) +#define REAL_WORKSPACE_SIZE 0 +#endif + namespace Cantera { - /** - * Exception thrown when a IDA error is encountered. + /** + * Exception thrown when a IDA error is encountered. + */ + class IDA_Err : public CanteraError { + public: + IDA_Err(std::string msg) : CanteraError("IDA_Solver", msg){} + }; + + + class ResidData; // forward reference + + class IDA_Solver : public DAE_Solver { + public: + + //! Constructor. + /*! + * Default settings: dense jacobian, no user-supplied Jacobian function, Newton iteration. + * + * @param f Function that will supply the time dependent residual to be solved */ - class IDA_Err : public CanteraError { - public: - IDA_Err(std::string msg) : CanteraError("IDA_Solver", msg){} - }; + IDA_Solver(ResidJacEval& f); + + virtual ~IDA_Solver(); + + /** + * Set error tolerances. This version specifies a scalar + * relative tolerance, and a vector absolute tolerance. + */ + virtual void setTolerances(doublereal reltol, + doublereal* abstol); + + /** + * Set error tolerances. This version specifies a scalar + * relative tolerance, and a scalar absolute tolerance. + */ + virtual void setTolerances(doublereal reltol, doublereal abstol); + + virtual void setLinearSolverType(int solverType); + + //! Set up the problem to use a dense linear direct solver + virtual void setDenseLinearSolver(); + + //! Set up the problem to use a band solver + /*! + * @param m_upper upper band width of the matrix + * @param m_lower lower band width of the matrix + */ + virtual void setBandedLinearSolver(int m_upper, int m_lower); + + virtual void setMaxOrder(int n); + + //! Set the maximum number of time steps + /*! + * @param n input of maximum number of time steps + */ + virtual void setMaxNumSteps(int n); + + //! Sset the initial step size + /*! + * @param h0 initial step size value + */ + virtual void setInitialStepSize(doublereal h0); + + //! Set the stop time + /*! + * @param tstop the independent variable value past which the solution is not to proceed. + */ + virtual void setStopTime(doublereal tstop); + + //! Get the current step size from IDA via a call + /*! + * @return Returns the current step size. + */ + virtual double getCurrentStepFromIDA(); - class ResidData; // forward reference - - class IDA_Solver : public DAE_Solver { - public: - - IDA_Solver(ResidEval& f); - - virtual ~IDA_Solver(); - - /** - * Set error tolerances. This version specifies a scalar - * relative tolerance, and a vector absolute tolerance. - */ - virtual void setTolerances(doublereal reltol, - doublereal* abstol); - - /** - * Set error tolerances. This version specifies a scalar - * relative tolerance, and a scalar absolute tolerance. - */ - virtual void setTolerances(doublereal reltol, doublereal abstol); - - virtual void setLinearSolverType(int solverType); - - virtual void setDenseLinearSolver(); - virtual void setBandedLinearSolver(int m_upper, int m_lower); - - virtual void setMaxTime(doublereal tmax); - - virtual void setMaxOrder(int n); - - virtual void setMaxNumSteps(int n); - virtual void setInitialStepSize(doublereal h0); - virtual void setStopTime(doublereal tstop); - virtual void setMaxErrTestFailures(int n); - virtual void setMaxNonlinIterations(int n); - virtual void setMaxNonlinConvFailures(int n); - virtual void inclAlgebraicInErrorTest(bool yesno); - - virtual void setInputParameter(int flag, doublereal value); - virtual doublereal getOutputParameter(int flag); + //! Set the form of the jacobian + /*! + * + * @param formJac Form of the jacobian + * + * 0 numerical jacobian + * 1 analytical jacobian given by the evalJacobianDP() function + */ + virtual void setJacobianType(int formJac); - /** - * This method may be called if the initial conditions do not - * satisfy the residual equation F = 0. Given the derivatives - * of all variables, this method computes the initial y - * values. - */ - virtual void correctInitial_Y_given_Yp(doublereal* y, doublereal* yp, - doublereal tout); + virtual void setMaxErrTestFailures(int n); - /** - * This method may be called if the initial conditions do not - * satisfy the residual equation F = 0. Given the initial - * values of all differential variables, it computes the - * initial values of all algebraic variables and the initial - * derivatives of all differential variables. - */ - virtual void correctInitial_YaYp_given_Yd(doublereal* y, doublereal* yp, - doublereal tout); + //! Set the maximum number of nonlinear iterations on a timestep + /*! + * @param n Set the max iterations. The default is 4, which seems awefully low to me. + */ + virtual void setMaxNonlinIterations(int n); + + //! Set the maximum number of nonlinear solver convergence failures + /*! + * @param n Value of nonlin failures. If value is exceeded, the calculation terminates. + */ + virtual void setMaxNonlinConvFailures(int n); - virtual int solve(doublereal tout); + virtual void inclAlgebraicInErrorTest(bool yesno); - virtual doublereal step(doublereal tout); + /** + * Get the value of a solver-specific output parameter. + */ + virtual doublereal getOutputParameter(int flag) const; - virtual void init(doublereal t0); + //! Calculate consistent value of the starting solution given the starting solution derivatives + /*! + * This method may be called if the initial conditions do not + * satisfy the residual equation F = 0. Given the derivatives + * of all variables, this method computes the initial y + * values. + */ + virtual void correctInitial_Y_given_Yp(doublereal* y, doublereal* yp, + doublereal tout); - /// the current value of solution component k. - virtual doublereal solution(int k) const; + //! Calculate consistent value of the algebraic constraints and derivatives at the start of the problem + /*! + * This method may be called if the initial conditions do not + * satisfy the residual equation F = 0. Given the initial + * values of all differential variables, it computes the + * initial values of all algebraic variables and the initial + * derivatives of all differential variables. + */ + virtual void correctInitial_YaYp_given_Yd(doublereal* y, doublereal* yp, doublereal tout); + + //! Step the system to a final value of the time + /*! + * @param tout Final value of the time + * + * @return Returns the IDASolve() return flag + * + * The return values for IDASolve are described below. + * (The numerical return values are defined above in this file.) + * All unsuccessful returns give a negative return value. + * + * IDA_SUCCESS + * IDASolve succeeded and no roots were found. + * + * IDA_ROOT_RETURN: IDASolve succeeded, and found one or more roots. + * If nrtfn > 1, call IDAGetRootInfo to see which g_i were found + * to have a root at (*tret). + * + * IDA_TSTOP_RETURN: + * IDASolve returns computed results for the independent variable + * value tstop. That is, tstop was reached. + * + * IDA_MEM_NULL: + * The IDA_mem argument was NULL. + * + * IDA_ILL_INPUT: + * One of the inputs to IDASolve is illegal. This includes the + * situation when a component of the error weight vectors + * becomes < 0 during internal stepping. It also includes the + * situation where a root of one of the root functions was found + * both at t0 and very near t0. The ILL_INPUT flag + * will also be returned if the linear solver function IDA--- + * (called by the user after calling IDACreate) failed to set one + * of the linear solver-related fields in ida_mem or if the linear + * solver's init routine failed. In any case, the user should see + * the printed error message for more details. + * + * + * IDA_TOO_MUCH_WORK: + * The solver took mxstep internal steps but could not reach tout. + * The default value for mxstep is MXSTEP_DEFAULT = 500. + * + * IDA_TOO_MUCH_ACC: + * The solver could not satisfy the accuracy demanded by the user + * for some internal step. + * + * IDA_ERR_FAIL: + * Error test failures occurred too many times (=MXETF = 10) during + * one internal step. + * + * IDA_CONV_FAIL: + * Convergence test failures occurred too many times (= MXNCF = 10) + * during one internal step. + * + * IDA_LSETUP_FAIL: + * The linear solver's setup routine failed + * in an unrecoverable manner. + * + * IDA_LSOLVE_FAIL: + * The linear solver's solve routine failed + * in an unrecoverable manner. + * + * IDA_CONSTR_FAIL: + * The inequality constraints were violated, + * and the solver was unable to recover. + * + * IDA_REP_RES_ERR: + * The user's residual function repeatedly returned a recoverable + * error flag, but the solver was unable to recover. + * + * IDA_RES_FAIL: + * The user's residual function returned a nonrecoverable error + * flag. + * + */ + virtual int solve(doublereal tout); - virtual const doublereal* solutionVector() const; + virtual doublereal step(doublereal tout); - /// the current value of the derivative of solution component k. - virtual doublereal derivative(int k) const; + virtual void init(doublereal t0); - virtual const doublereal* derivativeVector() const; + //! the current value of solution component k. + /*! + * @param k index of the solution + */ + virtual doublereal solution(int k) const; - protected: + virtual const doublereal* solutionVector() const; - int m_neq; - void* m_ida_mem; - doublereal m_t0; - void *m_y, *m_ydot, *m_id, *m_constraints, *m_abstol; - int m_type; - int m_itol; - int m_iter; - doublereal m_reltol; - doublereal m_abstols; - int m_nabs; - doublereal m_hmax, m_hmin; - int m_maxsteps, m_maxord; - ResidData* m_fdata; - int m_mupper, m_mlower; - }; + //! the current value of the derivative of solution component k. + virtual doublereal derivative(int k) const; + + virtual const doublereal* derivativeVector() const; + + void *IDAMemory() { + return m_ida_mem; + } + + protected: + + //! Pointer to the IDA memory for the problem + void* m_ida_mem; + + //! Initial value of the time + doublereal m_t0; + + //! Current value of the solution vector + void *m_y; + + //! Current value of the derivative of the solution vector + void *m_ydot; + void *m_id; + void *m_constraints; + void *m_abstol; + int m_type; + + + int m_itol; + int m_iter; + doublereal m_reltol; + doublereal m_abstols; + int m_nabs; + + //! Maximum value of the timestep allowed + doublereal m_hmax; + + //! Minimum value of the timestep allowd + doublereal m_hmin; + + //! Value of the initial time step + doublereal m_h0; + + //! Maximum number of time steps allowed + int m_maxsteps; + + //! maximum time step order of the method + int m_maxord; + + //! Form of the jacobian + /*! + * 0 numerical jacobian created by ida + * 1 analytical jacobian. Must have populated the evalJacobianDP() + * function in the ResidJacEval class. + * 2 numerical jacobian formed by the ResidJacEval class (unimplemented) + */ + int m_formJac; + + //! maximum time + doublereal m_tstop; + + //! Value of the previous, previous time + doublereal m_told_old; + + //! Value of the previous time + doublereal m_told; + + //! Value of the current time + doublereal m_tcurrent; + + //! Value of deltaT for the current step + doublereal m_deltat; + + //! maximum number of error test failures + int m_maxErrTestFails; + + //! Maximum number of nonlinear solver iterations at one solution + /*! + * If zero, this is the default of 4. + */ + int m_maxNonlinIters; + + //! Maximum number of nonlinear convergence failures + int m_maxNonlinConvFails; + + //! If true, the algebraic variables don't contribute to error tolerances + int m_setSuppressAlg; + + ResidData* m_fdata; + int m_mupper; + int m_mlower; + }; } #endif +#endif diff --git a/Cantera/src/numerics/Integrator.h b/Cantera/src/numerics/Integrator.h index 6b498dc0a..be04bc2d4 100644 --- a/Cantera/src/numerics/Integrator.h +++ b/Cantera/src/numerics/Integrator.h @@ -1,7 +1,8 @@ /** * @file Integrator.h - * - * $Author$ + */ + +/* $Author$ * $Date$ * $Revision$ * @@ -46,18 +47,20 @@ namespace Cantera { Adams_Method /**< Adams */ }; - /** - * Specifies the method used for iteration. + //! Specifies the method used for iteration. + /*! * Not all methods are supported by all integrators. */ enum IterType { - Newton_Iter, /**< Newton iteration */ - Functional_Iter /**< Functional iteration */ + //! Newton Iteration + Newton_Iter, + //! Functional Iteration + Functional_Iter }; - /** - * Abstract base class for ODE system integrators. + //! Abstract base class for ODE system integrators. + /*! * @ingroup odeGroup */ class Integrator { @@ -76,8 +79,8 @@ namespace Cantera { /** Set or reset the number of equations. */ //virtual void resize(int n)=0; - /** - * Set error tolerances. + //! Set error tolerances. + /*! * @param reltol scalar relative tolerance * @param number of equations * @param abstol array of N absolute tolerance values @@ -95,13 +98,20 @@ namespace Cantera { virtual void setTolerances(doublereal reltol, doublereal abstol) { warn("setTolerances"); } - virtual void setSensitivityTolerances(doublereal reltol, doublereal abstol) - {}// { warn("setSensitivityTolerances"); } - - /** - * Set problem type. + //! Set the sensitvity error tolerances + /*! + * @param reltol scalar relative tolerance + * @param abstol scalar absolute tolerance */ - virtual void setProblemType(int probtype) { warn("setProblemType"); } + virtual void setSensitivityTolerances(doublereal reltol, doublereal abstol) + { } + + //! Set the problem type. + /*! + * @param probtype Type of the problem + */ + virtual void setProblemType(int probtype) + { warn("setProblemType"); } /** * Initialize the integrator for a new problem. Call after @@ -115,10 +125,10 @@ namespace Cantera { virtual void reinitialize(doublereal t0, FuncEval& func) { warn("reinitialize"); } - /** - * Integrate the system of equations. - * @param tout integrate to this time. Note that this is the - * absolute time value, not a time interval. + //! Integrate the system of equations. + /*! + * @param tout Integrate to this time. Note that this is the + * absolute time value, not a time interval. */ virtual void integrate(doublereal tout) { warn("integrate"); } diff --git a/Cantera/src/numerics/Makefile.in b/Cantera/src/numerics/Makefile.in index bffd2a159..e83028c68 100644 --- a/Cantera/src/numerics/Makefile.in +++ b/Cantera/src/numerics/Makefile.in @@ -30,17 +30,21 @@ PURIFY=@PURIFY@ PIC_FLAG=@PIC@ +#LOCAL_DEFS=-DDEBUG_DOGLEG + CXX_FLAGS = @CXXFLAGS@ $(LOCAL_DEFS) $(CXX_OPT) $(PIC_FLAG) $(DEBUG_FLAG) NUMERICS_OBJ = DenseMatrix.o funcs.o Func1.o \ ODE_integrators.o BandMatrix.o DAE_solvers.o \ - funcs.o sort.o SquareMatrix.o ResidJacEval.o NonlinearSolver.o + funcs.o sort.o SquareMatrix.o ResidJacEval.o NonlinearSolver.o \ + solveProb.o BEulerInt.o RootFind.o IDA_Solver.o GeneralMatrix.o NUMERICS_H = ArrayViewer.h DenseMatrix.h \ funcs.h ctlapack.h Func1.h FuncEval.h \ polyfit.h\ BandMatrix.h Integrator.h DAE_Solver.h ResidEval.h sort.h \ - SquareMatrix.h ResidJacEval.h NonlinearSolver.h + SquareMatrix.h ResidJacEval.h NonlinearSolver.h \ + solveProb.h BEulerInt.h RootFind.h IDA_Solver.h GeneralMatrix.h ifeq ($(use_sundials), 1) ODEPACKAGE_H = CVodesIntegrator.h diff --git a/Cantera/src/numerics/NonlinearSolver.cpp b/Cantera/src/numerics/NonlinearSolver.cpp index caae05959..a79765aa4 100644 --- a/Cantera/src/numerics/NonlinearSolver.cpp +++ b/Cantera/src/numerics/NonlinearSolver.cpp @@ -19,44 +19,51 @@ #include #include "SquareMatrix.h" +#include "GeneralMatrix.h" #include "NonlinearSolver.h" +#include "ctlapack.h" #include "clockWC.h" #include "vec_functions.h" -#include - #include "mdp_allo.h" + #include - -extern void print_line(const char *, int); - +#include #include #include #include +//@{ +extern void print_line(const char *, int); #ifndef MAX #define MAX(x,y) (( (x) > (y) ) ? (x) : (y)) #define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) #endif +#ifndef CONSTD_DATA_PTR +#define CONSTD_DATA_PTR(x) (( const doublereal *) (&x[0])) +#endif +//@} using namespace std; namespace Cantera { - + //==================================================================================================================== //----------------------------------------------------------- // Constants //----------------------------------------------------------- - - const double DampFactor = 4; + //! Dampfactor is the factor by which the damping factor is reduced by when a reduction in step length is warranted + const doublereal DampFactor = 4.0; + //! Number of damping steps that are carried out before the solution is deemed a failure const int NDAMP = 7; - - //----------------------------------------------------------- - // Static Functions - //----------------------------------------------------------- - + //==================================================================================================================== + //! Print a line of a single repeated character string + /*! + * @param str Character string + * @param n Iteration length + */ static void print_line(const char *str, int n) { for (int i = 0; i < n; i++) { printf("%s", str); @@ -64,13 +71,64 @@ namespace Cantera { printf("\n"); } + bool NonlinearSolver::s_TurnOffTiming(false); + +#ifdef DEBUG_NUMJAC + bool NonlinearSolver::s_print_NumJac(true); +#else + bool NonlinearSolver::s_print_NumJac(false); +#endif + + // Turn off printing of dogleg information + bool NonlinearSolver::s_print_DogLeg(false); + + // Turn off solving the system twice and comparing the answer. + /* + * Turn this on if you want to compare the Hessian and Newton solve results. + */ + bool NonlinearSolver::s_doBothSolvesAndCompare(false); + + // This toggle turns off the use of the Hessian when it is warranted by the condition number. + /* + * This is a debugging option. + */ + bool NonlinearSolver::s_alwaysAssumeNewtonGood(false); + + //==================================================================================================================== // Default constructor /* * @param func Residual and jacobian evaluator function object */ NonlinearSolver::NonlinearSolver(ResidJacEval *func) : m_func(func), + solnType_(NSOLN_TYPE_STEADY_STATE), neq_(0), + m_ewt(0), + m_manualDeltaStepSet(0), + m_deltaStepMinimum(0), + m_y_n_curr(0), + m_ydot_n_curr(0), + m_y_nm1(0), + m_y_n_1(0), + m_ydot_n_1(0), + m_colScales(0), + m_rowScales(0), + m_rowWtScales(0), + m_resid(0), + m_wksp(0), + m_wksp_2(0), + m_residWts(0), + m_normResid_0(0.0), + m_normResid_Bound(0.0), + m_normResid_1(0.0), + m_normDeltaSoln_Newton(0.0), + m_normDeltaSoln_CP(0.0), + m_normResidTrial(0.0), + m_resid_scaled(false), + m_y_high_bounds(0), + m_y_low_bounds(0), + m_dampBound(1.0), + m_dampRes(1.0), delta_t_n(-1.0), m_nfe(0), m_colScaling(0), @@ -78,23 +136,76 @@ namespace Cantera { m_numTotalLinearSolves(0), m_numTotalNewtIts(0), m_min_newt_its(0), - filterNewstep(0), + maxNewtIts_(100), + m_jacFormMethod(NSOLN_JAC_NUM), + m_nJacEval(0), time_n(0.0), m_matrixConditioning(0), m_order(1), rtol_(1.0E-3), - atolBase_(1.0E-10) + atolBase_(1.0E-10), + m_ydot_nm1(0), + atolk_(0), + userResidAtol_(0), + userResidRtol_(1.0E-3), + checkUserResidualTols_(0), + m_print_flag(0), + m_ScaleSolnNormToResNorm(0.001), + jacCopyPtr_(0), + HessianPtr_(0), + deltaX_CP_(0), + deltaX_Newton_(0), + residNorm2Cauchy_(0.0), + dogLegID_(0), + dogLegAlpha_(1.0), + RJd_norm_(0.0), + lambdaStar_(0.0), + Jd_(0), + deltaX_trust_(0), + norm_deltaX_trust_(0.0), + trustDelta_(1.0), + trustRegionInitializationMethod_(2), + trustRegionInitializationFactor_(1.0), + Nuu_(0.0), + dist_R0_(0.0), + dist_R1_(0.0), + dist_R2_(0.0), + dist_Total_(0.0), + JdJd_norm_(0.0), + normTrust_Newton_(0.0), + normTrust_CP_(0.0), + doDogLeg_(0), + doAffineSolve_(0) , + CurrentTrustFactor_(1.0), + NextTrustFactor_ (1.0), + ResidWtsReevaluated_(false), + ResidDecreaseSDExp_(0.0), + ResidDecreaseSD_(0.0), + ResidDecreaseNewtExp_(0.0), + ResidDecreaseNewt_(0.0) { neq_ = m_func->nEquations(); m_ewt.resize(neq_, rtol_); - m_y_n.resize(neq_, 0.0); + m_deltaStepMinimum.resize(neq_, 0.001); + m_deltaStepMaximum.resize(neq_, 1.0E10); + m_y_n_curr.resize(neq_, 0.0); + m_ydot_n_curr.resize(neq_, 0.0); m_y_nm1.resize(neq_, 0.0); + m_y_n_1.resize(neq_, 0.0); + m_ydot_n_1.resize(neq_, 0.0); m_colScales.resize(neq_, 1.0); m_rowScales.resize(neq_, 1.0); + m_rowWtScales.resize(neq_, 1.0); m_resid.resize(neq_, 0.0); + m_wksp.resize(neq_, 0.0); + m_wksp_2.resize(neq_, 0.0); + m_residWts.resize(neq_, 0.0); atolk_.resize(neq_, atolBase_); - doublereal hb = std::numeric_limits::max(); + deltaX_Newton_.resize(neq_, 0.0); + m_step_1.resize(neq_, 0.0); + m_y_n_1.resize(neq_, 0.0); + doublereal hb = std::numeric_limits::max(); m_y_high_bounds.resize(neq_, hb); m_y_low_bounds.resize(neq_, -hb); @@ -102,16 +213,114 @@ namespace Cantera { atolk_[i] = atolBase_; m_ewt[i] = atolk_[i]; } - } - NonlinearSolver::NonlinearSolver(const NonlinearSolver &right) { + + // jacCopyPtr_->resize(neq_, 0.0); + deltaX_CP_.resize(neq_, 0.0); + Jd_.resize(neq_, 0.0); + deltaX_trust_.resize(neq_, 1.0); + + } + //==================================================================================================================== + NonlinearSolver::NonlinearSolver(const NonlinearSolver &right) : + m_func(right.m_func), + solnType_(NSOLN_TYPE_STEADY_STATE), + neq_(0), + m_ewt(0), + m_manualDeltaStepSet(0), + m_deltaStepMinimum(0), + m_y_n_curr(0), + m_ydot_n_curr(0), + m_y_nm1(0), + m_y_n_1(0), + m_ydot_n_1(0), + m_step_1(0), + m_colScales(0), + m_rowScales(0), + m_rowWtScales(0), + m_resid(0), + m_wksp(0), + m_wksp_2(0), + m_residWts(0), + m_normResid_0(0.0), + m_normResid_Bound(0.0), + m_normResid_1(0.0), + m_normDeltaSoln_Newton(0.0), + m_normDeltaSoln_CP(0.0), + m_normResidTrial(0.0), + m_resid_scaled(false), + m_y_high_bounds(0), + m_y_low_bounds(0), + m_dampBound(1.0), + m_dampRes(1.0), + delta_t_n(-1.0), + m_nfe(0), + m_colScaling(0), + m_rowScaling(0), + m_numTotalLinearSolves(0), + m_numTotalNewtIts(0), + m_min_newt_its(0), + maxNewtIts_(100), + m_jacFormMethod(NSOLN_JAC_NUM), + m_nJacEval(0), + time_n(0.0), + m_matrixConditioning(0), + m_order(1), + rtol_(1.0E-3), + atolBase_(1.0E-10), + m_ydot_nm1(0), + atolk_(0), + userResidAtol_(0), + userResidRtol_(1.0E-3), + checkUserResidualTols_(0), + m_print_flag(0), + m_ScaleSolnNormToResNorm(0.001), + jacCopyPtr_(0), + HessianPtr_(0), + deltaX_CP_(0), + deltaX_Newton_(0), + residNorm2Cauchy_(0.0), + dogLegID_(0), + dogLegAlpha_(1.0), + RJd_norm_(0.0), + lambdaStar_(0.0), + Jd_(0), + deltaX_trust_(0), + norm_deltaX_trust_(0.0), + trustDelta_(1.0), + trustRegionInitializationMethod_(2), + trustRegionInitializationFactor_(1.0), + Nuu_(0.0), + dist_R0_(0.0), + dist_R1_(0.0), + dist_R2_(0.0), + dist_Total_(0.0), + JdJd_norm_(0.0), + normTrust_Newton_(0.0), + normTrust_CP_(0.0), + doDogLeg_(0), + doAffineSolve_(0), + CurrentTrustFactor_(1.0), + NextTrustFactor_ (1.0), + ResidWtsReevaluated_(false), + ResidDecreaseSDExp_(0.0), + ResidDecreaseSD_(0.0), + ResidDecreaseNewtExp_(0.0), + ResidDecreaseNewt_(0.0) + { *this =operator=(right); } - + //==================================================================================================================== NonlinearSolver::~NonlinearSolver() { + if (jacCopyPtr_) { + delete jacCopyPtr_; + } + if (HessianPtr_) { + delete HessianPtr_; + } } - + //==================================================================================================================== NonlinearSolver& NonlinearSolver::operator=(const NonlinearSolver &right) { if (this == &right) { return *this; @@ -120,15 +329,35 @@ namespace Cantera { // create a deep copy m_func = right.m_func->duplMyselfAsResidJacEval(); + solnType_ = right.solnType_; neq_ = right.neq_; m_ewt = right.m_ewt; - m_y_n = right.m_y_n; + m_manualDeltaStepSet = right.m_manualDeltaStepSet; + m_deltaStepMinimum = right.m_deltaStepMinimum; + m_y_n_curr = right.m_y_n_curr; + m_ydot_n_curr = right.m_ydot_n_curr; m_y_nm1 = right.m_y_nm1; + m_y_n_1 = right.m_y_n_1; + m_ydot_n_1 = right.m_ydot_n_1; + m_step_1 = right.m_step_1; m_colScales = right.m_colScales; m_rowScales = right.m_rowScales; + m_rowWtScales = right.m_rowWtScales; m_resid = right.m_resid; + m_wksp = right.m_wksp; + m_wksp_2 = right.m_wksp_2; + m_residWts = right.m_residWts; + m_normResid_0 = right.m_normResid_0; + m_normResid_Bound = right.m_normResid_Bound; + m_normResid_1 = right.m_normResid_1; + m_normDeltaSoln_Newton = right.m_normDeltaSoln_Newton; + m_normDeltaSoln_CP = right.m_normDeltaSoln_CP; + m_normResidTrial = right.m_normResidTrial; + m_resid_scaled = right.m_resid_scaled; m_y_high_bounds = right.m_y_high_bounds; m_y_low_bounds = right.m_y_low_bounds; + m_dampBound = right.m_dampBound; + m_dampRes = right.m_dampRes; delta_t_n = right.delta_t_n; m_nfe = right.m_nfe; m_colScaling = right.m_colScaling; @@ -136,17 +365,65 @@ namespace Cantera { m_numTotalLinearSolves = right.m_numTotalLinearSolves; m_numTotalNewtIts = right.m_numTotalNewtIts; m_min_newt_its = right.m_min_newt_its; - filterNewstep = right.filterNewstep; + maxNewtIts_ = right.maxNewtIts_; + m_jacFormMethod = right.m_jacFormMethod; + m_nJacEval = right.m_nJacEval; time_n = right.time_n; m_matrixConditioning = right.m_matrixConditioning; m_order = right.m_order; rtol_ = right.rtol_; atolBase_ = right.atolBase_; atolk_ = right.atolk_; + userResidAtol_ = right.userResidAtol_; + userResidRtol_ = right.userResidRtol_; + checkUserResidualTols_ = right.checkUserResidualTols_; + m_print_flag = right.m_print_flag; + m_ScaleSolnNormToResNorm = right.m_ScaleSolnNormToResNorm; + + if (jacCopyPtr_) { + delete (jacCopyPtr_); + } + jacCopyPtr_ = (right.jacCopyPtr_)->duplMyselfAsGeneralMatrix(); + if (HessianPtr_) { + delete (HessianPtr_); + } + HessianPtr_ = (right.HessianPtr_)->duplMyselfAsGeneralMatrix(); + + deltaX_CP_ = right.deltaX_CP_; + deltaX_Newton_ = right.deltaX_Newton_; + residNorm2Cauchy_ = right.residNorm2Cauchy_; + dogLegID_ = right.dogLegID_; + dogLegAlpha_ = right.dogLegAlpha_; + RJd_norm_ = right.RJd_norm_; + lambdaStar_ = right.lambdaStar_; + Jd_ = right.Jd_; + deltaX_trust_ = right.deltaX_trust_; + norm_deltaX_trust_ = right.norm_deltaX_trust_; + trustDelta_ = right.trustDelta_; + trustRegionInitializationMethod_ = right.trustRegionInitializationMethod_; + trustRegionInitializationFactor_ = right.trustRegionInitializationFactor_; + Nuu_ = right.Nuu_; + dist_R0_ = right.dist_R0_; + dist_R1_ = right.dist_R1_; + dist_R2_ = right.dist_R2_; + dist_Total_ = right.dist_Total_; + JdJd_norm_ = right.JdJd_norm_; + normTrust_Newton_ = right.normTrust_Newton_; + normTrust_CP_ = right.normTrust_CP_; + doDogLeg_ = right.doDogLeg_; + doAffineSolve_ = right.doAffineSolve_; + CurrentTrustFactor_ = right.CurrentTrustFactor_; + NextTrustFactor_ = right.NextTrustFactor_; + + ResidWtsReevaluated_ = right.ResidWtsReevaluated_; + ResidDecreaseSDExp_ = right.ResidDecreaseSDExp_; + ResidDecreaseSD_ = right.ResidDecreaseSD_; + ResidDecreaseNewtExp_ = right.ResidDecreaseNewtExp_; + ResidDecreaseNewt_ = right.ResidDecreaseNewt_; return *this; } - + //==================================================================================================================== // Create solution weights for convergence criteria /* * We create soln weights from the following formula @@ -156,170 +433,524 @@ namespace Cantera { * The program always assumes that atol is specific * to the solution component * - * param y vector of the current solution values + * @param y vector of the current solution values */ - void NonlinearSolver::createSolnWeights(const double * const y) { + void NonlinearSolver::createSolnWeights(const doublereal * const y) { for (int i = 0; i < neq_; i++) { m_ewt[i] = rtol_ * fabs(y[i]) + atolk_[i]; } } - + //==================================================================================================================== // set bounds constraints for all variables in the problem /* * * @param y_low_bounds Vector of lower bounds * @param y_high_bounds Vector of high bounds */ - void NonlinearSolver::setBoundsConstraints(const double * const y_low_bounds, - const double * const y_high_bounds) { + void NonlinearSolver::setBoundsConstraints(const doublereal * const y_low_bounds, + const doublereal * const y_high_bounds) { for (int i = 0; i < neq_; i++) { m_y_low_bounds[i] = y_low_bounds[i]; m_y_high_bounds[i] = y_high_bounds[i]; } } - - /** - * L2 Norm of a delta in the solution + //==================================================================================================================== + void NonlinearSolver::setSolverScheme(int doDogLeg, int doAffineSolve) { + doDogLeg_ = doDogLeg; + doAffineSolve_ = doAffineSolve; + } + //==================================================================================================================== + std::vector & NonlinearSolver::lowBoundsConstraintVector() { + return m_y_low_bounds; + } + //==================================================================================================================== + std::vector & NonlinearSolver::highBoundsConstraintVector() { + return m_y_high_bounds; + } + //==================================================================================================================== + // L2 norm of the delta of the solution vector + /* + * calculate the norm of the solution vector. This will + * involve the column scaling of the matrix * - * The second argument has a default of false. However, - * if true, then a table of the largest values is printed - * out to standard output. + * The third argument has a default of false. However, + * if true, then a table of the largest values is printed + * out to standard output. + * + * @param delta_y Vector to take the norm of + * @param title Optional title to be printed out + * @param printLargest int indicating how many specific lines should be printed out + * @param dampFactor Current value of the damping factor. Defaults to 1. + * only used for printout out a table. */ - double NonlinearSolver::solnErrorNorm(const double * const delta_y, - bool printLargest) + doublereal NonlinearSolver::solnErrorNorm(const doublereal * const delta_y, const char * title, int printLargest, + const doublereal dampFactor) const { - int i; - double sum_norm = 0.0, error; + int i; + doublereal sum_norm = 0.0, error; for (i = 0; i < neq_; i++) { error = delta_y[i] / m_ewt[i]; sum_norm += (error * error); } sum_norm = sqrt(sum_norm / neq_); - if (printLargest) { - const int num_entries = 8; - double dmax1, normContrib; - int j; - int *imax = mdp::mdp_alloc_int_1(num_entries, -1); - printf("\t\tPrintout of Largest Contributors to norm " - "of value (%g)\n", sum_norm); - printf("\t\t I ysoln deltaY weightY " - "Error_Norm**2\n"); - printf("\t\t "); print_line("-", 80); - for (int jnum = 0; jnum < num_entries; jnum++) { - dmax1 = -1.0; - for (i = 0; i < neq_; i++) { - bool used = false; - for (j = 0; j < jnum; j++) { - if (imax[j] == i) used = true; - } - if (!used) { - error = delta_y[i] / m_ewt[i]; - normContrib = sqrt(error * error); - if (normContrib > dmax1) { - imax[jnum] = i; - dmax1 = normContrib; + if (printLargest) { + if ((printLargest == 1) || (m_print_flag >= 4 && m_print_flag <= 5)) { + + printf("\t\t solnErrorNorm(): "); + if (title) { + printf("%s", title); + } else { + printf(" Delta soln norm "); + } + printf(" = %-11.4E\n", sum_norm); + } else if (m_print_flag >= 6) { + + + + const int num_entries = printLargest; + printf("\t\t "); print_line("-", 90); + printf("\t\t solnErrorNorm(): "); + if (title) { + printf("%s", title); + } else { + printf(" Delta soln norm "); + } + printf(" = %-11.4E\n", sum_norm); + + doublereal dmax1, normContrib; + int j; + int *imax = mdp::mdp_alloc_int_1(num_entries, -1); + printf("\t\t Printout of Largest Contributors: (damp = %g)\n", dampFactor); + printf("\t\t I weightdeltaY/sqtN| deltaY " + "ysolnOld ysolnNew Soln_Weights\n"); + printf("\t\t "); print_line("-", 88); + + for (int jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < neq_; i++) { + bool used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = delta_y[i] / m_ewt[i]; + normContrib = sqrt(error * error); + if (normContrib > dmax1) { + imax[jnum] = i; + dmax1 = normContrib; + } } } + i = imax[jnum]; + if (i >= 0) { + error = delta_y[i] / m_ewt[i]; + normContrib = sqrt(error * error); + printf("\t\t %4d %12.4e | %12.4e %12.4e %12.4e %12.4e\n", i, normContrib/sqrt((double)neq_), + delta_y[i], m_y_n_curr[i], m_y_n_curr[i] + dampFactor * delta_y[i], m_ewt[i]); + + } } - i = imax[jnum]; - if (i >= 0) { - printf("\t\t %4d %12.4e %12.4e %12.4e %12.4e\n", - i, m_y_n[i], delta_y[i], m_ewt[i], dmax1); - } + printf("\t\t "); print_line("-", 90); + mdp::mdp_safe_free((void **) &imax); } - printf("\t\t "); print_line("-", 80); - mdp::mdp_safe_free((void **) &imax); } return sum_norm; } - - /** + //==================================================================================================================== + /* * L2 Norm of the residual * * The second argument has a default of false. However, * if true, then a table of the largest values is printed * out to standard output. */ - double NonlinearSolver::residErrorNorm(const double * const resid, - bool printLargest) + doublereal NonlinearSolver::residErrorNorm(const doublereal * const resid, const char * title, const int printLargest, + const doublereal * const y) const { int i; - double sum_norm = 0.0, error; + doublereal sum_norm = 0.0, error; + for (i = 0; i < neq_; i++) { - error = resid[i] / m_rowScales[i]; +#ifdef DEBUG_HKM + mdp::checkFinite(resid[i]); +#endif + error = resid[i] / m_residWts[i]; +#ifdef DEBUG_HKM + mdp::checkFinite(error); +#endif sum_norm += (error * error); } sum_norm = sqrt(sum_norm / neq_); +#ifdef DEBUG_HKM + mdp::checkFinite(sum_norm); +#endif if (printLargest) { - const int num_entries = 8; - double dmax1, normContrib; + const int num_entries = printLargest; + doublereal dmax1, normContrib; int j; int *imax = mdp::mdp_alloc_int_1(num_entries, -1); - printf("\t\tPrintout of Largest Contributors to norm " - "of Residual (%g)\n", sum_norm); - printf("\t\t I resid rowScale weightN " - "Error_Norm**2\n"); - printf("\t\t "); print_line("-", 80); - for (int jnum = 0; jnum < num_entries; jnum++) { - dmax1 = -1.0; - for (i = 0; i < neq_; i++) { - bool used = false; - for (j = 0; j < jnum; j++) { - if (imax[j] == i) used = true; - } - if (!used) { - error = resid[i] / m_rowScales[i]; - normContrib = sqrt(error * error); - if (normContrib > dmax1) { - imax[jnum] = i; - dmax1 = normContrib; + + if (m_print_flag >= 4 && m_print_flag <= 5) { + printf("\t\t residErrorNorm():"); + if (title) { + printf(" %s ", title); + } else { + printf(" residual L2 norm "); + } + printf("= %12.4E\n", sum_norm); + } + if (m_print_flag >= 6) { + printf("\t\t "); print_line("-", 90); + printf("\t\t residErrorNorm(): "); + if (title) { + printf(" %s ", title); + } else { + printf(" residual L2 norm "); + } + printf("= %12.4E\n", sum_norm); + printf("\t\t Printout of Largest Contributors to norm:\n"); + printf("\t\t I |Resid/ResWt| UnsclRes ResWt | y_curr\n"); + printf("\t\t "); + print_line("-", 88); + for (int jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < neq_; i++) { + bool used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = resid[i] / m_residWts[i]; + normContrib = sqrt(error * error); + if (normContrib > dmax1) { + imax[jnum] = i; + dmax1 = normContrib; + } } } + i = imax[jnum]; + if (i >= 0) { + error = resid[i] / m_residWts[i]; + normContrib = sqrt(error * error); + printf("\t\t %4d %12.4e %12.4e %12.4e | %12.4e\n", i, normContrib, resid[i], m_residWts[i], y[i]); + } } - i = imax[jnum]; - if (i >= 0) { - printf("\t\t %4d %12.4e %12.4e %12.4e \n", - i, resid[i], m_rowScales[i], normContrib); - } + + printf("\t\t "); + print_line("-", 90); } - printf("\t\t "); print_line("-", 80); mdp::mdp_safe_free((void **) &imax); } return sum_norm; } - - - /** - * setColumnScales(): + //==================================================================================================================== + // Set the column scaling that are used for the inversion of the matrix + /* + * There are three ways to do this. + * + * The first method is to set the bool useColScaling to true, leaving the scaling factors unset. + * Then, the column scales will be set to the solution error weighting factors. This has the + * effect of ensuring that all delta variables will have the same order of magnitude at convergence + * end. + * + * The second way is the explicity set the column factors in the second argument of this function call. + * + * The final way to input the scales is to override the ResidJacEval member function call, + * + * calcSolnScales(double time_n, const double *m_y_n_curr, const double *m_y_nm1, double *m_colScales) + * + * Overriding this function call will trump all other ways to specify the column scaling factors. + * + * @param useColScaling Turn this on if you want to use column scaling in the calculations + * @param scaleFactors A vector of doubles that specifies the column factors. + */ + void NonlinearSolver::setColumnScaling(bool useColScaling, const double * const scaleFactors) { + if (useColScaling) { + if (scaleFactors) { + m_colScaling = 2; + for (int i = 0; i < neq_; i++) { + m_colScales[i] = scaleFactors[i]; + if (m_colScales[i] <= 1.0E-200) { + throw CanteraError("NonlinearSolver::setColumnScaling() ERROR", "Bad column scale factor"); + } + } + } else { + m_colScaling = 1; + } + } else { + m_colScaling = 0; + } + } + //==================================================================================================================== + // Set the rowscaling that are used for the inversion of the matrix + /* + * Row scaling is set here. Right now the row scaling is set internally in the code. + * + * @param useRowScaling Turn row scaling on or off. + */ + void NonlinearSolver::setRowScaling(bool useRowScaling) { + m_rowScaling = useRowScaling; + } + //==================================================================================================================== + /* + * calcColumnScales(): * * Set the column scaling vector at the current time */ - void NonlinearSolver::setColumnScales() { - m_func->calcSolnScales(time_n, DATA_PTR(m_y_n), DATA_PTR(m_y_nm1), - DATA_PTR(m_colScales)); + void NonlinearSolver::calcColumnScales() { + if (m_colScaling == 1) { + for (int i = 0; i < neq_; i++) { + m_colScales[i] = m_ewt[i]; + } + } else { + for (int i = 0; i < neq_; i++) { + m_colScales[i] = 1.0; + } + } + if (m_colScaling) { + m_func->calcSolnScales(time_n, DATA_PTR(m_y_n_curr), DATA_PTR(m_y_nm1), DATA_PTR(m_colScales)); + } } - - - void NonlinearSolver::doResidualCalc(const double time_curr, const int typeCalc, - const double * const y_curr, - const double * const ydot_curr, double* const residual, - int loglevel) + //==================================================================================================================== + // Compute the current residual + /* + * @param time_curr Value of the time + * @param typeCalc Type of the calculation + * @param y_curr Current value of the solution vector + * @param ydot_curr Current value of the time derivative of the solution vector + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + int NonlinearSolver::doResidualCalc(const doublereal time_curr, const int typeCalc, const doublereal * const y_curr, + const doublereal * const ydot_curr, const ResidEval_Type_Enum evalType) const { - - - // Calculate the current residual - // Put the current residual into the vector, delta_y[] - // We need to pull this out of this function and carry it in. - m_func->evalResidNJ(time_curr, delta_t_n, y_curr, ydot_curr, residual); + int retn = m_func->evalResidNJ(time_curr, delta_t_n, y_curr, ydot_curr, DATA_PTR(m_resid), evalType); m_nfe++; + m_resid_scaled = false; + return retn; } + //==================================================================================================================== + // Scale the matrix + /* + * @param jac Jacobian + * @param y_comm Current value of the solution vector + * @param ydot_comm Current value of the time derivative of the solution vector + * @param time_curr current value of the time + */ + void NonlinearSolver::scaleMatrix(GeneralMatrix& jac, doublereal * const y_comm, doublereal * const ydot_comm, + doublereal time_curr, int num_newt_its) + { + int irow, jcol; + int ku, kl; + int ivec[2]; + jac.nRowsAndStruct(ivec); + double *colP_j; - - // Compute the undamped Newton step + /* + * Column scaling -> We scale the columns of the Jacobian + * by the nominal important change in the solution vector + */ + if (m_colScaling) { + if (!jac.factored()) { + if (jac.matrixType_ == 0) { + /* + * Go get new scales -> Took this out of this inner loop. + * Needs to be done at a larger scale. + */ + // setColumnScales(); + + /* + * Scale the new Jacobian + */ + doublereal *jptr = &(*(jac.begin())); + for (jcol = 0; jcol < neq_; jcol++) { + for (irow = 0; irow < neq_; irow++) { + *jptr *= m_colScales[jcol]; + jptr++; + } + } + } else if (jac.matrixType_ == 1) { + kl = ivec[0]; + ku = ivec[1]; + for (jcol = 0; jcol < neq_; jcol++) { + colP_j = (doublereal *) jac.ptrColumn(jcol); + for (irow = jcol - ku; irow <= jcol + kl; irow++) { + if (irow >= 0 && irow < neq_) { + colP_j[kl + ku + irow - jcol] *= m_colScales[jcol]; + } + } + } + } + } + } + /* + * row sum scaling -> Note, this is an unequivical success + * at keeping the small numbers well balanced and nonnegative. + */ + if (! jac.factored()) { + /* + * Ok, this is ugly. jac.begin() returns an vector iterator + * to the first data location. + * Then &(*()) reverts it to a doublereal *. + */ + doublereal *jptr = &(*(jac.begin())); + for (irow = 0; irow < neq_; irow++) { + m_rowScales[irow] = 0.0; + m_rowWtScales[irow] = 0.0; + } + if (jac.matrixType_ == 0) { + for (jcol = 0; jcol < neq_; jcol++) { + for (irow = 0; irow < neq_; irow++) { + if (m_rowScaling) { + m_rowScales[irow] += fabs(*jptr); + } + if (m_colScaling) { + // This is needed in order to mitgate the change in J_ij carried out just above this loop. + // Alternatively, we could move this loop up to the top + m_rowWtScales[irow] += fabs(*jptr) * m_ewt[jcol] / m_colScales[jcol]; + } else { + m_rowWtScales[irow] += fabs(*jptr) * m_ewt[jcol]; + } + jptr++; + } + } + } else if (jac.matrixType_ == 1) { + kl = ivec[0]; + ku = ivec[1]; + for (jcol = 0; jcol < neq_; jcol++) { + colP_j = (doublereal *) jac.ptrColumn(jcol); + for (irow = jcol - ku; irow <= jcol + kl; irow++) { + if (irow >= 0 && irow < neq_) { + double vv = fabs(colP_j[kl + ku + irow - jcol]); + if (m_rowScaling) { + m_rowScales[irow] += vv; + } + if (m_colScaling) { + // This is needed in order to mitgate the change in J_ij carried out just above this loop. + // Alternatively, we could move this loop up to the top + m_rowWtScales[irow] += vv * m_ewt[jcol] / m_colScales[jcol]; + } else { + m_rowWtScales[irow] += vv * m_ewt[jcol]; + } + } + } + } + } + if (m_rowScaling) { + for (irow = 0; irow < neq_; irow++) { + m_rowScales[irow] = 1.0/m_rowScales[irow]; + } + } else { + for (irow = 0; irow < neq_; irow++) { + m_rowScales[irow] = 1.0; + } + } + // What we have defined is a maximum value that the residual can be and still pass. + // This isn't sufficient. + + if (m_rowScaling) { + if (jac.matrixType_ == 0) { + jptr = &(*(jac.begin())); + for (jcol = 0; jcol < neq_; jcol++) { + for (irow = 0; irow < neq_; irow++) { + *jptr *= m_rowScales[irow]; + jptr++; + } + } + } else if (jac.matrixType_ == 1) { + kl = ivec[0]; + ku = ivec[1]; + for (jcol = 0; jcol < neq_; jcol++) { + colP_j = (doublereal *) jac.ptrColumn(jcol); + for (irow = jcol - ku; irow <= jcol + kl; irow++) { + if (irow >= 0 && irow < neq_) { + colP_j[kl + ku + irow - jcol] *= m_rowScales[irow]; + } + } + } + } + } + + if (num_newt_its % 5 == 1) { + computeResidWts(); + } + + } + } + //==================================================================================================================== + // Calculate the scaling factor for translating residual norms into solution norms. + /* + * This routine calls computeResidWts() a couple of times in the calculation of m_ScaleSolnNormToResNorm. + * A more sophisticated routine may do more with signs to get a better value. Perhaps, a series of calculations + * with different signs attached may be in order. Then, m_ScaleSolnNormToResNorm would be calculated + * as the minimum of a series of calculations. + */ + void NonlinearSolver::calcSolnToResNormVector() + { + if (! jacCopyPtr_->factored()) { + + if (checkUserResidualTols_ != 1) { + doublereal sum = 0.0; + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = m_rowWtScales[irow] / neq_; + sum += m_residWts[irow]; + } + sum /= neq_; + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = (m_residWts[irow] + atolBase_ * atolBase_ * sum); + } + if (checkUserResidualTols_ == 2) { + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = MIN(m_residWts[irow], userResidAtol_[irow] + userResidRtol_ * m_rowWtScales[irow] / neq_); + } + } + } else { + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = userResidAtol_[irow] + userResidRtol_ * m_rowWtScales[irow] / neq_; + } + } + + + for (int irow = 0; irow < neq_; irow++) { + m_wksp[irow] = 0.0; + } + doublereal *jptr = &(jacCopyPtr_->operator()(0,0)); + for (int jcol = 0; jcol < neq_; jcol++) { + for (int irow = 0; irow < neq_; irow++) { + m_wksp[irow] += (*jptr) * m_ewt[jcol]; + jptr++; + } + } + doublereal resNormOld = 0.0; + doublereal error; + + for (int irow = 0; irow < neq_; irow++) { + error = m_wksp[irow] / m_residWts[irow]; + resNormOld += error * error; + } + resNormOld = sqrt(resNormOld / neq_); + + if (resNormOld > 0.0) { + m_ScaleSolnNormToResNorm = resNormOld; + } + if (m_ScaleSolnNormToResNorm < 1.0E-8) { + m_ScaleSolnNormToResNorm = 1.0E-8; + } + + // Recalculate the residual weights now that we know the value of m_ScaleSolnNormToResNorm + computeResidWts(); + } else { + throw CanteraError("NonlinearSolver::calcSolnToResNormVector()" , "Logic error"); + } + } + //==================================================================================================================== + // Compute the undamped Newton step based on the current jacobian and an input rhs /* * Compute the undamped Newton step. The residual function is * evaluated at the current time, t_n, at the current values of the - * solution vector, m_y_n, and the solution time derivative, m_ydot_n. + * solution vector, m_y_n_curr, and the solution time derivative, m_ydot_n. * The Jacobian is not recomputed. * * A factored jacobian is reused, if available. If a factored jacobian @@ -328,95 +959,32 @@ namespace Cantera { * recomputed. The row scales are recomputed here, after column * scaling has been implemented. */ - void NonlinearSolver::doNewtonSolve(const double time_curr, const double * const y_curr, - const double * const ydot_curr, double* const delta_y, - SquareMatrix& jac, int loglevel) - { - int irow, jcol; + int NonlinearSolver::doNewtonSolve(const doublereal time_curr, const doublereal * const y_curr, + const doublereal * const ydot_curr, doublereal * const delta_y, + GeneralMatrix& jac) + { + int irow; - //! multiply the residual by -1 - for (int n = 0; n < neq_; n++) { - delta_y[n] = -delta_y[n]; - } - - - /* - * Column scaling -> We scale the columns of the Jacobian - * by the nominal important change in the solution vector - */ - if (m_colScaling) { - if (!jac.m_factored) { - /* - * Go get new scales -> Took this out of this inner loop. - * Needs to be done at a larger scale. - */ - // setColumnScales(); - - /* - * Scale the new Jacobian - */ - double *jptr = &(*(jac.begin())); - for (jcol = 0; jcol < neq_; jcol++) { - for (irow = 0; irow < neq_; irow++) { - *jptr *= m_colScales[jcol]; - jptr++; - } - } - } - } - - // if (m_matrixConditioning) { - // if (jac.m_factored) { - // m_func->matrixConditioning(0, neq_, delta_y); - // } else { - //double *jptr = &(*(jac.begin())); - // m_func->matrixConditioning(jptr, neq_, delta_y); - // } - //} - - /* - * row sum scaling -> Note, this is an unequivical success - * at keeping the small numbers well balanced and - * nonnegative. - */ - if (m_rowScaling) { - if (! jac.m_factored) { - /* - * Ok, this is ugly. jac.begin() returns an vector iterator - * to the first data location. - * Then &(*()) reverts it to a double *. - */ - double *jptr = &(*(jac.begin())); - for (irow = 0; irow < neq_; irow++) { - m_rowScales[irow] = 0.0; - } - for (jcol = 0; jcol < neq_; jcol++) { - for (irow = 0; irow < neq_; irow++) { - m_rowScales[irow] += fabs(*jptr); - jptr++; - } - } - - jptr = &(*(jac.begin())); - for (jcol = 0; jcol < neq_; jcol++) { - for (irow = 0; irow < neq_; irow++) { - *jptr /= m_rowScales[irow]; - jptr++; - } - } + // multiply the residual by -1 + if (m_rowScaling && !m_resid_scaled) { + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_rowScales[n] * m_resid[n]; } - for (irow = 0; irow < neq_; irow++) { - delta_y[irow] /= m_rowScales[irow]; + m_resid_scaled = true; + } else { + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_resid[n]; } } + /* * Solve the system -> This also involves inverting the * matrix */ - (void) jac.solve(delta_y); + int info = jac.solve(DATA_PTR(delta_y)); /* @@ -424,7 +992,7 @@ namespace Cantera { */ if (m_colScaling) { for (irow = 0; irow < neq_; irow++) { - delta_y[irow] *= m_colScales[irow]; + delta_y[irow] = delta_y[irow] * m_colScales[irow]; } } @@ -432,14 +1000,13 @@ namespace Cantera { if (printJacContributions) { for (int iNum = 0; iNum < numRows; iNum++) { if (iNum > 0) focusRow++; - double dsum = 0.0; + doublereal dsum = 0.0; vector_fp& Jdata = jacBack.data(); - double dRow = Jdata[neq_ * focusRow + focusRow]; + doublereal dRow = Jdata[neq_ * focusRow + focusRow]; printf("\n Details on delta_Y for row %d \n", focusRow); printf(" Value before = %15.5e, delta = %15.5e," "value after = %15.5e\n", y_curr[focusRow], - delta_y[focusRow], - y_curr[focusRow] + delta_y[focusRow]); + delta_y[focusRow], y_curr[focusRow] + delta_y[focusRow]); if (!freshJac) { printf(" Old Jacobian\n"); } @@ -453,8 +1020,8 @@ namespace Cantera { dsum += RRow[iNum] / dRow; for (int ii = 0; ii < neq_; ii++) { if (ii != focusRow) { - double aij = Jdata[neq_ * ii + focusRow]; - double contrib = aij * delta_y[ii] * (-1.0) / dRow; + doublereal aij = Jdata[neq_ * ii + focusRow]; + doublereal contrib = aij * delta_y[ii] * (-1.0) / dRow; dsum += contrib; if (fabs(contrib) > Pcutoff) { printf("%6d %15.5e %15.5e %15.5e\n", ii, @@ -471,10 +1038,1305 @@ namespace Cantera { #endif - m_numTotalLinearSolves++; + m_numTotalLinearSolves++; + m_numLocalLinearSolves++; + return info; + } + //==================================================================================================================== + // Compute the newton step, either by direct newton's or by solving a close problem that is represented + // by a Hessian ( + /* + * This is algorith A.6.5.1 in Dennis / Schnabel + * + * Compute the QR decomposition + * + * Notes on banded Hessian solve: + * The matrix for jT j has a larger band width. Both the top and bottom band widths + * are doubled, going from KU to KU+KL and KL to KU+KL in size. This is not an impossible increase in cost, but + * has to be considered. + */ + int NonlinearSolver::doAffineNewtonSolve(const doublereal * const y_curr, const doublereal * const ydot_curr, + doublereal * const delta_y, GeneralMatrix& jac) + { + bool newtonGood = true; + int irow; + doublereal *delyNewton = 0; + // We can default to QR here ( or not ) + jac.useFactorAlgorithm(1); + int useQR = jac.factorAlgorithm(); + // multiplyl the residual by -1 + // Scale the residual if there is row scaling. Note, the matrix has already been scaled + if (m_rowScaling && !m_resid_scaled) { + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_rowScales[n] * m_resid[n]; + } + m_resid_scaled = true; + } else { + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_resid[n]; + } + } + + // Factor the matrix using a standard Newton solve + m_conditionNumber = 1.0E300; + int info = 0; + if (!jac.factored()) { + if (useQR) { + info = jac.factorQR(); + } else { + info = jac.factor(); + } + } + /* + * Find the condition number of the matrix + * If we have failed to factor, we will fall back to calculating and factoring a modified Hessian + */ + if (info == 0) { + doublereal rcond = 0.0; + if (useQR) { + rcond = jac.rcondQR(); + } else { + doublereal a1norm = jac.oneNorm(); + rcond = jac.rcond(a1norm); + } + if (rcond > 0.0) { + m_conditionNumber = 1.0 / rcond; + } + } else { + m_conditionNumber = 1.0E300; + newtonGood = false; + if (m_print_flag >= 1) { + printf("\t\t doAffineNewtonSolve: "); + if (useQR) { + printf("factorQR()"); + } else { + printf("factor()"); + } + printf(" returned with info = %d, indicating a zero row or column\n", info); + } + } + bool doHessian = false; + if (s_doBothSolvesAndCompare) { + doHessian = true; + } + bool useNewton = false; + if (m_conditionNumber < 1.0E7) { + useNewton = true; + if (m_print_flag >= 4) { + printf("\t\t doAffineNewtonSolve: Condition number = %g during regular solve\n", m_conditionNumber); + } + + /* + * Solve the system -> This also involves inverting the matrix + */ + int info = jac.solve(DATA_PTR(delta_y)); + if (info) { + if (m_print_flag >= 2) { + printf("\t\t doAffineNewtonSolve() ERROR: QRSolve returned INFO = %d. Switching to Hessian solve\n", info); + } + doHessian = true; + newtonGood = false; + } + /* + * reverse the column scaling if there was any on a successful solve + */ + if (m_colScaling) { + for (irow = 0; irow < neq_; irow++) { + delta_y[irow] = delta_y[irow] * m_colScales[irow]; + } + } + + } else { + if (jac.matrixType_ == 1) { + useNewton = true; + newtonGood = true; + if (m_print_flag >= 3) { + printf("\t\t doAffineNewtonSolve() WARNING: Condition number too large, %g, But Banded Hessian solve " + "not implemented yet \n", m_conditionNumber); + } + } else { + doHessian = true; + newtonGood = false; + if (m_print_flag >= 3) { + printf("\t\t doAffineNewtonSolve() WARNING: Condition number too large, %g. Doing a Hessian solve \n", m_conditionNumber); + } + } + } + + if (doHessian) { + // Store the old value for later comparison + + delyNewton = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + for (irow = 0; irow < neq_; irow++) { + delyNewton[irow] = delta_y[irow]; + } + + // Get memory if not done before + if (HessianPtr_ == 0) { + HessianPtr_ = jac.duplMyselfAsGeneralMatrix(); + } + + /* + * Calculate the symmetric Hessian + */ + GeneralMatrix &hessian = *HessianPtr_; + GeneralMatrix &jacCopy = *jacCopyPtr_; + hessian.zero(); + if (m_rowScaling) { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + for (int k = 0; k < neq_; k++) { + hessian(i,j) += jacCopy(k,i) * jacCopy(k,j) * m_rowScales[k] * m_rowScales[k]; + } + hessian(j,i) = hessian(i,j); + } + } + } else { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + for (int k = 0; k < neq_; k++) { + hessian(i,j) += jacCopy(k,i) * jacCopy(k,j); + } + hessian(j,i) = hessian(i,j); + } + } + } + + /* + * Calculate the matrix norm of the Hessian + */ + doublereal hnorm = 0.0; + doublereal hcol = 0.0; + if (m_colScaling) { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + hcol += fabs(hessian(j,i)) * m_colScales[j]; + } + for (int j = i+1; j < neq_; j++) { + hcol += fabs(hessian(i,j)) * m_colScales[j]; + } + hcol *= m_colScales[i]; + if (hcol > hnorm) { + hnorm = hcol; + } + } + } else { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + hcol += fabs(hessian(j,i)); + } + for (int j = i+1; j < neq_; j++) { + hcol += fabs(hessian(i,j)); + } + if (hcol > hnorm) { + hnorm = hcol; + } + } + } + /* + * Add junk to the Hessian diagonal + * -> Note, testing indicates that this will get too big for ill-conditioned systems. + */ + hcol = sqrt(neq_) * 1.0E-7 * hnorm; +#ifdef DEBUG_HKM_NOT + if (hcol > 1.0) { + hcol = 1.0E1; + } +#endif + if (m_colScaling) { + for (int i = 0; i < neq_; i++) { + hessian(i,i) += hcol / (m_colScales[i] * m_colScales[i]); + } + } else { + for (int i = 0; i < neq_; i++) { + hessian(i,i) += hcol; + } + } + + /* + * Factor the Hessian + */ + int info; + ct_dpotrf(ctlapack::UpperTriangular, neq_, &(*(HessianPtr_->begin())), neq_, info); + if (info) { + if (m_print_flag >= 2) { + printf("\t\t doAffineNewtonSolve() ERROR: Hessian isn't positive definate DPOTRF returned INFO = %d\n", info); + } + return info; + } + + // doublereal *JTF = delta_y; + doublereal *delyH = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + // First recalculate the scaled residual. It got wiped out doing the newton solve + if (m_rowScaling) { + for (int n = 0; n < neq_; n++) { + delyH[n] = -m_rowScales[n] * m_resid[n]; + } + } else { + for (int n = 0; n < neq_; n++) { + delyH[n] = -m_resid[n]; + } + } + + if (m_rowScaling) { + for (int j = 0; j < neq_; j++) { + delta_y[j] = 0.0; + for (int i = 0; i < neq_; i++) { + delta_y[j] += delyH[i] * jacCopy(i,j) * m_rowScales[i]; + } + } + } else { + for (int j = 0; j < neq_; j++) { + delta_y[j] = 0.0; + for (int i = 0; i < neq_; i++) { + delta_y[j] += delyH[i] * jacCopy(i,j); + } + } + } + + + /* + * Solve the factored Hessian System + */ + ct_dpotrs(ctlapack::UpperTriangular, neq_, 1,&(*(hessian.begin())), neq_, delta_y, neq_, info); + if (info) { + if (m_print_flag >= 2) { + printf("\t\t NonlinearSolver::doAffineNewtonSolve() ERROR: DPOTRS returned INFO = %d\n", info); + } + return info; + } + /* + * reverse the column scaling if there was any. + */ + if (m_colScaling) { + for (irow = 0; irow < neq_; irow++) { + delta_y[irow] = delta_y[irow] * m_colScales[irow]; + } + } + + + if (doDogLeg_ && m_print_flag > 7) { + double normNewt = solnErrorNorm(CONSTD_DATA_PTR(delyNewton)); + double normHess = solnErrorNorm(CONSTD_DATA_PTR(delta_y)); + printf("\t\t doAffineNewtonSolve(): Printout Comparison between Hessian deltaX and Newton deltaX\n"); + + printf("\t\t I Hessian+Junk Newton"); + if (newtonGood || s_alwaysAssumeNewtonGood) { + printf(" (USING NEWTON DIRECTION)\n"); + } else { + printf(" (USING HESSIAN DIRECTION)\n"); + } + printf("\t\t Norm: %12.4E %12.4E\n", normHess, normNewt); + + printf("\t\t --------------------------------------------------------\n"); + for (int i =0; i < neq_; i++) { + printf("\t\t %3d %13.5E %13.5E\n", i, delta_y[i], delyNewton[i]); + } + printf("\t\t --------------------------------------------------------\n"); + } else if (doDogLeg_ && m_print_flag >= 4) { + double normNewt = solnErrorNorm(CONSTD_DATA_PTR(delyNewton)); + double normHess = solnErrorNorm(CONSTD_DATA_PTR(delta_y)); + printf("\t\t doAffineNewtonSolve(): Hessian update norm = %12.4E \n" + "\t\t Newton update norm = %12.4E \n", normHess, normNewt); + if (newtonGood || s_alwaysAssumeNewtonGood) { + printf("\t\t (USING NEWTON DIRECTION)\n"); + } else { + printf("\t\t (USING HESSIAN DIRECTION)\n"); + } + } + + /* + * Choose the delta_y to use + */ + if (newtonGood || s_alwaysAssumeNewtonGood) { + mdp::mdp_copy_dbl_1(DATA_PTR(delta_y), CONSTD_DATA_PTR(delyNewton), neq_); + } + mdp::mdp_safe_free((void **) &delyH); + mdp::mdp_safe_free((void **) &delyNewton); + } + +#ifdef DEBUG_JAC + if (printJacContributions) { + for (int iNum = 0; iNum < numRows; iNum++) { + if (iNum > 0) focusRow++; + doublereal dsum = 0.0; + vector_fp& Jdata = jacBack.data(); + doublereal dRow = Jdata[neq_ * focusRow + focusRow]; + printf("\n Details on delta_Y for row %d \n", focusRow); + printf(" Value before = %15.5e, delta = %15.5e," + "value after = %15.5e\n", y_curr[focusRow], + delta_y[focusRow], y_curr[focusRow] + delta_y[focusRow]); + if (!freshJac) { + printf(" Old Jacobian\n"); + } + printf(" col delta_y aij " + "contrib \n"); + printf("-----------------------------------------------------------------------------------------------\n"); + printf(" Res(%d) %15.5e %15.5e %15.5e (Res = %g)\n", + focusRow, delta_y[focusRow], + dRow, RRow[iNum] / dRow, RRow[iNum]); + dsum += RRow[iNum] / dRow; + for (int ii = 0; ii < neq_; ii++) { + if (ii != focusRow) { + doublereal aij = Jdata[neq_ * ii + focusRow]; + doublereal contrib = aij * delta_y[ii] * (-1.0) / dRow; + dsum += contrib; + if (fabs(contrib) > Pcutoff) { + printf("%6d %15.5e %15.5e %15.5e\n", ii, + delta_y[ii] , aij, contrib); + } + } + } + printf("-----------------------------------------------------------------------------------------------\n"); + printf(" %15.5e %15.5e\n", + delta_y[focusRow], dsum); + } + } + +#endif + + m_numTotalLinearSolves++; + m_numLocalLinearSolves++; + return info; + + } + //==================================================================================================================== + // Do a steepest descent calculation + /* + * This call must be made on the unfactored jacobian! + */ + doublereal NonlinearSolver::doCauchyPointSolve(GeneralMatrix& jac) + { + doublereal rowFac = 1.0; + doublereal colFac = 1.0; + doublereal normSoln; + // Calculate the descent direction + /* + * For confirmation of the scaling factors, see Dennis and Schnabel p, 152, p, 156 and my notes + * + * The colFac and rowFac values are used to eliminate the scaling of the matrix from the + * actual equation + * + * Here we calculate the steepest descent direction. This is equation (11) in the notes. It is + * storred in deltaX_CP_[].The value corresponds to d_descent[]. + */ + for (int j = 0; j < neq_; j++) { + deltaX_CP_[j] = 0.0; + if (m_colScaling) { + colFac = 1.0 / m_colScales[j]; + } + for (int i = 0; i < neq_; i++) { + if (m_rowScaling) { + rowFac = 1.0 / m_rowScales[i]; + } + deltaX_CP_[j] -= m_resid[i] * jac(i,j) * colFac * rowFac * m_ewt[j] * m_ewt[j] + / (m_residWts[i] * m_residWts[i]); +#ifdef DEBUG_MODE + mdp::checkFinite(deltaX_CP_[j]); +#endif + } + } + + /* + * Calculate J_hat d_y_descent. This is formula 18 in the notes. + */ + for (int i = 0; i < neq_; i++) { + Jd_[i] = 0.0; + if (m_rowScaling) { + rowFac = 1.0 / m_rowScales[i]; + } else { + rowFac = 1.0; + } + for (int j = 0; j < neq_; j++) { + if (m_colScaling) { + colFac = 1.0 / m_colScales[j]; + } + Jd_[i] += deltaX_CP_[j] * jac(i,j) * rowFac * colFac / m_residWts[i]; + } + } + + /* + * Calculate the distance along the steepest descent until the Cauchy point + * This is Eqn. 17 in the notes. + */ + RJd_norm_ = 0.0; + JdJd_norm_ = 0.0; + for (int i = 0; i < neq_; i++) { + RJd_norm_ += m_resid[i] * Jd_[i] / m_residWts[i]; + JdJd_norm_ += Jd_[i] * Jd_[i]; + } + //if (RJd_norm_ > -1.0E-300) { + // printf("we are here: zero residual\n"); + //} + if (fabs(JdJd_norm_) < 1.0E-290) { + if (fabs(RJd_norm_) < 1.0E-300) { + lambdaStar_ = 0.0; + } else { + throw CanteraError("NonlinearSolver::doCauchyPointSolve()", "Unexpected condition: norms are zero"); + } + } else { + lambdaStar_ = - RJd_norm_ / (JdJd_norm_); + } + + /* + * Now we modify the steepest descent vector such that its length is equal to the + * Cauchy distance. From now on, if we want to recreate the descent vector, we have + * to unnormalize it by dividing by lambdaStar_. + */ + for (int i = 0; i < neq_; i++) { + deltaX_CP_[i] *= lambdaStar_; + } + + + doublereal normResid02 = m_normResid_0 * m_normResid_0 * neq_; + + /* + * Calculate the expected square of the risdual at the Cauchy point if the linear model is correct + */ + if (fabs(JdJd_norm_) < 1.0E-290) { + residNorm2Cauchy_ = normResid02; + } else { + residNorm2Cauchy_ = normResid02 - RJd_norm_ * RJd_norm_ / (JdJd_norm_); + } + + + // Extra printout section + if (m_print_flag > 2) { + // Calculate the expected residual at the Cauchy point if the linear model is correct + doublereal residCauchy = 0.0; + if (residNorm2Cauchy_ > 0.0) { + residCauchy = sqrt(residNorm2Cauchy_ / neq_); + } else { + if (fabs(JdJd_norm_) < 1.0E-290) { + residCauchy = m_normResid_0; + } else { + residCauchy = m_normResid_0 - sqrt(RJd_norm_ * RJd_norm_ / (JdJd_norm_)); + } + } + // Compute the weighted norm of the undamped step size descentDir_[] + if ((s_print_DogLeg || doDogLeg_) && m_print_flag >= 6) { + normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 10); + } else { + normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 0); + } + if ((s_print_DogLeg || doDogLeg_) && m_print_flag >= 5) { + printf("\t\t doCauchyPointSolve: Steepest descent to Cauchy point: \n"); + printf("\t\t\t R0 = %g \n", m_normResid_0); + printf("\t\t\t Rpred = %g\n", residCauchy); + printf("\t\t\t Rjd = %g\n", RJd_norm_); + printf("\t\t\t JdJd = %g\n", JdJd_norm_); + printf("\t\t\t deltaX = %g\n", normSoln); + printf("\t\t\t lambda = %g\n", lambdaStar_); + } + } else { + // Calculate the norm of the Cauchy solution update in any case + normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 0); + } + return normSoln; + } + //=================================================================================================================== + void NonlinearSolver::descentComparison(doublereal time_curr, doublereal *ydot0, doublereal *ydot1, int &numTrials) + { + int info; + doublereal ff = 1.0E-5; + doublereal ffNewt = 1.0E-5; + doublereal *y_n_1 = DATA_PTR(m_wksp); + doublereal cauchyDistanceNorm = solnErrorNorm(DATA_PTR(deltaX_CP_)); + if (cauchyDistanceNorm < 1.0E-2) { + ff = 1.0E-9 / cauchyDistanceNorm; + if (ff > 1.0E-2) { + ff = 1.0E-2; + } + } + for (int i = 0; i < neq_; i++) { + y_n_1[i] = m_y_n_curr[i] + ff * deltaX_CP_[i]; + } + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); + } + + doublereal normResid02 = m_normResid_0 * m_normResid_0 * neq_; + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteep2 = residSteep * residSteep * neq_; + doublereal funcDecreaseSD = 0.5 * (residSteep2 - normResid02) / ( ff * cauchyDistanceNorm); + + doublereal sNewt = solnErrorNorm(DATA_PTR(deltaX_Newton_)); + if (sNewt > 1.0) { + ffNewt = ffNewt / sNewt; + } + for (int i = 0; i < neq_; i++) { + y_n_1[i] = m_y_n_curr[i] + ffNewt * deltaX_Newton_[i]; + } + /* + * Calculate the residual that would result if y1[] were the new solution vector. + * Here we use the lagged solution components in the residual calculation as well. We are + * interested in the linear model and its agreement with the nonlinear model. + * + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); + } + doublereal residNewt = residErrorNorm(DATA_PTR(m_resid)); + doublereal residNewt2 = residNewt * residNewt * neq_; + + doublereal funcDecreaseNewt2 = 0.5 * (residNewt2 - normResid02) / ( ffNewt * sNewt); + + // This is the expected inital rate of decrease in the Cauchy direction. + // -> This is Eqn. 29 = Rhat dot Jhat dy / || d || + doublereal funcDecreaseSDExp = RJd_norm_ / cauchyDistanceNorm * lambdaStar_; + + doublereal funcDecreaseNewtExp2 = - normResid02 / sNewt; + + if ( m_normResid_0 > 1.0E-100) { + ResidDecreaseSDExp_ = funcDecreaseSDExp / neq_ / m_normResid_0; + ResidDecreaseSD_ = funcDecreaseSD / neq_ / m_normResid_0; + ResidDecreaseNewtExp_ = funcDecreaseNewtExp2 / neq_ / m_normResid_0; + ResidDecreaseNewt_ = funcDecreaseNewt2 / neq_ / m_normResid_0; + } else { + ResidDecreaseSDExp_ = 0.0; + ResidDecreaseSD_ = funcDecreaseSD / neq_; + ResidDecreaseNewtExp_ = 0.0; + ResidDecreaseNewt_ = funcDecreaseNewt2 / neq_; + } + numTrials += 2; + + /* + * HKM These have been shown to exactly match up. + * The steepest direction is always largest even when there are variable solution weights + * + * HKM When a hessian is used with junk on the diagonal, funcDecreaseNewtExp2 is no longer accurate as the + * direction gets signficantly shorter with increasing condition number. This suggests an algorithm where the + * newton step from the Hessian should be increased so as to match funcDecreaseNewtExp2 = funcDecreaseNewt2. + * This roughly equals the ratio of the norms of the hessian and newton steps. This increased Newton step can + * then be used with the trust region double dogleg algorithm. + */ + if ((s_print_DogLeg && m_print_flag >= 3) || (doDogLeg_ && m_print_flag >= 5)) { + printf("\t\t descentComparison: initial rate of decrease of func in cauchy dir (expected) = %g\n", funcDecreaseSDExp); + printf("\t\t descentComparison: initial rate of decrease of func in cauchy dir = %g\n", funcDecreaseSD); + printf("\t\t descentComparison: initial rate of decrease of func in newton dir (expected) = %g\n", funcDecreaseNewtExp2); + printf("\t\t descentComparison: initial rate of decrease of func in newton dir = %g\n", funcDecreaseNewt2); + } + if ((s_print_DogLeg && m_print_flag >= 3) || (doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t descentComparison: initial rate of decrease of Resid in cauchy dir (expected) = %g\n", ResidDecreaseSDExp_); + printf("\t\t descentComparison: initial rate of decrease of Resid in cauchy dir = %g\n", ResidDecreaseSD_); + printf("\t\t descentComparison: initial rate of decrease of Resid in newton dir (expected) = %g\n", ResidDecreaseNewtExp_); + printf("\t\t descentComparison: initial rate of decrease of Resid in newton dir = %g\n", ResidDecreaseNewt_); + } + + if ((s_print_DogLeg && m_print_flag >= 5) || (doDogLeg_ && m_print_flag >= 5)) { + if (funcDecreaseNewt2 >= 0.0) { + printf("\t\t %13.5E %22.16E\n", funcDecreaseNewtExp2, m_normResid_0); + double ff = ffNewt * 1.0E-5; + for (int ii = 0; ii < 13; ii++) { + ff *= 10.; + if (ii == 12) { + ff = ffNewt; + } + for (int i = 0; i < neq_; i++) { + y_n_1[i] = m_y_n_curr[i] + ff * deltaX_Newton_[i]; + } + numTrials += 1; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); + } + residNewt = residErrorNorm(DATA_PTR(m_resid)); + residNewt2 = residNewt * residNewt * neq_; + funcDecreaseNewt2 = 0.5 * (residNewt2 - normResid02) / ( ff * sNewt); + printf("\t\t %10.3E %13.5E %22.16E\n", ff, funcDecreaseNewt2, residNewt ); + } + + } + + + } + } - /************************************************************************** + //==================================================================================================================== + // Setup the parameters for the double dog leg + /* + * The calls to the doCauchySolve() and doNewtonSolve() routines are done at the main level. This routine comes + * after those calls. We calculate the point Nuu_ here, the distances of the dog-legs, + * and the norms of the CP and Newton points in terms of the trust vectors. + */ + void NonlinearSolver::setupDoubleDogleg() + { + /* + * Gamma = ||grad f ||**4 + * --------------------------------------------- + * (grad f)T H (grad f) (grad f)T H-1 (grad f) + */ + // doublereal sumG = 0.0; + // doublereal sumH = 0.0; + // for (int i = 0; i < neq_; i++) { + // sumG = deltax_cp_[i] * deltax_cp_[i]; + // sumH = deltax_cp_[i] * newtDir[i]; + // } + // double fac1 = sumG / lambdaStar_; + // double fac2 = sumH / lambdaStar_; + // double gamma = fac1 / fac2; + // doublereal gamma = m_normDeltaSoln_CP / m_normDeltaSoln_Newton; + /* + * This hasn't worked. so will do it heuristically. One issue is that the newton + * direction is not the inverse of the Hessian times the gradient. The Hession + * is the matrix squared. Until I have the inverse of the Hessian from QR factorization + * I may not be able to do it this way. + */ + + /* + * Heuristic algorithm - Find out where on the Newton line the residual is the same + * as the residual at the cauchy point. Then, go halfway to + * the newton point and call that Nuu. + * Maybe we need to check that the linearized residual is + * monotonic along that line. However, we haven't needed to yet. + */ + doublereal residSteepLin = expectedResidLeg(0, 1.0); + doublereal Nres2CP = residSteepLin * residSteepLin * neq_; + doublereal Nres2_o = m_normResid_0 * m_normResid_0 * neq_; + doublereal a = Nres2CP / Nres2_o; + doublereal betaEqual = (2.0 - sqrt(4.0 - 4 * (1.0 - a))) / 2.0; + doublereal beta = (1.0 + betaEqual) / 2.0; + + + Nuu_ = beta; + + dist_R0_ = m_normDeltaSoln_CP; + for (int i = 0; i < neq_; i++) { + m_wksp[i] = Nuu_ * deltaX_Newton_[i] - deltaX_CP_[i]; + } + dist_R1_ = solnErrorNorm(DATA_PTR(m_wksp)); + dist_R2_ = (1.0 - Nuu_) * m_normDeltaSoln_Newton; + dist_Total_ = dist_R0_ + dist_R1_ + dist_R2_; + + /* + * Calculate the trust distances + */ + normTrust_Newton_ = calcTrustDistance(deltaX_Newton_); + normTrust_CP_ = calcTrustDistance(deltaX_CP_); + + } + //==================================================================================================================== + // Change the global lambda coordinate into the (leg,alpha) coordinate for the double dogleg + /* + * @param lambda Global value of the distance along the double dogleg + * @param alpha relative value along the particular leg + * + * @return Returns the leg number ( 0, 1, or 2). + */ + int NonlinearSolver::lambdaToLeg(const doublereal lambda, doublereal &alpha) const { + + if (lambda < dist_R0_ / dist_Total_) { + alpha = lambda * dist_Total_ / dist_R0_; + return 0; + } else if (lambda < ((dist_R0_ + dist_R1_)/ dist_Total_)) { + alpha = (lambda * dist_Total_ - dist_R0_) / dist_R1_; + return 1; + } + alpha = (lambda * dist_Total_ - dist_R0_ - dist_R1_) / dist_R2_; + return 2; + } + //==================================================================================================================== + // Calculated the expected residual along the double dogleg curve. + /* + * @param leg 0, 1, or 2 representing the curves of the dogleg + * @param alpha Relative distance along the particular curve. + * + * @return Returns the expected value of the residual at that point according to the quadratic model. + * The residual at the newton point will always be zero. + */ + doublereal NonlinearSolver::expectedResidLeg(int leg, doublereal alpha) const { + + doublereal resD2, res2, resNorm; + doublereal normResid02 = m_normResid_0 * m_normResid_0 * neq_; + + if (leg == 0) { + /* + * We are on the steepest descent line + * along that line + * R2 = R2 + 2 lambda R dot Jd + lambda**2 Jd dot Jd + */ + + doublereal tmp = - 2.0 * alpha + alpha * alpha; + doublereal tmp2 = - RJd_norm_ * lambdaStar_; + resD2 = tmp2 * tmp; + + } else if (leg == 1) { + + /* + * Same formula as above for lambda=1. + */ + doublereal tmp2 = - RJd_norm_ * lambdaStar_; + doublereal RdotJS = - tmp2; + doublereal JsJs = tmp2; + + + doublereal res0_2 = m_normResid_0 * m_normResid_0 * neq_; + + res2 = res0_2 + (1.0 - alpha) * 2 * RdotJS - 2 * alpha * Nuu_ * res0_2 + + (1.0 - alpha) * (1.0 - alpha) * JsJs + + alpha * alpha * Nuu_ * Nuu_ * res0_2 + - 2 * alpha * Nuu_ * (1.0 - alpha) * RdotJS; + + resNorm = sqrt(res2 / neq_); + return resNorm; + + } else { + doublereal beta = Nuu_ + alpha * (1.0 - Nuu_); + doublereal tmp2 = normResid02; + doublereal tmp = 1.0 - 2.0 * beta + 1.0 * beta * beta - 1.0; + resD2 = tmp * tmp2; + } + + res2 = m_normResid_0 * m_normResid_0 * neq_ + resD2; + if (res2 < 0.0) { + resNorm = m_normResid_0 - sqrt(resD2/neq_); + } else { + resNorm = sqrt(res2 / neq_); + } + + return resNorm; + + } + //==================================================================================================================== + // Here we print out the residual at various points along the double dogleg, comparing against the quadratic model + // in a table format + /* + * @param time_curr INPUT current time + * @param ydot0 INPUT Current value of the derivative of the solution vector for non-time dependent + * determinations + * @param legBest OUTPUT leg of the dogleg that gives the lowest residual + * @param alphaBest OUTPUT distance along dogleg for best result. + */ + void NonlinearSolver::residualComparisonLeg(const doublereal time_curr, const doublereal * const ydot0, int &legBest, + doublereal &alphaBest) const { + doublereal *y1 = DATA_PTR(m_wksp); + doublereal *ydot1 = DATA_PTR(m_wksp_2); + doublereal sLen; + doublereal alpha; + + doublereal residSteepBest = 1.0E300; + doublereal residSteepLinBest = 0.0; + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t residualComparisonLeg() \n"); + printf("\t\t Point StepLen Residual_Actual Residual_Linear RelativeMatch\n"); + } + // First compare at 1/4 along SD curve + std::vector alphaT; + alphaT.push_back(0.00); + alphaT.push_back(0.01); + alphaT.push_back(0.1); + alphaT.push_back(0.25); + alphaT.push_back(0.50); + alphaT.push_back(0.75); + alphaT.push_back(1.0); + for (int iteration = 0; iteration < (int) alphaT.size(); iteration++) { + alpha = alphaT[iteration]; + for (int i = 0; i < neq_; i++) { + y1[i] = m_y_n_curr[i] + alpha * deltaX_CP_[i]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y1, ydot1); + } + sLen = alpha * solnErrorNorm(DATA_PTR(deltaX_CP_)); + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); + } else { + doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); + } + + + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteepLin = expectedResidLeg(0, alpha); + if (residSteep < residSteepBest) { + legBest = 0; + alphaBest = alpha; + residSteepBest = residSteep; + residSteepLinBest = residSteepLin; + } + + doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 0, alpha, sLen, residSteep, residSteepLin , relFit); + } + } + + for (int iteration = 0; iteration < (int) alphaT.size(); iteration++) { + doublereal alpha = alphaT[iteration]; + for (int i = 0; i < neq_; i++) { + y1[i] = m_y_n_curr[i] + (1.0 - alpha) * deltaX_CP_[i]; + y1[i] += alpha * Nuu_ * deltaX_Newton_[i]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y1, ydot1); + } + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); + } else { + doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); + } + + for (int i = 0; i < neq_; i++) { + y1[i] -= m_y_n_curr[i]; + } + sLen = solnErrorNorm(DATA_PTR(y1)); + + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteepLin = expectedResidLeg(1, alpha); + if (residSteep < residSteepBest) { + legBest = 1; + alphaBest = alpha; + residSteepBest = residSteep; + residSteepLinBest = residSteepLin; + } + + doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 1, alpha, sLen, residSteep, residSteepLin , relFit); + } + } + + for (int iteration = 0; iteration < (int) alphaT.size(); iteration++) { + doublereal alpha = alphaT[iteration]; + for (int i = 0; i < neq_; i++) { + y1[i] = m_y_n_curr[i] + ( Nuu_ + alpha * (1.0 - Nuu_))* deltaX_Newton_[i]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y1, ydot1); + } + sLen = ( Nuu_ + alpha * (1.0 - Nuu_)) * solnErrorNorm(DATA_PTR(deltaX_Newton_)); + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); + } else { + doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); + } + + + + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteepLin = expectedResidLeg(2, alpha); + if (residSteep < residSteepBest) { + legBest = 2; + alphaBest = alpha; + residSteepBest = residSteep; + residSteepLinBest = residSteepLin; + } + doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 2, alpha, sLen, residSteep, residSteepLin , relFit); + } + } + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t Best Result: \n"); + doublereal relFit = (residSteepBest - residSteepLinBest) / (fabs(residSteepLinBest) + 1.0E-10); + if (m_print_flag <= 6) { + printf("\t\t Leg %2d alpha %5g: NonlinResid = %g LinResid = %g, relfit = %g\n", + legBest, alphaBest, residSteepBest, residSteepLinBest, relFit); + } else { + if (legBest == 0) { + sLen = alpha * solnErrorNorm(DATA_PTR(deltaX_CP_)); + } else if (legBest == 1) { + for (int i = 0; i < neq_; i++) { + y1[i] = (1.0 - alphaBest) * deltaX_CP_[i]; + y1[i] += alphaBest * Nuu_ * deltaX_Newton_[i]; + } + sLen = solnErrorNorm(DATA_PTR(y1)); + } else { + sLen = ( Nuu_ + alpha * (1.0 - Nuu_)) * solnErrorNorm(DATA_PTR(deltaX_Newton_)); + } + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", legBest, alphaBest, sLen, + residSteepBest, residSteepLinBest , relFit); + } + } + + } + //==================================================================================================================== + // Calculate the length of the current trust region in terms of the solution error norm + /* + * We carry out a norm of deltaX_trust_ first. Then, we multiply that value + * by trustDelta_ + */ + doublereal NonlinearSolver::trustRegionLength() const + { + norm_deltaX_trust_ = solnErrorNorm(DATA_PTR(deltaX_trust_)); + return (trustDelta_ * norm_deltaX_trust_); + } + //==================================================================================================================== + void NonlinearSolver::setDefaultDeltaBoundsMagnitudes() + { + for (int i = 0; i < neq_; i++) { + m_deltaStepMinimum[i] = 1000. * atolk_[i]; + m_deltaStepMinimum[i] = MAX(m_deltaStepMinimum[i], 0.1 * fabs(m_y_n_curr[i])); + } + } + //==================================================================================================================== + void NonlinearSolver::adjustUpStepMinimums() { + for (int i = 0; i < neq_; i++) { + doublereal goodVal = deltaX_trust_[i] * trustDelta_; + if (deltaX_trust_[i] * trustDelta_ > m_deltaStepMinimum[i]) { + m_deltaStepMinimum[i] = 1.1 * goodVal; + } + + } + } + //==================================================================================================================== + void NonlinearSolver::setDeltaBoundsMagnitudes(const doublereal * const deltaStepMinimum) + { + + for (int i = 0; i < neq_; i++) { + m_deltaStepMinimum[i] = deltaStepMinimum[i]; + } + m_manualDeltaStepSet = 1; + } + //==================================================================================================================== + /* + * + * Return the factor by which the undamped Newton step 'step0' + * must be multiplied in order to keep the update within the bounds of an accurate jacobian. + * + * The idea behind these is that the Jacobian couldn't possibly be representative, if the + * variable is changed by a lot. (true for nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: + * factor of 1.5 + * Maximum decrease in variable in any one newton iteration: + * factor of 2 + * + * @param y_n_curr Initial value of the solution vector + * @param step_1 initial proposed step size + * + * @return returns the damping factor + */ + double + NonlinearSolver::deltaBoundStep(const doublereal * const y_n_curr, const doublereal * const step_1) { + + int i_fbounds = 0; + int ifbd = 0; + int i_fbd = 0; + doublereal UPFAC = 2.0; + + doublereal sameSign = 0.0; + doublereal ff; + doublereal f_delta_bounds = 1.0; + doublereal ff_alt; + for (int i = 0; i < neq_; i++) { + doublereal y_new = y_n_curr[i] + step_1[i]; + sameSign = y_new * y_n_curr[i]; + + /* + * Now do a delta bounds + * Increase variables by a factor of UPFAC only + * decrease variables by a factor of 2 only + */ + ff = 1.0; + + + if (sameSign >= 0.0) { + if ((fabs(y_new) > UPFAC * fabs(y_n_curr[i])) && + (fabs(y_new - y_n_curr[i]) > m_deltaStepMinimum[i])) { + ff = (UPFAC - 1.0) * fabs(y_n_curr[i]/(y_new - y_n_curr[i])); + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + ifbd = 1; + } + if ((fabs(2.0 * y_new) < fabs(y_n_curr[i])) && + (fabs(y_new - y_n_curr[i]) > m_deltaStepMinimum[i])) { + ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (1.0 - 2.0)/2.0; + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + ifbd = 0; + } + } else { + /* + * This handles the case where the value crosses the origin. + * - First we don't let it cross the origin until its shrunk to the size of m_deltaStepMinimum[i] + */ + if (fabs(y_n_curr[i]) > m_deltaStepMinimum[i]) { + ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (1.0 - 2.0)/2.0; + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + if (y_n_curr[i] >= 0.0) { + ifbd = 0; + } else { + ifbd = 1; + } + } + /* + * Second when it does cross the origin, we make sure that its magnitude is only 50% of the previous value. + */ + else if (fabs(y_new) > 0.5 * fabs(y_n_curr[i])) { + ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (-1.5); + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + ifbd = 0; + } + } + + if (ff < f_delta_bounds) { + f_delta_bounds = ff; + i_fbounds = i; + i_fbd = ifbd; + } + + + } + + + /* + * Report on any corrections + */ + if (m_print_flag >= 3) { + if (f_delta_bounds < 1.0) { + if (i_fbd) { + printf("\t\tdeltaBoundStep: Increase of Variable %d causing " + "delta damping of %g: origVal = %10.3g, undampedNew = %10.3g, dampedNew = %10.3g\n", + i_fbounds, f_delta_bounds, y_n_curr[i_fbounds], y_n_curr[i_fbounds] + step_1[i_fbounds], + y_n_curr[i_fbounds] + f_delta_bounds * step_1[i_fbounds] ); + } else { + printf("\t\tdeltaBoundStep: Decrease of variable %d causing" + "delta damping of %g: origVal = %10.3g, undampedNew = %10.3g, dampedNew = %10.3g\n", + i_fbounds, f_delta_bounds, y_n_curr[i_fbounds], y_n_curr[i_fbounds] + step_1[i_fbounds], + y_n_curr[i_fbounds] + f_delta_bounds * step_1[i_fbounds]); + } + } + } + + + return f_delta_bounds; + } + //==================================================================================================================== + // Readjust the trust region vectors + /* + * The trust region is made up of the trust region vector calculation and the trustDelta_ value + * We periodically recalculate the trustVector_ values so that they renormalize to the + * correct length. + */ + void NonlinearSolver::readjustTrustVector() + { + doublereal trustDeltaOld = trustDelta_; + doublereal wtSum = 0.0; + for (int i = 0; i < neq_; i++) { + wtSum += m_ewt[i]; + } + wtSum /= neq_; + doublereal trustNorm = solnErrorNorm(DATA_PTR(deltaX_trust_)); + doublereal deltaXSizeOld = trustNorm; + doublereal trustNormGoal = trustNorm * trustDelta_; + + // This is the size of each component. + // doublereal trustDeltaEach = trustDelta_ * trustNorm / neq_; + doublereal oldVal; + doublereal fabsy; + // we use the old value of the trust region as an indicator + for (int i = 0; i < neq_; i++) { + oldVal = deltaX_trust_[i]; + fabsy = fabs(m_y_n_curr[i]); + // First off make sure that each trust region vector is 1/2 the size of each variable or smaller + // unless overridden by the deltaStepMininum value. + // doublereal newValue = trustDeltaEach * m_ewt[i] / wtSum; + doublereal newValue = trustNormGoal * m_ewt[i]; + if (newValue > 0.5 * fabsy) { + if (fabsy * 0.5 > m_deltaStepMinimum[i]) { + deltaX_trust_[i] = 0.5 * fabsy; + } else { + deltaX_trust_[i] = m_deltaStepMinimum[i]; + } + } else { + if (newValue > 4.0 * oldVal) { + newValue = 4.0 * oldVal; + } else if (newValue < 0.25 * oldVal) { + newValue = 0.25 * oldVal; + if (deltaX_trust_[i] < m_deltaStepMinimum[i]) { + newValue = m_deltaStepMinimum[i]; + } + } + deltaX_trust_[i] = newValue; + if (deltaX_trust_[i] > 0.75 * m_deltaStepMaximum[i]) { + deltaX_trust_[i] = 0.75 * m_deltaStepMaximum[i]; + } + } + } + + + // Final renormalization. + norm_deltaX_trust_ = solnErrorNorm(DATA_PTR(deltaX_trust_)); + doublereal sum = trustNormGoal / trustNorm; + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = deltaX_trust_[i] * sum; + } + norm_deltaX_trust_ = solnErrorNorm(DATA_PTR(deltaX_trust_)); + trustDelta_ = trustNormGoal / norm_deltaX_trust_; + + if (doDogLeg_ && m_print_flag >= 4) { + printf("\t\t reajustTrustVector(): Trust size = %11.3E: Old deltaX size = %11.3E trustDelta_ = %11.3E\n" + "\t\t new deltaX size = %11.3E trustdelta_ = %11.3E\n", + trustNormGoal, deltaXSizeOld, trustDeltaOld, norm_deltaX_trust_, trustDelta_ ); + } + } + //==================================================================================================================== + //! Initialize the size of the trust vector. + /*! + * The algorithm we use is to set it equal to the length of the Distance to the Cauchy point. + */ + void NonlinearSolver::initializeTrustRegion() + { + if (trustRegionInitializationMethod_ == 0) { + return; + } + if (trustRegionInitializationMethod_ == 1) { + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = m_ewt[i] * trustRegionInitializationFactor_; + } + trustDelta_ = 1.0; + } + if (trustRegionInitializationMethod_ == 2) { + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = m_ewt[i] * m_normDeltaSoln_CP * trustRegionInitializationFactor_; + } + doublereal cpd = calcTrustDistance(deltaX_CP_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd); + } + trustDelta_ = trustDelta_ * cpd * trustRegionInitializationFactor_; + readjustTrustVector(); + cpd = calcTrustDistance(deltaX_CP_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd); + } + } + if (trustRegionInitializationMethod_ == 3) { + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = m_ewt[i] * m_normDeltaSoln_Newton * trustRegionInitializationFactor_; + } + doublereal cpd = calcTrustDistance(deltaX_Newton_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Newton Vector wrt Trust Vector = %g\n", cpd); + } + trustDelta_ = trustDelta_ * cpd; + readjustTrustVector(); + cpd = calcTrustDistance(deltaX_Newton_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Newton Vector wrt Trust Vector = %g\n", cpd); + } + } + } + + //==================================================================================================================== + // Fill a dogleg solution step vector + /* + * Previously, we have filled up deltaX_Newton_[], deltaX_CP_[], and Nuu_, so that + * this routine is straightforward. + * + * @param leg Leg of the dog leg you are on (0, 1, or 2) + * @param alpha Relative length along the dog length that you are on. + * @param deltaX Vector to be filled up + */ + void NonlinearSolver::fillDogLegStep(int leg, doublereal alpha, std::vector & deltaX) const { + if (leg == 0) { + for (int i = 0; i < neq_; i++) { + deltaX[i] = alpha * deltaX_CP_[i]; + } + } else if (leg == 2) { + for (int i = 0; i < neq_; i++) { + deltaX[i] = (alpha + (1.0 - alpha) * Nuu_) * deltaX_Newton_[i]; + } + } else { + for (int i = 0; i < neq_; i++) { + deltaX[i] = deltaX_CP_[i] * (1.0 - alpha) + alpha * Nuu_ * deltaX_Newton_[i]; + } + } + } + //==================================================================================================================== + // Calculate the trust distance of a step in the solution variables + /* + * The trust distance is defined as the length of the step according to the norm wrt to the trust region. + * We calculate the trust distance by the following method + * + * trustDist = || delta_x dot 1/trustDeltaX_ || / trustDelta_ + * + * @param deltaX Current value of deltaX + */ + doublereal NonlinearSolver::calcTrustDistance(std::vector const & deltaX) const + { + doublereal sum = 0.0; + doublereal tmp = 0.0; + for (int i = 0; i < neq_; i++) { + tmp = deltaX[i] / deltaX_trust_[i]; + sum += tmp * tmp; + } + sum = sqrt(sum / neq_) / trustDelta_; + return sum; + } + //==================================================================================================================== + // Given a trust distance, this routine calculates the intersection of the this distance with the + // double dogleg curve + /* + * @param trustDelta (INPUT) Value of the trust distance + * @param lambda (OUTPUT) Returns the internal coordinate of the double dogleg + * @param alpha (OUTPUT) Returns the relative distance along the appropriate leg + * @return leg (OUTPUT) Returns the leg ID (0, 1, or 2) + */ + int NonlinearSolver::calcTrustIntersection(doublereal trustDelta, doublereal &lambda, doublereal &alpha) const + { + doublereal dist; + if (normTrust_Newton_ < trustDelta) { + lambda = 1.0; + alpha = 1.0; + return 2; + } + + if (normTrust_Newton_ * Nuu_ < trustDelta) { + alpha = (trustDelta - normTrust_Newton_ * Nuu_) / (normTrust_Newton_ - normTrust_Newton_ * Nuu_); + dist = dist_R0_ + dist_R1_ + alpha * dist_R2_; + lambda = dist / dist_Total_; + return 2; + } + if (normTrust_CP_ > trustDelta) { + lambda = 1.0; + dist = dist_R0_ * trustDelta / normTrust_CP_; + lambda = dist / dist_Total_; + alpha = trustDelta / normTrust_CP_; + return 0; + } + doublereal sumv = 0.0; + for (int i = 0; i < neq_; i++) { + sumv += (deltaX_Newton_[i] / deltaX_trust_[i]) * (deltaX_CP_[i] / deltaX_trust_[i]); + } + + doublereal a = normTrust_Newton_ * normTrust_Newton_ * Nuu_ * Nuu_; + doublereal b = 2.0 * Nuu_ * sumv; + doublereal c = normTrust_CP_ * normTrust_CP_ - trustDelta * trustDelta; + + alpha =( -b + sqrt( b * b - 4.0 * a * c)) / (2.0 * a); + + + dist = dist_R0_ + alpha * dist_R1_; + lambda = dist / dist_Total_; + return 1; + } + //==================================================================================================================== + /* * * boundStep(): * @@ -501,11 +2363,11 @@ namespace Cantera { * Maximum decrease in variable in any one newton iteration: * factor of 5 */ - double NonlinearSolver::boundStep(const double* const y, - const double* const step0, const int loglevel) { - int i, i_lower = -1, i_fbounds, ifbd = 0, i_fbd = 0; - double fbound = 1.0, f_bounds = 1.0, f_delta_bounds = 1.0; - double ff, y_new, ff_alt; + doublereal NonlinearSolver::boundStep(const doublereal * const y, const doublereal * const step0) + { + int i, i_lower = -1; + doublereal fbound = 1.0, f_bounds = 1.0; + doublereal ff, y_new; for (i = 0; i < neq_; i++) { y_new = y[i] + step0[i]; @@ -513,8 +2375,8 @@ namespace Cantera { * Force the step to only take 80% a step towards the lower bounds */ if (step0[i] < 0.0) { - if (y_new < m_y_low_bounds[i]) { - double legalDelta = 0.8*(m_y_low_bounds[i] - y[i]); + if (y_new < (y[i] + 0.8 * (m_y_low_bounds[i] - y[i]))) { + doublereal legalDelta = 0.8*(m_y_low_bounds[i] - y[i]); ff = legalDelta / step0[i]; if (ff < f_bounds) { f_bounds = ff; @@ -526,8 +2388,8 @@ namespace Cantera { * Force the step to only take 80% a step towards the high bounds */ if (step0[i] > 0.0) { - if (y_new > m_y_high_bounds[i]) { - double legalDelta = 0.8*(m_y_high_bounds[i] - y[i]); + if (y_new > (y[i] + 0.8 * (m_y_high_bounds[i] - y[i]))) { + doublereal legalDelta = 0.8*(m_y_high_bounds[i] - y[i]); ff = legalDelta / step0[i]; if (ff < f_bounds) { f_bounds = ff; @@ -535,63 +2397,26 @@ namespace Cantera { } } } - /** - * Now do a delta bounds - * Increase variables by a factor of 2 only - * decrease variables by a factor of 5 only - */ - ff = 1.0; - if ((fabs(y_new) > 2.0 * fabs(y[i])) && - (fabs(y_new-y[i]) > m_ewt[i])) { - ff = fabs(y[i]/(y_new - y[i])); - ff_alt = fabs(m_ewt[i] / (y_new - y[i])); - ff = MAX(ff, ff_alt); - ifbd = 1; - } - if ((fabs(5.0 * y_new) < fabs(y[i])) && - (fabs(y_new - y[i]) > m_ewt[i])) { - ff = y[i]/(y_new-y[i]) * (1.0 - 5.0)/5.0; - ff_alt = fabs(m_ewt[i] / (y_new - y[i])); - ff = MAX(ff, ff_alt); - ifbd = 0; - } - if (ff < f_delta_bounds) { - f_delta_bounds = ff; - i_fbounds = i; - i_fbd = ifbd; - } - f_delta_bounds = MIN(f_delta_bounds, ff); + } - fbound = MIN(f_bounds, f_delta_bounds); + /* * Report on any corrections */ - if (loglevel > 1) { - if (fbound != 1.0) { - if (f_bounds < f_delta_bounds) { - printf("\t\tboundStep: Variable %d causing bounds " - "damping of %g\n", - i_lower, f_bounds); - } else { - if (ifbd) { - printf("\t\tboundStep: Decrease of Variable %d causing " - "delta damping of %g\n", - i_fbd, f_delta_bounds); - } else { - printf("\t\tboundStep: Increase of variable %d causing" - "delta damping of %g\n", - i_fbd, f_delta_bounds); - } - } + if (m_print_flag >= 3) { + if (f_bounds != 1.0) { + printf("\t\tboundStep: Variable %d causing bounds damping of %g\n", i_lower, f_bounds); } } - //return fbound; - return 1.0; - } - /************************************************************************** - * - * dampStep(): + doublereal f_delta_bounds = deltaBoundStep(y, step0); + fbound = MIN(f_bounds, f_delta_bounds); + + return fbound; + } + //=================================================================================================================== + // Find a damping coefficient through a look-ahead mechanism + /* * * On entry, step0 must contain an undamped Newton step to the * current solution y0. This method attempts to find a damping coefficient @@ -599,31 +2424,46 @@ namespace Cantera { * that of step0. If successful, the new solution after taking the * damped step is returned in y1, and the undamped step at y1 is * returned in step1. + * + * + * @return 1 Successful step was taken: Next step was less than previous step. + * s1 is calculated + * 2 Successful step: Next step's norm is less than 0.8 + * 3 Success: The final residual is less than 1.0 + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 4 Success: The final residual is less than the residual + * from the previous step. + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 0 Uncertain Success: s1 is about the same as s0 + * NSOLN_RETN_FAIL_DAMPSTEP + * Unsuccessful step. We can not find a damping factor that is suitable. */ - int NonlinearSolver::dampStep(const double time_curr, const double* y0, - const double *ydot0, const double* step0, - double* const y1, double* const ydot1, double* step1, - double& s1, SquareMatrix& jac, - int& loglevel, bool writetitle, - int& num_backtracks) { - - - // Compute the weighted norm of the undamped step size step0 - double s0 = solnErrorNorm(step0); + int NonlinearSolver::dampStep(const doublereal time_curr, const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, doublereal * const step_1, + doublereal * const y_n_1, doublereal * const ydot_n_1, doublereal * const step_2, + doublereal & stepNorm_2, GeneralMatrix& jac, bool writetitle, int& num_backtracks) + { + int j, m; + int info = 0; + int retnTrial = NSOLN_RETN_FAIL_DAMPSTEP; + // Compute the weighted norm of the undamped step size step_1 + doublereal stepNorm_1 = solnErrorNorm(step_1); - // Compute the multiplier to keep all components in bounds - // A value of one indicates that there is no limitation - // on the current step size in the nonlinear method due to - // bounds constraints (either negative values of delta + doublereal * step_1_orig = DATA_PTR(m_wksp); + for (j = 0; j < neq_; j++) { + step_1_orig[j] = step_1[j]; + } + + + // Compute the multiplier to keep all components in bounds.A value of one indicates that there is no limitation + // on the current step size in the nonlinear method due to bounds constraints (either negative values of delta // bounds constraints. - double fbound = boundStep(y0, step0, loglevel); + m_dampBound = boundStep(y_n_curr, step_1); - // if fbound is very small, then y0 is already close to the - // boundary and step0 points out of the allowed domain. In - // this case, the Newton algorithm fails, so return an error - // condition. - if (fbound < 1.e-10) { - if (loglevel > 1) printf("\t\t\tdampStep: At limits.\n"); + // If fbound is very small, then y0 is already close to the boundary and step0 points out of the allowed domain. In + // this case, the Newton algorithm fails, so return an error condition. + if (m_dampBound < 1.e-30) { + if (m_print_flag > 1) printf("\t\t\tdampStep(): At limits.\n"); return -3; } @@ -632,13 +2472,13 @@ namespace Cantera { //-------------------------------------------- // damping coefficient starts at 1.0 - double damp = 1.0; - int j, m; - double ff; + m_dampRes = 1.0; + + doublereal ff = m_dampBound; num_backtracks = 0; for (m = 0; m < NDAMP; m++) { - ff = fbound*damp; + ff = m_dampBound * m_dampRes; // step the solution by the damped step size /* @@ -646,33 +2486,97 @@ namespace Cantera { * update the time derivative. */ for (j = 0; j < neq_; j++) { - y1[j] = y0[j] + ff * step0[j]; + step_1[j] = ff * step_1_orig[j]; + y_n_1[j] = y_n_curr[j] + step_1[j]; + } + + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y_n_1, ydot_n_1); + } + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_curr, Base_LaggedSolutionComponents); + } + if (info != 1) { + if (m_print_flag > 0) { + printf("\t\t\tdampStep(): current trial step and damping led to Residual Calc ERROR %d. Bailing\n", info); + } + return -1; + } + m_normResidTrial = residErrorNorm(DATA_PTR(m_resid)); + m_normResid_1 = m_normResidTrial; + if (m == 0) { + m_normResid_Bound = m_normResidTrial; } - calc_ydot(m_order, y1, ydot1); - doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, y1, ydot1, step1, loglevel); - - // compute the next undamped step, step1[], that would result - // if y1[] were accepted. + bool steepEnough = (m_normResidTrial < m_normResid_0 * (0.9 * (1.0 - ff) * (1.0 - ff)* (1.0 - ff) + 0.1)); - doNewtonSolve(time_curr, y1, ydot1, step1, jac, loglevel); + if (m_normResidTrial < 1.0 || steepEnough) { + if (m_print_flag >= 5) { + if (m_normResidTrial < 1.0) { + printf("\t dampStep(): Current trial step and damping" + " coefficient accepted because residTrial test step < 1:\n"); + printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); + } else if (steepEnough) { + printf("\t dampStep(): Current trial step and damping" + " coefficient accepted because resid0 > residTrial and steep enough:\n"); + printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); + } else { + printf("\t dampStep(): Current trial step and damping" + " coefficient accepted because residual solution damping is turned off:\n"); + printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); + } + } + /* + * We aren't going to solve the system if we don't need to. Therefore, return an estimate + * of the next solution update based on the ratio of the residual reduction. + */ + if (m_normResid_0 > 0.0) { + stepNorm_2 = stepNorm_1 * m_normResidTrial / m_normResid_0; + } + else { + stepNorm_2 = 0; + } + if (m_normResidTrial < 1.0) { + retnTrial = 3; + } else { + retnTrial = 4; + } + break; + } + + // Compute the next undamped step, step1[], that would result if y1[] were accepted. + // We now have two steps that we have calculated step0[] and step1[] + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doNewtonSolve(time_curr, y_n_1, ydot_n_1, step_2, jac); + } else { + info = doNewtonSolve(time_curr, y_n_1, ydot_n_curr, step_2, jac); + } + if (info) { + if (m_print_flag > 0) { + printf("\t\t\tdampStep: current trial step and damping led to LAPACK ERROR %d. Bailing\n", info); + } + return -1; + } // compute the weighted norm of step1 - s1 = solnErrorNorm(step1); + stepNorm_2 = solnErrorNorm(step_2); // write log information - if (loglevel > 3) { - print_solnDelta_norm_contrib((const double *) step0, - "DeltaSolnTrial", - (const double *) step1, - "DeltaSolnTrialTest", - "dampNewt: Important Entries for " - "Weighted Soln Updates:", - y0, y1, ff, 5); + if (m_print_flag >= 5) { + print_solnDelta_norm_contrib((const doublereal *) step_1_orig, "DeltaSoln", + (const doublereal *) step_2, "DeltaSolnTrial", + "dampNewt: Important Entries for Weighted Soln Updates:", + y_n_curr, y_n_1, ff, 5); } - if (loglevel > 1) { - printf("\t\t\tdampNewt: s0 = %g, s1 = %g, fbound = %g," - "damp = %g\n", s0, s1, fbound, damp); + if (m_print_flag >= 4) { + printf("\t\t\tdampStep(): s1 = %g, s2 = %g, dampBound = %g," + "dampRes = %g\n", stepNorm_1, stepNorm_2, m_dampBound, m_dampRes); } @@ -681,21 +2585,23 @@ namespace Cantera { // step would result in a converged solution. Otherwise, // decrease the damping coefficient and try again. - if (s1 < 1.0E-5 || s1 < s0) { - if (loglevel > 2) { - if (s1 > s0) { - if (s1 > 1.0) { - printf("\t\t\tdampStep: current trial step and damping" - " coefficient accepted because test step < 1\n"); - printf("\t\t\t s1 = %g, s0 = %g\n", s1, s0); + if (stepNorm_2 < 0.8 || stepNorm_2 < stepNorm_1) { + if (stepNorm_2 < 1.0) { + if (m_print_flag >= 3) { + if (stepNorm_2 < 1.0) { + printf("\t\t\tdampStep: current trial step and damping coefficient accepted because test step < 1\n"); + printf("\t\t\t s2 = %g, s1 = %g\n", stepNorm_2, stepNorm_1); } - } + } + retnTrial = 2; + } else { + retnTrial = 1; } break; } else { - if (loglevel > 1) { + if (m_print_flag > 1) { printf("\t\t\tdampStep: current step rejected: (s1 = %g > " - "s0 = %g)", s1, s0); + "s0 = %g)", stepNorm_2, stepNorm_1); if (m < (NDAMP-1)) { printf(" Decreasing damping factor and retrying"); } else { @@ -705,25 +2611,413 @@ namespace Cantera { } } num_backtracks++; - damp /= DampFactor; + m_dampRes /= DampFactor; } // If a damping coefficient was found, return 1 if the // solution after stepping by the damped step would represent // a converged solution, and return 0 otherwise. If no damping - // coefficient could be found, return -2. + // coefficient could be found, return NSOLN_RETN_FAIL_DAMPSTEP. if (m < NDAMP) { - if (s1 > 1.0) return 0; - else return 1; + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current trial step accepted retnTrial = %d, its = %d, damp = %g\n", retnTrial, m+1, ff); + } + return retnTrial; } else { - if (s1 < 0.5 && (s0 < 0.5)) return 1; - if (s1 < 1.0) return 0; + if (stepNorm_2 < 0.5 && (stepNorm_1 < 0.5)) { + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current trial step accepted kindof retnTrial = %d, its = %d, damp = %g\n", 2, m+1, ff); + } + return 2; + } + if (stepNorm_2 < 1.0) { + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current trial step accepted and soln converged retnTrial =" + "%d, its = %d, damp = %g\n", 0, m+1, ff); + } + return 0; + } + } + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current direction is rejected! retnTrial = %d, its = %d, damp = %g\n", + NSOLN_RETN_FAIL_DAMPSTEP, m+1, ff); + } + return NSOLN_RETN_FAIL_DAMPSTEP; + } + //==================================================================================================================== + // Damp using the dog leg approach + /* + * + * @param time_curr INPUT Current value of the time + * @param y_n_curr INPUT Current value of the solution vector + * @param ydot_n_curr INPUT Current value of the derivative of the solution vector + * @param step_1 INPUT First trial step for the first iteration + * @param y_n_1 INPUT First trial value of the solution vector + * @param ydot_n_1 INPUT First trial value of the derivative of the solution vector + * @param s1 OUTPUT Norm of the vector step_1 + * @param jac INPUT jacobian + * @param numTrials OUTPUT number of trials taken in the current damping step + * + * + * @return 1 Success: Good step was taken. The predicted residual norm is less than one + * 2 Success: Good step: Next step's norm is less than 0.8 + * 3 Success: The final residual is less than 1.0 + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 4 Success: The final residual is less than the residual from the previous step. + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 0 Unknown Uncertain Success: s1 is about the same as s0 + * NSOLN_RETN_FAIL_DAMPSTEP + * Unsuccessful step. Can not find a damping coefficient that is suitable + */ + int NonlinearSolver::dampDogLeg(const doublereal time_curr, const doublereal* y_n_curr, + const doublereal *ydot_n_curr, std::vector & step_1, + doublereal* const y_n_1, doublereal* const ydot_n_1, + doublereal& stepNorm_1, doublereal& stepNorm_2, GeneralMatrix& jac, int& numTrials) + { + doublereal lambda; + int info; + + bool success = false; + int retn = 0; + bool haveASuccess = false; + doublereal trustDeltaOld = trustDelta_; + doublereal* stepLastGood = DATA_PTR(m_wksp); + //-------------------------------------------- + // Attempt damped step + //-------------------------------------------- + + // damping coefficient starts at 1.0 + m_dampRes = 1.0; + int j, m; + doublereal tlen; + + + for (m = 0; m < NDAMP; m++) { + numTrials++; + /* + * Find the initial value of lambda that satisfies the trust distance, trustDelta_ + */ + dogLegID_ = calcTrustIntersection(trustDelta_, lambda, dogLegAlpha_); + if (m_print_flag >= 4) { + tlen = trustRegionLength(); + printf("\t\t dampDogLeg: trust region with length %13.5E has intersection at leg = %d, alpha = %g, lambda = %g\n", + tlen, dogLegID_, dogLegAlpha_, lambda); + } + /* + * Figure out the new step vector, step_1, based on (leg, alpha). Here we are using the + * intersection of the trust oval with the dog-leg curve. + */ + fillDogLegStep(dogLegID_, dogLegAlpha_, step_1); + + /* + * OK, now that we have step0, Bound the step + */ + m_dampBound = boundStep(y_n_curr, DATA_PTR(step_1)); + /* + * Decrease the step length if we are bound + */ + if (m_dampBound < 1.0) { + for (j = 0; j < neq_; j++) { + step_1[j] = step_1[j] * m_dampBound; + } + } + /* + * Calculate the new solution value y1[] given the step size + */ + for (j = 0; j < neq_; j++) { + y_n_1[j] = y_n_curr[j] + step_1[j]; + } + /* + * Calculate the new solution time derivative given the step size + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y_n_1, ydot_n_1); + } + /* + * OK, we have the step0. Now, ask the question whether it satisfies the acceptance criteria + * as a good step. The overall outcome is returned in the variable info. + */ + info = decideStep(time_curr, dogLegID_, dogLegAlpha_, y_n_curr, ydot_n_curr, step_1, + y_n_1, ydot_n_1, trustDeltaOld); + m_normResid_Bound = m_normResid_1; + + /* + * The algorithm failed to find a solution vector sufficiently different than the current point + */ + if (info == -1) { + + if (m_print_flag >= 1) { + doublereal stepNorm = solnErrorNorm(DATA_PTR(step_1)); + printf("\t\t dampDogLeg: Current direction rejected, update became too small %g\n", stepNorm); + success = false; + retn = NSOLN_RETN_FAIL_STEPTOOSMALL; + break; + } + } + if (info == -2) { + if (m_print_flag >= 1) { + printf("\t\t dampDogLeg: current trial step and damping led to LAPACK ERROR %d. Bailing\n", info); + success = false; + retn = NSOLN_RETN_MATRIXINVERSIONERROR; + break; + } + } + if (info == 0) { + success = true; + break; + } + if (info == 3) { + + haveASuccess = true; + // Store the good results in stepLastGood + mdp::mdp_copy_dbl_1(DATA_PTR(stepLastGood), CONSTD_DATA_PTR(step_1), neq_); + // Within the program decideStep(), we have already increased the value of trustDelta_. We store the + // value of step0 in step1, recalculate a larger step0 in the next fillDogLegStep(), + // and then attempt to see if the larger step works in the next iteration + } + if (info == 2) { + // Step was a failure. If we had a previous success with a smaller stepsize, haveASuccess is true + // and we execute the next block and break. If we didn't have a previous success, trustDelta_ has + // already been decreased in the decideStep() routine. We go back and try another iteration with + // a smaller trust region. + if (haveASuccess) { + mdp::mdp_copy_dbl_1(DATA_PTR(step_1), CONSTD_DATA_PTR(stepLastGood), neq_); + for (j = 0; j < neq_; j++) { + y_n_1[j] = y_n_curr[j] + step_1[j]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y_n_1, ydot_n_1); + } + success = true; + break; + } else { + + } + } + } + + /* + * Estimate s1, the norm after the next step + */ + stepNorm_1 = solnErrorNorm(DATA_PTR(step_1)); + stepNorm_2 = stepNorm_1; + if (m_dampBound < 1.0) { + stepNorm_2 /= m_dampBound; + } + stepNorm_2 /= lambda; + stepNorm_2 *= m_normResidTrial / m_normResid_0; + + + if (success) { + if (m_normResidTrial < 1.0) { + if (normTrust_Newton_ < trustDelta_ && m_dampBound == 1.0) { + return 1; + } else { + return 0; + } + } + return 0; + } + return NSOLN_RETN_FAIL_DAMPSTEP; + } + //==================================================================================================================== + // Decide whether the current step is acceptable and adjust the trust region size + /* + * This is an extension of algorithm 6.4.5 of Dennis and Schnabel. + * + * Here we decide whether to accept the current step + * At the end of the calculation a new estimate of the trust region is calculated + * + * @param time_curr INPUT Current value of the time + * @param leg INPUT Leg of the dogleg that we are on + * @param alpha INPUT Distance down that leg that we are on + * @param y0 INPUT Current value of the solution vector + * @param ydot0 INPUT Current value of the derivative of the solution vector + * @param step0 INPUT Trial step + * @param y1 OUTPUT Solution values at the conditions which are evalulated for success + * @param ydot1 OUTPUT Time derivates of solution at the conditions which are evalulated for success + * @param trustDeltaOld INPUT Value of the trust length at the old conditions + * + * + * @return This function returns a code which indicates whether the step will be accepted or not. + * 3 Step passed with flying colors. Try redoing the calculation with a bigger trust region. + * 2 Step didn't pass deltaF requirement. Decrease the size of the next trust region for a retry and return + * 0 The step passed. + * -1 The step size is now too small (||d || < 0.1). A really small step isn't decreasing the function. + * This is an error condition. + * -2 Current value of the solution vector caused a residual error in its evaluation. + * Step is a failure, and the step size must be reduced in order to proceed further. + */ + int NonlinearSolver::decideStep(const doublereal time_curr, int leg, doublereal alpha, + const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, const std::vector & step_1, + const doublereal * const y_n_1, const doublereal * const ydot_n_1, + doublereal trustDeltaOld) + { + int retn = 2; + bool goodStep = false; + int info; + doublereal ll; + // Calculate the solution step length + doublereal stepNorm = solnErrorNorm(DATA_PTR(step_1)); + + // Calculate the initial (R**2 * neq) value for the old function + doublereal normResid0_2 = m_normResid_0 * m_normResid_0 * neq_; + + // Calculate the distance to the cauchy point + doublereal cauchyDistanceNorm = solnErrorNorm(DATA_PTR(deltaX_CP_)); + + // This is the expected inital rate of decrease in the cauchy direction. + // -> This is Eqn. 29 = Rhat dot Jhat dy / || d || + doublereal funcDecreaseSDExp = RJd_norm_ / cauchyDistanceNorm * lambdaStar_; + if (funcDecreaseSDExp > 0.0) { + if (m_print_flag >= 5) { + printf("\t\tdecideStep(): Unexpected condition -> cauchy slope is positive\n"); + } + } + + /* + * Calculate the residual that would result if y1[] were the new solution vector. + * The Lagged solution components are kept lagged here. Unfortunately, it just doesn't work in some cases to use a + * Jacobian from a lagged state and then use a residual from an unlagged condition. The linear model doesn't + * agree with the nonlinear model. + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_curr, Base_LaggedSolutionComponents); + } + + if (info != 1) { + if (m_print_flag >= 2) { + printf("\t\tdecideStep: current trial step and damping led to Residual Calc ERROR %d. Bailing\n", info); + } return -2; } - } + /* + * Ok we have a successful new residual. Calculate the normalized residual value and store it in + * m_normResidTrial + */ + m_normResidTrial = residErrorNorm(DATA_PTR(m_resid)); + doublereal normResidTrial_2 = neq_ * m_normResidTrial * m_normResidTrial; - /** - * + /* + * We have a minimal acceptance test for passage. deltaf < 1.0E-4 (CauchySlope) (deltS) + * This is the condition that D&S use in 6.4.5 + */ + doublereal funcDecrease = 0.5 * (normResidTrial_2 - normResid0_2); + doublereal acceptableDelF = funcDecreaseSDExp * stepNorm * 1.0E-4; + if (funcDecrease < acceptableDelF) { + m_normResid_1 = m_normResidTrial; + goodStep = true; + m_normResid_1 = m_normResidTrial; + retn = 0; + if (m_print_flag >= 4) { + printf("\t\t decideStep: Norm Residual(leg=%1d, alpha=%10.2E) = %11.4E passes\n", + dogLegID_, dogLegAlpha_, m_normResidTrial); + } + } else { + if (m_print_flag >= 4) { + printf("\t\t decideStep: Norm Residual(leg=%1d, alpha=%10.2E) = %11.4E failes\n", + dogLegID_, dogLegAlpha_, m_normResidTrial); + } + trustDelta_ *= 0.33; + CurrentTrustFactor_ *= 0.33; + retn = 2; + // error condition if step is getting too small + if (rtol_ * stepNorm < 1.0E-6) { + retn = -1; + } + return retn; + } + /* + * Figure out the next trust region. We are here iff retn = 0 + * + * If we had to bounds delta the update, decrease the trust region + */ + if (m_dampBound < 1.0) { + // trustDelta_ *= 0.5; + // NextTrustFactor_ *= 0.5; + // ll = trustRegionLength(); + // if (m_print_flag >= 5) { + // printf("\t\tdecideStep(): Trust region decreased from %g to %g due to bounds constraint\n", ll*2, ll); + //} + } else { + retn = 0; + /* + * Calculate the expected residual from the quadratic model + */ + doublereal expectedNormRes = expectedResidLeg(leg, alpha); + doublereal expectedFuncDecrease = 0.5 * (neq_ * expectedNormRes * expectedNormRes - normResid0_2); + if (funcDecrease > 0.1 * expectedFuncDecrease) { + if ((m_normResidTrial > 0.5 * m_normResid_0) && (m_normResidTrial > 0.1)) { + trustDelta_ *= 0.5; + NextTrustFactor_ *= 0.5; + ll = trustRegionLength(); + if (m_print_flag >= 4) { + printf("\t\t decideStep: Trust region decreased from %g to %g due to bad quad approximation\n", + ll*2, ll); + } + } + } else { + /* + * If we are doing well, consider increasing the trust region and recalculating + */ + if (funcDecrease < 0.8 * expectedFuncDecrease || (m_normResidTrial < 0.33 * m_normResid_0)) { + if (trustDelta_ <= trustDeltaOld && (leg != 2 || alpha < 0.75) ) { + trustDelta_ *= 2.0; + CurrentTrustFactor_ *= 2; + adjustUpStepMinimums(); + ll = trustRegionLength(); + if (m_print_flag >= 4) { + if (m_normResidTrial < 0.33 * m_normResid_0) { + printf("\t\t decideStep: Redo line search with trust region increased from %g to %g due to good nonlinear behavior\n", + ll*0.5, ll); + } else { + printf("\t\t decideStep: Redi line search with trust region increased from %g to %g due to good linear model approximation\n", + ll*0.5, ll); + } + } + retn = 3; + } else { + /* + * Increase the size of the trust region for the next calculation + */ + if (m_normResidTrial < 0.99 * expectedNormRes || (m_normResidTrial < 0.20 * m_normResid_0) || + (funcDecrease < -1.0E-50 && ( funcDecrease < 0.9 *expectedFuncDecrease)) ) { + if (leg == 2 && alpha == 1.0 ) { + ll = trustRegionLength(); + if (ll < 2.0 * m_normDeltaSoln_Newton) { + trustDelta_ *= 2.0; + NextTrustFactor_ *= 2.0; + adjustUpStepMinimums(); + ll = trustRegionLength(); + if (m_print_flag >= 4) { + printf("\t\t decideStep: Trust region further increased from %g to %g next step due to good linear model behavior\n", + ll*0.5, ll); + } + } + } else { + ll = trustRegionLength(); + trustDelta_ *= 2.0; + NextTrustFactor_ *= 2.0; + adjustUpStepMinimums(); + ll = trustRegionLength(); + if (m_print_flag >= 4) { + printf("\t\t decideStep: Trust region further increased from %g to %g next step due to good linear model behavior\n", + ll*0.5, ll); + } + } + } + } + } + } + } + return retn; + } + //==================================================================================================================== + /* * solve_nonlinear_problem(): * * Find the solution to F(X) = 0 by damped Newton iteration. On @@ -732,206 +3026,589 @@ namespace Cantera { * * SolnType = TRANSIENT -> we will assume we are relaxing a transient * equation system for now. Will make it more general later, - * if an application comes up. - * + * if an application comes up. + * + * @return A positive value indicates a successful convergence + * -1 Failed convergence */ - int NonlinearSolver::solve_nonlinear_problem(int SolnType, double* y_comm, - double* ydot_comm, double CJ, - double time_curr, - SquareMatrix& jac, - int &num_newt_its, - int &num_linear_solves, - int &num_backtracks, - int loglevelInput) + int NonlinearSolver::solve_nonlinear_problem(int SolnType, doublereal * const y_comm, doublereal * const ydot_comm, + doublereal CJ, doublereal time_curr, GeneralMatrix& jac, + int &num_newt_its, int &num_linear_solves, + int &num_backtracks, int loglevelInput) { clockWC wc; + int convRes = 0; + solnType_ = SolnType; + int info = 0; bool m_residCurrent = false; - int m = 0; + num_linear_solves -= m_numTotalLinearSolves; + int retnDamp = 0; + int retnCode = 0; bool forceNewJac = false; - double s1=1.e30; - std::vector y_curr(neq_, 0.0); - std::vector ydot_curr(neq_, 0.0); - std::vector stp(neq_, 0.0); - std::vector stp1(neq_, 0.0); - - std::vector y_new(neq_, 0.0); - std::vector ydot_new(neq_, 0.0); - - mdp::mdp_copy_dbl_1(DATA_PTR(y_curr), y_comm, neq_); - // copyn((size_t)neq_, y_comm, y_curr); - mdp::mdp_copy_dbl_1(DATA_PTR(ydot_curr), ydot_comm, neq_); - - + if (jacCopyPtr_) { + delete jacCopyPtr_; + } + jacCopyPtr_ = jac.duplMyselfAsGeneralMatrix(); + + doublereal stepNorm_1; + doublereal stepNorm_2; +#ifdef DEBUG_MODE + int legBest; + doublereal alphaBest; +#endif + bool trInit = false; + + mdp::mdp_copy_dbl_1(DATA_PTR(m_y_n_curr), DATA_PTR(y_comm), neq_); + + if (SolnType != NSOLN_TYPE_STEADY_STATE || ydot_comm) { + mdp::mdp_copy_dbl_1(DATA_PTR(m_ydot_n_curr), ydot_comm, neq_); + mdp::mdp_copy_dbl_1(DATA_PTR(m_ydot_n_1), ydot_comm, neq_); + } + // Redo the solution weights every time we enter the function + createSolnWeights(DATA_PTR(m_y_n_curr)); + m_normDeltaSoln_Newton = 1.0E1; bool frst = true; num_newt_its = 0; - num_linear_solves = - m_numTotalLinearSolves; num_backtracks = 0; - int i_backtracks; - int loglevel = loglevelInput; + int i_numTrials; + m_print_flag = loglevelInput; + + if (trustRegionInitializationMethod_ == 0) { + trInit = true; + } else if (trustRegionInitializationMethod_ == 1) { + trInit = true; + initializeTrustRegion(); + } else { + mdp::mdp_init_dbl_1(DATA_PTR(deltaX_trust_), 1.0, neq_); + trustDelta_ = 1.0; + } + + if (m_print_flag == 2 || m_print_flag == 3) { + printf("\tsolve_nonlinear_problem():\n\n"); + if (doDogLeg_) { + printf("\tWt Iter Resid NewJac log(CN)| dRdS_CDexp dRdS_CD dRdS_Newtexp dRdS_Newt |" + "DS_Cauchy DS_Newton DS_Trust | legID legAlpha Fbound | CTF NTF | nTr|" + "DS_Final ResidLag ResidFull\n"); + printf("\t---------------------------------------------------------------------------------------------------" + "--------------------------------------------------------------------------------\n"); + } else { + printf("\t Wt Iter Resid NewJac | Fbound ResidBound | DampIts Fdamp DS_Step1 DS_Step2" + "ResidLag | DS_Damp DS_Newton ResidFull\n"); + printf("\t--------------------------------------------------------------------------------------------------" + "----------------------------------\n"); + } + } while (1 > 0) { + CurrentTrustFactor_ = 1.0; + NextTrustFactor_ = 1.0; + ResidWtsReevaluated_ = false; + i_numTrials = 0; /* * Increment Newton Solve counter */ m_numTotalNewtIts++; num_newt_its++; + m_numLocalLinearSolves = 0; - - if (loglevel > 1) { - printf("\t\tSolve_Nonlinear_Problem: iteration %d:\n", + if (m_print_flag > 3) { + printf("\t"); + print_line("=", 119); + printf("\tsolve_nonlinear_problem(): iteration %d:\n", num_newt_its); } + /* + * If we are far enough away from the solution, redo the solution weights and the trust vectors. + */ + if (m_normDeltaSoln_Newton > 1.0E2) { + createSolnWeights(DATA_PTR(m_y_n_curr)); +#ifdef DEBUG_MODE + if (trInit) { + readjustTrustVector(); + } +#else + if (doDogLeg_ && trInit) { + readjustTrustVector(); + } +#endif + } else { + // Do this stuff every 5 iterations + if ((num_newt_its % 5) == 1) { + createSolnWeights(DATA_PTR(m_y_n_curr)); +#ifdef DEBUG_MODE + if (trInit) { + readjustTrustVector(); + } +#else + if (doDogLeg_ && trInit) { + readjustTrustVector(); + } +#endif + } + } + + /* + * Set default values of Delta bounds constraints + */ + if (!m_manualDeltaStepSet) { + setDefaultDeltaBoundsMagnitudes(); + } // Check whether the Jacobian should be re-evaluated. forceNewJac = true; if (forceNewJac) { - if (loglevel > 1) { - printf("\t\t\tGetting a new Jacobian and solving system\n"); + if (m_print_flag > 3) { + printf("\t solve_nonlinear_problem(): Getting a new Jacobian\n"); + } + info = beuler_jac(jac, DATA_PTR(m_resid), time_curr, CJ, DATA_PTR(m_y_n_curr), + DATA_PTR(m_ydot_n_curr), num_newt_its); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Jacobian Formation Error: %d Bailing\n", info); + } + retnDamp = NSOLN_RETN_JACOBIANFORMATIONERROR ; + goto done; } - beuler_jac(jac, DATA_PTR(m_resid), time_curr, CJ, DATA_PTR(y_curr), DATA_PTR(ydot_curr), - num_newt_its); m_residCurrent = true; } else { - if (loglevel > 1) { - printf("\t\t\tSolving system with old jacobian\n"); + if (m_print_flag > 1) { + printf("\t solve_nonlinear_problem(): Solving system with old jacobian\n"); } m_residCurrent = false; } /* * Go get new scales */ - setColumnScales(); + calcColumnScales(); - doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, - DATA_PTR(y_curr), DATA_PTR(ydot_curr), DATA_PTR(stp), loglevel); + /* + * Calculate the base residual + */ + if (m_print_flag >= 6) { + printf("\t solve_nonlinear_problem(): Calculate the base residual\n"); + } + info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr)); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Residual Calc ERROR %d. Bailing\n", info); + } + retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; + goto done; + } + + /* + * Scale the matrix and the rhs, if they aren't already scaled + * Figure out and store the residual scaling factors. + */ + scaleMatrix(jac, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), time_curr, num_newt_its); + + + /* + * Optional print out the initial residual + */ + if (m_print_flag >= 6) { + m_normResid_0 = residErrorNorm(DATA_PTR(m_resid), "Initial norm of the residual", 10, DATA_PTR(m_y_n_curr)); + } else { + m_normResid_0 = residErrorNorm(DATA_PTR(m_resid), "Initial norm of the residual", 0, DATA_PTR(m_y_n_curr)); + if (m_print_flag == 4 || m_print_flag == 5 ) { + printf("\t solve_nonlinear_problem(): Initial Residual Norm = %13.4E\n", m_normResid_0); + } + } + + +#ifdef DEBUG_MODE + if (m_print_flag > 3) { + printf("\t solve_nonlinear_problem(): Calculate the steepest descent direction and Cauchy Point\n"); + } + m_normDeltaSoln_CP = doCauchyPointSolve(jac); + +#else + if (doDogLeg_) { + if (m_print_flag > 3) { + printf("\t solve_nonlinear_problem(): Calculate the steepest descent direction and Cauchy Point\n"); + } + m_normDeltaSoln_CP = doCauchyPointSolve(jac); + } +#endif // compute the undamped Newton step - doNewtonSolve(time_curr, DATA_PTR(y_curr), DATA_PTR(ydot_curr), DATA_PTR(stp), - jac, loglevel); - - // damp the Newton step - m = dampStep(time_curr, DATA_PTR(y_curr), DATA_PTR(ydot_curr), - DATA_PTR(stp), DATA_PTR(y_new), DATA_PTR(ydot_new), - DATA_PTR(stp1), s1, jac, loglevel, frst, i_backtracks); - frst = false; - num_backtracks += i_backtracks; + if (doAffineSolve_) { + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Calculate the Newton direction via an Affine solve\n"); + } + info = doAffineNewtonSolve(DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), DATA_PTR(deltaX_Newton_), jac); + } else { + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Calculate the Newton direction via a Newton solve\n"); + } + info = doNewtonSolve(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), DATA_PTR(deltaX_Newton_), jac); + } + + if (info) { + retnDamp = NSOLN_RETN_MATRIXINVERSIONERROR; + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Matrix Inversion Error: %d Bailing\n", info); + } + goto done; + } + mdp::mdp_copy_dbl_1(DATA_PTR(m_step_1), CONSTD_DATA_PTR(deltaX_Newton_), neq_); + + if (m_print_flag >= 6) { + m_normDeltaSoln_Newton = solnErrorNorm(DATA_PTR(deltaX_Newton_), "Initial Undamped Newton Step of the iteration", 10); + } else { + m_normDeltaSoln_Newton = solnErrorNorm(DATA_PTR(deltaX_Newton_), "Initial Undamped Newton Step of the iteration", 0); + } + + if (m_numTotalNewtIts == 1) { + if (trustRegionInitializationMethod_ == 2 || trustRegionInitializationMethod_ == 3) { + if (m_print_flag > 3) { + if (trustRegionInitializationMethod_ == 2) { + printf("\t solve_nonlinear_problem(): Initialize the trust region size as the length of the Cauchy Vector times %f\n", + trustRegionInitializationFactor_); + } else { + printf("\t solve_nonlinear_problem(): Initialize the trust region size as the length of the Newton Vector times %f\n", + trustRegionInitializationFactor_); + } + } + initializeTrustRegion(); + trInit = true; + } + } + + + if (doDogLeg_) { + + + +#ifdef DEBUG_MODE + doublereal trustD = calcTrustDistance(m_step_1); + if (m_print_flag >= 4) { + if (trustD > trustDelta_) { + printf("\t\t Newton's method step size, %g trustVectorUnits, larger than trust region, %g trustVectorUnits\n", + trustD, trustDelta_); + printf("\t\t Newton's method step size, %g trustVectorUnits, larger than trust region, %g trustVectorUnits\n", + trustD, trustDelta_); + } else { + printf("\t\t Newton's method step size, %g trustVectorUnits, smaller than trust region, %g trustVectorUnits\n", + trustD, trustDelta_); + } + } +#endif + } + + /* + * Filter out bad directions + */ + filterNewStep(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_step_1)); + + + + if (s_print_DogLeg && m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Compare descent rates for Cauchy and Newton directions\n"); + descentComparison(time_curr, DATA_PTR(m_ydot_n_curr), DATA_PTR(m_ydot_n_1), i_numTrials); + } else { + if (doDogLeg_) { + descentComparison(time_curr, DATA_PTR(m_ydot_n_curr), DATA_PTR(m_ydot_n_1), i_numTrials); + } + } + + + + if (doDogLeg_) { + setupDoubleDogleg(); +#ifdef DEBUG_MODE + if (s_print_DogLeg && m_print_flag >= 5) { + printf("\t solve_nonlinear_problem(): Compare Linear and nonlinear residuals along double dog-leg path\n"); + residualComparisonLeg(time_curr, DATA_PTR(m_ydot_n_curr), legBest, alphaBest); + } +#endif + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Calculate damping along dog-leg path to ensure residual decrease\n"); + } + retnDamp = dampDogLeg(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), + m_step_1, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1), stepNorm_1, stepNorm_2, jac, i_numTrials); + } +#ifdef DEBUG_MODE + else { + if (s_print_DogLeg && m_print_flag >= 5) { + printf("\t solve_nonlinear_problem(): Compare Linear and nonlinear residuals along double dog-leg path\n"); + residualComparisonLeg(time_curr, DATA_PTR(m_ydot_n_curr), legBest, alphaBest); + } + } +#endif + + // Damp the Newton step + /* + * On return the recommended new solution and derivatisve is located in: + * y_new + * y_dot_new + * The update delta vector is located in + * stp1 + * The estimate of the solution update norm for the next step is located in + * s1 + */ + if (!doDogLeg_) { + retnDamp = dampStep(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), + DATA_PTR(m_step_1), DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1), + DATA_PTR(m_wksp_2), stepNorm_2, jac, frst, i_numTrials); + frst = false; + num_backtracks += i_numTrials; + stepNorm_1 = solnErrorNorm(DATA_PTR(m_step_1)); + } + /* * Impose the minimum number of newton iterations critera */ if (num_newt_its < m_min_newt_its) { - if (m == 1) m = 0; + if (retnDamp > NSOLN_RETN_CONTINUE) { + if (m_print_flag > 2) { + printf("\t solve_nonlinear_problem(): Damped Newton successful (m=%d) but minimum newton" + "iterations not attained. Resolving ...\n", retnDamp); + } + retnDamp = NSOLN_RETN_CONTINUE; + } } + /* * Impose max newton iteration */ - if (num_newt_its > 20) { - m = -1; - if (loglevel > 1) { - printf("\t\t\tDampnewton unsuccessful (max newts exceeded) sfinal = %g\n", s1); + if (num_newt_its > maxNewtIts_) { + retnDamp = NSOLN_RETN_MAXIMUMITERATIONSEXCEEDED; + if (m_print_flag > 1) { + printf("\t solve_nonlinear_problem(): Damped newton unsuccessful (max newts exceeded) sfinal = %g\n", + stepNorm_1); } } - if (loglevel > 1) { - if (m == 1) { - printf("\t\t\tDampNewton iteration successful, nonlin " - "converged sfinal = %g\n", s1); - } else if (m == 0) { - printf("\t\t\tDampNewton iteration successful, get new" - "direction, sfinal = %g\n", s1); - } else { - printf("\t\t\tDampnewton unsuccessful sfinal = %g\n", s1); + /* + * Do a full residual calculation with the unlagged solution components. + * Then get the norm of the residual + */ + info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1)); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): current trial step and damping led to Residual Calc " + "ERROR %d. Bailing\n", info); } + retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; + goto done; + } + if (m_print_flag >= 4) { + m_normResid_full = residErrorNorm(DATA_PTR(m_resid), " Resulting full residual norm", 10, DATA_PTR(m_y_n_1)); + if (fabs(m_normResid_full - m_normResid_1) > 1.0E-3 * ( m_normResid_1 + m_normResid_full + 1.0E-4)) { + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Full residual norm changed from %g to %g due to " + "lagging of components\n", m_normResid_1, m_normResid_full); + } + } + } else { + m_normResid_full = residErrorNorm(DATA_PTR(m_resid)); } - // If we are converged, then let's use the best solution possible - // for an end result. We did a resolve in dampStep(). Let's update - // the solution to reflect that. - // HKM 5/16 -> Took this out, since if the last step was a - // damped step, then adding stp1[j] is undamped, and - // may lead to oscillations. It kind of defeats the - // purpose of dampStep() anyway. - // if (m == 1) { - // for (int j = 0; j < neq_; j++) { - // y_new[j] += stp1[j]; - // HKM setting intermediate y's to zero was a tossup. - // slightly different, equivalent results - // #ifdef DEBUG_HKM - // y_new[j] = MAX(0.0, y_new[j]); - // #endif - // } - // } - + /* + * Check the convergence criteria + */ + convRes = 0; + if (retnDamp > NSOLN_RETN_CONTINUE) { + convRes = convergenceCheck(retnDamp, stepNorm_1); + } + + + + bool m_filterIntermediate = false; if (m_filterIntermediate) { - if (m == 0) { - (void) filterNewStep(time_n, DATA_PTR(y_new), DATA_PTR(ydot_new)); + if (retnDamp == NSOLN_RETN_CONTINUE) { + (void) filterNewSolution(time_n, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1)); } } + // Exchange new for curr solutions - if (m == 0 || m == 1) { - mdp::mdp_copy_dbl_1(DATA_PTR(y_curr), DATA_PTR(y_new), neq_); - calc_ydot(m_order, DATA_PTR(y_curr), DATA_PTR(ydot_curr)); + if (retnDamp >= NSOLN_RETN_CONTINUE) { + mdp::mdp_copy_dbl_1(DATA_PTR(m_y_n_curr), CONSTD_DATA_PTR(m_y_n_1), neq_); + + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr)); + } } + if (m_print_flag == 2 || m_print_flag == 3) { + // printf("\t Iter Resid NewJac | Fbound | ResidBound | Fdamp DampIts | DeltaSolnNewton ResidFinal \n"); + if (ResidWtsReevaluated_) { + printf("\t*"); + } else { + printf("\t "); + } + printf(" %3d %11.3E", num_newt_its, m_normResid_0); + bool m_jacAge = false; + if (!m_jacAge) { + printf(" Y "); + } else { + printf(" N "); + } + if (doDogLeg_) { + printf("%5.1F |", log10(m_conditionNumber)); + // printf("\t Iter Resid NewJac | DS_Cauchy DS_Newton DS_Trust | legID legAlpha Fbound | | DS_F ResidFinal \n"); + printf("%10.3E %10.3E %10.3E %10.3E|", ResidDecreaseSDExp_, ResidDecreaseSD_, + ResidDecreaseNewtExp_, ResidDecreaseNewt_); + printf("%10.3E %10.3E %10.3E|", m_normDeltaSoln_CP , m_normDeltaSoln_Newton, norm_deltaX_trust_ * trustDelta_); + printf("%2d %10.2E %10.2E", dogLegID_ , dogLegAlpha_, m_dampBound); + printf("| %3.2f %3.2f |", CurrentTrustFactor_, NextTrustFactor_); + printf(" %2d ", i_numTrials); + printf("| %10.3E %10.3E %10.3E", stepNorm_1, m_normResid_1, m_normResid_full); + } else { + printf(" |"); + printf("%10.2E %10.3E |", m_dampBound, m_normResid_Bound); + printf("%2d %10.2E %10.3E %10.3E %10.3E", i_numTrials + 1, m_dampRes, + stepNorm_1 / ( m_dampRes * m_dampBound), stepNorm_2, m_normResid_1); + printf("| %10.3E %10.3E %10.3E", stepNorm_1, m_normDeltaSoln_Newton, m_normResid_full); + } + printf("\n"); + + } + if (m_print_flag >= 4) { + if (doDogLeg_) { + if (convRes > 0) { + printf("\t solve_nonlinear_problem(): Problem Converged, stepNorm = %11.3E, reduction of res from %11.3E to %11.3E\n", + stepNorm_1, m_normResid_0, m_normResid_full); + printf("\t"); + print_line("=", 119); + } else { + printf("\t solve_nonlinear_problem(): Successfull step taken with stepNorm = %11.3E, reduction of res from %11.3E to %11.3E\n", + stepNorm_1, m_normResid_0, m_normResid_full); + } + } else { + if (convRes > 0) { + printf("\t solve_nonlinear_problem(): Damped Newton iteration successful, nonlin " + "converged, final estimate of the next solution update norm = %-12.4E\n", stepNorm_2); + printf("\t"); + print_line("=", 119); + } else if (retnDamp >= NSOLN_RETN_CONTINUE) { + printf("\t solve_nonlinear_problem(): Damped Newton iteration successful, " + "estimate of the next solution update norm = %-12.4E\n", stepNorm_2); + } else { + printf("\t solve_nonlinear_problem(): Damped Newton unsuccessful, final estimate " + "of the next solution update norm = %-12.4E\n", stepNorm_2); + } + } + } // convergence - if (m == 1) goto done; + if (convRes) { + goto done; + } // If dampStep fails, first try a new Jacobian if an old // one was being used. If it was a new Jacobian, then // return -1 to signify failure. - else if (m < 0) { + else if (retnDamp < NSOLN_RETN_CONTINUE) { goto done; } } done: - mdp::mdp_copy_dbl_1(y_comm, DATA_PTR(y_curr), neq_); - mdp::mdp_copy_dbl_1(ydot_comm, DATA_PTR(ydot_curr), neq_); + + + if (m_print_flag == 2 || m_print_flag == 3) { + if (convRes > 0) { + if (doDogLeg_) { + if (convRes == 3) { + printf("\t | | " + " | | converged = 3 |(%11.3E) \n", stepNorm_2); + } else { + printf("\t | | " + " | | converged = %1d | %10.3E %10.3E\n", convRes, + stepNorm_2, m_normResidTrial); + } + printf("\t-----------------------------------------------------------------------------------------------------" + "------------------------------------------------------------------------------\n"); + } else { + if (convRes == 3) { + printf("\t | " + " | converged = 3 | (%11.3E) \n", stepNorm_2); + } else { + printf("\t | " + " | converged = %1d | %10.3E %10.3E\n", convRes, + stepNorm_2, m_normResidTrial); + } + printf("\t------------------------------------------------------------------------------------" + "-----------------------------------------------\n"); + } + } + + + } + + mdp::mdp_copy_dbl_1(y_comm, CONSTD_DATA_PTR(m_y_n_curr), neq_); + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + mdp::mdp_copy_dbl_1(ydot_comm, CONSTD_DATA_PTR(m_ydot_n_curr), neq_); + } num_linear_solves += m_numTotalLinearSolves; - double time_elapsed = wc.secondsWC(); - if (loglevel > 1) { - if (m == 1) { - printf("\t\tNonlinear problem solved successfully in " - "%d its, time elapsed = %g sec\n", - num_newt_its, time_elapsed); + doublereal time_elapsed = wc.secondsWC(); + if (m_print_flag > 1 ) { + if (retnDamp > 0) { + if (NonlinearSolver::s_TurnOffTiming) { + printf("\tNonlinear problem solved successfully in %d its\n", + num_newt_its); + } else { + printf("\tNonlinear problem solved successfully in %d its, time elapsed = %g sec\n", + num_newt_its, time_elapsed); + } + } else { + printf("\tNonlinear problem failed to solve after %d its\n", num_newt_its); } } - return m; + retnCode = retnDamp; + if (retnDamp > 0) { + retnCode = NSOLN_RETN_SUCCESS; + } + + + return retnCode; } - - /***************************************************************8 - * + //==================================================================================================================== + // Print solution norm contribution + /* + * Prints out the most important entries to the update to the solution vector for the current step * + * @param step_1 Raw update vector for the current nonlinear step + * @param stepNorm_1 Norm of the vector step_1 + * @param step_2 Raw update vector for the next solution value based on the old matrix + * @param stepNorm_2 Norm of the vector step_2 + * @param title title of the printout + * @param y_n_curr Old value of the solution + * @param y_n_1 New value of the solution after damping corrections + * @param damp Value of the damping factor + * @param num_entries Number of entries to print out */ void NonlinearSolver:: - print_solnDelta_norm_contrib(const double * const solnDelta0, - const char * const s0, - const double * const solnDelta1, - const char * const s1, + print_solnDelta_norm_contrib(const doublereal * const step_1, + const char * const stepNorm_1, + const doublereal * const step_2, + const char * const stepNorm_2, const char * const title, - const double * const y0, - const double * const y1, - double damp, + const doublereal * const y_n_curr, + const doublereal * const y_n_1, + doublereal damp, int num_entries) { int i, j, jnum; bool used; - double dmax0, dmax1, error, rel_norm; + doublereal dmax0, dmax1, error, rel_norm; printf("\t\t%s currentDamp = %g\n", title, damp); - printf("\t\t I ysoln %10s ysolnTrial " - "%10s weight relSoln0 relSoln1\n", s0, s1); + printf("\t\t I ysolnOld %13s ysolnNewRaw | ysolnNewTrial " + "%10s ysolnNewTrialRaw | solnWeight wtDelSoln wtDelSolnTrial\n", stepNorm_1, stepNorm_2); int *imax = mdp::mdp_alloc_int_1(num_entries, -1); - printf("\t\t "); print_line("-", 90); + printf("\t\t "); print_line("-", 125); for (jnum = 0; jnum < num_entries; jnum++) { dmax1 = -1.0; for (i = 0; i < neq_; i++) { @@ -940,9 +3617,9 @@ namespace Cantera { if (imax[j] == i) used = true; } if (!used) { - error = solnDelta0[i] / m_ewt[i]; + error = step_1[i] / m_ewt[i]; rel_norm = sqrt(error * error); - error = solnDelta1[i] / m_ewt[i]; + error = step_2[i] / m_ewt[i]; rel_norm += sqrt(error * error); if (rel_norm > dmax1) { imax[jnum] = i; @@ -952,21 +3629,556 @@ namespace Cantera { } if (imax[jnum] >= 0) { i = imax[jnum]; - error = solnDelta0[i] / m_ewt[i]; + error = step_1[i] / m_ewt[i]; dmax0 = sqrt(error * error); - error = solnDelta1[i] / m_ewt[i]; + error = step_2[i] / m_ewt[i]; dmax1 = sqrt(error * error); - printf("\t\t %4d %12.4e %12.4e %12.4e %12.4e " - "%12.4e %12.4e %12.4e\n", - i, y0[i], solnDelta0[i], y1[i], - solnDelta1[i], m_ewt[i], dmax0, dmax1); + printf("\t\t %4d %12.4e %12.4e %12.4e | %12.4e %12.4e %12.4e |%12.4e %12.4e %12.4e\n", + i, y_n_curr[i], step_1[i], y_n_curr[i] + step_1[i], y_n_1[i], + step_2[i], y_n_1[i]+ step_2[i], m_ewt[i], dmax0, dmax1); } } - printf("\t\t "); print_line("-", 90); + printf("\t\t "); print_line("-", 125); mdp::mdp_safe_free((void **) &imax); } + //==================================================================================================================== + //! This routine subtracts two numbers for one another + /*! + * This routine subtracts 2 numbers. If the difference is less + * than 1.0E-14 times the magnitude of the smallest number, then diff returns an exact zero. + * It also returns an exact zero if the difference is less than + * 1.0E-300. + * + * returns: a - b + * + * This routine is used in numerical differencing schemes in order + * to avoid roundoff errors resulting in creating Jacobian terms. + * Note: This is a slow routine. However, jacobian errors may cause + * loss of convergence. Therefore, in practice this routine has proved cost-effective. + * + * @param a Value of a + * @param b value of b + * + * @return returns the difference between a and b + */ + static inline doublereal subtractRD(doublereal a, doublereal b) { + doublereal diff = a - b; + doublereal d = MIN(fabs(a), fabs(b)); + d *= 1.0E-14; + doublereal ad = fabs(diff); + if (ad < 1.0E-300) { + diff = 0.0; + } + if (ad < d) { + diff = 0.0; + } + return diff; + } + //==================================================================================================================== + /* + * + * Function called by BEuler to evaluate the Jacobian matrix and the + * current residual at the current time step. + * @param N = The size of the equation system + * @param J = Jacobian matrix to be filled in + * @param f = Right hand side. This routine returns the current + * value of the rhs (output), so that it does + * not have to be computed again. + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * 0 Means an unsuccessful operation + */ + int NonlinearSolver::beuler_jac(GeneralMatrix &J, doublereal * const f, + doublereal time_curr, doublereal CJ, + doublereal * const y, doublereal * const ydot, + int num_newt_its) + { + int i, j; + double* col_j; + int info; + doublereal ysave, ydotsave, dy; + int retn = 1; + + /* + * Clear the factor flag + */ + J.clearFactorFlag(); + if (m_jacFormMethod == NSOLN_JAC_ANAL) { + /******************************************************************** + * Call the function to get a jacobian. + */ + info = m_func->evalJacobian(time_curr, delta_t_n, CJ, y, ydot, J, f); + m_nJacEval++; + m_nfe++; + if (info != 1) { + return info; + } + } else { + if (J.matrixType_ == 0) { + /******************************************************************* + * Generic algorithm to calculate a numerical Jacobian + */ + /* + * Calculate the current value of the rhs given the + * current conditions. + */ + + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); + m_nfe++; + if (info != 1) { + return info; + } + m_nJacEval++; + + /* + * Malloc a vector and call the function object to return a set of + * deltaY's that are appropriate for calculating the numerical + * derivative. + */ + doublereal *dyVector = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + retn = m_func->calcDeltaSolnVariables(time_curr, y, ydot, dyVector, DATA_PTR(m_ewt)); + + + + if (s_print_NumJac) { + if (m_print_flag >= 7) { + if (neq_ < 20) { + printf("\t\tUnk m_ewt y dyVector ResN\n"); + for (int iii = 0; iii < neq_; iii++){ + printf("\t\t %4d %16.8e %16.8e %16.8e %16.8e \n", + iii, m_ewt[iii], y[iii], dyVector[iii], f[iii]); + } + } + } + } + + /* + * Loop over the variables, formulating a numerical derivative + * of the dense matrix. + * For the delta in the variable, we will use a variety of approaches + * The original approach was to use the error tolerance amount. + * This may not be the best approach, as it could be overly large in + * some instances and overly small in others. + * We will first protect from being overly small, by using the usual + * sqrt of machine precision approach, i.e., 1.0E-7, + * to bound the lower limit of the delta. + */ + for (j = 0; j < neq_; j++) { + + + /* + * Get a pointer into the column of the matrix + */ + + + col_j = (doublereal *) J.ptrColumn(j); + ysave = y[j]; + dy = dyVector[j]; + //dy = fmaxx(1.0E-6 * m_ewt[j], fabs(ysave)*1.0E-7); + + y[j] = ysave + dy; + dy = y[j] - ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydotsave = ydot[j]; + ydot[j] += dy * CJ; + } + /* + * Call the function + */ + + + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, DATA_PTR(m_wksp), + JacDelta_ResidEval, j, dy); + m_nfe++; + if (info != 1) { + mdp::mdp_safe_free((void **) &dyVector); + return info; + } + + doublereal diff; + for (i = 0; i < neq_; i++) { + diff = subtractRD(m_wksp[i], f[i]); + col_j[i] = diff / dy; + } + y[j] = ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydot[j] = ydotsave; + } + + } + /* + * Release memory + */ + mdp::mdp_safe_free((void **) &dyVector); + } else if (J.matrixType_ == 1) { + int ku, kl; + int ivec[2]; + int n = J.nRowsAndStruct(ivec); + kl = ivec[0]; + ku = ivec[1]; + if (n != neq_) { + printf("we have probs\n"); exit(-1); + } + + // --------------------------------- BANDED MATRIX BRAIN DEAD --------------------------------------------------- + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); + m_nfe++; + if (info != 1) { + return info; + } + m_nJacEval++; + + + doublereal *dyVector = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + retn = m_func->calcDeltaSolnVariables(time_curr, y, ydot, dyVector, DATA_PTR(m_ewt)); + if (s_print_NumJac) { + if (m_print_flag >= 7) { + if (neq_ < 20) { + printf("\t\tUnk m_ewt y dyVector ResN\n"); + for (int iii = 0; iii < neq_; iii++){ + printf("\t\t %4d %16.8e %16.8e %16.8e %16.8e \n", + iii, m_ewt[iii], y[iii], dyVector[iii], f[iii]); + } + } + } + } + + + for (j = 0; j < neq_; j++) { + + + col_j = (doublereal *) J.ptrColumn(j); + ysave = y[j]; + dy = dyVector[j]; + + + y[j] = ysave + dy; + dy = y[j] - ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydotsave = ydot[j]; + ydot[j] += dy * CJ; + } + + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, DATA_PTR(m_wksp), JacDelta_ResidEval, j, dy); + m_nfe++; + if (info != 1) { + mdp::mdp_safe_free((void **) &dyVector); + return info; + } + + doublereal diff; + for (int i = j - ku; i <= j + kl; i++) { + if (i >= 0 && i < neq_) { + diff = subtractRD(m_wksp[i], f[i]); + col_j[kl + ku + i - j] = diff / dy; + } + } + y[j] = ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydot[j] = ydotsave; + } + + } + + mdp::mdp_safe_free((void **) &dyVector); + double vSmall; + int ismall = J.checkRows(vSmall); + if (vSmall < 1.0E-100) { + printf("WE have a zero row, %d\n", ismall); + exit(-1); + } + ismall = J.checkColumns(vSmall); + if (vSmall < 1.0E-100) { + printf("WE have a zero column, %d\n", ismall); + exit(-1); + } + + // ---------------------BANDED MATRIX BRAIN DEAD ----------------------- + } + } + + if (m_print_flag >= 7 && s_print_NumJac) { + if (neq_ < 30) { + printf("\t\tCurrent Matrix and Residual:\n"); + printf("\t\t I,J | "); + for (j = 0; j < neq_; j++) { + printf(" %5d ", j); + } + printf("| Residual \n"); + printf("\t\t --"); + for (j = 0; j < neq_; j++) { + printf("------------"); + } + printf("| -----------\n"); + + + for (i = 0; i < neq_; i++) { + printf("\t\t %4d |", i); + for (j = 0; j < neq_; j++) { + printf(" % 11.4E", J(i,j) ); + } + printf(" | % 11.4E\n", f[i]); + } + + printf("\t\t --"); + for (j = 0; j < neq_; j++) { + printf("------------"); + } + printf("--------------\n"); + } + } + /* + * Make a copy of the data. Note, this jacobian copy occurs before any matrix scaling operations. + * It's the raw matrix producted by this routine. + */ + jacCopyPtr_->copyData(J); + + return retn; + } + //==================================================================================================================== + // Internal function to calculate the time derivative of the solution at the new step + /* + * Previously, the user must have supplied information about the previous time step for this routine to + * work as intended. + * + * @param order of the BDF method + * @param y_curr current value of the solution + * @param ydot_curr Calculated value of the solution derivative that is consistent with y_curr + */ + void NonlinearSolver:: + calc_ydot(const int order, const doublereal * const y_curr, doublereal * const ydot_curr) const + { + if (!ydot_curr) { + return; + } + int i; + doublereal c1; + switch (order) { + case 0: + case 1: /* First order forward Euler/backward Euler */ + c1 = 1.0 / delta_t_n; + for (i = 0; i < neq_; i++) { + ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]); + } + return; + case 2: /* Second order Adams-Bashforth / Trapezoidal Rule */ + c1 = 2.0 / delta_t_n; + for (i = 0; i < neq_; i++) { + ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]) - m_ydot_nm1[i]; + } + + return; + default: + throw CanteraError("calc_ydot()", "Case not covered"); + } + } + //==================================================================================================================== + // Apply a filtering process to the new step + /* + * @param timeCurrent Current value of the time + * @param y_current current value of the solution + * @param ydot_current Current value of the solution derivative. + * + * @return Returns the norm of the value of the amount filtered + */ + doublereal NonlinearSolver::filterNewStep(const doublereal timeCurrent, + const doublereal * const ybase, doublereal * const step0) { + doublereal tmp = m_func->filterNewStep(timeCurrent, ybase, step0); + return tmp; + } + //==================================================================================================================== + // Apply a filtering process to the new solution + /* + * @param timeCurrent Current value of the time + * @param y_current current value of the solution + * @param ydot_current Current value of the solution derivative. + * + * @return Returns the norm of the value of the amount filtered + */ + doublereal NonlinearSolver::filterNewSolution(const doublereal timeCurrent, + doublereal * const y_current, doublereal *const ydot_current) { + doublereal tmp = m_func->filterSolnPrediction(timeCurrent, y_current); + return tmp; + } + //==================================================================================================================== + // Compute the Residual Weights + /* + * The residual weights are defined here to be equal to the inverse of the row scaling factors used to + * row scale the matrix, after column scaling is used. They are multiplied by rtol and an atol factor + * is added as well so that if the residual is less than 1, then the calculation is deemed to be converged. + * + * The basic idea is that a change in the solution vector on the order of the convergence tolerance + * multiplied by [RJC] which is of order one after row scaling should give you the relative weight + * of the row. Values of the residual for that row can then be normalized by the value of this weight. + * When the tolerance in delta x is achieved, the tolerance in the residual should also be achieved + * and should be checked. + */ + void + NonlinearSolver::computeResidWts() + { + ResidWtsReevaluated_ = true; + if (checkUserResidualTols_ == 1) { + for (int i = 0; i < neq_; i++) { + m_residWts[i] = userResidAtol_[i] + userResidRtol_ * m_rowWtScales[i] / neq_; + } + } else { + doublereal sum = 0.0; + for (int i = 0; i < neq_; i++) { + m_residWts[i] = m_rowWtScales[i] / neq_; + sum += m_residWts[i]; + } + sum /= neq_; + for (int i = 0; i < neq_; i++) { + m_residWts[i] = m_ScaleSolnNormToResNorm * (m_residWts[i] + atolBase_ * atolBase_ * sum); + } + if (checkUserResidualTols_ == 2) { + for (int i = 0; i < neq_; i++) { + double uR = userResidAtol_[i] + userResidRtol_ * m_rowWtScales[i] / neq_; + m_residWts[i] = MIN(m_residWts[i], uR); + } + } + } + } + //===================================================================================================================== + // return the residual weights + /* + * @param residWts Vector of length neq_ + */ + void + NonlinearSolver::getResidWts(doublereal * const residWts) const + { + for (int i = 0; i < neq_; i++) { + residWts[i] = (m_residWts)[i]; + } + } + //===================================================================================================================== + // Check to see if the nonlinear problem has converged + /* + * + * @return integer is returned. If positive, then the problem has converged + * 1 Successful step was taken: Next step's norm is less than 1.0. + * The final residual norm is less than 1.0. + * 2 Successful step: Next step's norm is less than 0.8. + * This step's norm is less than 1.0. + * The residual norm can be anything. + * 3 Success: The final residual is less than 1.0E-2 + * The predicted deltaSoln is below 1.0E-2. + * 0 Not converged yet + */ + int + NonlinearSolver::convergenceCheck(int dampCode, doublereal s1) + { + int retn = 0; + if (m_dampBound < 0.9999) { + return retn; + } + if (m_dampRes < 0.9999) { + return retn; + } + if (dampCode <= 0) { + return retn; + } + if (dampCode == 3) { + if (s1 < 1.0E-2) { + if (m_normResidTrial < 1.0E-6) { + return 3; + } + } + if (s1 < 0.8) { + if (m_normDeltaSoln_Newton < 1.0) { + return 2; + } + } + } + if (dampCode == 4) { + if (s1 < 1.0E-2) { + if (m_normResidTrial < 1.0E-6) { + return 3; + } + } + } + + if (s1 < 0.8) { + if (m_normDeltaSoln_Newton < 1.0) { + return 2; + } + } + if (dampCode == 1 || dampCode == 2) { + if (s1 < 1.0) { + if (m_normResidTrial < 1.0) { + return 1; + } + } + } + return retn; + } + //===================================================================================================================== + // Set the absolute tolerances for the solution variables + /* + * Set the absolute tolerances used in the calculation + * + * @param atol Vector of length neq_ that contains the tolerances to be used for the solution variables + */ + void NonlinearSolver::setAtol(const doublereal * const atol) + { + for (int i = 0; i < neq_; i++) { + atolk_[i]= atol[i]; + } + } + //===================================================================================================================== + // Set the relative tolerances for the solution variables + /* + * Set the relative tolerances used in the calculation for the solution variables. + * + * @param rtol single double + */ + void NonlinearSolver::setRtol(const doublereal rtol) + { + rtol_ = rtol; + } + //===================================================================================================================== + // Set the relative and absolute tolerances for the Residual norm comparisons, if used + /* + * + * residWeightNorm[i] = residAtol[i] + residRtol * m_rowWtScales[i] / neq + * + * @param residNormHandling Parameter that sets the default handling of the residual norms + * 0 The residual weighting vector is calculated to make sure that the solution + * norms are roughly 1 when the residual norm is roughly 1. + * This is the default if this routine is not called. + * 1 Use the user residual norm specified by the parameters in this routine + * 2 Use the minimum value of the residual weights calculcated by method 1 and 2. + * This is the default if this routine is called and this parameter isn't specified. + */ + void NonlinearSolver::setResidualTols(double residRtol, double * residATol, int residNormHandling) + { + if (residNormHandling < 0 || residNormHandling > 2) { + throw CanteraError("NonlinearSolver::setResidualTols()", + "Unknown int for residNormHandling"); + } + checkUserResidualTols_ = residNormHandling; + userResidRtol_ = residRtol; + if (residATol) { + userResidAtol_.resize(neq_); + for (int i = 0; i < neq_; i++) { + userResidAtol_[i] = residATol[i]; + } + } else { + if (residNormHandling ==1 || residNormHandling == 2) { + throw CanteraError("NonlinearSolver::setResidualTols()", + "Must set residATol vector"); + } + } + } + //===================================================================================================================== + void NonlinearSolver::setPrintLvl(int printLvl) + { + m_print_flag = printLvl; + } + //===================================================================================================================== } diff --git a/Cantera/src/numerics/NonlinearSolver.h b/Cantera/src/numerics/NonlinearSolver.h index 420ce23e1..c6c92c366 100644 --- a/Cantera/src/numerics/NonlinearSolver.h +++ b/Cantera/src/numerics/NonlinearSolver.h @@ -1,5 +1,5 @@ /** - * @file NonlinearSolve.h + * @file NonlinearSolver.h * Class that calculates the solution to a nonlinear, dense, set * of equations (see \ref numerics * and class \link Cantera::NonlinearSolver NonlinearSolver\endlink). @@ -20,20 +20,122 @@ #define CT_NONLINEARSOLVER_H #include "ResidJacEval.h" +#include "SquareMatrix.h" namespace Cantera { - + + //@{ + /// @name Constant which determines the type of the nonlinear solve + /*! + * I think steady state is the only option I'm gunning for + */ + //! The nonlinear problem is part of a pseudo time dependent calculation (NOT TESTED) #define NSOLN_TYPE_PSEUDO_TIME_DEPENDENT 2 + //! The nonlinear problem is part of a time dependent calculation #define NSOLN_TYPE_TIME_DEPENDENT 1 + //! The nonlinear problem is part of a steady state calculation #define NSOLN_TYPE_STEADY_STATE 0 + //@} + + + //@{ + /// @name Constant which determines the Return int from the nonlinear solver + /*! + * This int is returned from the nonlinear solver + */ + //! The nonlinear solve is successful. +#define NSOLN_RETN_SUCCESS 1 + //! Problem isn't solved yet +#define NSOLN_RETN_CONTINUE 0 + //! The nonlinear problem started to take too small an update step. This indicates that either the + //! Jacobian is bad, or a constraint is being bumped up against. +#define NSOLN_RETN_FAIL_STEPTOOSMALL -1 + //! The nonlinear problem didn't solve the problem +#define NSOLN_RETN_FAIL_DAMPSTEP -2 + //! The nonlinear problem's jacobian is singular +#define NSOLN_RETN_MATRIXINVERSIONERROR -3 + //! The nonlinear problem's jacobian formation produced an error +#define NSOLN_RETN_JACOBIANFORMATIONERROR -4 + //! The nonlinear problem's base residual produced an error +#define NSOLN_RETN_RESIDUALFORMATIONERROR -5 + //! The nonlinear problem's max number of iterations has been exceeded +#define NSOLN_RETN_MAXIMUMITERATIONSEXCEEDED -7 + //@} + //@} + + //@{ + /// @name Constant which determines the type of the Jacobian + //! The jacobian will be calculated from a numerical method +#define NSOLN_JAC_NUM 1 + //! The jacobian is calculated from an analytical function +#define NSOLN_JAC_ANAL 2 + //@} + //! Class that calculates the solution to a nonlinear system /*! + * This is a small nonlinear solver that can solve highly nonlinear problems that + * must use a dense matrix to relax the system. + * + * Newton's method is used. + * + * Damping is used extensively when relaxing the system. + * + * + * The basic idea is that we predict a direction that is parameterized by an overall coordinate + * value, beta, from zero to one, This may or may not be the same as the value, damp, + * depending upon whether the direction is straight. + * + * + * TIME STEP TYPE + * + * The code solves a nonlinear problem. Frequently the nonlinear problem is created from time-dependent + * residual. Whenever you change the solution vector, you are also changing the derivative of the + * solution vector. Therefore, the code has the option of altering ydot, a vector of time derivatives + * of the solution in tandem with the solution vector and then feeding a residual and Jacobian routine + * with the time derivatives as well as the solution. The code has support for a backwards euler method + * and a second order Adams-Bashforth or Trapezoidal Rule. + * + * In order to use these methods, the solver must be initialized with delta_t and m_y_nm1[i] to specify + * the conditions at the previous time step. For second order methods, the time derivative at t_nm1 must + * also be supplied, m_ydot_nm1[i]. Then the solution type NSOLN_TYPE_TIME_DEPENDENT may be used to + * solve the problem. + * + * For steady state problem whose residual doesn't have a solution time derivative in it, you should + * use the NSOLN_TYPE_STEADY_STATE problem type. + * + * We have a NSOLN_TYPE_PSEUDO_TIME_DEPENDENT defined. However, this is not implemented yet. This would + * be a pseudo time dependent calculation, where an optional time derivative could be added in order to + * help equilibrate a nonlinear steady state system. The time transient is not important in and of + * itself. Many physical systems have a time dependence to them that provides a natural way to relax + * the nonlinear system. + * + * MATRIX SCALING + * + * + * + * + * @code + * + * + * NonlinearSolver *nls = new NonlinearSolver(&r1); + * + * int solnType = NSOLN_TYPE_STEADY_STATE ; + * + * nls->setDeltaBoundsMagnitudes(deltaBounds); + * + * nls->solve_nonlinear_problem(solnType, y_comm, ydot_comm, CJ, time_curr, jac, + * num_newt_its, num_linear_solves, numBacktracks, + * loglevelInput); + * + * @endcode + * * * @ingroup numerics */ class NonlinearSolver { + public: //! Default constructor /*! * @param func Residual and jacobian evaluator function object @@ -59,7 +161,6 @@ namespace Cantera { */ NonlinearSolver& operator=(const NonlinearSolver &right); - //! Create solution weights for convergence criteria /*! * We create soln weights from the following formula @@ -69,22 +170,29 @@ namespace Cantera { * The program always assumes that atol is specific * to the solution component * - * param y vector of the current solution values + * @param y vector of the current solution values */ - void createSolnWeights(const double * const y); - + void createSolnWeights(const doublereal * const y); //! L2 norm of the delta of the solution vector /*! * calculate the norm of the solution vector. This will * involve the column scaling of the matrix * - * The second argument has a default of false. However, + * The third argument has a default of false. However, * if true, then a table of the largest values is printed * out to standard output. + * + * @param delta_y Vector to take the norm of + * @param title Optional title to be printed out + * @param printLargest int indicating how many specific lines should be printed out + * @param dampFactor Current value of the damping factor. Defaults to 1. + * only used for printout out a table. + * + * @return Returns the L2 norm of the delta */ - double solnErrorNorm(const double * const delta_y, - bool printLargest = false); + doublereal solnErrorNorm(const doublereal * const delta_y, const char * title = 0, int printLargest = 0, + const doublereal dampFactor = 1.0) const; //! L2 norm of the residual of the equation system /*! @@ -94,33 +202,37 @@ namespace Cantera { * The second argument has a default of false. However, * if true, then a table of the largest values is printed * out to standard output. + * + * @param resid Vector of the residuals + * @param title Optional title to be printed out + * @param printLargest Number of specific entries to be printed + * @param y Current value of y - only used for printouts + * + * + * @return Returns the L2 norm of the delta */ - double residErrorNorm(const double * const resid, - bool printLargest = false); + doublereal residErrorNorm(const doublereal * const resid, const char * title = 0, const int printLargest = 0, + const doublereal * const y = 0) const; - //! Compute the current Residual + //! Compute the current residual /*! - * Compute the time dependent residual of - * the set of equations. + * The current value of the residual is storred in the internal work array m_resid, which is defined + * as mutable + * + * @param time_curr Value of the time + * @param typeCalc Type of the calculation + * @param y_curr Current value of the solution vector + * @param ydot_curr Current value of the time derivative of the solution vector + * @param evalType Base evalulation type + * Defaults to Base_ResidEval + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation */ - void doTDResidualCalc(const double time_curr, const int typeCalc, - const double * const y_curr, - const double * const ydot_curr, double* const residual, - int loglevel); - - //! Compute the current Residual - /*! - * Compute the steady state residual of - * the set of equations. - */ - void doSteadyResidualCalc(const double time_curr, const int typeCalc, - const double * const y_curr, - double* const residual, int loglevel); - - void doResidualCalc(const double time_curr, const int typeCalc, - const double * const y_curr, - const double * const ydot_curr, double* const residual, - int loglevel); + int doResidualCalc(const doublereal time_curr, const int typeCalc, const doublereal * const y_curr, + const doublereal * const ydot_curr, + const ResidEval_Type_Enum evalType = Base_ResidEval) const; //! Compute the undamped Newton step /*! @@ -136,12 +248,119 @@ namespace Cantera { * recomputed. The row scales are recomputed here, after column * scaling has been implemented. * + * @param time_curr Current value of the time + * @param y_curr Current value of the solution + * @param ydot_curr Current value of the solution derivative. + * @param delta_y return value of the raw change in y + * @param jac Jacobian + * + * @return Returns the result code from lapack. A zero means success. Anything + * else indicates a failure. */ - void doNewtonSolve(const double time_curr, const double * const y_curr, - const double * const ydot_curr, double* const delta_y, - SquareMatrix& jac, int loglevel); + int doNewtonSolve(const doublereal time_curr, const doublereal * const y_curr, + const doublereal * const ydot_curr, doublereal * const delta_y, + GeneralMatrix& jac); + + //! Compute the newton step, either by direct newton's or by solving a close problem that is represented + //! by a Hessian ( + /*! + * This is algorith A.6.5.1 in Dennis / Schnabel + * + * Compute the QR decomposition + * + * Compute the undamped Newton step. The residual function is + * evaluated at the current time, t_n, at the current values of the + * solution vector, m_y_n, and the solution time derivative, m_ydot_n. + * The Jacobian is not recomputed. + * + * A factored jacobian is reused, if available. If a factored jacobian + * is not available, then the jacobian is factored. Before factoring, + * the jacobian is row and column-scaled. Column scaling is not + * recomputed. The row scales are recomputed here, after column + * scaling has been implemented. + * + * @param y_curr Current value of the solution + * @param ydot_curr Current value of the solution derivative. + * @param delta_y return value of the raw change in y + * @param jac Jacobian + * + * Internal input + * --------------- + * internal m_resid Storred residual is used as input + * + * + * @return Returns the result code from lapack. A zero means success. Anything + * else indicates a failure. + */ + int doAffineNewtonSolve(const doublereal * const y_curr, const doublereal * const ydot_curr, + doublereal * const delta_y, GeneralMatrix& jac); + + //! Calculate the length of the current trust region in terms of the solution error norm + /*! + * We carry out a norm of deltaX_trust_ first. Then, we multiply that value + * by trustDelta_ + */ + doublereal trustRegionLength() const; + + //! Set default deulta bounds amounts + /*! + * Delta bounds are set to 0.01 for all unknowns arbitrarily and capriciously + * Then, for each call to the nonlinear solver + * Then, they are increased to 1000 x atol + * then, they are increased to 0.1 fab(y[i]) + */ + void setDefaultDeltaBoundsMagnitudes(); + + //! Adjust the step minimums + void adjustUpStepMinimums(); + + //! Set the delta Bounds magnitudes by hand + /*! + * @param deltaBoundsMagnitudes set the deltaBoundsMagnitude vector + */ + void setDeltaBoundsMagnitudes(const doublereal * const deltaBoundsMagnitudes); - //! + protected: + + //! Readjust the trust region vectors + /*! + * The trust region is made up of the trust region vector calculation and the trustDelta_ value + * We periodically recalculate the trustVector_ values so that they renormalize to the + * correct length. We change the trustDelta_ values regularly + * + * The trust region calculate is based on + * + * || delta_x dot 1/trustDeltaX_ || <= trustDelta_ + * + */ + void readjustTrustVector(); + + //! Fill a dogleg solution step vector + /*! + * Previously, we have filled up deltaX_Newton_[], deltaX_CP_[], and Nuu_, so that + * this routine is straightforward. + * + * @param leg Leg of the dog leg you are on (0, 1, or 2) + * @param alpha Relative length along the dog length that you are on. + * @param deltaX Vector to be filled up + */ + void fillDogLegStep(int leg, doublereal alpha, std::vector & deltaX) const; + + //! Calculate the trust distance of a step in the solution variables + /*! + * The trust distance is defined as the length of the step according to the norm wrt to the trust region. + * We calculate the trust distance by the following method. + * + * trustDist = || delta_x dot 1/trustDeltaX_ || + * + * @param deltaX Current value of deltaX + */ + doublereal calcTrustDistance(std::vector const & deltaX) const; + + + + public: + //! Bound the step /*! * * Return the factor by which the undamped Newton step 'step0' @@ -166,67 +385,134 @@ namespace Cantera { * factor of 2 * Maximum decrease in variable in any one newton iteration: * factor of 5 + * + * @param y Current solution value of the old step + * @param step0 Proposed step change in the solution + * + * @return Returns the damping factor determined by the bounds calculation */ - double boundStep(const double* const y, - const double* const step0, const int loglevel); + doublereal boundStep(const doublereal * const y, const doublereal * const step0); - - //! set bounds constraints for all variables in the problem + //! Set bounds constraints for all variables in the problem /*! * * @param y_low_bounds Vector of lower bounds * @param y_high_bounds Vector of high bounds */ - void setBoundsConstraints(const double * const y_low_bounds, - const double * const y_high_bounds); + void setBoundsConstraints(const doublereal * const y_low_bounds, + const doublereal * const y_high_bounds); - /** - * Internal function to calculate the predicted solution - * at a time step. + //! Return an editable vector of the low bounds constraints + std::vector & lowBoundsConstraintVector(); + + //! Return an editable vector of the high bounds constraints + std::vector & highBoundsConstraintVector(); + + //! Internal function to calculate the time derivative of the solution at the new step + /*! + * Previously, the user must have supplied information about the previous time step for this routine to + * work as intended. + * + * @param order of the BDF method + * @param y_curr current value of the solution + * @param ydot_curr Calculated value of the solution derivative that is consistent with y_curr + */ + void calc_ydot(const int order, const doublereal * const y_curr, doublereal * const ydot_curr) const; + + //! Function called to evaluate the jacobian matrix and the current + //! residual vector at the current time step + /*! + * + * + * @param J Jacobian matrix to be filled in + * @param f Right hand side. This routine returns the current + * value of the rhs (output), so that it does + * not have to be computed again. + * @param time_curr Current time + * @param CJ inverse of the value of deltaT + * @param y value of the solution vector + * @param ydot value of the time derivative of the solution vector + * @param num_newt_its Number of newton iterations + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * 0 Means an unsuccessful operation */ - void calc_y_pred(int); + int beuler_jac(GeneralMatrix &J, doublereal * const f, + doublereal time_curr, doublereal CJ, doublereal * const y, + doublereal * const ydot, int num_newt_its); - /** - * Internal function to calculate the time derivative at the - * new step + //! Apply a filtering process to the step + /*! + * @param timeCurrent Current value of the time + * @param ybase current value of the solution + * @param step0 Proposed step change in the solution + * + * @return Returns the norm of the value of the amount filtered */ - void calc_ydot(int order, double * const y_curr, double * const ydot_curr); - - void beuler_jac(SquareMatrix &, double * const, - double, double, double * const, double * const, int); + doublereal filterNewStep(const doublereal timeCurrent, const doublereal * const ybase, doublereal * const step0); + //! Apply a filter to the solution + /*! + * @param timeCurrent Current value of the time + * @param y_current current value of the solution + * @param ydot_current Current value of the solution derivative. + * + * @return Returns the norm of the value of the amount filtered + */ + doublereal filterNewSolution(const doublereal timeCurrent, doublereal * const y_current, + doublereal * const ydot_current); - double filterNewStep(double, double *, double *); - + //! Return the factor by which the undamped Newton step 'step0' + //! must be multiplied in order to keep the update within the bounds of an accurate jacobian. + /*! + * + * The idea behind these is that the Jacobian couldn't possibly be representative, if the + * variable is changed by a lot. (true for nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: + * factor of 1.5 + * Maximum decrease in variable in any one newton iteration: + * factor of 2 + * + * @param y Initial value of the solution vector + * @param step0 initial proposed step size + * + * @return returns the damping factor + */ + doublereal deltaBoundStep(const doublereal * const y, const doublereal * const step0); + //! Find a damping coefficient through a look-ahead mechanism /*! - * On entry, step0 must contain an undamped Newton step for the - * solution x0. This method attempts to find a damping coefficient + * On entry, step_1 must contain an undamped Newton step for the + * solution y_n_curr. This method attempts to find a damping coefficient * such that all components stay in bounds, and the next * undamped step would have a norm smaller than - * that of step0. If successful, the new solution after taking the - * damped step is returned in y1, and the undamped step at y1 is - * returned in step1. + * that of step_1. If successful, the new solution after taking the + * damped step is returned in y_n_1, and the undamped step at y_n_1 is + * returned in step_2. * * @param time_curr Current physical time - * @param y0 Base value of the solution before any steps - * are taken - * @param ydot0 Base value of the time derivative of teh - * solution - * @param step0 Initial step suggested. - * @param y1 + * @param y_n_curr Base value of the solution before any steps + * are taken + * @param ydot_n_curr Base value of the time derivative of teh + * solution + * @param step_1 Initial step suggested. + * @param y_n_1 Value of y1, the suggested solution after damping + * @param ydot_n_1 Value of the time derivative of the solution at y_n_1 + * @param step_2 Value of the step change from y_n_1 to y_n_2 + * @param stepNorm_2 norm of the step change in going from y_n_1 to y_n_2 + * @param jac Jacobian + * @param writetitle Write a title line + * @param num_backtracks Number of backtracks taken + * + * @return returns an integer indicating what happened. */ - int dampStep(const double time_curr, const double* y0, - const double *ydot0, const double* step0, - double* const y1, double* const ydot1, double* step1, - double& s1, SquareMatrix& jac, - int& loglevel, bool writetitle, + int dampStep(const doublereal time_curr, const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, doublereal * const step_1, + doublereal * const y_n_1, doublereal * const ydot_n_1, doublereal * step_2, + doublereal & stepNorm_2, GeneralMatrix& jac, bool writetitle, int& num_backtracks); - - - // Compute the weighted norm of the undamped step size step0 - //! Find the solution to F(X) = 0 by damped Newton iteration. /*! * On @@ -236,32 +522,399 @@ namespace Cantera { * SolnType = TRANSIENT -> we will assume we are relaxing a transient * equation system for now. Will make it more general later, * if an application comes up. - * + * + * @param SolnType Solution type + * @param y_comm Initial value of the solution. On return this is the converged + * value of the solution + * @param ydot_comm Initial value of the solution derivative. On return this is the + * converged value of the solution derivative. + * @param CJ Inverse of the value of deltaT + * @param time_curr Current value of the time + * @param jac Matrix that will be used to store the jacobian + * @param num_newt_its Number of newton iterations taken + * @param num_linear_solves Number of linear solves taken + * @param num_backtracks Number of backtracking steps taken + * @param loglevelInput Input log level determines the amount of printing. + * + * + * @return A positive value indicates a successful convergence + * -1 Failed convergence */ - int solve_nonlinear_problem(int SolnType, double* y_comm, - double* ydot_comm, double CJ, - double time_curr, - SquareMatrix& jac, - int &num_newt_its, - int &num_linear_solves, - int &num_backtracks, - int loglevelInput); + int solve_nonlinear_problem(int SolnType, doublereal * const y_comm, doublereal * const ydot_comm, doublereal CJ, + doublereal time_curr, GeneralMatrix & jac, int &num_newt_its, + int &num_linear_solves, int &num_backtracks, int loglevelInput); + + private: + //! Set the column scales + void calcColumnScales(); + + public: + + //! Set the column scaling that are used for the inversion of the matrix + /*! + * There are three ways to do this. + * + * The first method is to set the bool useColScaling to true, leaving the scaling factors unset. + * Then, the column scales will be set to the solution error weighting factors. This has the + * effect of ensuring that all delta variables will have the same order of magnitude at convergence + * end. + * + * The second way is the explicity set the column factors in the second argument of this function call. + * + * The final way to input the scales is to override the ResidJacEval member function call, + * + * calcSolnScales(double time_n, const double *m_y_n_curr, const double *m_y_nm1, double *m_colScales) + * + * Overriding this function call will trump all other ways to specify the column scaling factors. + * + * @param useColScaling Turn this on if you want to use column scaling in the calculations + * @param scaleFactors A vector of doubles that specifies the column factors. + */ + void setColumnScaling(bool useColScaling, const double * const scaleFactors = 0); - void setColumnScales(); + //! Set the rowscaling that are used for the inversion of the matrix + /*! + * Row scaling is set here. Right now the row scaling is set internally in the code. + * + * @param useRowScaling Turn row scaling on or off. + */ + void setRowScaling(bool useRowScaling); + //! Scale the matrix + /*! + * @param jac Jacobian + * @param y_comm Current value of the solution vector + * @param ydot_comm Current value of the time derivative of the solution vector + * @param time_curr current value of the time + * @param num_newt_its Current value of the number of newt its + */ + void scaleMatrix(GeneralMatrix& jac, doublereal * const y_comm, doublereal * const ydot_comm, + doublereal time_curr, int num_newt_its); + + //! Print solution norm contribution + /*! + * Prints out the most important entries to the update to the solution vector for the current step + * + * @param step_1 Raw update vector for the current nonlinear step + * @param stepNorm_1 Norm of the vector step_1 + * @param step_2 Raw update vector for the next solution value based on the old matrix + * @param stepNorm_2 Norm of the vector step_2 + * @param title title of the printout + * @param y_n_curr Old value of the solution + * @param y_n_1 New value of the solution after damping corrections + * @param damp Value of the damping factor + * @param num_entries Number of entries to print out + */ void - print_solnDelta_norm_contrib(const double * const solnDelta0, - const char * const s0, - const double * const solnDelta1, - const char * const s1, - const char * const title, - const double * const y0, - const double * const y1, - double damp, - int num_entries); + print_solnDelta_norm_contrib(const doublereal * const step_1, const char * const stepNorm_1, + const doublereal * const step_2, const char * const stepNorm_2, + const char * const title, const doublereal * const y_n_curr, + const doublereal * const y_n_1, doublereal damp, int num_entries); + + //! Compute the Residual Weights + /*! + * The residual weights are defined here to be equal to the inverse of the row scaling factors used to + * row scale the matrix, after column scaling is used. They are multiplied by 10-3 because the column + * weights are also multiplied by that same quantity. + * + * The basic idea is that a change in the solution vector on the order of the convergence tolerance + * multiplied by [RJC] which is of order one after row scaling should give you the relative weight + * of the row. Values of the residual for that row can then be normalized by the value of this weight. + * When the tolerance in delta x is achieved, the tolerance in the residual is also achieved. + */ + void computeResidWts(); + + //! Return the residual weights + /*! + * @param residWts Vector of length neq_ + */ + void getResidWts(doublereal * const residWts) const; + + + + //! Check to see if the nonlinear problem has converged + /*! + * + * @param dampCode Code from the damping routine + * @param s1 Value of the norm of the step change + * + * @return integer is returned. If positive, then the problem has converged + * 1 Successful step was taken: Next step's norm is less than 1.0. + * The final residual norm is less than 1.0. + * 2 Successful step: Next step's norm is less than 0.8. + * This step's norm is less than 1.0. + * The residual norm can be anything. + * 3 Success: The final residual is less than 1.0 + * The predicted deltaSoln is below 1.0. + * 0 Not converged yet + */ + int convergenceCheck(int dampCode, doublereal s1); + + //! Set the absolute tolerances for the solution variables + /*! + * Set the absolute tolerances used in the calculation + * + * @param atol Vector of length neq_ that contains the tolerances to be used for the solution variables + */ + void setAtol(const doublereal * const atol); + + //! Set the relative tolerances for the solution variables + /*! + * Set the relative tolerances used in the calculation + * + * @param rtol single double + */ + void setRtol(const doublereal rtol); + + //! Set the relative and absolute tolerances for the Residual norm comparisons, if used + /*! + * Residual norms are used to calculate convergence within the nonlinear solver, since + * these are the norms that are associated with convergence proofs, especially for ill-conditioned systems. + * Usually the residual weights for each row are calculated by the program such that they + * correlate with the convergence requirements on the solution variables input by the user using + * the routines setAtol() and setRtol(). + * The residual weights are essentially calculated from the value + * + * residWeightNorm[i] = m_ScaleSolnNormToResNorm * sum_j ( fabs(A_i,j) ewt(j)) + * + * The factor, m_ScaleSolnNormToResNorm, is computed periodically to ensure that the solution norms + * and the residual norms are converging at the same time and thus accounts for some-illconditioning issues + * but not all. + * + * The user specified tolerance for the residual is given by the following quantity + * + * residWeightNorm[i] = residAtol[i] + residRtol * m_rowWtScales[i] / neq + * + * @param residNormHandling Parameter that sets the default handling of the residual norms + * 0 The residual weighting vector is calculated to make sure that the solution + * norms are roughly 1 when the residual norm is roughly 1. + * This is the default if this routine is not called. + * 1 Use the user residual norm specified by the parameters in this routine + * 2 Use the minimum value of the residual weights calculcated by method 1 and 2. + * This is the default if this routine is called and this parameter isn't specified. + */ + void setResidualTols(double residRtol, double * residATol, int residNormHandling = 2); + + //! Set the value of the maximum # of newton iterations + /*! + * @param maxNewtIts Maximum number of newton iterations + */ + void setMaxNewtIts(const int maxNewtIts); + + //! Calculate the scaling factor for translating residual norms into solution norms. + /*! + * This routine calls computeResidWts() a couple of times in the calculation of m_ScaleSolnNormToResNorm. + * A more sophisticated routine may do more with signs to get a better value. Perhaps, a series of calculations + * with different signs attached may be in order. Then, m_ScaleSolnNormToResNorm would be calculated + * as the minimum of a series of calculations. + */ + void calcSolnToResNormVector(); + + //! Calculate the steepest descent direction and the Cauchy Point where the quadratic formulation + //! of the nonlinear problem expects a minimum along the descent direction. + /*! + * @param jac Jacobian matrix: must be unfactored. + * + * @return Returns the norm of the solution update + */ + doublereal doCauchyPointSolve(GeneralMatrix& jac); + + //! This is a utility routine that can be used to print out the rates of the initial residual decline + /*! + * The residual**2 decline for various directions is printed out. The rate of decline of the + * square of the residuals multiplied by the number of equations along each direction is printed out + * This quantity can be directly related to the theory, and may be calculated from derivatives at the + * original point. + * + * ( (r)**2 * neq - (r0)**2 * neq ) / distance + * + * What's printed out: + * + * The theoretical linearized residual decline + * The actual residual decline in the steepest descent direction determined by numerical differencing + * The actual residual decline in the newton direction determined by numerical differencing + * + * This routine doesn't need to be called for the solution of the nonlinear problem. + * + * @param time_curr Current time + * @param ydot0 INPUT Current value of the derivative of the solution vector + * @param ydot1 INPUT Time derivates of solution at the conditions which are evalulated for success + * @param numTrials OUTPUT Counter for the number of residual evaluations + */ + void descentComparison(doublereal time_curr ,doublereal * ydot0, doublereal * ydot1, int &numTrials); + + + //! Setup the parameters for the double dog leg + /*! + * The calls to the doCauchySolve() and doNewtonSolve() routines are done at the main level. This routine comes + * after those calls. We calculate the point Nuu_ here, the distances of the dog-legs, + * and the norms of the CP and Newton points in terms of the trust vectors. + */ + void setupDoubleDogleg(); + + //! Change the global lambda coordinate into the (leg,alpha) coordinate for the double dogleg + /*! + * @param lambda Global value of the distance along the double dogleg + * @param alpha relative value along the particular leg + * + * @return Returns the leg number ( 0, 1, or 2). + */ + int lambdaToLeg(const doublereal lambda, doublereal &alpha) const; + + //! Given a trust distance, this routine calculates the intersection of the this distance with the + //! double dogleg curve + /*! + * @param trustVal (INPUT) Value of the trust distance + * @param lambda (OUTPUT) Returns the internal coordinate of the double dogleg + * @param alpha (OUTPUT) Returns the relative distance along the appropriate leg + * @return leg (OUTPUT) Returns the leg ID (0, 1, or 2) + */ + int calcTrustIntersection(doublereal trustVal, doublereal &lambda, doublereal &alpha) const; + + //! Initialize the size of the trust vector. + /*! + * The algorithm we use is to set it equal to the length of the Distance to the Cauchy point. + */ + void initializeTrustRegion(); + + //! Set Trust region initialization strategy + /*! + * The default is use method 2 with a factor of 1. + * Then, on subsequent invocations of solve_nonlinear_problem() the strategy flips to method 0. + * + * @param method Method to set the strategy + * 0 No strategy - Use the previous strategy + * 1 Factor of the solution error weights + * 2 Factor of the first Cauchy Point distance + * 3 Factor of the first Newton step distance + * + * @param factor Factor to use in combination with the method + * + */ + void setTrustRegionInitializationMethod(int method, doublereal factor); + //! Damp using the dog leg approach + /*! + * + * @param time_curr INPUT Current value of the time + * @param y_n_curr INPUT Current value of the solution vector + * @param ydot_n_curr INPUT Current value of the derivative of the solution vector + * @param step_1 INPUT First trial step for the first iteration + * @param y_n_1 INPUT First trial value of the solution vector + * @param ydot_n_1 INPUT First trial value of the derivative of the solution vector + * @param stepNorm_1 OUTPUT Norm of the vector step_1 + * @param stepNorm_2 OUTPUT Estimated norm of the vector step_2 + * @param jac INPUT jacobian + * @param num_backtracks OUTPUT number of backtracks taken in the current damping step + * + * @return 1 Successful step was taken. The predicted residual norm is less than one + * 2 Successful step: Next step's norm is less than 0.8 + * 3 Success: The final residual is less than 1.0 + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 4 Success: The final residual is less than the residual + * from the previous step. + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 0 Uncertain Success: s1 is about the same as s0 + * -2 Unsuccessful step. + */ + int dampDogLeg(const doublereal time_curr, const doublereal* y_n_curr, + const doublereal *ydot_n_curr, std::vector & step_1, + doublereal* const y_n_1, doublereal* const ydot_n_1, + doublereal& stepNorm_1, doublereal& stepNorm_2, GeneralMatrix& jac, int& num_backtracks); + + //! Decide whether the current step is acceptable and adjust the trust region size + /*! + * This is an extension of algorithm 6.4.5 of Dennis and Schnabel. + * + * Here we decide whether to accept the current step + * At the end of the calculation a new estimate of the trust region is calculated + * + * @param time_curr INPUT Current value of the time + * @param leg INPUT Leg of the dogleg that we are on + * @param alpha INPUT Distance down that leg that we are on + * @param y_n_curr INPUT Current value of the solution vector + * @param ydot_n_curr INPUT Current value of the derivative of the solution vector + * @param step_1 INPUT Trial step + * @param y_n_1 OUTPUT Solution values at the conditions which are evalulated for success + * @param ydot_n_1 OUTPUT Time derivates of solution at the conditions which are evalulated for success + * @param trustDeltaOld INPUT Value of the trust length at the old conditions + * + * + * @return This function returns a code which indicates whether the step will be accepted or not. + * 3 Step passed with flying colors. Try redoing the calculation with a bigger trust region. + * 2 Step didn't pass deltaF requirement. Decrease the size of the next trust region for a retry and return + * 0 The step passed. + * -1 The step size is now too small (||d || < 0.1). A really small step isn't decreasing the function. + * This is an error condition. + * -2 Current value of the solution vector caused a residual error in its evaluation. + * Step is a failure, and the step size must be reduced in order to proceed further. + */ + int decideStep(const doublereal time_curr, int leg, doublereal alpha, const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, + const std::vector & step_1, + const doublereal * const y_n_1, const doublereal * const ydot_n_1, doublereal trustDeltaOld); + + //! Calculated the expected residual along the double dogleg curve. + /*! + * @param leg 0, 1, or 2 representing the curves of the dogleg + * @param alpha Relative distance along the particular curve. + * + * @return Returns the expected value of the residual at that point according to the quadratic model. + * The residual at the newton point will always be zero. + */ + doublereal expectedResidLeg(int leg, doublereal alpha) const; + + //! Here we print out the residual at various points along the double dogleg, comparing against the quadratic model + //! in a table format + /*! + * @param time_curr INPUT current time + * @param ydot0 INPUT Current value of the derivative of the solution vector for non-time dependent + * determinations + * @param legBest OUTPUT leg of the dogleg that gives the lowest residual + * @param alphaBest OUTPUT distance along dogleg for best result. + */ + void residualComparisonLeg(const doublereal time_curr, const doublereal * const ydot0, int & legBest, + doublereal & alphaBest) const; + + //! Set the print level from the nonlinear solver + /*! + * + * 0 -> absolutely nothing is printed for a single time step. + * 1 -> One line summary per solve_nonlinear call + * 2 -> short description, points of interest: Table of nonlinear solve - one line per iteration + * 3 -> Table is included -> More printing per nonlinear iteration (default) that occurs during the table + * 4 -> Summaries of the nonlinear solve iteration as they are occurring -> table no longer printed + * 5 -> Algorithm information on the nonlinear iterates are printed out + * 6 -> Additional info on the nonlinear iterates are printed out + * 7 -> Additional info on the linear solve is printed out. + * 8 -> Info on a per iterate of the linear solve is printed out. + * + * @param printLvl integer value + */ + void setPrintLvl(int printLvl); + + //! Parameter to turn on solution solver schemes + /*! + * @param doDogLeg Parameter to turn on the double dog leg scheme + * Default is to always use a damping scheme in the Newton Direction. + * When this is nonzero, a model trust region approach is used using a double dog leg + * with the steepest descent direction used for small step sizes. + * + * @param doAffineSolve Parameter to turn on or off the solution of the system using a Hessian + * if the matrix has a bad condition number. + */ + void setSolverScheme(int doDogLeg, int doAffineSolve); + + + + /* + * ----------------------------------------------------------------------------------------------------------------- + * MEMBER DATA + * ------------------------------------------------------------------------------------------------ + */ + private: //! Pointer to the residual and jacobian evaluator for the //! function @@ -270,21 +923,109 @@ namespace Cantera { */ ResidJacEval *m_func; + //! Solution type + int solnType_; + //! Local copy of the number of equations int neq_; //! Soln error weights std::vector m_ewt; - std::vector m_y_n; + //! Boolean indicating whether a manual delta bounds has been input. + int m_manualDeltaStepSet; + + //! Soln Delta bounds magnitudes + std::vector m_deltaStepMinimum; + + //! Value of the delta step magnitudes + std::vector m_deltaStepMaximum; + + //! Vector containing the current solution vector within the nonlinear solver + std::vector m_y_n_curr; + + //! Vector containing the time derivative of the current solution vector within the nonlinear solver + //! (where applicable) + std::vector m_ydot_n_curr; + + //! Vector containing the solution at the previous time step std::vector m_y_nm1; + + //! Vector containing the solution at the previous time step + std::vector m_y_n_1; + + //! Value of the solution time derivative at the new point that is to be considered + std::vector m_ydot_n_1; + + //! Value of the step to be taken in the solution + std::vector m_step_1; + + //! Vector of column scaling factors std::vector m_colScales; //! Weights for normalizing the values of the residuals - + /*! + * These are computed if row scaling, m_rowScaling, is turned on. They are calculated currently as the + * sum of the absolute values of the rows of the jacobian. + */ std::vector m_rowScales; - std::vector m_resid; + //! Weights for normalizing the values of the residuals + /*! + * They are calculated as the sum of the absolute values of the jacobian + * multiplied by the solution weight function. + * This is carried out in scaleMatrix(). + */ + std::vector m_rowWtScales; + + //! Value of the residual for the nonlinear problem + mutable std::vector m_resid; + + //! Workspace of length neq_ + mutable std::vector m_wksp; + + //! Workspace of length neq_ + mutable std::vector m_wksp_2; + + /***************************************************************************************** + * INTERNAL WEIGHTS FOR TAKING SOLUTION NORMS + ******************************************************************************************/ + //! Vector of residual weights + /*! + * These are used to establish useful and informative weighted norms of the residual vector. + */ + std::vector m_residWts; + + //! Norm of the residual at the start of each nonlinear iteration + doublereal m_normResid_0; + + //! Norm of the residual after it has been bounded + doublereal m_normResid_Bound; + + //! Norm of the residual at the end of the first leg of the current iteration + doublereal m_normResid_1; + + //! Norm of the residual at the end of the first leg of the current iteration + doublereal m_normResid_full; + + //! Norm of the solution update created by the iteration in its raw, undamped form, using the solution norm + doublereal m_normDeltaSoln_Newton; + + //! Norm of the distance to the cauchy point using the solution norm + doublereal m_normDeltaSoln_CP; + + //! Norm of the residual for a trial calculation which may or may not be used + doublereal m_normResidTrial; + + //! Vector of the norm + doublereal m_normResidPoints[15]; + + //! Boolean indicating whether we should scale the residual + mutable bool m_resid_scaled; + + /***************************************************************************************** + * INTERNAL BOUNDARY INFO FOR SOLUTIONS + *****************************************************************************************/ //! Bounds vector for each species std::vector m_y_high_bounds; @@ -292,41 +1033,272 @@ namespace Cantera { //! Lower bounds vector for each species std::vector m_y_low_bounds; - double delta_t_n; + //! Damping factor imposed by hard bounds and by delta bounds + doublereal m_dampBound; + + //! Additional damping factor due to bounds on the residual and solution norms + doublereal m_dampRes; + + //! Delta t for the current step + doublereal delta_t_n; //! Counter for the total number of function evaluations - int m_nfe; + mutable int m_nfe; - //! The type of column scaled used in the solution of the problem - bool m_colScaling; + /*********************************************************************************************** + * MATRIX INFORMATION + **************************************************************************************/ + + //! The type of column scaling used in the matrix inversion of the problem + /*! + * If 1 then colScaling = m_ewt[] + * If 2 then colScaling = user set + * if 0 then colScaling = 1.0 + */ + int m_colScaling; //! int indicating whether row scaling is turned on (1) or not (0) int m_rowScaling; + //! Total number of linear solves taken by the solver object int m_numTotalLinearSolves; + //! Number of local linear solves done during the current iteration + int m_numLocalLinearSolves; + + //! Total number of newton iterations int m_numTotalNewtIts; + //! Minimum number of newton iterations to use int m_min_newt_its; - int filterNewstep; + //! Maximum number of newton iterations + int maxNewtIts_; + + //! Jacobian formation method + /*! + * 1 = numerical (default) + * 2 = analytical + */ + int m_jacFormMethod; + + //! Number of Jacobian evaluations + int m_nJacEval; //! Current system time /*! * Note, we assume even for steady state problems that the residual * is a function of a system time. */ - double time_n; + doublereal time_n; + //! Boolean indicating matrix conditioning int m_matrixConditioning; + //! Order of the time step method = 1 int m_order; + //! value of the relative tolerance to use in solving the equation set doublereal rtol_; + //! Base value of the absolute tolerance doublereal atolBase_; + //! Pointer containing the solution derivative at the previous time step + doublereal *m_ydot_nm1; + + //! absolute tolerance in the solution unknown + /*! + * This is used to evaluating the weighting factor + */ std::vector atolk_; + + //! absolute tolerance in the unscaled solution unknowns + std::vector userResidAtol_; + + //! absolute tolerance in the unscaled solution unknowns + doublereal userResidRtol_; + + //! Check the residual tolerances explictly against user input + /*! + * 0 Don't calculate residual weights from residual tolerance inputs + * 1 Calculate residual weights from residual tolerance inputs only + * 2 Calculate residual weights from a minimum of the solution error weights process and the direct residual tolerance inputs + */ + int checkUserResidualTols_; + + //! Determines the level of printing for each time step. + /*! + * 0 -> absolutely nothing is printed for a single time step. + * 1 -> One line summary per solve_nonlinear call + * 2 -> short description, points of interest: Table of nonlinear solve - one line per iteration + * 3 -> Table is included -> More printing per nonlinear iteration (default) that occurs during the table + * 4 -> Summaries of the nonlinear solve iteration as they are occurring -> table no longer printed + * 5 -> Algorithm information on the nonlinear iterates are printed out + * 6 -> Additional info on the nonlinear iterates are printed out + * 7 -> Additional info on the linear solve is printed out. + * 8 -> Info on a per iterate of the linear solve is printed out. + */ + int m_print_flag; + + //! Scale factor for turning residual norms into solution norms + doublereal m_ScaleSolnNormToResNorm; + + //! Copy of the jacobian that doesn't get overwritten when the inverse is determined + /*! + * The jacobian storred here is the raw matrix, before any row or column scaling is carried out + */ + Cantera::GeneralMatrix * jacCopyPtr_; + + //! Hessian + Cantera::GeneralMatrix * HessianPtr_; + + /********************************************************************************************* + * VARIABLES ASSOCIATED WITH STEPS AND ASSOCIATED DOUBLE DOGLEG PARAMETERS + *********************************************************************************************/ + + //! Steepest descent direction. This is also the distance to the Cauchy Point + std::vector deltaX_CP_; + + //! Newton Step - This is the newton step determined from the straight Jacobian + /* + * Newton step for the current step only + */ + std::vector deltaX_Newton_; + + //! Expected value of the residual norm at the Cauchy point if the quadratic model + //! were valid + doublereal residNorm2Cauchy_; + + //! Current leg + int dogLegID_; + + //! Current Alpha param along the leg + doublereal dogLegAlpha_; + + //! Residual dot Jd norm + /*! + * This is equal to R_hat dot J_hat d_y_descent + */ + doublereal RJd_norm_; + + //! Value of lambdaStar_ which is used to calculate the Cauchy point + doublereal lambdaStar_; + + //! Jacobian times the steepest descent direction in the normalized coordinates. + /*! + * This is equal to [ Jhat d^y_{descent} ] in the notes, Eqn. 18. + */ + std::vector Jd_; + + //! Vector of trust region values. + std::vector deltaX_trust_; + + //! Current norm of the vector deltaX_trust_ in terms of the solution norm + mutable doublereal norm_deltaX_trust_; + + //! Current value of trust radius. This is used with deltaX_trust_ to + //! calculate the max step size. + doublereal trustDelta_; + + //! Method for handling the trust region initialization + /*! + * Then, on subsequent invocations of solve_nonlinear_problem() the strategy flips to method 0. + * + * method Method to set the strategy + * 0 No strategy - Use the previous strategy + * 1 Factor of the solution error weights + * 2 Factor of the first Cauchy Point distance + * 3 Factor of the first Newton step distance + */ + int trustRegionInitializationMethod_; + + //! Factor used to set the initial trust region + doublereal trustRegionInitializationFactor_; + + //! Relative distance down the Newton step that the second dogleg starts + doublereal Nuu_; + + //! Distance of the zeroeth leg of the dogleg in terms of the solution norm + doublereal dist_R0_; + + //! Distance of the first leg of the dogleg in terms of the solution norm + doublereal dist_R1_; + + //! Distance of the second leg of the dogleg in terms of the solution norm + doublereal dist_R2_; + + //! Distance of the sum of all legs of the doglegs in terms of the solution norm + doublereal dist_Total_; + + //! Dot product of the Jd_ variable defined above with itself. + doublereal JdJd_norm_; + + //! Norm of the Newton Step wrt trust region + doublereal normTrust_Newton_; + + //! Norm of the Cauchy Step direction wrt trust region + doublereal normTrust_CP_; + + //! General toggle for turning on dog leg damping. + int doDogLeg_; + + //! General toggle for turning on Affine solve with Hessian + int doAffineSolve_; + + //! Condition number of the matrix + doublereal m_conditionNumber; + + //! Factor indicating how much trust region has been changed this iteration - output variable + doublereal CurrentTrustFactor_; + + //! Factor indicating how much trust region has been changed next iteration - output variable + doublereal NextTrustFactor_; + + //! Boolean indicating that the residual weights have been reevalulated this iteration - output variable + bool ResidWtsReevaluated_; + + //! Expected DResid_dS for the steepest descent path - output variable + doublereal ResidDecreaseSDExp_; + + //! Actual DResid_dS for the steepest descent path - output variable + doublereal ResidDecreaseSD_; + + //! Expected DResid_dS for the Newton path - output variable + doublereal ResidDecreaseNewtExp_; + + //! Actual DResid_dS for the newton path - output variable + doublereal ResidDecreaseNewt_; + + /******************************************************************************************* + * STATIC VARIABLES + *****************************************************************************************/ + + public: + //! Turn off printing of time + /*! + * Necessary to do for test suites + */ + static bool s_TurnOffTiming; + + //! Turn on or off printing of the Jacobian + static bool s_print_NumJac; + + //! Turn on extra printing of dogleg information + static bool s_print_DogLeg; + + //! Turn on solving both the Newton and Hessian systems and comparing the results + /*! + * This is off by default + */ + static bool s_doBothSolvesAndCompare; + + //! This toggle turns off the use of the Hessian when it is warranted by the condition number. + /*! + * This is a debugging option. + */ + static bool s_alwaysAssumeNewtonGood; + }; } diff --git a/Cantera/src/numerics/ResidEval.h b/Cantera/src/numerics/ResidEval.h old mode 100755 new mode 100644 index ec61bd2d2..4f1eb5e61 --- a/Cantera/src/numerics/ResidEval.h +++ b/Cantera/src/numerics/ResidEval.h @@ -31,7 +31,7 @@ namespace Cantera { * Virtual base class for DAE residual function evaluators. * Classes derived from ResidEval evaluate the residual function * \f[ - \vec{F}(t,\vec{y}, \vec{y^\prime}) + * \vec{F}(t,\vec{y}, \vec{y^\prime}) * \f] * The DAE solver attempts to find a solution y(t) such that F = 0. * @ingroup DAE_Group @@ -59,13 +59,28 @@ namespace Cantera { return c_NONE; } + //! Initialization function + virtual void initSizes() + { + int neq = nEquations(); + m_alg.resize(neq, 0); + } + /** * Specify that solution component k is purely algebraic - * that is, the derivative of this component does not appear * in the residual function. */ - virtual void setAlgebraic(const int k) { m_alg[k] = 1; } - virtual bool isAlgebraic(const int k) {return (m_alg[k] == 1); } + virtual void setAlgebraic(const int k) { + if ((int) m_alg.size() < (k+1)) { + initSizes(); + } + m_alg[k] = 1; + } + + virtual bool isAlgebraic(const int k) { + return (m_alg[k] == 1); + } /** @@ -82,24 +97,81 @@ namespace Cantera { throw CanteraError("ResidEval::eval()", "base class called"); } + virtual int evalSS(const doublereal t, const doublereal * const y, + doublereal * const r) { + return eval(t, y, 0, r); + } + + virtual int evalSimpleTD(const doublereal t, const doublereal * const y, + const doublereal * const yold, doublereal deltaT, + doublereal * const r) { + int nn = nEquations(); + vector_fp ydot(nn); + for (int i = 0; i < nn; i++) { + ydot[i] = (y[i] - yold[i]) / deltaT; + } + return eval(t, y, DATA_PTR(ydot), r); + } + /** * Fill the solution and derivative vectors with the initial - * conditions at initial time t0. If these do not satisfy the - * residual equation, call one of the "corrrectInitial_xxx" - * methods before calling solve. + * conditions at initial time t0. + * @return 1 Everything is fine + * 0 or neg Something went wrong */ - virtual void getInitialConditions(const doublereal t0, doublereal * const y, + virtual int getInitialConditions(const doublereal t0, doublereal * const y, doublereal * const ydot) { + initSizes(); throw CanteraError("ResidEval::GetInitialConditions()", "base class called"); + return 1; } //! Return the number of equations in the equation system virtual int nEquations() const = 0; + + //! Write out to a file or to standard output the current solution + /*! + * ievent is a description of the event that caused this + * function to be called. + */ + virtual void writeSolution(int ievent, const double time, + const double deltaT, + const int time_step_num, + const double *y, const double *ydot) { + int k; + printf("ResidEval::writeSolution\n"); + printf(" Time = %g, ievent = %d, deltaT = %g\n", time, ievent, deltaT); + if (ydot) { + printf(" k y[] ydot[]\n"); + for (k = 0; k < nEquations(); k++) { + printf("%d %g %g\n", k, y[k], ydot[k]); + } + } else { + printf(" k y[]\n"); + for (k = 0; k < nEquations(); k++) { + printf("%d %g \n", k, y[k]); + } + } + } + + //! Return the number of parameters in the calculation + /*! + * This is the number of parameters in the sensitivity calculation. We have + * set this to zero and have included it for later expansion + */ + int nparams () const { + return 0; + } protected: - std::map m_alg; + //! Mapping vector that stores whether a degree of freedom is a DAE or not + /*! + * The first index is the equation number. The second index is 1 if it is a DAE, + * and zero if it is not. + */ + std::vector m_alg; std::map m_constrain; private: diff --git a/Cantera/src/numerics/ResidJacEval.cpp b/Cantera/src/numerics/ResidJacEval.cpp index 18168c055..a4fc0ac22 100644 --- a/Cantera/src/numerics/ResidJacEval.cpp +++ b/Cantera/src/numerics/ResidJacEval.cpp @@ -23,21 +23,14 @@ using namespace std; namespace Cantera { - - /************************************************************************* - * - * ResidJacEval(): - * - * Default constructor for the ResidJacEval class. - * - * atol has a default of 1.0E-13. - */ + //==================================================================================================================== + ResidJacEval::ResidJacEval(doublereal atol) : ResidEval(), m_atol(atol) { } - + //==================================================================================================================== // Copy Constructor for the %ResidJacEval object /* */ @@ -46,14 +39,11 @@ namespace Cantera { { *this = operator=(right); } - - /* - * - */ + //==================================================================================================================== ResidJacEval::~ResidJacEval() { } - + //==================================================================================================================== ResidJacEval& ResidJacEval::operator=(const ResidJacEval &right) { if (this == &right) { return *this; @@ -66,9 +56,8 @@ namespace Cantera { return *this; } - - // Duplication routine for objects which inherit from - // %ResidJacEval + //==================================================================================================================== + // Duplication routine for objects which inherit from %ResidJacEval /* * This virtual routine can be used to duplicate %ResidJacEval objects * inherited from %ResidJacEval even if the application only has @@ -81,16 +70,14 @@ namespace Cantera { ResidJacEval *ff = new ResidJacEval(*this); return ff; } - + //==================================================================================================================== int ResidJacEval::nEquations() const { return neq_; } - + //==================================================================================================================== + // Set a global value of the absolute tolerance /* - * - * setAtol(): - * - * Set the absolute tolerance value + * @param atol Value of atol */ void ResidJacEval::setAtol(doublereal atol) { @@ -100,17 +87,17 @@ namespace Cantera { "atol must be greater than zero"); } } - - /************************************************************************** + //==================================================================================================================== + //! Fill in the initial conditions + /*! + * Values for both the solution and the value of ydot may be provided. * - * - * - * Fill the solution vector with the initial conditions - * at initial time t0. + * @param t0 Time (input) + * @param y Solution vector (output) + * @param ydot Rate of change of solution vector. (output) */ - void ResidJacEval:: - getInitialConditionsDot(const doublereal t0, const size_t leny, - doublereal * const y, doublereal * const ydot) { + int ResidJacEval:: + getInitialConditions(doublereal t0, doublereal * const y, doublereal * const ydot) { for (int i = 0; i < neq_; i++) { y[i] = 0.0; } @@ -119,66 +106,82 @@ namespace Cantera { ydot[i] = 0.0; } } + return 1; } - - /************************************************************************** + //==================================================================================================================== + // This function may be used to create output at various points in the execution of an application. + /* * + * @param ifunc identity of the call + * 0 Initial call + * 1 Called at the end of every successful time step + * -1 Called at the end of every unsuccessful time step + * 2 Called at the end of every call to integrateRJE() * - * - * Fill the solution vector with the initial conditions - * at initial time t0. - * - */ - void ResidJacEval:: - getInitialConditions(doublereal t0, - doublereal * const y, doublereal * const ydot) { - size_t leny = neq_; - getInitialConditionsDot(t0, leny, y, 0); - } - - /************************************************************************** - * - * user_out(): - * - * This function may be used to create output at various points in the - * execution of an application. - * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input) */ void ResidJacEval:: user_out2(const int ifunc, const doublereal t, const doublereal deltaT, const doublereal *y, const doublereal *ydot) { - } + //==================================================================================================================== + // This function may be used to create output at various points in the execution of an application. + /* + * This routine calls user_out2(). + * + * @param ifunc identity of the call + * @param t Time (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input) + */ void ResidJacEval:: user_out(const int ifunc, const doublereal t, const doublereal *y, const doublereal *ydot) { user_out2(ifunc, t, 0.0, y, ydot); } - - /************************************************************************** - * + //==================================================================================================================== + //! Evaluate the time tracking equations, if any + /*! + * Evaluate time integrated quantities that are calculated at the + * end of every successful time step. This call is made once at the end of every successful + * time step that advances the time. It's also made once at the start of the time stepping. * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) */ - void ResidJacEval:: - evalTimeTrackingEqns(const doublereal t, const doublereal deltaT, - const doublereal *y, - const doublereal *ydot) { - + int ResidJacEval:: + evalTimeTrackingEqns(const doublereal t, const doublereal delta_t, const doublereal *y, + const doublereal *ydot) + { + return 1; } - - /******************************************************************** + //==================================================================================================================== + // Return a vector of delta y's for calculation of the numerical Jacobian + /* + * There is a default algorithm provided. * + * delta_y[i] = atol[i] + 1.0E-6 ysoln[i] + * delta_y[i] = atol[i] + MAX(1.0E-6 ysoln[i] * 0.01 * solnWeights[i]) * + * @param t Time (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param delta_y Value of the delta to be used in calculating the numerical jacobian + * @param solnWeights Value of the solution weights that are used in determining convergence (default = 0) * - * Return a vector of delta y's for calculation of the - * numerical Jacobian + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * 0 Means an unsuccessful operation */ - void ResidJacEval:: - calcDeltaSolnVariables(const doublereal t, - const doublereal * const ySoln, - const doublereal * const ySolnDot, - doublereal * const deltaYSoln, + int ResidJacEval:: + calcDeltaSolnVariables(const doublereal t, const doublereal * const ySoln, + const doublereal * const ySolnDot, doublereal * const deltaYSoln, const doublereal *const solnWeights) { if (!solnWeights) { @@ -187,100 +190,179 @@ namespace Cantera { } } else { for (int i = 0; i < neq_; i++) { - deltaYSoln[i] = m_atol + - fmaxx(1.0E-2 * solnWeights[i], 1.0E-6 * fabs(ySoln[i])); + deltaYSoln[i] = fmaxx(1.0E-2 * solnWeights[i], 1.0E-6 * fabs(ySoln[i])); } } + return 1; } - - /****************************************************************** + //==================================================================================================================== + // Returns a vector of column scale factors that can be used to column scale Jacobians. + /* + * Default to yScales[] = 1.0 * - * calcSolnScales(): - * - * Returns a vector of ysolnScales[] that can be used to column scale - * Jacobians. + * @param t Time (input) + * @param y Solution vector (input, do not modify) + * @param y_old Old Solution vector (input, do not modify) + * @param yScales Value of the column scales */ void ResidJacEval:: - calcSolnScales(const doublereal t, - const doublereal * const ysoln, - const doublereal * const ysolnOld, + calcSolnScales(const doublereal t, const doublereal * const ysoln, const doublereal * const ysolnOld, doublereal * const ysolnScales) { - for (int i = 0; i < neq_; i++) { - ysolnScales[i] = 1.0; + if (ysolnScales) { + if (ysolnScales[0] == 0.0) { + for (int i = 0; i < neq_; i++) { + ysolnScales[i] = 1.0; + } + } } } - - void ResidJacEval::filterSolnPrediction(doublereal t, - doublereal * const y) { - + //==================================================================================================================== + // Filter the solution predictions + /* + * Codes might provide a predicted step change. This routine filters the predicted + * solution vector eliminating illegal directions. + * + * @param t Time (input) + * @param y Solution vector (input, output) + * @param step Proposed step in the solution that will be cropped + */ + doublereal ResidJacEval::filterNewStep(doublereal t, const doublereal * const ybase, doublereal * const step) + { + return 0.0; } - - /************************************************************************** + //==================================================================================================================== + // Filter the solution predictions + /* + * Codes might provide a predicted solution vector. This routine filters the predicted + * solution vector. * - * evalStoppingCriteria() + * @param t Time (input) + * @param y Solution vector (input, output) + */ + doublereal ResidJacEval::filterSolnPrediction(doublereal t, doublereal * const y) + { + return 0.0; + } + //==================================================================================================================== + // Evalulate any stopping criteria other than a final time limit + /* + * If we are to stop the time integration for any reason other than reaching a final time limit, tout, + * provide a test here. This call is made at the end of every succesful time step iteration * - * If there is a stopping critera other than time set it here. + * @return If true, the the time stepping is stopped. If false, then time stepping is stopped if t >= tout + * Defaults to false. * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) */ bool ResidJacEval:: - evalStoppingCritera(doublereal &time_current, - doublereal &delta_t_n, - doublereal *y_n, - doublereal *ydot_n) + evalStoppingCritera(const doublereal t, + const doublereal delta_t, + const doublereal * const y, + const doublereal * const ydot) { return false; } - - /************************************************************************** + //==================================================================================================================== + // Multiply the matrix by another matrix that leads to better conditioning + /* + * Provide a left sided matrix that will multiply the current jacobian, after scaling + * and lead to a better conditioned system. + * This routine is called just before the matrix is factored. + * + * Original Problem: + * J delta_x = - Resid * - * matrixConditioning() + * New problem: + * M (J delta_x) = - M Resid * - * Multiply the matrix by the inverse of a matrix which lead to a - * better conditioned system. The default, specified here, is to - * do nothing. + * @param matrix Pointer to the current jacobian (if zero, it's already been factored) + * @param nrows offsets for the matrix + * @param rhs residual vector. This also needs to be lhs multiplied by M */ - void ResidJacEval:: - matrixConditioning(doublereal * const matrix, const int nrows, - doublereal * const rhs) + int ResidJacEval:: + matrixConditioning(doublereal * const matrix, const int nrows, doublereal * const rhs) { + return 1; } - - /************************************************************************** - * - */ - void ResidJacEval:: - evalResidNJ(doublereal t, const doublereal deltaT, - const doublereal * y, - const doublereal * ydot, - doublereal * resid, - bool NJevaluation, - int id_x, - doublereal delta_x) - { - printf("Not implemented\n"); - std::exit(-1); + //==================================================================================================================== + // Evaluate the residual function + /* + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param resid Value of the residual that is computed (output) + * @param evalType Type of the residual being computed (defaults to Base_ResidEval) + * @param id_x Index of the variable that is being numerically differenced to find + * the jacobian (defaults to -1, which indicates that no variable is being + * differenced or that the residual doesn't take this issue into account) + * @param delta_x Value of the delta used in the numerical differencing + */ + int ResidJacEval:: + evalResidNJ(const doublereal t, const doublereal deltaT, const doublereal * y, + const doublereal * ydot, doublereal * const resid, const ResidEval_Type_Enum evalType, + const int id_x, const doublereal delta_x) + { + throw CanteraError("ResidJacEval::evalResidNJ()", "Not implemented\n"); + return 1; } - - /************************************************************************** + //==================================================================================================================== + int ResidJacEval::eval(const doublereal t, const doublereal * const y, const doublereal * const ydot, + doublereal * const r) { + double deltaT = -1.0; + int flag = evalResidNJ(t, deltaT, y, ydot, r); + return flag; + } + //==================================================================================================================== + // Calculate an analytical jacobian and the residual at the current time and values. + /* + * Only called if the jacFormation method is set to analytical * - * evalJacobian() - * - * Calculate the jacobian and the residual at the current - * time and values. - * Backwards Euler is assumed. + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param J Reference to the SquareMatrix object to be calculated (output) + * @param resid Value of the residual that is computed (output) */ - void ResidJacEval:: - evalJacobian(const doublereal t, const doublereal deltaT, + int ResidJacEval:: + evalJacobian(const doublereal t, const doublereal delta_t, doublereal cj, const doublereal * const y, const doublereal * const ydot, - SquareMatrix &J, + GeneralMatrix &J, doublereal * const resid) { - printf("Not implemented\n"); - std::exit(-1); + doublereal * const * jac_colPts = J.colPts(); + return evalJacobianDP(t, delta_t, cj, y, ydot, jac_colPts, resid); } - + //==================================================================================================================== + // Calculate an analytical jacobian and the residual at the current time and values. + /* + * Only called if the jacFormation method is set to analytical + * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param c_j The current value of the coefficient of the time derivative + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param jac_colPts Reference to the SquareMatrix object to be calculated (output) + * @param resid Value of the residual that is computed (output) + */ + int ResidJacEval:: + evalJacobianDP(const doublereal t, const doublereal delta_t, + const doublereal c_j, + const doublereal * const y, + const doublereal * const ydot, + doublereal * const * jac_colPts, + doublereal * const resid) + { + throw CanteraError("ResidJacEval::evalJacobianDP()", "Not implemented\n"); + return 1; + } + //==================================================================================================================== } - diff --git a/Cantera/src/numerics/ResidJacEval.h b/Cantera/src/numerics/ResidJacEval.h index daa3bb6aa..ccbaf4b98 100644 --- a/Cantera/src/numerics/ResidJacEval.h +++ b/Cantera/src/numerics/ResidJacEval.h @@ -21,20 +21,48 @@ #define CT_RESIDJACEVAL_H #include "ResidEval.h" -#include "SquareMatrix.h" +#include "GeneralMatrix.h" namespace Cantera { - /** - * A class for full (non-sparse) matrices with Fortran-compatible - * data storage. Adds matrix operations to class Array2D. +//! Differentiates the type of residual evaluations according to functionality + enum ResidEval_Type_Enum + { + //! Base residual calculation for the time-stepping function + Base_ResidEval = 0, + //! Base residual calculation for the Jacobian calculation + JacBase_ResidEval, + //! Delta residual calculation for the Jacbobian calculation + JacDelta_ResidEval, + //! Base residual calculation for the showSolution routine + /*! + * We calculate this when we want to display a solution + */ + Base_ShowSolution, + //! Base residual calculation containing any lagged components + /*! + * We use this to calculate residuals when doing line searches along + * directions determined by Jacobians that are missing contributions + * from lagged entries. + */ + Base_LaggedSolutionComponents + }; + + //! Wrappers for the function evaluators for Nonlinear solvers and Time steppers + /*! + * A class for full (non-sparse dense matrices with Fortran-compatible data storage. + * The class adds support for identifying what types of calls are made to the residual + * evaluator by adding the ResidEval_Type_Enum class. + * + * */ class ResidJacEval : public ResidEval { public: - /** - * Default constructor + //!Default constructor + /*! + * @param atol Initial value of the global tolerance (defaults to 1.0E-13) */ ResidJacEval(doublereal atol = 1.0e-13); @@ -71,111 +99,272 @@ namespace Cantera { //! Return the number of equations in the equation system virtual int nEquations() const; - /** - * Evaluate the residual function. - * @param t time (input, do not modify) - * @param y solution vector (input, do not modify) - * @param ydot rate of change of solution vector. (input, do - * not modify) + //! Evaluate the residual function + /*! + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param resid Value of the residual that is computed (output) + * @param evalType Type of the residual being computed (defaults to Base_ResidEval) + * @param id_x Index of the variable that is being numerically differenced to find + * the jacobian (defaults to -1, which indicates that no variable is being + * differenced or that the residual doesn't take this issue into account) + * @param delta_x Value of the delta used in the numerical differencing + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation */ - virtual void evalResidNJ(doublereal t, const doublereal deltaT, + virtual int evalResidNJ(const doublereal t, const doublereal delta_t, const doublereal * const y, const doublereal * const ydot, doublereal * const resid, - bool NJevaluation = false, - int id_x = 0, - doublereal delta_x = 0.0); + const ResidEval_Type_Enum evalType = Base_ResidEval, + const int id_x = -1, + const doublereal delta_x = 0.0); + /** - * Fill the solution vector with the initial conditions - * at initial time t0. + * Evaluate the residual function. Called by the + * integrator. + * @param t time. (input) + * @param y solution vector. (input) + * @param ydot rate of change of solution vector. (input) + * @param r residual vector (output) */ - virtual void getInitialConditionsDot(const doublereal t0, size_t leny, - doublereal * const y, - doublereal * const ydot); + virtual int eval(const doublereal t, const doublereal * const y, + const doublereal * const ydot, + doublereal * const r); - virtual void getInitialConditions(const doublereal t0, - doublereal * const y, - doublereal * const ydot); + + + //! Fill in the initial conditions + /*! + * Values for both the solution and the value of ydot may be provided. + * + * @param t0 Time (input) + * @param y Solution vector (output) + * @param ydot Rate of change of solution vector. (output) + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + virtual int getInitialConditions(const doublereal t0, doublereal * const y, doublereal * const ydot); - virtual void filterSolnPrediction(doublereal t, - doublereal * const y); + //! Filter the solution predictions + /*! + * Codes might provide a predicted step change. This routine filters the predicted + * solution vector eliminating illegal directions. + * + * @param t Time (input) + * @param ybase Solution vector (input, output) + * @param step Proposed step in the solution that will be cropped + * + * @return Return the norm of the amount of filtering + */ + virtual doublereal filterNewStep(const doublereal t, const doublereal * const ybase, + doublereal * const step); + //! Filter the solution predictions + /*! + * Codes might provide a predicted solution vector. This routine filters the predicted + * solution vector. + * + * @param t Time (input) + * @param y Solution vector (input, output) + * + * @return Return the norm of the amount of filtering + */ + virtual doublereal filterSolnPrediction(const doublereal t, doublereal * const y); + + //! Set a global value of the absolute tolerance + /*! + * @param atol Value of atol + */ void setAtol(doublereal atol); - virtual void evalTimeTrackingEqns(const doublereal t, const doublereal deltaT, - const doublereal * const y, + //! Evaluate the time tracking equations, if any + /*! + * Evaluate time integrated quantities that are calculated at the + * end of every successful time step. This call is made once at the end of every successful + * time step that advances the time. It's also made once at the start of the time stepping. + * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + virtual int evalTimeTrackingEqns(const doublereal t, const doublereal delta_t, const doublereal * const y, const doublereal * const ydot); - virtual bool evalStoppingCritera(doublereal &time_current, - doublereal &delta_t_n, - doublereal *y_n, - doublereal *ydot_n); - /** - * Return a vector of delta y's for calculation of the - * numerical Jacobian - */ - virtual void - calcDeltaSolnVariables(const doublereal t, - const doublereal * const ysoln, - const doublereal * const ysolnDot, - doublereal * const deltaYsoln, - const doublereal * const solnWeights=0); - - /** - * Returns a vector of ysolnScales[] that can be used to column - * scale Jacobians. - */ - virtual void calcSolnScales(const doublereal t, - const doublereal * const ysoln, - const doublereal * const ysolnOld, - doublereal * const ysolnScales); - - /** - * This function may be used to create output at various points in the - * execution of an application. + //! Evalulate any stopping criteria other than a final time limit + /*! + * If we are to stop the time integration for any reason other than reaching a final time limit, tout, + * provide a test here. This call is made at the end of every succesful time step iteration * + * @return If true, the the time stepping is stopped. If false, then time stepping is stopped if t >= tout + * Defaults to false. + * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + */ + virtual bool evalStoppingCritera(const doublereal t, + const doublereal delta_t, + const doublereal * const y, + const doublereal * const ydot); + + //! Return a vector of delta y's for calculation of the numerical Jacobian + /*! + * There is a default algorithm provided. + * + * delta_y[i] = atol[i] + 1.0E-6 ysoln[i] + * delta_y[i] = atol[i] + MAX(1.0E-6 ysoln[i] * 0.01 * solnWeights[i]) + * + * @param t Time (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param delta_y Value of the delta to be used in calculating the numerical jacobian + * @param solnWeights Value of the solution weights that are used in determining convergence (default = 0) + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + virtual int + calcDeltaSolnVariables(const doublereal t, + const doublereal * const y, + const doublereal * const ydot, + doublereal * const delta_y, + const doublereal * const solnWeights = 0); + + //! Returns a vector of column scale factors that can be used to column scale Jacobians. + /*! + * Default to yScales[] = 1.0 + * + * @param t Time (input) + * @param y Solution vector (input, do not modify) + * @param y_old Old Solution vector (input, do not modify) + * @param yScales Value of the column scales + */ + virtual void calcSolnScales(const doublereal t, const doublereal * const y, + const doublereal * const y_old, doublereal * const yScales); + + //! This function may be used to create output at various points in the execution of an application. + /*! + * + * @param ifunc identity of the call + * 0 Initial call + * 1 Called at the end of every successful time step + * -1 Called at the end of every unsuccessful time step + * 2 Called at the end of every call to integrateRJE() + * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input) */ virtual void user_out2(const int ifunc, const doublereal t, - const doublereal deltaT, + const doublereal delta_t, const doublereal * const y, const doublereal * const ydot); + //! This function may be used to create output at various points in the execution of an application. + /*! + * This routine calls user_out2(). + * + * @param ifunc identity of the call + * @param t Time (input) + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input) + */ virtual void user_out(const int ifunc, const doublereal t, const doublereal *y, const doublereal *ydot); - - virtual void matrixConditioning(doublereal * const matrix, const int nrows, + //! Multiply the matrix by another matrix that leads to better conditioning + /*! + * Provide a left sided matrix that will multiply the current jacobian, after scaling + * and lead to a better conditioned system. + * This routine is called just before the matrix is factored. + * + * Original Problem: + * J delta_x = - Resid + * + * New problem: + * M (J delta_x) = - M Resid + * + * @param matrix Pointer to the current jacobian (if zero, it's already been factored) + * @param nrows offsets for the matrix + * @param rhs residual vector. This also needs to be lhs multiplied by M + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + virtual int matrixConditioning(doublereal * const matrix, const int nrows, doublereal * const rhs); - /********************************************************************* + //! Calculate an analytical jacobian and the residual at the current time and values. + /*! + * Only called if the jacFormation method is set to analytical * - * evalJacobian() + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param cj Coefficient of yprime used in the evalulation of the jacobian + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param J Reference to the SquareMatrix object to be calculated (output) + * @param resid Value of the residual that is computed (output) * - * Calculate the jacobian and the residual at the current - * time and values. - * Backwards Euler is assumed. + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation */ - virtual void evalJacobian(const doublereal t, const doublereal deltaT, - - const double* const y, - const double* const ydot, - SquareMatrix &J, - doublereal * const resid); + virtual int evalJacobian(const doublereal t, const doublereal delta_t, doublereal cj, + const doublereal* const y, const doublereal* const ydot, + GeneralMatrix &J, doublereal * const resid); + //! Calculate an analytical jacobian and the residual at the current time and values. + /*! + * Only called if the jacFormation method is set to analytical + * + * @param t Time (input) + * @param delta_t The current value of the time step (input) + * @param cj Coefficient of yprime used in the evalulation of the jacobian + * @param y Solution vector (input, do not modify) + * @param ydot Rate of change of solution vector. (input, do not modify) + * @param jacobianColPts Pointer to the vector of pts to columns of the SquareMatrix + * object to be calculated (output) + * @param resid Value of the residual that is computed (output) + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + virtual int evalJacobianDP(const doublereal t, const doublereal delta_t, doublereal cj, + const doublereal* const y, + const doublereal* const ydot, + doublereal * const *jacobianColPts, + doublereal * const resid); protected: + //! constant value of atol doublereal m_atol; + //! Number of equations int neq_; - }; } #endif - - diff --git a/Cantera/src/numerics/RootFind.cpp b/Cantera/src/numerics/RootFind.cpp new file mode 100644 index 000000000..4d5760fca --- /dev/null +++ b/Cantera/src/numerics/RootFind.cpp @@ -0,0 +1,1390 @@ +/* + * @file: RootFind.cpp root finder for 1D problems + */ +/* + * $Id$ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#include "ct_defs.h" +#include "RootFind.h" + +#include "global.h" +#ifdef DEBUG_MODE +#include "mdp_allo.h" +#endif +#include "stringUtils.h" +/* Standard include files */ + +#include +#include +#include + +#include + +using namespace std; +namespace Cantera { + + + +#ifndef MAX +# define MAX(x,y) (( (x) > (y) ) ? (x) : (y)) /* max function */ +#endif + +#ifndef MIN +# define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) /* min function */ +#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 + +#ifdef SWAP +#undef SWAP +#endif +#ifndef SWAP +#define SWAP(x1, x2, tmp) ((tmp) = (x2), (x2) = (x1), (x1) = (tmp)) +#endif + +// turn on debugging for now +#ifndef DEBUG_MODE +#define DEBUG_MODE +#endif + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ +#ifdef DEBUG_MODE + //! Print out a form for the current function evaluation + /*! + * @param fp Pointer to the FILE object + * @param xval Current value of x + * @param fval Current value of f + * @param its Current iteration value + */ + static void print_funcEval(FILE *fp, doublereal xval, doublereal fval, int its) + { + fprintf(fp,"\n"); + fprintf(fp,"...............................................................\n"); + fprintf(fp,".................. RootFind 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 + //================================================================================================ + //! Solve Ax = b using gauss's method + /*! + * @param c Matrix + * @param idem Assumed number of rows in the matrix + * @param n Number of rows and columns + * @param b right hand side + * @param m Number of right hand sides + */ + static int smlequ(doublereal *c, int idem, int n, doublereal *b, int m) { + int i, j, k, l; + doublereal R; + if (n > idem || n <= 0) { + writelogf("smlequ ERROR: badly dimensioned matrix: %d %d\n", n, idem); + return 1; + } + + /* + * Loop over the rows + * -> At the end of each loop, the only nonzero entry in the column + * will be on the diagonal. We can therfore just invert the + * diagonal at the end of the program to solve the equation system. + */ + for (i = 0; i < n; ++i) { + if (c[i + i * idem] == 0.0) { + /* + * Do a simple form of row pivoting to find a non-zero pivot + */ + for (k = i + 1; k < n; ++k) { + if (c[k + i * idem] != 0.0) goto FOUND_PIVOT; + } + writelogf("smlequ ERROR: Encountered a zero column: %d\n", i); + return 1; + FOUND_PIVOT: ; + for (j = 0; j < n; ++j) c[i + j * idem] += c[k + j * idem]; + for (j = 0; j < m; ++j) b[i + j * idem] += b[k + j * idem]; + } + + for (l = 0; l < n; ++l) { + if (l != i && c[l + i * idem] != 0.0) { + R = c[l + i * idem] / c[i + i * idem]; + c[l + i * idem] = 0.0; + for (j = i+1; j < n; ++j) c[l + j * idem] -= c[i + j * idem] * R; + for (j = 0; j < m; ++j) b[l + j * idem] -= b[i + j * idem] * R; + } + } + } + /* + * The negative in the last expression is due to the form of B upon + * input + */ + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + b[i + j * idem] = -b[i + j * idem] / c[i + i*idem]; + } + } + return 0; + } + //================================================================================================ + // Main constructor + RootFind::RootFind (ResidEval* resid) : + m_residFunc(resid), + m_funcTargetValue(0.0), + m_atolf(1.0E-11), + m_atolx(1.0E-11), + m_rtolf(1.0E-5), + m_rtolx(1.0E-5), + m_maxstep(1000), + printLvl(0), + writeLogAllowed_(false), + DeltaXnorm_(0.01), + specifiedDeltaXnorm_(0), + DeltaXMax_(1.0E6), + specifiedDeltaXMax_(0), + FuncIsGenerallyIncreasing_(false), + FuncIsGenerallyDecreasing_(false), + deltaXConverged_(0.0), + x_maxTried_(-1.0E300), + fx_maxTried_(0.0), + x_minTried_(1.0E300), + fx_minTried_(0.0) + { + + } + //================================================================================================ + RootFind::RootFind(const RootFind &r) : + m_residFunc(r.m_residFunc), + m_funcTargetValue(0.0), + m_atolf(1.0E-11), + m_atolx(1.0E-11), + m_rtolf(1.0E-5), + m_rtolx(1.0E-5), + m_maxstep(1000), + printLvl(0), + writeLogAllowed_(false), + DeltaXnorm_(0.01), + specifiedDeltaXnorm_(0), + DeltaXMax_(1.0E6), + specifiedDeltaXMax_(0), + FuncIsGenerallyIncreasing_(false), + FuncIsGenerallyDecreasing_(false), + deltaXConverged_(0.0), + x_maxTried_(-1.0E300), + fx_maxTried_(0.0), + x_minTried_(1.0E300), + fx_minTried_(0.0) + { + *this = r; + } + //================================================================================================ + // Empty destructor + RootFind::~RootFind() { + } + //==================================================================================================================== + RootFind & RootFind::operator=(const RootFind &right) { + if (this == &right) { + return *this; + } + m_residFunc = right.m_residFunc; + m_funcTargetValue = right.m_funcTargetValue; + m_atolf = right.m_atolf; + m_atolx = right.m_atolx; + m_rtolf = right.m_rtolf; + m_rtolx = right.m_rtolx; + m_maxstep = right.m_maxstep; + printLvl = right.printLvl; + writeLogAllowed_ = right.writeLogAllowed_; + DeltaXnorm_ = right.DeltaXnorm_; + specifiedDeltaXnorm_ = right.specifiedDeltaXnorm_; + DeltaXMax_ = right.DeltaXMax_; + specifiedDeltaXMax_ = right.specifiedDeltaXMax_; + FuncIsGenerallyIncreasing_ = right.FuncIsGenerallyIncreasing_; + FuncIsGenerallyDecreasing_ = right.FuncIsGenerallyDecreasing_; + deltaXConverged_ = right.deltaXConverged_; + x_maxTried_ = right.x_maxTried_; + fx_maxTried_ = right.fx_maxTried_; + x_minTried_ = right.x_minTried_; + fx_minTried_ = right.fx_minTried_; + + return *this; + } + //================================================================================================ + // Calculate a deltaX from an input value of x + /* + * This routine ensure that the deltaX will be greater or equal to DeltaXNorm_ + * or 1.0E-14 x + * + * @param x1 input value of x + */ + doublereal RootFind::delXNonzero(doublereal x1) const { + doublereal deltaX = 1.0E-14 * fabs(x1); + doublereal delmin = DeltaXnorm_ * 1.0E-14; + if (delmin > deltaX) { + return delmin; + } + return deltaX; + } + //================================================================================================ + // Calculate a deltaX from an input value of x + /* + * This routine ensure that the deltaX will be greater or equal to DeltaXNorm_ + * or 1.0E-14 x or deltaXConverged_. + * + * @param x1 input value of x + */ + doublereal RootFind::delXMeaningful(doublereal x1) const { + doublereal del = delXNonzero(x1); + if (deltaXConverged_ > del) { + return deltaXConverged_; + } + return del; + } + //================================================================================================ + // Calcuated a controlled, nonzero delta between two numbers + /* + * The delta is designed to be greater than or equal to delXNonzero(x) defined above + * with the same sign as the original delta. Therefore if you subtract it from either + * of the two original numbers, you get a different number. + * + * @param x1 first number + * @param x2 second number + */ + double RootFind::deltaXControlled(doublereal x2, doublereal x1) const { + doublereal sgnn = 1.0; + if (x1 > x2) { + sgnn = -1.0; + } + doublereal deltaX = x2 - x1; + doublereal x = fabs(x2) + fabs(x1); + doublereal deltaXm = delXNonzero(x); + if (fabs(deltaX) < deltaXm) { + deltaX = sgnn * deltaXm; + } + return deltaX; + } + //==================================================================================================================== + // Function to decide whether two real numbers are the same or not + /* + * A comparison is made between the two numbers to decide whether they + * are close to one another. This is defined as being within factor * delXMeaningful() of each other. + * + * @param x2 First number + * @param x1 second number + * @param factor Multiplicative factor for delta X. defaults to 1 + * + * @return Returns a boolean indicating whether the two numbers are the same or not. + */ + bool RootFind::theSame(doublereal x2, doublereal x1, doublereal factor) const { + doublereal x = fabs(x2) + fabs(x1); + doublereal deltaX = delXMeaningful(x); + doublereal deltaXSmall = factor * deltaX; + deltaXSmall = MAX(deltaXSmall , x * 1.0E-15); + if (fabs(x2 - x1) < deltaXSmall) { + return true; + } + return false; + } + //==================================================================================================================== + /* + * The following calculation is a line search method to find the root of a function + * + * + * xbest Returns the x that satisfies the function + * On input, xbest should contain the best estimate + * + * return: + * 0 Found function + */ + int RootFind::solve(doublereal xmin, doublereal xmax, int itmax, doublereal &funcTargetValue, doublereal *xbest) { + + /* + * We store the function target and then actually calculate a modified functional + * + * func = eval(x1) - m_funcTargetValue = 0 + * + * + */ + m_funcTargetValue = funcTargetValue; + + static int callNum = 0; + const char *stre = "RootFind ERROR: "; + const char *strw = "RootFind WARNING: "; + int converged = 0; + int bottomBump = 0; + int topBump = 0; +#ifdef DEBUG_MODE + char fileName[80]; + FILE *fp = 0; +#endif + int doFinalFuncCall = 0; + doublereal x1, x2, xnew, f1, f2, fnew, slope; + doublereal deltaX1 = 0.0, deltaX2 = 0.0, deltaXnew = 0.0; + + int posStraddle = 0; + int retn = ROOTFIND_FAILEDCONVERGENCE; + int foundPosF = 0; + int foundNegF = 0; + int foundStraddle = 0; + doublereal xPosF = 0.0; + doublereal fPosF = 1.0E300; + doublereal xNegF = 0.0; + doublereal fNegF = -1.0E300; + doublereal fnorm; /* A valid norm for the making the function value dimensionless */ + doublereal x0 = 0.0, f0 = 0.0, xDelMin; + doublereal sgn; + doublereal dtmp; + doublereal fnoise = 0.0; + rfHistory_.clear(); + rfTable rfT; + rfT.clear(); + rfT.reasoning = "First Point: "; + + callNum++; +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + sprintf(fileName, "RootFind_%d.log", callNum); + fp = fopen(fileName, "w"); + fprintf(fp, " Iter TP_its xval Func_val | Reasoning\n"); + fprintf(fp, "-----------------------------------------------------" + "-------------------------------\n"); + } +#else + if (printLvl >= 3) { + writelog("WARNING: RootFind: printlvl >= 3, but debug mode not turned on\n"); + } +#endif + if (xmax <= xmin) { + writelogf("%sxmin and xmax are bad: %g %g\n", stre, xmin, xmax); + funcTargetValue = func(*xbest); + return ROOTFIND_BADINPUT; + } + + /* + * If the maximum step size has not been specified, set it here to 1/5 of the + * domain range of x. + */ + if (!specifiedDeltaXMax_) { + DeltaXMax_ = 0.2 *(xmax - xmin); + } + + if (!specifiedDeltaXnorm_) { + DeltaXnorm_ = 0.2 * DeltaXMax_; + } else { + if (DeltaXnorm_ > DeltaXMax_ ) { + if (specifiedDeltaXnorm_) { + DeltaXMax_ = DeltaXnorm_; + } else { + DeltaXnorm_ = 0.5 * DeltaXMax_; + } + } + } + + /* + * Calculate an initial value of deltaXConverged_ + */ + deltaXConverged_ = m_rtolx * (*xbest) + m_atolx; + if (DeltaXnorm_ < deltaXConverged_ ) { + writelogf("%s DeltaXnorm_, %g, is too small compared to tols, increasing to %g\n", + stre, DeltaXnorm_, deltaXConverged_); + DeltaXnorm_ = deltaXConverged_; + } + + /* + * Find the first function value f1 = func(x1), by using the value entered into xbest. + * Process it + */ + x1 = *xbest; + if (x1 < xmin || x1 > xmax) { + x1 = (xmin + xmax) / 2.0; + rfT.reasoning += " x1 set middle between xmin and xmax because entrance is outside bounds."; + } else { + rfT.reasoning += " x1 set to entrance x."; + } + + x_maxTried_ = x1; + x_minTried_ = x1; + int its = 1; + f1 = func(x1); + +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + print_funcEval(fp, x1, f1, its); + fprintf(fp, "%-5d %-5d %-15.5E %-15.5E\n", -2, 0, x1, f1); + } +#endif + + + if (f1 == 0.0) { + *xbest = x1; + return 0; + } else if (f1 > fnoise) { + foundPosF = 1; + xPosF = x1; + fPosF = f1; + } else if (f1 < -fnoise) { + foundNegF = 1; + xNegF = x1; + fNegF = f1; + } + rfT.its = its; + rfT.TP_its = 0; + rfT.xval = x1; + rfT.fval = f1; + rfT.foundPos = foundPosF; + rfT.foundNeg = foundNegF; + rfT.deltaXConverged = m_rtolx * (fabs(x1) + 0.001); + rfT.deltaFConverged = fabs(f1) * m_rtolf; + rfT.delX = xmax - xmin; + rfHistory_.push_back(rfT); + rfT.clear(); + + /* + * Now, this is actually a tricky part of the algorithm - Find the x value for + * the second point. It's tricky because we don't have a valid idea of the scale of x yet + * + */ + rfT.reasoning = "Second Point: "; + if (x1 == 0.0) { + x2 = x1 + 0.01 * DeltaXnorm_; + rfT.reasoning += "Set by DeltaXnorm_"; + } else { + x2 = x1 * 1.0001; + rfT.reasoning += "Set slightly higher."; + } + if (x2 > xmax) { + x2 = x1 - 0.01 * DeltaXnorm_; + rfT.reasoning += " - But adjusted to be within bounds"; + } + + /* + * Find the second function value f2 = func(x2), Process it + */ + deltaX2 = x2 - x1; + its++; + f2 = func(x2); +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + print_funcEval(fp, x2, f2, its); + fprintf(fp, "%-5d %-5d %-15.5E %-15.5E", -1, 0, x2, f2); + } +#endif + + /* + * Calculate the norm of the function, this is the nominal value of f. We try + * to reduce the nominal value of f by rtolf, this is the main convergence requirement. + */ + if (m_funcTargetValue != 0.0) { + fnorm = m_atolf + fabs(m_funcTargetValue); + } else { + fnorm = 0.5*(fabs(f1) + fabs(f2)) + fabs(m_funcTargetValue) + m_atolf; + } + fnoise = 1.0E-100; + + + if (f2 > fnoise) { + if (!foundPosF) { + foundPosF = 1; + xPosF = x2; + fPosF = f2; + } + } else if (f2 < - fnoise) { + if (!foundNegF) { + foundNegF = 1; + xNegF = x2; + fNegF = f2; + } + } else if (f2 == 0.0) { + *xbest = x2; + return ROOTFIND_SUCCESS; + } + rfT.its = its; + rfT.TP_its = 0; + rfT.xval = x2; + rfT.fval = f2; + rfT.foundPos = foundPosF; + rfT.foundNeg = foundNegF; + + + /* + * See if we have already achieved a straddle + */ + foundStraddle = foundPosF && foundNegF; + if (foundStraddle) { + if (xPosF > xNegF) posStraddle = 1; + else posStraddle = 0; + } + + bool useNextStrat = false; + bool slopePointingToHigher = true; + // --------------------------------------------------------------------------------------------- + // MAIN LOOP + // --------------------------------------------------------------------------------------------- + do { + /* + * Find an estimate of the next point, xnew, to try based on + * a linear approximation from the last two points. + */ +#ifdef DEBUG_MODE + if (fabs(x2 - x1) < 1.0E-14) { + printf(" RootFind: we are here x2 = %g x1 = %g\n", x2, x1); + } +#endif + + doublereal delXtmp = deltaXControlled(x2, x1); + slope = (f2 - f1) / delXtmp; + rfT.slope = slope; + rfHistory_.push_back(rfT); + rfT.clear(); + rfT.reasoning = ""; + if (fabs(slope) <= 1.0E-100) { + if (printLvl >= 2) { + writelogf("%s functions evals produced the same result, %g, at %g and %g\n", + strw, f2, x1, x2); + } + xnew = x2 + DeltaXnorm_; + slopePointingToHigher = true; + useNextStrat = true; + rfT.reasoning += "Slope is close to zero. "; + } else { + useNextStrat = false; + xnew = x2 - f2 / slope; + if (xnew > x2) { + slopePointingToHigher = true; + } else { + slopePointingToHigher = false; + } + rfT.reasoning += "Slope is good. "; + } +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | xlin = %-11.5E", xnew); + } +#endif + deltaXnew = xnew - x2; + /* + * If the suggested step size is too big, throw out step + */ + if (!foundStraddle) { + if (fabs(xnew - x2) > DeltaXMax_) { + useNextStrat = true; + rfT.reasoning += "Too large change in xnew from slope. "; + } + if (fabs(deltaXnew) < fabs(deltaX2)) { + deltaXnew = 1.2 * deltaXnew; + xnew = x2 + deltaXnew; + } + } + /* + * If the slope can't be trusted using a different strategy for picking the next point + */ + if (useNextStrat) { + rfT.reasoning += "Using DeltaXnorm, " + fp2str(DeltaXnorm_) + " and FuncIsGenerallyIncreasing hints. "; + if (f2 < 0.0) { + if (FuncIsGenerallyIncreasing_) { + if (slopePointingToHigher) { + xnew = MIN(x2 + 3.0*DeltaXnorm_, xnew); + } else { + xnew = x2 + DeltaXnorm_; + } + } else if (FuncIsGenerallyDecreasing_) { + if ( !slopePointingToHigher) { + xnew = MAX(x2 - 3.0*DeltaXnorm_, xnew); + } else { + xnew = x2 - DeltaXnorm_; + } + } else { + if (slopePointingToHigher) { + xnew = x2 + DeltaXnorm_; + } else { + xnew = x2 - DeltaXnorm_; + } + } + } else { + if (FuncIsGenerallyDecreasing_) { + if (!slopePointingToHigher) { + xnew = MAX(x2 + 3.0*DeltaXnorm_, xnew); + } else { + xnew = x2 + DeltaXnorm_; + } + } else if (FuncIsGenerallyIncreasing_) { + if (! slopePointingToHigher) { + xnew = MIN(x2 - 3.0*DeltaXnorm_, xnew); + } else { + xnew = x2 - DeltaXnorm_; + } + } else { + if (slopePointingToHigher) { + xnew = x2 + DeltaXnorm_; + } else { + xnew = x2 - DeltaXnorm_; + } + } + } + } + + /* + * Here, if we have a straddle, we purposefully overshoot the smaller side by 5%. Yes it does lead to + * more iterations. However, we're interested in bounding x, and not just doing Newton's method. + */ + if (foundStraddle) { + double delta = fabs(x2 - x1); + if (fabs(xnew - x1) < .01 * delta) { + xnew = x1 + 0.01 * (x2 - x1); + } else if (fabs(xnew - x2) < .01 * delta) { + xnew = x1 + 0.01 * (x2 - x1); + } else if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) { + if (fabs(xnew - x1) < fabs(x2 - xnew)) { + xnew = x1 + 20./19. * (xnew - x1); + } else { + xnew = x2 + 20./19. * (xnew - x2); + } + } + } + /* + * OK, we have an estimate xnew. + * + * + * Put heuristic bounds on the step jump + */ + if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) { + /* + * If we are doing a jump in between the two previous points, make sure + * the new trial is no closer that 10% of the distances between x2-x1 to + * any of the original points. This is an important part of finding a good bound. + */ + xDelMin = fabs(x2 - x1) / 10.; + if (fabs(xnew - x1) < xDelMin) { + xnew = x1 + DSIGN(xnew-x1) * xDelMin; +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | x10%% = %-11.5E", xnew); + } +#endif + } + if (fabs(xnew - x2) < 0.1 * xDelMin) { + xnew = x2 + DSIGN(xnew-x2) * 0.1 * xDelMin; +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | x10%% = %-11.5E", xnew); + } +#endif + } + } else { + /* + * If we are venturing into new ground, only allow the step jump + * to increase by 50% at each interation, unless the step jump is less than + * the user has said that it is ok to take + */ + doublereal xDelMax = 1.5 * fabs(x2 - x1); + if (specifiedDeltaXnorm_) { + if (0.5 * DeltaXnorm_ > xDelMax) { + xDelMax = 0.5 *DeltaXnorm_ ; + } + } + if (fabs(xDelMax) < fabs(xnew - x2)) { + xnew = x2 + DSIGN(xnew-x2) * xDelMax; +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | xlimitsize = %-11.5E", xnew); + } +#endif + } + /* + * If we are doing a jump outside the two previous points, make sure + * the new trial is no closer that 10% of the distances between x2-x1 to + * any of the original points. This is an important part of finding a good bound. + */ + xDelMin = 0.1 * fabs(x2 - x1); + if (fabs(xnew - x2) < xDelMin) { + xnew = x2 + DSIGN(xnew - x2) * xDelMin; +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | x10%% = %-11.5E", xnew); + } +#endif + } + if (fabs(xnew - x1) < xDelMin) { + xnew = x1 + DSIGN(xnew - x1) * xDelMin; +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | x10%% = %-11.5E", xnew); + } +#endif + } + } + /* + * HKM -> Not sure this section is needed + */ + if (foundStraddle) { +#ifdef DEBUG_MODE + double xorig = 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_MODE + if (printLvl >= 3 && writeLogAllowed_) { + if (xorig != xnew) { + fprintf(fp, " | xstraddle = %-11.5E", xnew); + } + } +#endif + } + + /* + * Enforce a minimum stepsize if we haven't found a straddle. + */ + deltaXnew = xnew - x2; + if (fabs(deltaXnew) < 1.2 * delXMeaningful(xnew)) { + if (!foundStraddle) { + sgn = 1.0; + if (x2 > xnew) { + sgn = -1.0; + } + deltaXnew = 1.2 * delXMeaningful(xnew) * sgn; + rfT.reasoning += "Enforcing minimum stepsize from " + fp2str(xnew - x2) + + " to " + fp2str(deltaXnew); + xnew = x2 + deltaXnew; + } + } + + /* + * Guard against going above xmax or below xmin + */ + if (xnew > xmax) { + topBump++; + if (topBump < 3) { + xnew = x2 + (xmax - x2) / 2.0; + rfT.reasoning += ("xval reduced to " + fp2str(xnew) + " because predicted xnew was above max value of " + fp2str(xmax)); + } else { + if (x2 == xmax || x1 == xmax) { + // we are here when we are bumping against the top limit. + // No further action is possible + retn = ROOTFIND_SOLNHIGHERTHANXMAX; + *xbest = xnew; + rfT.slope = slope; + rfT.reasoning += "Giving up because we're at xmax and xnew point higher: " + fp2str(xnew); + goto done; + } else { + rfT.reasoning += "xval reduced from " + fp2str(xnew) + " to the max value, " + fp2str(xmax); + xnew = xmax; + } + } +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | xlimitmax = %-11.5E", xnew); + } +#endif + } + if (xnew < xmin) { + bottomBump++; + if (bottomBump < 3) { + rfT.reasoning += ("xnew increased from " + fp2str(xnew) +" to " + fp2str(x2 - (x2 - xmin) / 2.0) + + " because above min value of " + fp2str(xmin)); + xnew = x2 - (x2 - xmin) / 2.0; + } else { + if (x2 == xmin || x1 == xmin) { + // we are here when we are bumping against the bottom limit. + // No further action is possible + retn = ROOTFIND_SOLNLOWERTHANXMIN; + *xbest = xnew; + rfT.slope = slope; + rfT.reasoning = "Giving up because we're already at xmin and xnew points lower: " + fp2str(xnew); + goto done; + } else { + rfT.reasoning += "xval increased from " + fp2str(xnew) + " to the min value, " + fp2str(xmin); + xnew = xmin; + } + } +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | xlimitmin = %-11.5E", xnew); + } +#endif + } + + its++; + fnew = func(xnew); + +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp,"\n"); + print_funcEval(fp, xnew, fnew, its); + fprintf(fp, "%-5d %-5d %-15.5E %-15.5E", its, 0, xnew, fnew); + } +#endif + rfT.xval = xnew; + rfT.fval = fnew; + rfT.its = its; + if (foundStraddle) { + if (posStraddle) { + if (fnew > 0.0) { + if (xnew < xPosF) { + xPosF = xnew; + fPosF = fnew; + } + } else { + if (xnew > xNegF) { + xNegF = xnew; + fNegF = fnew; + } + } + } else { + if (fnew > 0.0) { + if (xnew > xPosF) { + xPosF = xnew; + fPosF = fnew; + } + } else { + if (xnew < xNegF) { + xNegF = xnew; + fNegF = fnew; + } + } + } + } + + if (! foundStraddle) { + if (fnew > fnoise) { + if (!foundPosF) { + foundPosF = 1; + rfT.foundPos = 1; + xPosF = xnew; + fPosF = fnew; + foundStraddle = 1; + if (xPosF > xNegF) posStraddle = 1; + else posStraddle = 0; + } + } else if (fnew < - fnoise) { + if (!foundNegF) { + foundNegF = 1; + rfT.foundNeg = 1; + xNegF = xnew; + fNegF = fnew; + foundStraddle = 1; + if (xPosF > xNegF) posStraddle = 1; + else posStraddle = 0; + } + } + } + + x0 = x1; + f0 = f1; + x1 = x2; + f1 = f2; + + x2 = xnew; + f2 = fnew; + + /* + * As we go on to new data points, we make sure that + * we have the best straddle of the solution with the choice of F1 and F2 when + * we do have a straddle to work with. + */ + if (foundStraddle) { + bool foundBetterPos = false; + bool foundBetterNeg = false; + if (posStraddle) { + if (f2 > 0.0) { + if (xPosF < x2) { + foundBetterPos = false; + x2 = xPosF; + f2 = fPosF; + } + if (f1 > 0.0) { + if (foundBetterPos) { + x1 = xNegF; + f1 = fNegF; + } else { + if (x1 >= x2) { + x1 = xNegF; + f1 = fNegF; + } + } + } + } else { + if (xNegF > x2) { + foundBetterNeg = false; + x2 = xNegF; + f2 = fNegF; + } + if (f1 < 0.0) { + if (foundBetterNeg) { + x1 = xPosF; + f1 = fPosF; + } else { + if (x1 <= x2) { + x1 = xPosF; + f1 = fPosF; + } + } + } + } + } else { + if (f2 < 0.0) { + if (xNegF < x2) { + foundBetterNeg = false; + x2 = xNegF; + f2 = fNegF; + } + if (f1 < 0.0) { + if (foundBetterNeg) { + x1 = xPosF; + f1 = fPosF; + } else { + if (x1 >= x2) { + x1 = xPosF; + f1 = fPosF; + } + } + } + } else { + if (xPosF > x2) { + foundBetterPos = true; + x2 = xPosF; + f2 = fPosF; + } + if (f1 > 0.0) { + if (foundBetterNeg) { + x1 = xNegF; + f1 = fNegF; + } else { + if (x1 <= x2) { + x1 = xNegF; + f1 = fNegF; + } + } + } + } + } + AssertThrow((f1 * f2 <= 0.0), "F1 and F2 aren't bounding"); + } + + deltaX1 = deltaX2; + deltaX2 = deltaXnew; + deltaXnew = x2 - x1; + deltaXConverged_ = 0.5 * deltaXConverged_ + 0.5 * (m_rtolx * 0.5 * (fabs(x2) + fabs(x1)) + m_atolx); + rfT.deltaXConverged = deltaXConverged_; + rfT.deltaFConverged = fnorm * m_rtolf; + if (foundStraddle) { + rfT.delX = MAX(fabs(deltaX2), fabs(deltaXnew)); + } else { + rfT.delX = MAX(fabs(deltaX2), fabs(deltaXnew)); + if (x2 < x1) { + rfT.delX = MAX(rfT.delX, x2 - xmin); + } else { + rfT.delX = MAX(rfT.delX, xmax - x2); + } + } + /* + * Section To Determine CONVERGENCE criteria + */ + doFinalFuncCall = 0; + if ((fabs(fnew / fnorm) < m_rtolf) && foundStraddle) { + if (fabs(deltaX2) < deltaXConverged_ && fabs(deltaXnew) < deltaXConverged_) { + converged = 1; + rfT.reasoning += "NormalConvergence"; + retn = ROOTFIND_SUCCESS; + } + + else if (fabs(slope) > 1.0E-100) { + double xdels = fabs(fnew / slope); + if (xdels < deltaXConverged_ * 0.3) { + converged = 1; + rfT.reasoning += "NormalConvergence-SlopelimitsDelX"; + doFinalFuncCall = 1; + retn = ROOTFIND_SUCCESS; + } + } + + + /* + * Check for excess convergence in the x coordinate + */ + if (!converged) { + if (foundStraddle) { + doublereal denom = fabs(x1 - x2); + if (denom < 1.0E-200) { + retn = ROOTFIND_FAILEDCONVERGENCE; + converged = true; + rfT.reasoning += "ConvergenceFZero but X1X2Identical"; + } + if (theSame(x2, x1, 1.0E-2)) { + converged = true; + rfT.reasoning += " ConvergenceF and XSame"; + retn = ROOTFIND_SUCCESS; + } + } + } + } else { + /* + * We are here when F is not converged, but we may want to end anyway + */ + if (!converged) { + if (foundStraddle) { + doublereal denom = fabs(x1 - x2); + if (denom < 1.0E-200) { + retn = ROOTFIND_FAILEDCONVERGENCE; + converged = true; + rfT.reasoning += "FNotConverged but X1X2Identical"; + } + /* + * The premise here is that if x1 and x2 get close to one another, + * then the accuracy of the calculation gets destroyed. + */ + if (theSame(x2, x1, 1.0E-5)) { + converged = true; + retn = ROOTFIND_SUCCESS_XCONVERGENCEONLY; + rfT.reasoning += "FNotConverged but XSame"; + } + } + } + } + } while (! converged && its < itmax); + + done: + if (converged) { + rfT.slope = slope; + rfHistory_.push_back(rfT); + rfT.clear(); + rfT.its = its; + AssertThrow((f1 * f2 <= 0.0), "F1 and F2 aren't bounding"); + + double x_fpos = x2; + double x_fneg = x1; + if (f2 < 0.0) { + x_fpos = x1; + x_fneg = x2; + } + rfT.delX = fabs(x_fpos - x_fneg); + if (doFinalFuncCall || (fabs(f1) < 2.0 * fabs(f2))) { + double delXtmp = deltaXControlled(x2, x1); + slope = (f2 - f1) / delXtmp; + xnew = x2 - f2 / slope; + its++; + fnew = func(xnew); + if (fnew > 0.0) { + if (fabs(xnew - x_fneg) < fabs(x_fpos - x_fneg)) { + x_fpos = xnew; + rfT.delX = fabs(xnew - x_fneg); + } + } else { + if (fabs(xnew - x_fpos) < fabs(x_fpos - x_fneg)) { + x_fneg = xnew; + rfT.delX = fabs(xnew - x_fpos); + } + } + rfT.its = its; + if (fabs(fnew) < fabs(f2) && (fabs(fnew) < fabs(f1))) { + *xbest = xnew; + if (doFinalFuncCall) { + rfT.reasoning += "CONVERGENCE: Another Evaluation Requested"; + rfT.delX = fabs(xnew - x2); + } else { + rfT.reasoning += "CONVERGENCE: Another Evaluation done because f1 < f2"; + rfT.delX = fabs(xnew - x1); + } + rfT.fval = fnew; + rfT.xval = xnew; + x2 = xnew; + f2 = fnew; + } else if (fabs(f1) < fabs(f2)) { + rfT.its = its; + rfT.xval = xnew; + rfT.fval = fnew; + + rfT.slope = slope; + rfT.reasoning += "CONVERGENCE: Another Evaluation not as good as Second Point "; + rfHistory_.push_back(rfT); + rfT.clear(); + rfT.its = its; + SWAP(f1, f2, dtmp); + SWAP(x1, x2, dtmp); + *xbest = x2; + if (fabs(fnew) < fabs(f1)) { + if (f1 * fnew > 0.0) { + SWAP(f1, fnew, dtmp); + SWAP(x1, xnew, dtmp); + } + } + + rfT.its = its; + rfT.xval = *xbest; + rfT.fval = f2; + rfT.delX = fabs(x_fpos - x_fneg); + rfT.reasoning += "CONVERGENCE: NormalEnding -> Second point used"; + } else { + rfT.its = its; + rfT.xval = xnew; + rfT.fval = fnew; + + rfT.slope = slope; + rfT.reasoning += "CONVERGENCE: Another Evaluation not as good as First Point "; + rfHistory_.push_back(rfT); + rfT.clear(); + rfT.its = its; + *xbest = x2; + rfT.xval = *xbest; + rfT.fval = f2; + rfT.delX = fabs(x_fpos - x_fneg); + rfT.reasoning += "CONVERGENCE: NormalEnding -> Last point used"; + } + } else { + + *xbest = x2; + + rfT.xval = *xbest; + rfT.fval = f2; + rfT.delX = fabs(x2 - x1); + rfT.reasoning += "CONVERGENCE: NormalEnding -> Last point used"; + } + funcTargetValue = f2 + m_funcTargetValue; + rfT.slope = slope; + + if (printLvl >= 1) { + writelogf("RootFind success: convergence achieved\n"); + } +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, " | RootFind success in %d its, fnorm = %g\n", its, fnorm); + } +#endif + rfHistory_.push_back(rfT); + } else { + rfT.reasoning = "FAILED CONVERGENCE "; + rfT.slope = slope; + rfT.its = its; + if (retn == ROOTFIND_SOLNHIGHERTHANXMAX) { + if (printLvl >= 1) { + writelogf("RootFind ERROR: Soln probably lies higher than xmax, %g: best guess = %g\n", xmax, *xbest); + } + rfT.reasoning += "Soln probably lies higher than xmax, " + fp2str(xmax) + ": best guess = " + fp2str(*xbest); + } else if (retn == ROOTFIND_SOLNLOWERTHANXMIN) { + if (printLvl >= 1) { + writelogf("RootFind ERROR: Soln probably lies lower than xmin, %g: best guess = %g\n", xmin, *xbest); + } + rfT.reasoning += "Soln probably lies lower than xmin, " + fp2str(xmin) + ": best guess = " + fp2str(*xbest); + } else { + retn = ROOTFIND_FAILEDCONVERGENCE; + if (printLvl >= 1) { + writelogf("RootFind ERROR: maximum iterations exceeded without convergence, cause unknown\n"); + } + rfT.reasoning += "Maximum iterations exceeded without convergence, cause unknown"; + } +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fprintf(fp, "\nRootFind failure in %d its\n", its); + } +#endif + + *xbest = x2; + funcTargetValue = f2 + m_funcTargetValue; + rfT.xval = *xbest; + rfT.fval = f2; + rfHistory_.push_back(rfT); + } +#ifdef DEBUG_MODE + if (printLvl >= 3 && writeLogAllowed_) { + fclose(fp); + } +#endif + + if (printLvl >= 2) { + printTable(); + } + + return retn; + } + //==================================================================================================================== + doublereal RootFind::func(doublereal x) { + doublereal r; +#ifdef DEBUG_MODE + mdp::checkFinite(x); +#endif + m_residFunc->evalSS(0.0, &x, &r); +#ifdef DEBUG_MODE + mdp::checkFinite(r); +#endif + doublereal ff = r - m_funcTargetValue; + if (x >= x_maxTried_) { + x_maxTried_ = x; + fx_maxTried_ = ff; + } + if (x <= x_minTried_) { + x_minTried_ = x; + fx_minTried_ = ff; + } + return ff; + } + //==================================================================================================================== + // Set the tolerance parameters for the rootfinder + /* + * These tolerance parameters are used on the function value to determine convergence + * + * + * @param rtol Relative tolerance. The default is 10^-5 + * @param atol absolute tolerance. The default is 10^-11 + */ + void RootFind::setTol(doublereal rtolf, doublereal atolf, doublereal rtolx, doublereal atolx) + { + m_atolf = atolf; + m_rtolf = rtolf; + if (rtolx <= 0.0) { + m_rtolx = atolf; + } else { + m_rtolx = rtolx; + } + if (atolx <= 0.0) { + m_atolx = atolf; + } else { + m_atolx = atolx; + } + } + //==================================================================================================================== + // Set the print level from the rootfinder + /* + * + * 0 -> absolutely nothing is printed for a single time step. + * 1 -> One line summary per solve_nonlinear call + * 2 -> short description, points of interest: Table of nonlinear solve - one line per iteration + * 3 -> Table is included -> More printing per nonlinear iteration (default) that occurs during the table + * 4 -> Summaries of the nonlinear solve iteration as they are occurring -> table no longer printed + * 5 -> Algorithm information on the nonlinear iterates are printed out + * 6 -> Additional info on the nonlinear iterates are printed out + * 7 -> Additional info on the linear solve is printed out. + * 8 -> Info on a per iterate of the linear solve is printed out. + * + * @param printLvl integer value + */ + void RootFind::setPrintLvl(int printlvl) + { + printLvl = printlvl; + } + //==================================================================================================================== + // Set the function behavior flag + /* + * If this is true, the function is generally an increasing function of x. + * In particular, if the algorithm is seeking a higher value of f, it will look + * in the positive x direction. + * + * This type of function is needed because this algorithm must deal with regions of f(x) where + * f is not changing with x. + * + * @param value boolean value + */ + void RootFind::setFuncIsGenerallyIncreasing(bool value) + { + if (value) { + FuncIsGenerallyDecreasing_ = false; + } + FuncIsGenerallyIncreasing_ = value; + } + //==================================================================================================================== + // Set the function behavior flag + /* + * If this is true, the function is generally a decreasing function of x. + * In particular, if the algorithm is seeking a higher value of f, it will look + * in the negative x direction. + * + * This type of function is needed because this algorithm must deal with regions of f(x) where + * f is not changing with x. + * + * @param value boolean value + */ + void RootFind::setFuncIsGenerallyDecreasing(bool value) + { + if (value) { + FuncIsGenerallyIncreasing_ = false; + } + FuncIsGenerallyDecreasing_ = value; + } + //==================================================================================================================== + // Set the nominal value of deltaX + /* + * This sets the value of deltaXNorm_ + * + * @param deltaXNorm + */ + void RootFind::setDeltaX(doublereal deltaXNorm) + { + DeltaXnorm_ = deltaXNorm; + specifiedDeltaXnorm_ = 1; + } + //==================================================================================================================== + // Set the maximum value of deltaX + /* + * This sets the value of deltaXMax_ + * + * @param deltaX + */ + void RootFind::setDeltaXMax(doublereal deltaX) + { + DeltaXMax_ = deltaX; + specifiedDeltaXMax_ = 1; + } + //==================================================================================================================== + + //==================================================================================================================== + void RootFind::printTable() { + printf("\t----------------------------------------------------------------------------------------------------------------------------------------\n"); + printf("\t RootFinder Summary table: \n"); + printf("\t FTarget = %g\n", m_funcTargetValue); + printf("\t Iter | xval delX deltaXConv | slope | foundP foundN| F - F_targ deltaFConv | Reasoning\n"); + printf("\t----------------------------------------------------------------------------------------------------------------------------------------\n"); + for (int i = 0; i < (int) rfHistory_.size(); i++) { + struct rfTable rfT = rfHistory_[i]; + printf("\t %3d |%- 17.11E %- 13.7E %- 13.7E |%- 13.5E| %3d %3d | %- 12.5E %- 12.5E | %s \n", + rfT.its, rfT.xval, rfT.delX, rfT.deltaXConverged, rfT.slope, rfT.foundPos, rfT.foundNeg, rfT.fval, + rfT.deltaFConverged, (rfT.reasoning).c_str()); + } + printf("\t----------------------------------------------------------------------------------------------------------------------------------------\n"); + } + //==================================================================================================================== + +} diff --git a/Cantera/src/numerics/RootFind.h b/Cantera/src/numerics/RootFind.h new file mode 100644 index 000000000..016827660 --- /dev/null +++ b/Cantera/src/numerics/RootFind.h @@ -0,0 +1,469 @@ +/** + * @file RootFind.h + * Header file for implicit nonlinear solver of a one dimensional function + * (see \ref numerics and class \link Cantera::RootFind RootFind\endlink). + */ +/* + * $Id$ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#ifndef CT_ROOTFIND_H +#define CT_ROOTFIND_H +/** + * @defgroup solverGroup Solvers for Equation Systems + */ + +#include +#include "ResidEval.h" + +namespace Cantera { + + //@{ + /// @name Constant which determines the return integer from the routine + + //! This means that the root solver was a success +#define ROOTFIND_SUCCESS 0 + //! This return value means that the root finder resolved a solution in the x coordinate + //! However, convergence in F was not achieved. + /*! + * A common situation for this to happen is that f(x) is discontinuous about f(x) = f_0, + * where we seek the x where the function is equal to f_0. f(x) spans the + * f_0 while not being equal to f_0 anywhere. + */ +#define ROOTFIND_SUCCESS_XCONVERGENCEONLY 1 + //! This means that the root solver failed to achieve convergence +#define ROOTFIND_FAILEDCONVERGENCE -1 + //! This means that the input to the root solver was defective +#define ROOTFIND_BADINPUT -2 + //! This means that the rootfinder believes the solution is lower than xmin +#define ROOTFIND_SOLNLOWERTHANXMIN -3 + //! This means that the rootfinder believes the solution is higher than xmax + /*! + * + */ +#define ROOTFIND_SOLNHIGHERTHANXMAX -4 + //@} + + + + + //! Root finder for 1D problems + /*! + * + * The root finder solves a single nonlinear equation described below. + * + * \f[ + * f(x) = f_0 + * \f] + * + * \f$ f(x) \f$ is assumed to be single valued as a function of x.\f$ f(x) \f$ is not assumed to be continuous nor is + * its derivative assumed to be well formed. + * + * Root finders are significantly different in the sense that do not have to rely + * solely on Newton's method to find the answer to the problem. Instead they use a method to bound + * the solution between high and low values and then use a method to refine that bound. The eventual + * solution to the problem is presented as x_best and as a bound, delta_X, on the solution + * component. Because of this, they are far more stable for functions and Jacobians that have discontinuities + * or noise associated with them. + * + * The algorithm is a convolution of a local Secant method with an approach of finding a straddle in x. + * The Jacobian is never required. + * + * There is a general breakdown of the algorithm into stages. The first stage seeks to find a straddle of the + * function. The second stage seeks to reduce the bounds in x and f in order to satisfy the specification of the + * stopping criteria. In the last stage the algorithm seeks to find the base value of x that satisfies the + * original equation given what it current knows about the function. + * + * Globalization strategy + * + * Specifying the General Changes in x + * + * Supplying Hints with General Function Behavior Flags + * + * + * + * Stopping Criteria + * + * Specification of the Stopping Criteria + * + * + * Additional constraints + * + * Bounds Criteria For the Routine + * + * Example + * + * @code + * // Define a residual. The definition of a residual involves a lot more work than is shown here. + * ResidEval * ec; + * // Instantiate the root finder with the residual to be solved, ec. + * RootFind rf(&ec); + * // Set the relative and absolute tolerancess for f and x. + * rf.setTol(1.0E-5, 1.0E-10, 1.0E-5, 1.0E-11); + * // Give a hint about the function's dependence on x. This is needed, for example, if the function has + * // flat regions. + * rf.setFuncIsGenerallyIncreasing(true); + * rf.setDeltaX(0.01); + * // Supply an initial guess for the solution + * double xbest = phiM; + * double oldP = printLvl_; + * // Set the print level for the solver. Zero produces no output. Two produces a summary table of each iteration. + * rf.setPrintLvl(2); + * // Define a minimum and maximum for the independent variable. + * double phimin = 1.3; + * double phimax = 2.2; + * // Define a maximum iteration number + * int itmax = 100; + * // Define the f_0 value, and on return will contain the actual value of f(x) obtained + * double currentObtained; + * // Call the solver + * status = rf.solve(phimin, phimax, 100, currentObtained, &xbest); + * if (status == 0) { + * if (printLvl_ > 1) { + * printf("Electrode::integrateConstantCurrent(): Volts (%g amps) = %g\n", currentObtained, xbest); + * } + * } else { + * if (printLvl_) { + * printf("Electrode::integrateConstantCurrent(): bad status = %d Volts (%g amps) = %g\n", + * status, currentObtained, xbest); + * } + * } + * @endcode + * + * @todo Noise + * @todo General Search to be done when all else fails + * + */ + class RootFind { + + public: + + //! Constructor for the object + /*! + * + * @param resid Pointer to the residual function to be used to calculate f(x) + */ + RootFind(ResidEval* resid); + + //! Copy constructor + /*! + * @param r object to be copied + */ + RootFind(const RootFind &r); + + //! Destructor. Deletes the integrator. + ~RootFind(); + + //! Assignment operator + /*! + * @param right object to be copied + * + * @return returns a reference to the current object + */ + RootFind & operator=(const RootFind &right); + + + private: + //! Calculate a deltaX from an input value of x + /*! + * This routine ensure that the deltaX will be greater or equal to DeltaXNorm_ + * or 1.0E-14 x + * + * @param x1 input value of x + */ + doublereal delXNonzero(doublereal x1) const; + + //! Calculate a deltaX from an input value of x + /*! + * This routine ensure that the deltaX will be greater or equal to DeltaXNorm_ + * or 1.0E-14 x or deltaXConverged_. + * + * @param x1 input value of x + */ + doublereal delXMeaningful(doublereal x1) const; + + //! Calcuated a controlled, nonzero delta between two numbers + /*! + * The delta is designed to be greater than or equal to delXMeaningful(x) defined above + * with the same sign as the original delta. Therefore if you subtract it from either + * of the two original numbers, you get a different number. + * + * @param x2 first number + * @param x1 second number + */ + doublereal deltaXControlled(doublereal x2, doublereal x1) const; + + //! Function to decide whether two real numbers are the same or not + /*! + * A comparison is made between the two numbers to decide whether they + * are close to one another. This is defined as being within factor * delXMeaningful() of each other. + * + * The basic premise here is that if the two numbers are too close, the noise + * will prevent an accurate calculation of the function and its slope. + * + * @param x1 First number + * @param x2 second number + * @param factor Multiplicative factor to multiple deltaX with + * + * @return Returns a boolean indicating whether the two numbers are the same or not. + */ + bool theSame(doublereal x2, doublereal x1, doublereal factor = 1.0) const; + + public: + + //! Using a line search method, find the root of a 1D function + /*! + * This routine solves the following equation. + * + * \f[ + * R(x) = f(x) - f_o = 0 + * \f] + * + * @param xmin Minimum value of x to be used. + * @param xmax Maximum value of x to be used + * @param itmax maximum number of iterations. Usually, it can be less than 50. + * @param funcTargetValue + * Value of \f$ f_o \f$ in the equation. + * On return, it contains the value of the function actually obtained. + * @param xbest Returns the x that satisfies the function + * On input, xbest should contain the best estimate of the solution. + * An attempt to find the solution near xbest is made. + * + * @return: + * 0 = ROOTFIND_SUCCESS Found function + * -1 = ROOTFIND_FAILEDCONVERGENCE Failed to find the answer + * -2 = ROOTFIND_BADINPUT Bad input was detected + */ + int solve(doublereal xmin, doublereal xmax, int itmax, doublereal &funcTargetValue, doublereal *xbest); + + //! Return the function value + /*! + * This routine evaluates the following equation. + * + * \f[ + * R(x) = f(x) - f_o = 0 + * \f] + * + * @param x Value of the independent variable + * + * @return The routine returns the value of \f$ R(x) \f$ + */ + doublereal func(doublereal x); + + //! Set the tolerance parameters for the rootfinder + /*! + * These tolerance parameters are used on the function value and the independent value + * to determine convergence + * + * @param rtolf Relative tolerance. The default is 10^-5 + * @param atolf absolute tolerance. The default is 10^-11 + * @param rtolx Relative tolerance. The default is 10^-5 + * Default parameter is 0.0, in which case rtolx is set equal to rtolf + * @param atolx absolute tolerance. The default is 10^-11 + * Default parameter is 0.0, in which case atolx is set equal to atolf + */ + void setTol(doublereal rtolf, doublereal atolf, doublereal rtolx = 0.0, doublereal atolx = 0.0); + + //! Set the print level from the rootfinder + /*! + * + * 0 -> absolutely nothing is printed for a single time step. + * 1 -> One line summary per solve_nonlinear call + * 2 -> short description, points of interest: Table of nonlinear solve - one line per iteration + * 3 -> Table is included -> More printing per nonlinear iteration (default) that occurs during the table + * 4 -> Summaries of the nonlinear solve iteration as they are occurring -> table no longer printed + * 5 -> Algorithm information on the nonlinear iterates are printed out + * 6 -> Additional info on the nonlinear iterates are printed out + * 7 -> Additional info on the linear solve is printed out. + * 8 -> Info on a per iterate of the linear solve is printed out. + * + * @param printLvl integer value + */ + void setPrintLvl(int printLvl); + + //! Set the function behavior flag + /*! + * If this is true, the function is generally an increasing function of x. + * In particular, if the algorithm is seeking a higher value of f, it will look + * in the positive x direction. + * + * This type of function is needed because this algorithm must deal with regions of f(x) where + * f is not changing with x. + * + * @param value boolean value + */ + void setFuncIsGenerallyIncreasing(bool value); + + //! Set the function behavior flag + /*! + * If this is true, the function is generally a decreasing function of x. + * In particular, if the algorithm is seeking a higher value of f, it will look + * in the negative x direction. + * + * This type of function is needed because this algorithm must deal with regions of f(x) where + * f is not changing with x. + * + * @param value boolean value + */ + void setFuncIsGenerallyDecreasing(bool value); + + //! Set the minimum value of deltaX + /*! + * This sets the value of deltaXNorm_ + * + * @param deltaXNorm + */ + void setDeltaX(doublereal deltaXNorm); + + //! Set the maximum value of deltaX + /*! + * This sets the value of deltaXMax_ + * + * @param deltaX + */ + void setDeltaXMax(doublereal deltaX); + + //! Print the iteration history table + void printTable(); + + public: + + //! Pointer to the residual function evaluator + ResidEval *m_residFunc; + + //! Target value for the function. We seek the value of f that is equal to this value + doublereal m_funcTargetValue; + + //! Absolute tolerance for the value of f + doublereal m_atolf; + + //! Absolute tolerance for the value of x + doublereal m_atolx; + + //! Relative tolerance for the value of f and x + doublereal m_rtolf; + + //! Relative tolerance for the value of x + doublereal m_rtolx; + + //! Maximum number of step sizes + doublereal m_maxstep; + + protected: + + //! Print level + /*! + * 0 No printing of any kind + * 1 Single print line indicating success or failure of the routine. + * 2 Summary table printed at the end of the routine, with a convergence history + * 3 Printouts during the iteration are added. Summary table is printed out at the end. + * if writeLogAllowed_ is turned on, a file is written out with the convergence history. + */ + int printLvl; + + public: + + //! Boolean to turn on the possibility of writing a log file. + bool writeLogAllowed_; + + protected: + //! Delta X norm. This is the nominal value of deltaX that will be used by the program + doublereal DeltaXnorm_; + + //! Boolean indicating whether DeltaXnorm_ has been specified by the user or not + int specifiedDeltaXnorm_; + + //! Delta X Max. This is the maximum value of deltaX that will be used by the program + /*! + * Sometimes a large change in x causes problems. + */ + doublereal DeltaXMax_; + + //! Boolean indicating whether DeltaXMax_ has been specified by the user or not + int specifiedDeltaXMax_; + + //! Boolean indicating whether the function is an increasing with x + bool FuncIsGenerallyIncreasing_; + + //! Boolean indicating whether the function is decreasing with x + bool FuncIsGenerallyDecreasing_; + + //! Value of delta X that is needed for convergence + /*! + * X will be considered as converged if we are within deltaXConverged_ of the solution + * The default is zero. + */ + doublereal deltaXConverged_; + + //! Internal variable tracking largest x tried. + doublereal x_maxTried_; + + //! Internal variable tracking f(x) of largest x tried. + doublereal fx_maxTried_; + + //! Internal variable tracking smallest x tried. + doublereal x_minTried_; + + //! Internal variable tracking f(x) of smallest x tried. + doublereal fx_minTried_; + + + //! Structure containing the iteration history + struct rfTable { + //@{ + int its; + int TP_its; + double slope; + double xval; + double fval; + int foundPos; + int foundNeg; + double deltaXConverged; + double deltaFConverged; + double delX; + + + std::string reasoning; + + void clear() { + its = 0; + TP_its = 0; + slope = -1.0E300; + xval = -1.0E300; + fval = -1.0E300; + reasoning = ""; + }; + + rfTable() : + its(-2), + TP_its(0), + slope(-1.0E300), + xval(-1.0E300), + fval(-1.0E300), + foundPos(0), + foundNeg(0), + deltaXConverged(-1.0E300), + deltaFConverged(-1.0E300), + delX(-1.0E300), + reasoning("") + { + }; + + + //@} + }; + + //! Vector of iteration histories + std::vector rfHistory_; + + + + }; +} +#endif diff --git a/Cantera/src/numerics/SquareMatrix.cpp b/Cantera/src/numerics/SquareMatrix.cpp index 8b34c083f..29e16bef0 100644 --- a/Cantera/src/numerics/SquareMatrix.cpp +++ b/Cantera/src/numerics/SquareMatrix.cpp @@ -17,6 +17,7 @@ #include "stringUtils.h" #include "ctlapack.h" #include "SquareMatrix.h" +#include "global.h" #include #include @@ -26,37 +27,84 @@ using namespace std; namespace Cantera { - /** + + + //==================================================================================================================== + SquareMatrix::SquareMatrix() : + DenseMatrix(), + GeneralMatrix(0), + m_factored(0), + a1norm_(0.0), + useQR_(0) + { + } + + //==================================================================================================================== + // Constructor. + /* + * Create an \c n by \c n matrix, and initialize + * all elements to \c v. + * + * @param n size of the square matrix + * @param v intial value of all matrix components. + */ + SquareMatrix::SquareMatrix(int n, doublereal v) : + DenseMatrix(n, n, v), + GeneralMatrix(0), + m_factored(0), + a1norm_(0.0), + useQR_(0) + + { + } + //==================================================================================================================== + /* * * copy constructor */ SquareMatrix::SquareMatrix(const SquareMatrix& y) : - DenseMatrix(y), - m_factored(y.m_factored) + DenseMatrix(y), + GeneralMatrix(0), + m_factored(y.m_factored), + a1norm_(y.a1norm_), + useQR_(y.useQR_) { } - /** + //==================================================================================================================== + /* * Assignment operator */ SquareMatrix& SquareMatrix::operator=(const SquareMatrix& y) { if (&y == this) return *this; DenseMatrix::operator=(y); - m_factored = y.m_factored; + GeneralMatrix::operator=(y); + m_factored = y.m_factored; + a1norm_ = y.a1norm_; + useQR_ = y.useQR_; return *this; } - - /** + //==================================================================================================================== + SquareMatrix::~SquareMatrix() { + } + //==================================================================================================================== + /* * Solve Ax = b. Vector b is overwritten on exit with x. */ - int SquareMatrix::solve(double* b) + int SquareMatrix::solve(doublereal * b) { + if (useQR_) { + return solveQR(b); + } int info=0; /* * Check to see whether the matrix has been factored. */ if (!m_factored) { - factor(); + int retn = factor(); + if (retn) { + return retn; + } } /* * Solve the factored system @@ -64,13 +112,18 @@ namespace Cantera { ct_dgetrs(ctlapack::NoTranspose, static_cast(nRows()), 1, &(*(begin())), static_cast(nRows()), DATA_PTR(ipiv()), b, static_cast(nColumns()), info); - if (info != 0) - throw CanteraError("SquareMatrix::solve", - "DGETRS returned INFO = "+int2str(info)); - return 0; + if (info != 0) { + if (m_printLevel) { + writelogf("SquareMatrix::solve(): DGETRS returned INFO = %d\n", info); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::solve()", "DGETRS returned INFO = " + int2str(info)); + } + } + return info; } - - /** + //==================================================================================================================== + /* * Set all entries to zero */ void SquareMatrix::zero() { @@ -85,34 +138,316 @@ namespace Cantera { (void) memset((void *) sm, 0, nn * sizeof(double)); } } - - /** + //==================================================================================================================== + void SquareMatrix::resize(int n, int m, doublereal v) { + DenseMatrix::resize(n, m, v); + } + + //==================================================================================================================== + // Multiply A*b and write result to prod. + /* + * @param b Vector to do the rh multiplcation + * @param prod OUTPUT vector to receive the result + */ + void SquareMatrix::mult(const doublereal * const b, doublereal * const prod) const { + DenseMatrix::mult(b, prod); + } + //==================================================================================================================== + // Multiply b*A and write result to prod. + /* + * @param b Vector to do the lh multiplcation + * @param prod OUTPUT vector to receive the result + */ + void SquareMatrix::leftMult(const doublereal * const b, doublereal * const prod) const { + DenseMatrix::leftMult(b, prod); + } + //==================================================================================================================== + /* * Factor A. A is overwritten with the LU decomposition of A. */ int SquareMatrix::factor() { + if (useQR_) { + return factorQR(); + } + a1norm_ = ct_dlange('1', m_nrows, m_nrows, &(*(begin())), m_nrows, DATA_PTR(work)); integer n = static_cast(nRows()); int info=0; - m_factored = true; - ct_dgetrf(n, n, &(*(begin())), static_cast(nRows()), - DATA_PTR(ipiv()), info); + m_factored = 1; + ct_dgetrf(n, n, &(*(begin())), static_cast(nRows()), DATA_PTR(ipiv()), info); if (info != 0) { - cout << "Singular matrix, info = " << info << endl; - throw CanteraError("invert", - "DGETRF returned INFO="+int2str(info)); + if (m_printLevel) { + writelogf("SquareMatrix::factor(): DGETRS returned INFO = %d\n", info); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::factor()", "DGETRS returned INFO = "+int2str(info)); + } } - return 0; + return info; } + //===================================================================================================================== /* * clear the factored flag */ void SquareMatrix::clearFactorFlag() { - m_factored = false; + m_factored = 0; } - /** + //===================================================================================================================== + /* * set the factored flag */ void SquareMatrix::setFactorFlag() { - m_factored = true; + m_factored = 1; } + //===================================================================================================================== + int SquareMatrix::factorQR() { + if ((int) tau.size() < m_nrows) { + tau.resize(m_nrows, 0.0); + work.resize(8 * m_nrows, 0.0); + } + a1norm_ = ct_dlange('1', m_nrows, m_nrows, &(*(begin())), m_nrows, DATA_PTR(work)); + int info; + m_factored = 2; + int lwork = work.size(); + ct_dgeqrf(m_nrows, m_nrows, &(*(begin())), m_nrows, DATA_PTR(tau), DATA_PTR(work), lwork, info); + if (info != 0) { + if (m_printLevel) { + writelogf("SquareMatrix::factorQR(): DGEQRF returned INFO = %d\n", info); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::factorQR()", "DGEQRF returned INFO = " + int2str(info)); + } + } + int lworkOpt = work[0]; + if (lworkOpt > lwork) { + work.resize(lworkOpt); + } + + + return info; + } + //===================================================================================================================== + /* + * Solve Ax = b. Vector b is overwritten on exit with x. + */ + int SquareMatrix::solveQR(doublereal * b) + { + int info=0; + /* + * Check to see whether the matrix has been factored. + */ + if (!m_factored) { + int retn = factorQR(); + if (retn) { + return retn; + } + } + + int lwork = work.size(); + if (lwork < m_nrows) { + work.resize(8 * m_nrows, 0.0); + lwork = 8 * m_nrows; + } + + /* + * Solve the factored system + */ + ct_dormqr(ctlapack::Left, ctlapack::Transpose, m_nrows, 1, m_nrows, &(*(begin())), m_nrows, DATA_PTR(tau), b, m_nrows, + DATA_PTR(work), lwork, info); + if (info != 0) { + if (m_printLevel) { + writelogf("SquareMatrix::solveQR(): DORMQR returned INFO = %d\n", info); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::solveQR()", "DORMQR returned INFO = " + int2str(info)); + } + } + int lworkOpt = work[0]; + if (lworkOpt > lwork) { + work.resize(lworkOpt); + } + + char dd = 'N'; + + ct_dtrtrs(ctlapack::UpperTriangular, ctlapack::NoTranspose, &dd, m_nrows, 1, &(*(begin())), m_nrows, b, + m_nrows, info); + if (info != 0) { + if (m_printLevel) { + writelogf("SquareMatrix::solveQR(): DTRTRS returned INFO = %d\n", info); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::solveQR()", "DTRTRS returned INFO = " + int2str(info)); + } + } + + return info; + } + //===================================================================================================================== + doublereal SquareMatrix::rcond(doublereal anorm) { + + if ((int) iwork_.size() < m_nrows) { + iwork_.resize(m_nrows); + } + if ((int) work.size() <4 * m_nrows) { + work.resize(4 * m_nrows); + } + doublereal rcond = 0.0; + if (m_factored != 1) { + throw CELapackError("SquareMatrix::rcond()", "matrix isn't factored correctly"); + } + + // doublereal anorm = ct_dlange('1', m_nrows, m_nrows, &(*(begin())), m_nrows, DATA_PTR(work)); + + + int rinfo; + rcond = ct_dgecon('1', m_nrows, &(*(begin())), m_nrows, anorm, DATA_PTR(work), + DATA_PTR(iwork_), rinfo); + if (rinfo != 0) { + if (m_printLevel) { + writelogf("SquareMatrix::rcond(): DGECON returned INFO = %d\n", rinfo); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::rcond()", "DGECON returned INFO = " + int2str(rinfo)); + } + } + return rcond; + } + //===================================================================================================================== + doublereal SquareMatrix::oneNorm() const { + return a1norm_; + } + //===================================================================================================================== + doublereal SquareMatrix::rcondQR() { + + if ((int) iwork_.size() < m_nrows) { + iwork_.resize(m_nrows); + } + if ((int) work.size() <3 * m_nrows) { + work.resize(3 * m_nrows); + } + doublereal rcond = 0.0; + if (m_factored != 2) { + throw CELapackError("SquareMatrix::rcondQR()", "matrix isn't factored correctly"); + } + + int rinfo; + rcond = ct_dtrcon(0, ctlapack::UpperTriangular, 0, m_nrows, &(*(begin())), m_nrows, DATA_PTR(work), + DATA_PTR(iwork_), rinfo); + if (rinfo != 0) { + if (m_printLevel) { + writelogf("SquareMatrix::rcondQR(): DTRCON returned INFO = %d\n", rinfo); + } + if (! m_useReturnErrorCode) { + throw CELapackError("SquareMatrix::rcondQR()", "DTRCON returned INFO = " + int2str(rinfo)); + } + } + return rcond; + } + //===================================================================================================================== + void SquareMatrix::useFactorAlgorithm(int fAlgorithm) { + useQR_ = fAlgorithm; + } + //===================================================================================================================== + int SquareMatrix::factorAlgorithm() const { + return (int) useQR_; + } + //===================================================================================================================== + bool SquareMatrix::factored() const { + return m_factored; + } + //===================================================================================================================== + // Return a pointer to the top of column j, columns are contiguous in memory + /* + * @param j Value of the column + * + * @return Returns a pointer to the top of the column + */ + doublereal * SquareMatrix::ptrColumn(int j) { + return Array2D::ptrColumn(j); + } + //===================================================================================================================== + // Copy the data from one array into another without doing any checking + /* + * This differs from the assignment operator as no resizing is done and memcpy() is used. + * @param y Array to be copied + */ + void SquareMatrix::copyData(const GeneralMatrix& y) { + const SquareMatrix *yy_ptr = dynamic_cast(& y); + Array2D::copyData(*yy_ptr); + } + //===================================================================================================================== + size_t SquareMatrix::nRows() const { + return m_nrows; + } + //===================================================================================================================== + size_t SquareMatrix::nRowsAndStruct(int * const iStruct) const { + return m_nrows; + } + //===================================================================================================================== + GeneralMatrix * SquareMatrix::duplMyselfAsGeneralMatrix() const { + SquareMatrix *dd = new SquareMatrix(*this); + return static_cast(dd); + } + //===================================================================================================================== + // Return an iterator pointing to the first element + vector_fp::iterator SquareMatrix::begin() { + return m_data.begin(); + } + //===================================================================================================================== + // Return a const iterator pointing to the first element + vector_fp::const_iterator SquareMatrix::begin() const { + return m_data.begin(); + } + //===================================================================================================================== + // Return a vector of const pointers to the columns + /* + * Note the value of the pointers are protected by their being const. + * However, the value of the matrix is open to being changed. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + doublereal * const * SquareMatrix::colPts() { + return DenseMatrix::colPts(); + } + //===================================================================================================================== + + int SquareMatrix::checkRows(doublereal &valueSmall) const { + valueSmall = 1.0E300; + int iSmall = -1; + for (int i = 0; i < m_nrows; i++) { + double valueS = 0.0; + for (int j = 0; j < m_nrows; j++) { + if (fabs(value(i,j)) > valueS) { + valueS = fabs(value(i,j)); + } + } + if (valueS < valueSmall) { + iSmall = i; + valueSmall = valueS; + } + } + return iSmall; + } + //===================================================================================================================== + int SquareMatrix::checkColumns(doublereal &valueSmall) const { + valueSmall = 1.0E300; + int jSmall = -1; + for (int j = 0; j < m_nrows; j++) { + double valueS = 0.0; + for (int i = 0; i < m_nrows; i++) { + if (fabs(value(i,j)) > valueS) { + valueS = fabs(value(i,j)); + } + } + if (valueS < valueSmall) { + jSmall = j; + valueSmall = valueS; + } + } + return jSmall; + } + //===================================================================================================================== + + } diff --git a/Cantera/src/numerics/SquareMatrix.h b/Cantera/src/numerics/SquareMatrix.h index d6c767952..0eb03dbe8 100644 --- a/Cantera/src/numerics/SquareMatrix.h +++ b/Cantera/src/numerics/SquareMatrix.h @@ -18,6 +18,7 @@ #define CT_SQUAREMATRIX_H #include "DenseMatrix.h" +#include "GeneralMatrix.h" namespace Cantera { @@ -25,72 +26,264 @@ namespace Cantera { * A class for full (non-sparse) matrices with Fortran-compatible * data storage. Adds matrix inversion operations to this class from DenseMatrix. */ - class SquareMatrix: public DenseMatrix { + class SquareMatrix: public DenseMatrix, public GeneralMatrix { public: - SquareMatrix(): - DenseMatrix(), - m_factored(false) - { - } - /** - * Constructor. Create an \c n by \c n matrix, and initialize - * all elements to \c v. + //! Base Constructor. + /*! + * Create an \c 0 by \c 0 matrix, and initialize all elements to \c 0. */ - SquareMatrix(int n, doublereal v = 0.0) : - DenseMatrix(n, n, v), - m_factored(false) - { - } + SquareMatrix(); - /** - * Copy Constructor + //! Constructor. + /*! + * Create an \c n by \c n matrix, and initialize all elements to \c v. + * + * @param n size of the square matrix + * @param v intial value of all matrix components. */ - SquareMatrix(const SquareMatrix&); + SquareMatrix(int n, doublereal v = 0.0); - /** - * Assignment operator + //! Copy Constructor + /*! + * @param right Object to be copied */ - SquareMatrix& operator=(const SquareMatrix&); - - - /// Destructor. Does nothing. - virtual ~SquareMatrix(){} - - /** - * Solves the Ax = b system returning x in the b spot. + SquareMatrix(const SquareMatrix& right); + + //! Assignment operator + /*! + * @param right Object to be copied */ - int solve(double *b); + SquareMatrix& operator=(const SquareMatrix& right); + + + //! Destructor. Does nothing. + virtual ~SquareMatrix(); + + //! Solves the Ax = b system returning x in the b spot. + /*! + * @param b Vector for the rhs of the equation system + */ + int solve(doublereal *b); + + //! Resize the matrix + /*! + * @param n Number of rows + * @param m Number of columns + * @param v double to fill the new space (defaults to zero) + */ + void resize(int n, int m, doublereal v = 0.0); /** * Zero the matrix */ void zero(); + //! Multiply A*b and write result to prod. + /*! + * @param b Vector to do the rh multiplcation + * @param prod OUTPUT vector to receive the result + */ + virtual void mult(const doublereal * const b, doublereal * const prod) const; + + //! Multiply b*A and write result to prod. + /*! + * @param b Vector to do the lh multiplcation + * @param prod OUTPUT vector to receive the result + */ + virtual void leftMult(const doublereal * const b, doublereal * const prod) const; + /** * Factors the A matrix, overwriting A. We flip m_factored * boolean to indicate that the matrix is now A-1. */ int factor(); - /** - * clear the factored flag + + //! Factors the A matrix using the QR algorithm, overwriting A + /*! + * we set m_factored to 2 to indicate the matrix is now QR factored + * + * @return Returns the info variable from lapack */ - void clearFactorFlag(); - /** - * set the factored flag + virtual int factorQR(); + + //! Returns an estimate of the inverse of the condition number for the matrix + /*! + * The matrix must have been previously factored using the QR algorithm + * + * @return returns the inverse of the condition number */ + virtual doublereal rcondQR(); + + //! Returns an estimate of the inverse of the condition number for the matrix + /*! + * The matrix must have been previously factored using the LU algorithm + * + * @param a1norm Norm of the matrix + * + * @return returns the inverse of the condition number + */ + virtual doublereal rcond(doublereal a1norm); + + //! Returns the one norm of the matrix + virtual doublereal oneNorm() const; + + //! Solves the linear problem Ax=b using the QR algorithm returning x in the b spot + /*! + * @param b RHS to be solved. + */ + int solveQR(doublereal *b); + + + //! clear the factored flag + virtual void clearFactorFlag(); + + //! set the factored flag void setFactorFlag(); - /* - * the factor flag + //! Report whether the current matrix has been factored. + virtual bool factored() const; + + //! Change the way the matrix is factored + /*! + * @param fAlgorithm integer + * 0 LU factorization + * 1 QR factorization */ - bool m_factored; + virtual void useFactorAlgorithm(int fAlgorithm); + + //! Returns the factor algorithm used + /*! + * 0 LU decomposition + * 1 QR decomposition + * + * This routine will always return 0 + */ + virtual int factorAlgorithm() const; + + //! Return a pointer to the top of column j, columns are assumed to be contiguous in memory + /*! + * @param j Value of the column + * + * @return Returns a pointer to the top of the column + */ + virtual doublereal * ptrColumn(int j); + + //! Index into the (i,j) element + /*! + * @param i row + * @param j column + * + * (note, tried a using directive here, and it didn't seem to work) + * + * Returns a changeable reference to the matrix entry + */ + virtual doublereal& operator()(int i, int j) { + return Array2D::operator()(i, j); + } + + //! Copy the data from one array into another without doing any checking + /*! + * This differs from the assignment operator as no resizing is done and memcpy() is used. + * @param y Array to be copied + */ + virtual void copyData(const GeneralMatrix& y); + + //! Constant Index into the (i,j) element + /*! + * @param i row + * @param j column + * + * Returns an unchangeable reference to the matrix entry + */ + virtual doublereal operator() (int i, int j) const { + return Array2D::operator()(i, j); + } + + //! Return the number of rows in the matrix + virtual size_t nRows() const; + + //! Return the size and structure of the matrix + /*! + * This is inherited from GeneralMatrix + * + * @param iStruct OUTPUT Pointer to a vector of ints that describe the structure of the matrix. + * not used + * + * @return returns the number of rows and columns in the matrix. + */ + size_t nRowsAndStruct(int * const iStruct = 0) const; + + //! Duplicate this object + virtual GeneralMatrix * duplMyselfAsGeneralMatrix() const; + + + //! Return an iterator pointing to the first element + /*! + */ + virtual vector_fp::iterator begin(); + + + //! Return a const iterator pointing to the first element + virtual vector_fp::const_iterator begin() const; + + + //! Return a vector of const pointers to the columns + /*! + * Note the value of the pointers are protected by their being const. + * However, the value of the matrix is open to being changed. + * + * @return returns a vector of pointers to the top of the columns + * of the matrices. + */ + virtual doublereal * const * colPts(); + + //! Check to see if we have any zero rows in the jacobian + /*! + * This utility routine checks to see if any rows are zero. + * The smallest row is returned along with the largest coefficient in that row + * + * @param valueSmall OUTPUT value of the largest coefficient in the smallest row + * + * @return index of the row that is most nearly zero + */ + virtual int checkRows(doublereal & valueSmall) const; + + //! Check to see if we have any zero columns in the jacobian + /*! + * This utility routine checks to see if any columns are zero. + * The smallest column is returned along with the largest coefficient in that column + * + * @param valueSmall OUTPUT value of the largest coefficient in the smallest column + * + * @return index of the column that is most nearly zero + */ + virtual int checkColumns(doublereal & valueSmall) const; + + protected: + + //! the factor flag + int m_factored; + + public: + //! Work vector for QR algorithm + vector_fp tau; + + //! Work vector for QR algorithm + vector_fp work; + + //! Integer work vector for QR algorithms + std::vector iwork_; + protected: + //! 1-norm of the matrix. This is determined immediately before every factorization + doublereal a1norm_; + + //! Use the QR algorithm to factor and invert the matrix + int useQR_; }; } #endif - - diff --git a/Cantera/src/numerics/ctlapack.h b/Cantera/src/numerics/ctlapack.h old mode 100755 new mode 100644 index 0b5a6da3a..b1fae29b0 --- a/Cantera/src/numerics/ctlapack.h +++ b/Cantera/src/numerics/ctlapack.h @@ -29,12 +29,22 @@ #define _DGETRS_ dgetrs #define _DGETRI_ dgetri #define _DGELSS_ dgelss +#define _DGBCON_ dgbcon #define _DGBSV_ dgbsv #define _DGBTRF_ dgbtrf #define _DGBTRS_ dgbtrs +#define _DGECON_ dgecon +#define _DLANGE_ dlange #define _DSCAL_ dscal +#define _DGEQRF_ dgeqrf +#define _DORMQR_ dormqr +#define _DTRTRS_ dtrtrs +#define _DTRCON_ dtrcon +#define _DPOTRF_ dpotrf +#define _DPOTRS_ dpotrs + #else #define _DGEMV_ dgemv_ @@ -42,20 +52,35 @@ #define _DGETRS_ dgetrs_ #define _DGETRI_ dgetri_ #define _DGELSS_ dgelss_ +#define _DGBCON_ dgbcon_ #define _DGBSV_ dgbsv_ #define _DGBTRF_ dgbtrf_ #define _DGBTRS_ dgbtrs_ +#define _DGECON_ dgecon_ +#define _DLANGE_ dlange_ #define _DSCAL_ dscal_ +#define _DGEQRF_ dgeqrf_ +#define _DORMQR_ dormqr_ +#define _DTRTRS_ dtrtrs_ +#define _DTRCON_ dtrcon_ + +#define _DPOTRF_ dpotrf_ +#define _DPOTRS_ dpotrs_ + #endif namespace ctlapack { typedef enum {Transpose = 1, NoTranspose = 0} transpose_t; typedef enum {ColMajor = 1, RowMajor = 0} storage_t; + typedef enum {UpperTriangular = 0, LowerTriangular = 1} upperlower_t; + typedef enum {Left = 0, Right = 1} side_t; } const char no_yes[2] = {'N', 'T'}; +const char upper_lower[2] = {'U', 'L'}; +const char left_right[2] = {'L', 'R'}; #ifdef USE_CBLAS #include @@ -128,14 +153,101 @@ extern "C" { doublereal *b, integer *ldb, integer *info); #endif - int _DSCAL_(integer *n, doublereal *da, doublereal *dx, integer *incx); -void cblas_dscal(const int N, const double alpha, double *X, const int incX); + int _DSCAL_(integer *n, doublereal *da, doublereal *dx, integer *incx); + void cblas_dscal(const int N, const double alpha, double *X, const int incX); + + + int _DGEQRF_(const integer* m, const integer* n, doublereal* a, const integer* lda, + doublereal* tau, doublereal* work, const integer *lwork, integer *info); + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DORMQR_(const char* side, const char* trans, const integer* m, const integer* n, + const integer * k, doublereal* a, const integer* lda, + doublereal* tau, doublereal* c, const integer* ldc, + doublereal* work, const integer *lwork, integer *info, ftnlen sisize, ftnlen trsize); +#else + int _DORMQR_(const char* side, ftnlen sisize, const char* trans, ftnlen trsize, const integer* m, + const integer* n, const integer * k, doublereal* a, const integer* lda, + doublereal* tau,doublereal* c, const integer* ldc, + doublereal* work, const integer *lwork, integer *info); +#endif + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DTRTRS_(const char* uplo, const char* trans, const char *diag, const integer* n, + const integer * nrhs, doublereal* a, const integer* lda, + doublereal* b, const integer* ldb, integer *info, + ftnlen upsize, ftnlen trsize, ftnlen disize); +#else + int _DTRTRS_(const char* uplo, ftnlen upsize, const char* trans, ftnlen trsize, const char *diag, + ftnlen disize, const integer* n, const integer * nrhs, doublereal* a, const integer* lda, + doublereal* b, const integer* ldb, integer *info); +#endif + + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DTRCON_(const char* norm, const char* uplo, const char *diag, const integer* n, + doublereal* a, const integer* lda, const doublereal *rcond, + doublereal* work, const integer* iwork, integer *info, ftnlen nosize, + ftnlen upsize, ftnlen disize); +#else + int _DTRCON_(const char* norm, ftnlen nosize, const char* uplo, ftnlen upsize, const char *diag, + ftnlen disize, const integer* n, doublereal* a, const integer* lda, const doublereal *rcond, + doublereal* work, const integer* iwork, integer *info); +#endif + + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DPOTRF_(const char* uplo, const integer* n, doublereal* a, const integer* lda, integer *info, + ftnlen upsize); +#else + int _DPOTRF_(const char* uplo, ftnlen upsize, const integer* n, doublereal* a, const integer* lda, + integer *info ); +#endif + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DPOTRS_(const char* uplo, const integer* n, const integer* nrhs, doublereal* a, const integer* lda, + doublereal* b, const integer* ldb, integer *info, ftnlen upsize); +#else + int _DPOTRS_(const char* uplo, ftnlen upsize, const integer* n, const integer* nrhs, doublereal* a, const integer* lda, + doublereal* b, const integer* ldb, integer *info); +#endif + + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DGECON_(const char *norm, const integer* n, doublereal* a, const integer* lda, + const doublereal *rnorm, const doublereal *rcond, + doublereal* work, const integer* iwork, integer *info, ftnlen nosize); +#else + int _DGECON_(const char *norm, ftnlen nosize, const integer* n, doublereal* a, const integer* lda, + const doublereal *rnorm, const doublereal *rcond, + doublereal* work, const integer* iwork, integer *info); +#endif + + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + int _DGBCON_(const char *norm, const integer* n, integer *kl, integer *ku, doublereal* ab, const integer* ldab, + const integer *ipiv, const doublereal *anorm, const doublereal *rcond, + doublereal* work, const integer* iwork, integer *info, ftnlen nosize); +#else + int _DGBCON_(const char *norm, ftnlen nosize, const integer* n, integer *kl, integer *ku, doublereal* ab, const integer* ldab, + const integer *ipiv, const doublereal *anorm, const doublereal *rcond, + doublereal* work, const integer* iwork, integer *info); +#endif + +#ifdef LAPACK_FTN_STRING_LEN_AT_END + doublereal _DLANGE_(const char *norm, const integer* m, const integer* n, doublereal* a, const integer* lda, + doublereal* work, ftnlen nosize); +#else + doublereal _DLANGE_(const char *norm, ftnlen nosize, const integer* m, const integer* n, doublereal* a, const integer* lda, + doublereal* work); +#endif + } //#endif namespace Cantera { - + //==================================================================================================================== inline void ct_dgemv(ctlapack::storage_t storage, ctlapack::transpose_t trans, int m, int n, doublereal alpha, const doublereal* a, int lda, @@ -165,7 +277,7 @@ namespace Cantera { } - + //==================================================================================================================== inline void ct_dgbsv(int n, int kl, int ku, int nrhs, doublereal* a, int lda, integer* ipiv, doublereal* b, int ldb, int& info) { @@ -175,7 +287,7 @@ namespace Cantera { b, &f_ldb, &f_info); info = f_info; } - + //==================================================================================================================== inline void ct_dgbtrf(int m, int n, int kl, int ku, doublereal* a, int lda, integer* ipiv, int& info) { integer f_m = m, f_n = n, f_kl = kl, f_ku = ku, @@ -183,7 +295,7 @@ namespace Cantera { _DGBTRF_(&f_m, &f_n, &f_kl, &f_ku, a, &f_lda, ipiv, &f_info); info = f_info; } - + //==================================================================================================================== inline void ct_dgbtrs(ctlapack::transpose_t trans, int n, int kl, int ku, int nrhs, doublereal* a, int lda, integer* ipiv, doublereal* b, int ldb, int& info) { @@ -205,7 +317,7 @@ namespace Cantera { #endif info = f_info; } - + //==================================================================================================================== inline void ct_dgetrf(int m, int n, doublereal* a, int lda, integer* ipiv, int& info) { integer mm = m; @@ -215,7 +327,7 @@ namespace Cantera { _DGETRF_(&mm, &nn, a, &ldaa, ipiv, &infoo); info = infoo; } - + //==================================================================================================================== inline void ct_dgetrs(ctlapack::transpose_t trans, int n, int nrhs, doublereal* a, int lda, integer* ipiv, doublereal* b, int ldb, int& info) @@ -230,22 +342,20 @@ namespace Cantera { #else ftnlen trsize = 1; #ifdef LAPACK_FTN_STRING_LEN_AT_END - _DGETRS_(&tr, &f_n, &f_nrhs, a, &f_lda, ipiv, b, &f_ldb, - &f_info, trsize); + _DGETRS_(&tr, &f_n, &f_nrhs, a, &f_lda, ipiv, b, &f_ldb, &f_info, trsize); #else - _DGETRS_(&tr, trsize, &f_n, &f_nrhs, a, &f_lda, ipiv, b, &f_ldb, - &f_info); + _DGETRS_(&tr, trsize, &f_n, &f_nrhs, a, &f_lda, ipiv, b, &f_ldb, &f_info); #endif #endif info = f_info; } - + //==================================================================================================================== inline void ct_dgetri(int n, doublereal* a, int lda, integer* ipiv, - doublereal* work, int lwork, int& info) { + doublereal* work, int lwork, int& info) { integer f_n = n, f_lda = lda, f_lwork = lwork, f_info = info; _DGETRI_(&f_n, a, &f_lda, ipiv, work, &f_lwork, &f_info); } - + //==================================================================================================================== inline void ct_dgelss(int m, int n, int nrhs, doublereal* a, int lda, doublereal* b, int ldb, doublereal* s, doublereal rcond, int& rank, doublereal* work, int lwork, @@ -260,14 +370,247 @@ namespace Cantera { rank = f_rank; } - inline void ct_dscal(int n, doublereal da, doublereal* dx, int incx) { + inline void ct_dscal(int n, doublereal da, doublereal* dx, int incx) { //integer f_n = n, f_incx = incx; //_DSCAL_(&f_n, &da, dx, &f_incx); - cblas_dscal(n, da, dx, incx); - + cblas_dscal(n, da, dx, incx); + } + //==================================================================================================================== + inline void ct_dgeqrf(int m, int n, doublereal* a, int lda, doublereal *tau, + doublereal* work, int lwork, int &info) { + integer f_m = m; + integer f_n = n; + integer f_lda = lda; + integer f_lwork = lwork; + integer f_info = info; + _DGEQRF_(&f_m, &f_n, a, &f_lda, tau, work, &f_lwork, &f_info); + info = f_info; + } + //==================================================================================================================== + inline void ct_dormqr(ctlapack::side_t rlside, ctlapack::transpose_t trans, int m, + int n, int k, doublereal* a, int lda, doublereal *tau, doublereal *c, int ldc, + doublereal *work, int lwork, int &info) { + char side = left_right[rlside]; + char tr = no_yes[trans]; + integer f_m = m; + integer f_n = n; + integer f_k = k; + integer f_lwork = lwork; + integer f_lda = lda; + integer f_ldc = ldc; + integer f_info = info; +#ifdef NO_FTN_STRING_LEN_AT_END + _DORMQR_(&side, &tr, &f_m, &f_n, &f_k, a, &f_lda, tau, c, &f_ldc, work, &f_lwork, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DORMQR_(&side, &tr, &f_m, &f_n, &f_k, a, &f_lda, tau, c, &f_ldc, work, &f_lwork, &f_info, trsize, trsize); +#else + _DORMQR_(&side, trsize, &tr, trsize, &f_m, &f_n, &f_k, a, &f_lda, tau, c, &f_ldc, work, &f_lwork, &f_info); +#endif +#endif + info = f_info; + } + //==================================================================================================================== + inline void ct_dtrtrs(ctlapack::upperlower_t uplot, ctlapack::transpose_t trans, const char *diag, + int n, int nrhs, doublereal* a, int lda, doublereal *b, int ldb, int &info) { + char uplo = upper_lower[uplot]; + char tr = no_yes[trans]; + char dd = 'N'; + if (diag) { + dd = diag[0]; } - + integer f_n = n; + integer f_nrhs = nrhs; + integer f_lda = lda; + integer f_ldb = ldb; + integer f_info = info; +#ifdef NO_FTN_STRING_LEN_AT_END + _DTRTRS_(&uplo, &tr, &dd, &f_n, &f_nrhs, a, &f_lda, b, &f_ldb, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DTRTRS_(&uplo, &tr, &dd, &f_n, &f_nrhs, a, &f_lda, b, &f_ldb, &f_info, trsize, trsize, trsize); +#else + _DTRTRS_(&uplo, trsize, &tr, trsize, &dd, trsize, &f_n, &f_nrhs, a, &f_lda, b, &f_ldb, &f_info); +#endif +#endif + info = f_info; + } + //==================================================================================================================== + //! + /*! + * @param work Must be dimensioned equal to greater than 3N + * @param iwork Must be dimensioned equal to or greater than N + */ + inline doublereal ct_dtrcon(const char *norm, ctlapack::upperlower_t uplot, const char *diag, + int n, doublereal* a, int lda, doublereal *work, int *iwork, int &info) { + char uplo = upper_lower[uplot]; + char dd = 'N'; + if (diag) { + dd = diag[0]; + } + char nn = '1'; + if (norm) { + nn = norm[0]; + } + integer f_n = n; + integer f_lda = lda; + integer f_info = info; + doublereal rcond; +#ifdef NO_FTN_STRING_LEN_AT_END + _DTRCON_(&nn, &uplo, &dd, &f_n, a, &f_lda, &rcond, work, iwork, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DTRCON_(&nn, &uplo, &dd, &f_n, a, &f_lda, &rcond, work, iwork, &f_info, trsize, trsize, trsize); +#else + _DTRCON_(&nn, trsize, &uplo, trsize, &dd, trsize, &f_n, a, &f_lda, &rcond, work, iwork, &f_info); +#endif +#endif + info = f_info; + return rcond; + } + //==================================================================================================================== + //! + /*! + * @param work Must be dimensioned equal to greater than 3N + * @param iwork Must be dimensioned equal to or greater than N + */ + inline void ct_dpotrf(ctlapack::upperlower_t uplot, int n, doublereal* a, int lda, int &info) { + char uplo = upper_lower[uplot]; + integer f_n = n; + integer f_lda = lda; + integer f_info = info; +#ifdef NO_FTN_STRING_LEN_AT_END + _DPOTRF_(&uplo, &f_n, a, &f_lda, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DPOTRF_(&uplo, &f_n, a, &f_lda, &f_info, trsize); +#else + _DPOTRF_(&uplo, trsize, &f_n, a, &f_lda, &f_info); +#endif +#endif + info = f_info; + return; + } + //==================================================================================================================== + //! + /*! + */ + inline void ct_dpotrs(ctlapack::upperlower_t uplot, int n, int nrhs, doublereal* a, int lda, + doublereal* b, int ldb, int &info) { + char uplo = upper_lower[uplot]; + integer f_n = n; + integer f_nrhs = nrhs; + integer f_lda = lda; + integer f_ldb = ldb; + integer f_info = info; + +#ifdef NO_FTN_STRING_LEN_AT_END + _DPOTRS_(&uplo, &f_n, &f_nrhs, a, &f_lda, b, &f_ldb, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DPOTRS_(&uplo, &f_n, &f_nrhs, a, &f_lda, b, &f_ldb, &f_info, trsize); +#else + _DPOTRS_(&uplo, trsize, &f_n, &f_nrhs, a, &f_lda, b, &f_ldb, &f_info); +#endif +#endif + info = f_info; + return; + } + + //==================================================================================================================== + //! + /*! + */ + inline doublereal ct_dgecon(const char norm, int n, doublereal* a, int lda, doublereal anorm, + doublereal* work, int *iwork, int &info) { + char cnorm = '1'; + if (norm) { + cnorm = norm; + } + integer f_n = n; + integer f_lda = lda; + integer f_info = info; + doublereal rcond; + +#ifdef NO_FTN_STRING_LEN_AT_END + _DGECON_(&cnorm, &f_n a, &f_lda, &anorm, &rcond, work, iwork, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DGECON_(&cnorm, &f_n, a, &f_lda, &anorm, &rcond, work, iwork, &f_info, trsize); +#else + _DGECON_(&cnorm, trsize, &f_n, a, &f_lda, &anorm, &rcond, work, iwork, &f_info); +#endif +#endif + info = f_info; + return rcond; + } + + //==================================================================================================================== + //! + /*! + */ + inline doublereal ct_dgbcon(const char norm, int n, int kl, int ku, doublereal* a, int ldab, int *ipiv, doublereal anorm, + doublereal* work, int *iwork, int &info) { + char cnorm = '1'; + if (norm) { + cnorm = norm; + } + integer f_n = n; + integer f_kl = kl; + integer f_ku = ku; + integer f_ldab = ldab; + integer f_info = info; + doublereal rcond; + +#ifdef NO_FTN_STRING_LEN_AT_END + _DGBCON_(&cnorm, &f_n , &f_kl, &f_ku, a, &f_ldab, ipiv, &anorm, &rcond, work, iwork, &f_info); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + _DGBCON_(&cnorm, &f_n, &f_kl, &f_ku, a, &f_ldab, ipiv, &anorm, &rcond, work, iwork, &f_info, trsize); +#else + _DGBCON_(&cnorm, trsize, &f_n, &f_kl, &f_ku, a, &f_ldab, ipiv, &anorm, &rcond, work, iwork, &f_info); +#endif +#endif + info = f_info; + return rcond; + } + + //==================================================================================================================== + //! + /*! + */ + inline doublereal ct_dlange(const char norm, int m, int n, doublereal* a, int lda, + doublereal* work) { + char cnorm = '1'; + if (norm) { + cnorm = norm; + } + integer f_m = m; + integer f_n = n; + integer f_lda = lda; + doublereal anorm; + +#ifdef NO_FTN_STRING_LEN_AT_END + anorm = _DLANGE_(&cnorm, &f_m, &f_n a, &f_lda, work); +#else + ftnlen trsize = 1; +#ifdef LAPACK_FTN_STRING_LEN_AT_END + anorm = _DLANGE_(&cnorm, &f_m, &f_n, a, &f_lda, work, trsize); +#else + anorm = _DLANGE_(&cnorm, trsize, &f_m, &f_n, a, &f_lda, work); +#endif +#endif + return anorm; + } + //==================================================================================================================== } #endif diff --git a/Cantera/src/numerics/funcs.cpp b/Cantera/src/numerics/funcs.cpp old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/lapack.h b/Cantera/src/numerics/lapack.h old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/polyfit.h b/Cantera/src/numerics/polyfit.h old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/solveProb.cpp b/Cantera/src/numerics/solveProb.cpp new file mode 100644 index 000000000..6fcd09655 --- /dev/null +++ b/Cantera/src/numerics/solveProb.cpp @@ -0,0 +1,1001 @@ +/* + * @file: solveSP.cpp Implicit solver for nonlinear problems + */ +/* + * $Id$ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#include "solveProb.h" +#include "clockWC.h" +#include "ctlapack.h" + +/* Standard include files */ + +#include +#include +#include + +#include + +using namespace std; +namespace Cantera { + + /*************************************************************************** + * STATIC ROUTINES DEFINED IN THIS FILE + ***************************************************************************/ + + static doublereal calcWeightedNorm(const doublereal [], const doublereal dx[], int); + + /*************************************************************************** + * LAPACK PROTOTYPES + ***************************************************************************/ + + /***************************************************************************** + * PROTOTYPES and PREPROC DIRECTIVES FOR MISC. ROUTINES + *****************************************************************************/ + +#ifndef MAX +# define MAX(x,y) (( (x) > (y) ) ? (x) : (y)) /* max function */ +#endif + +#ifndef MIN +# define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) /* min function */ +#endif + + + /*************************************************************************** + * solveSP Class Definitinos + ***************************************************************************/ + //================================================================================================ + // Main constructor + solveProb::solveProb(ResidEval* resid) : + m_residFunc(resid), + m_neq(0), + m_atol(0), + m_rtol(1.0E-4), + m_maxstep(1000), + m_ioflag(0) + { + m_neq = m_residFunc->nEquations(); + + // Dimension solution vector + int dim1 = MAX(1, m_neq); + + m_atol.resize(dim1, 1.0E-9); + m_netProductionRatesSave.resize(dim1, 0.0); + m_numEqn1.resize(dim1, 0.0); + m_numEqn2.resize(dim1, 0.0); + m_CSolnSave.resize(dim1, 0.0); + m_CSolnSP.resize(dim1, 0.0); + m_CSolnSPInit.resize(dim1, 0.0); + m_CSolnSPOld.resize(dim1, 0.0); + m_wtResid.resize(dim1, 0.0); + m_wtSpecies.resize(dim1, 0.0); + m_resid.resize(dim1, 0.0); + m_ipiv.resize(dim1, 0); + m_topBounds.resize(dim1, 1.0); + m_botBounds.resize(dim1, 0.0); + + m_Jac.resize(dim1, dim1, 0.0); + m_JacCol.resize(dim1, 0); + for (int k = 0; k < dim1; k++) { + m_JacCol[k] = m_Jac.ptrColumn(k); + } + + } + //================================================================================================ + // Empty destructor + solveProb::~solveProb() { + } + //================================================================================================ + /* + * The following calculation is a Newton's method to + * get the surface fractions of the surface and bulk species by + * requiring that the + * surface species production rate = 0 and that the bulk fractions are + * proportional to their production rates. + */ + int solveProb::solve(int ifunc, doublereal time_scale, + doublereal reltol) + { + doublereal EXTRA_ACCURACY = 0.001; + if (ifunc == SOLVEPROB_JACOBIAN) { + EXTRA_ACCURACY *= 0.001; + } + int irow; + int jcol, info = 0; + int label_t=-1; /* Species IDs for time control */ + int label_d; /* Species IDs for damping control */ + int label_t_old=-1; + doublereal label_factor = 1.0; + int iter=0; // iteration number on numlinear solver + int iter_max=1000; // maximum number of nonlinear iterations + int nrhs=1; + doublereal deltaT = 1.0E-10; // Delta time step + doublereal damp=1.0, tmp; + // Weighted L2 norm of the residual. Currently, this is only + // used for IO purposes. It doesn't control convergence. + // Therefore, it is turned off when DEBUG_SOLVEPROB isn't defined. + doublereal resid_norm; + doublereal inv_t = 0.0; + doublereal t_real = 0.0, update_norm = 1.0E6; + + bool do_time = false, not_converged = true; + +#ifdef DEBUG_SOLVEPROB +#ifdef DEBUG_SOLVEPROB_TIME + doublereal t1; +#endif +#else + if (m_ioflag > 1) { + m_ioflag = 1; + } +#endif + +#ifdef DEBUG_SOLVEPROB +#ifdef DEBUG_SOLVEPROB_TIME + Cantera::clockWC wc; + if (m_ioflag) t1 = wc.secondsWC(); +#endif +#endif + + /* + * Set the initial value of the do_time parameter + */ + if (ifunc == SOLVEPROB_INITIALIZE || ifunc == SOLVEPROB_TRANSIENT) do_time = true; + + /* + * upload the initial conditions + */ + m_residFunc->getInitialConditions(t_real, DATA_PTR(m_CSolnSP), DATA_PTR(m_numEqn1)); + + /* + * Store the initial guess in the soln vector, + * CSolnSP, and in an separate vector CSolnSPInit. + */ + std::copy(m_CSolnSP.begin(), m_CSolnSP.end(), m_CSolnSPInit.begin()); + + + + if (m_ioflag) { + print_header(m_ioflag, ifunc, time_scale, reltol, + DATA_PTR(m_netProductionRatesSave)); + } + + /* + * Quick return when there isn't a surface problem to solve + */ + if (m_neq == 0) { + not_converged = false; + update_norm = 0.0; + } + + /* ------------------------------------------------------------------ + * Start of Newton's method + * ------------------------------------------------------------------ + */ + while (not_converged && iter < iter_max) { + iter++; + /* + * Store previous iteration's solution in the old solution vector + */ + std::copy(m_CSolnSP.begin(), m_CSolnSP.end(), m_CSolnSPOld.begin()); + + /* + * Evaluate the largest surface species for each surface phase every + * 5 iterations. + */ + // if (iter%5 == 4) { + // evalSurfLarge(DATA_PTR(m_CSolnSP)); + // } + + /* + * Calculate the value of the time step + * - heuristics to stop large oscillations in deltaT + */ + if (do_time) { + /* don't hurry increase in time step at the same time as damping */ + if (damp < 1.0) label_factor = 1.0; + tmp = calc_t(DATA_PTR(m_netProductionRatesSave), DATA_PTR(m_CSolnSP), + &label_t, &label_t_old, &label_factor, m_ioflag); + if (iter < 10) + inv_t = tmp; + else if (tmp > 2.0*inv_t) + inv_t = 2.0*inv_t; + else { + inv_t = tmp; + } + + /* + * Check end condition + */ + + if (ifunc == SOLVEPROB_TRANSIENT) { + tmp = t_real + 1.0/inv_t; + if (tmp > time_scale) inv_t = 1.0/(time_scale - t_real); + } + } + else { + /* make steady state calc a step of 1 million seconds to + prevent singular jacobians for some pathological cases */ + inv_t = 1.0e-6; + } + deltaT = 1.0/inv_t; + + /* + * Call the routine to numerically evaluation the jacobian + * and residual for the current iteration. + */ + resjac_eval(m_JacCol, DATA_PTR(m_resid), DATA_PTR(m_CSolnSP), + DATA_PTR(m_CSolnSPOld), do_time, deltaT); + + /* + * Calculate the weights. Make sure the calculation is carried + * out on the first iteration. + */ + if (iter%4 == 1) { + calcWeights(DATA_PTR(m_wtSpecies), DATA_PTR(m_wtResid), + DATA_PTR(m_CSolnSP)); + } + + /* + * Find the weighted norm of the residual + */ + resid_norm = calcWeightedNorm(DATA_PTR(m_wtResid), DATA_PTR(m_resid), m_neq); + +#ifdef DEBUG_SOLVEPROB + if (m_ioflag > 1) { + printIterationHeader(m_ioflag, damp, inv_t, t_real, iter, do_time); + /* + * Print out the residual and jacobian + */ + printResJac(m_ioflag, m_neq, m_Jac, DATA_PTR(m_resid), + DATA_PTR(m_wtResid), resid_norm); + } +#endif + + /* + * Solve Linear system (with LAPACK). The solution is in resid[] + */ + + ct_dgetrf(m_neq, m_neq, m_JacCol[0], m_neq, DATA_PTR(m_ipiv), info); + if (info==0) { + ct_dgetrs(ctlapack::NoTranspose, m_neq, nrhs, m_JacCol[0], + m_neq, DATA_PTR(m_ipiv), DATA_PTR(m_resid), m_neq, + info); + } + /* + * Force convergence if residual is small to avoid + * "nan" results from the linear solve. + */ + else { + if (m_ioflag) { + printf("solveSurfSS: Zero pivot, assuming converged: %g (%d)\n", + resid_norm, info); + } + for (jcol = 0; jcol < m_neq; jcol++) m_resid[jcol] = 0.0; + + /* print out some helpful info */ + if (m_ioflag > 1) { + printf("-----\n"); + printf("solveSurfProb: iter %d t_real %g delta_t %g\n\n", + iter,t_real, 1.0/inv_t); + printf("solveSurfProb: init guess, current concentration," + "and prod rate:\n"); + + printf("-----\n"); + } + if (do_time) t_real += time_scale; +#ifdef DEBUG_SOLVEPROB + if (m_ioflag) { + printf("\nResidual is small, forcing convergence!\n"); + } +#endif + } + + /* + * Calculate the Damping factor needed to keep all unknowns + * between 0 and 1, and not allow too large a change (factor of 2) + * in any unknown. + */ + + + damp = calc_damping(DATA_PTR(m_CSolnSP), DATA_PTR(m_resid), m_neq, &label_d); + + + /* + * Calculate the weighted norm of the update vector + * Here, resid is the delta of the solution, in concentration + * units. + */ + update_norm = calcWeightedNorm(DATA_PTR(m_wtSpecies), + DATA_PTR(m_resid), m_neq); + /* + * Update the solution vector and real time + * Crop the concentrations to zero. + */ + for (irow = 0; irow < m_neq; irow++) { + m_CSolnSP[irow] -= damp * m_resid[irow]; + } + + + if (do_time) t_real += damp/inv_t; + + if (m_ioflag) { + printIteration(m_ioflag, damp, label_d, label_t, inv_t, t_real, iter, + update_norm, resid_norm, + DATA_PTR(m_netProductionRatesSave), + DATA_PTR(m_CSolnSP), DATA_PTR(m_resid), + DATA_PTR(m_wtSpecies), m_neq, do_time); + } + + if (ifunc == SOLVEPROB_TRANSIENT) + not_converged = (t_real < time_scale); + else { + if (do_time) { + if (t_real > time_scale || + (resid_norm < 1.0e-7 && + update_norm*time_scale/t_real < EXTRA_ACCURACY) ) { + do_time = false; +#ifdef DEBUG_SOLVEPROB + if (m_ioflag > 1) { + printf("\t\tSwitching to steady solve.\n"); + } +#endif + } + } + else { + not_converged = ((update_norm > EXTRA_ACCURACY) || + (resid_norm > EXTRA_ACCURACY)); + } + } + } /* End of Newton's Method while statement */ + + /* + * End Newton's method. If not converged, print error message and + * recalculate sdot's at equal site fractions. + */ + if (not_converged) { + if (m_ioflag) { + printf("#$#$#$# Error in solveProb $#$#$#$ \n"); + printf("Newton iter on surface species did not converge, " + "update_norm = %e \n", update_norm); + printf("Continuing anyway\n"); + } + } +#ifdef DEBUG_SOLVEPROB +#ifdef DEBUG_SOLVEPROB_TIME + if (m_ioflag) { + printf("\nEnd of solve, time used: %e\n", wc.secondsWC()-t1); + } +#endif +#endif + + /* + * Decide on what to return in the solution vector + * - right now, will always return the last solution + * no matter how bad + */ + if (m_ioflag) { + fun_eval(DATA_PTR(m_resid), DATA_PTR(m_CSolnSP), DATA_PTR(m_CSolnSPOld), + false, deltaT); + resid_norm = calcWeightedNorm(DATA_PTR(m_wtResid), + DATA_PTR(m_resid), m_neq); + printFinal(m_ioflag, damp, label_d, label_t, inv_t, t_real, iter, + update_norm, resid_norm, DATA_PTR(m_netProductionRatesSave), + DATA_PTR(m_CSolnSP), DATA_PTR(m_resid), + DATA_PTR(m_wtSpecies), + DATA_PTR(m_wtResid), m_neq, do_time); + } + + /* + * Return with the appropriate flag + */ + if (update_norm > 1.0) { + return -1; + } + return 0; + } + //================================================================================================ + /* + * Update the surface states of the surface phases. + */ + void solveProb::reportState(doublereal * const CSolnSP) const { + std::copy(m_CSolnSP.begin(), m_CSolnSP.end(), CSolnSP); + } + //================================================================================================ + /* + * This calculates the net production rates of all species + * + * This calculates the function eval. + * (should switch to special_species formulation for sum condition) + * + * @internal + * This routine uses the m_numEqn1 and m_netProductionRatesSave vectors + * as temporary internal storage. + */ + void solveProb::fun_eval(doublereal * const resid, const doublereal * const CSoln, + const doublereal * const CSolnOld, const bool do_time, + const doublereal deltaT) + { + if (do_time) { + m_residFunc->evalSimpleTD(0.0, CSoln, CSolnOld, deltaT, resid); + } else { + m_residFunc->evalSS(0.0, CSoln, resid); + } + } + //================================================================================================ + /* + * Calculate the Jacobian and residual + * + * @internal + * This routine uses the m_numEqn2 vector + * as temporary internal storage. + */ + void solveProb::resjac_eval(std::vector &JacCol, + doublereal resid[], doublereal CSoln[], + const doublereal CSolnOld[], const bool do_time, + const doublereal deltaT) + { + int i, kCol; + doublereal dc, cSave, sd; + doublereal *col_j; + /* + * Calculate the residual + */ + fun_eval(resid, CSoln, CSolnOld, do_time, deltaT); + /* + * Now we will look over the columns perturbing each unknown. + */ + + for (kCol = 0; kCol < m_neq; kCol++) { + cSave = CSoln[kCol]; + sd = fabs(cSave) + fabs(CSoln[kCol]) + m_atol[kCol] * 1.0E6; + if (sd < 1.0E-200) { + sd = 1.0E-4; + } + dc = fmaxx(1.0E-11 * sd, fabs(cSave) * 1.0E-6); + CSoln[kCol] += dc; + fun_eval(DATA_PTR(m_numEqn2), CSoln, CSolnOld, do_time, deltaT); + col_j = JacCol[kCol]; + for (i = 0; i < m_neq; i++) { + col_j[i] = (m_numEqn2[i] - resid[i])/dc; + } + CSoln[kCol] = cSave; + } + + } + //================================================================================================ +#define APPROACH 0.50 + // This function calculates a damping factor for the Newton iteration update + // vector, dxneg, to insure that all solution components stay within perscribed bounds + /* + * The default for this class is that all solution components are bounded between zero and one. + * this is because the original unknowns were mole fractions and surface site fractions. + * + * dxneg[] = negative of the update vector. + * + * The constant "APPROACH" sets the fraction of the distance to the boundary + * that the step can take. If the full step would not force any fraction + * outside of the bounds, then Newton's method is mostly allowed to operate normally. + * There is also some solution damping employed. + * + * @param x Vector of the current solution components + * @param dxneg Vector of the negative of the full solution update vector. + * @param dim Size of the solution vector + * @param label return int, stating which solution component caused the most damping. + */ + doublereal solveProb::calc_damping(doublereal x[], doublereal dxneg[], int dim, int *label) + { + doublereal damp = 1.0, xnew, xtop, xbot; + static doublereal damp_old = 1.0; + *label = -1; + + for (int i = 0; i < dim; i++) { + doublereal topBounds = m_topBounds[i]; + doublereal botBounds = m_botBounds[i]; + /* + * Calculate the new suggested new value of x[i] + */ + double delta_x = - dxneg[i]; + xnew = x[i] - damp * dxneg[i]; + + /* + * Calculate the allowed maximum and minimum values of x[i] + * - Only going to allow x[i] to converge to the top and bottom bounds by a + * single order of magnitude at one time + */ + bool canCrossOrigin = false; + if (topBounds > 0.0 && botBounds < 0.0) { + canCrossOrigin = true; + } + + xtop = topBounds - 0.1 * fabs(topBounds - x[i]); + + xbot = botBounds + 0.1 * fabs(x[i] - botBounds); + + if (xnew > xtop) { + damp = - APPROACH * (xtop - x[i]) / dxneg[i]; + *label = i; + } + else if (xnew < xbot) { + damp = APPROACH * (x[i] - xbot) / dxneg[i]; + *label = i; + } + // else if (fabs(xnew) > 2.0*MAX(fabs(x[i]), 1.0E-10)) { +// damp = 0.5 * MAX(fabs(x[i]), 1.0E-9)/ fabs(xnew); +// *label = i; + // } + double denom = fabs(x[i]) + 1.0E5 * m_atol[i]; + if ((fabs(delta_x) / denom) > 0.3) { + double newdamp = 0.3 * denom / fabs(delta_x); + if (canCrossOrigin) { + if (xnew * x[i] < 0.0) { + if (fabs(x[i]) < 1.0E8 * m_atol[i]) { + newdamp = 2.0 * fabs(x[i]) / fabs(delta_x); + } + } + } + damp = MIN(damp, newdamp); + } + + } + + /* + * Only allow the damping parameter to increase by a factor of three each + * iteration. Heuristic to avoid oscillations in the value of damp + */ + if (damp > damp_old*3) { + damp = damp_old*3; + *label = -1; + } + + /* + * Save old value of the damping parameter for use + * in subsequent calls. + */ + damp_old = damp; + return damp; + + } +#undef APPROACH + //================================================================================================ + /* + * This function calculates the norm of an update, dx[], + * based on the weighted values of x. + */ + static doublereal calcWeightedNorm(const doublereal wtX[], const doublereal dx[], int dim) { + doublereal norm = 0.0; + doublereal tmp; + if (dim == 0) return 0.0; + for (int i = 0; i < dim; i++) { + tmp = dx[i] / wtX[i]; + norm += tmp * tmp; + } + return (sqrt(norm/dim)); + } + //================================================================================================ + /* + * Calculate the weighting factors for norms wrt both the species + * concentration unknowns and the residual unknowns. + * + */ + void solveProb::calcWeights(doublereal wtSpecies[], doublereal wtResid[], + const doublereal CSoln[]) + { + int k, jcol; + /* + * First calculate the weighting factor + */ + + for (k = 0; k < m_neq; k++) { + wtSpecies[k] = m_atol[k] + m_rtol * fabs(CSoln[k]); + } + /* + * Now do the residual Weights. Since we have the Jacobian, we + * will use it to generate a number based on the what a significant + * change in a solution variable does to each residual. + * This is a row sum scale operation. + */ + for (k = 0; k < m_neq; k++) { + wtResid[k] = 0.0; + for (jcol = 0; jcol < m_neq; jcol++) { + wtResid[k] += fabs(m_Jac(k,jcol) * wtSpecies[jcol]); + } + } + } + //================================================================================================ + /* + * This routine calculates a pretty conservative 1/del_t based + * on MAX_i(sdot_i/(X_i*SDen0)). This probably guarantees + * diagonal dominance. + * + * Small surface fractions are allowed to intervene in the del_t + * determination, no matter how small. This may be changed. + * Now minimum changed to 1.0e-12, + * + * Maximum time step set to time_scale. + */ + doublereal solveProb:: + calc_t(doublereal netProdRateSolnSP[], doublereal Csoln[], + int *label, int *label_old, doublereal *label_factor, int ioflag) + { + int k, kspSpecial; + doublereal tmp, inv_timeScale=0.0; + for (k = 0; k < m_neq; k++) { + if (Csoln[k] <= 1.0E-10) { + tmp = 1.0E-10; + } else { + tmp = Csoln[k]; + } + tmp = fabs(netProdRateSolnSP[k]/ tmp); + + + if (netProdRateSolnSP[k]> 0.0) tmp /= 100.; + if (tmp > inv_timeScale) { + inv_timeScale = tmp; + *label = k; + + kspSpecial = k; + } + } + + /* + * Increase time step exponentially as same species repeatedly + * controls time step + */ + if (*label == *label_old) { + *label_factor *= 1.5; + } else { + *label_old = *label; + *label_factor = 1.0; + } + inv_timeScale = inv_timeScale / *label_factor; +#ifdef DEBUG_SOLVEPROB + if (ioflag > 1) { + if (*label_factor > 1.0) { + printf("Delta_t increase due to repeated controlling species = %e\n", + *label_factor); + } + int kkin = m_kinSpecIndex[*label]; + + string sn = " " + printf("calc_t: spec=%d(%s) sf=%e pr=%e dt=%e\n", + *label, sn.c_str(), XMolSolnSP[*label], + netProdRateSolnSP[*label], 1.0/inv_timeScale); + } +#endif + + return (inv_timeScale); + + } + //==================================================================================================================== + // Set the bottom and top bounds on the solution vector + /* + * The default is for the bottom is 0.0, while the default for the top is 1.0 + * + * @param botBounds Vector of bottom bounds + * @param topBounds vector of top bounds + */ + void solveProb::setBounds(const doublereal botBounds[], const doublereal topBounds[]) + { + for (int k = 0; k < m_neq; k++) { + m_botBounds[k] = botBounds[k]; + m_topBounds[k] = topBounds[k]; + } + } + //==================================================================================================================== + /* + * printResJac(): prints out the residual and Jacobian. + * + */ +#ifdef DEBUG_SOLVEPROB + void solveProb::printResJac(int ioflag, int neq, const Array2D &Jac, + doublereal resid[], doublereal wtRes[], + doublereal norm) + { + + } +#endif + //================================================================================================ + /* + * Optional printing at the start of the solveProb problem + */ + void solveProb::print_header(int ioflag, int ifunc, doublereal time_scale, + doublereal reltol, + doublereal netProdRate[]) { + int damping = 1; + if (ioflag) { + printf("\n================================ SOLVEPROB CALL SETUP " + "========================================\n"); + if (ifunc == SOLVEPROB_INITIALIZE) { + printf("\n SOLVEPROB Called with Initialization turned on\n"); + printf(" Time scale input = %9.3e\n", time_scale); + } + else if (ifunc == SOLVEPROB_RESIDUAL) { + printf("\n SOLVEPROB Called to calculate steady state residual\n"); + printf( " from a good initial guess\n"); + } + else if (ifunc == SOLVEPROB_JACOBIAN) { + printf("\n SOLVEPROB Called to calculate steady state jacobian\n"); + printf( " from a good initial guess\n"); + } + else if (ifunc == SOLVEPROB_TRANSIENT) { + printf("\n SOLVEPROB Called to integrate surface in time\n"); + printf( " for a total of %9.3e sec\n", time_scale); + } + else { + fprintf(stderr,"Unknown ifunc flag = %d\n", ifunc); + exit(EXIT_FAILURE); + } + + + + if (damping) + printf(" Damping is ON \n"); + else + printf(" Damping is OFF \n"); + + printf(" Reltol = %9.3e, Abstol = %9.3e\n", reltol, m_atol[0]); + } + + /* + * Print out the initial guess + */ +#ifdef DEBUG_SOLVEPROB + if (ioflag > 1) { + printf("\n================================ INITIAL GUESS " + "========================================\n"); + int kindexSP = 0; + for (int isp = 0; isp < m_numSurfPhases; isp++) { + InterfaceKinetics *m_kin = m_objects[isp]; + int surfIndex = m_kin->surfacePhaseIndex(); + int nPhases = m_kin->nPhases(); + m_kin->getNetProductionRates(netProdRate); + updateMFKinSpecies(XMolKinSpecies, isp); + + printf("\n IntefaceKinetics Object # %d\n\n", isp); + + printf("\t Number of Phases = %d\n", nPhases); + printf("\t Phase:SpecName Prod_Rate MoleFraction kindexSP\n"); + printf("\t -------------------------------------------------------" + "----------\n"); + + int kspindex = 0; + bool inSurfacePhase = false; + for (int ip = 0; ip < nPhases; ip++) { + if (ip == surfIndex) { + inSurfacePhase = true; + } else { + inSurfacePhase = false; + } + ThermoPhase &THref = m_kin->thermo(ip); + int nsp = THref.nSpecies(); + string pname = THref.id(); + for (int k = 0; k < nsp; k++) { + string sname = THref.speciesName(k); + string cname = pname + ":" + sname; + if (inSurfacePhase) { + printf("\t %-24s %10.3e %10.3e %d\n", cname.c_str(), + netProdRate[kspindex], XMolKinSpecies[kspindex], + kindexSP); + kindexSP++; + } else { + printf("\t %-24s %10.3e %10.3e\n", cname.c_str(), + netProdRate[kspindex], XMolKinSpecies[kspindex]); + } + kspindex++; + } + } + printf("==========================================================" + "=================================\n"); + } + } +#endif + if (ioflag == 1) { + printf("\n\n\t Iter Time Del_t Damp DelX " + " Resid Name-Time Name-Damp\n"); + printf( "\t -----------------------------------------------" + "------------------------------------\n"); + } + } + //================================================================================================ + void solveProb::printIteration(int ioflag, doublereal damp, int label_d, + int label_t, + doublereal inv_t, doublereal t_real, int iter, + doublereal update_norm, doublereal resid_norm, + doublereal netProdRate[], doublereal CSolnSP[], + doublereal resid[], + doublereal wtSpecies[], int dim, bool do_time) + { + int i, k; + string nm; + if (ioflag == 1) { + + printf("\t%6d ", iter); + if (do_time) + printf("%9.4e %9.4e ", t_real, 1.0/inv_t); + else + for (i = 0; i < 22; i++) printf(" "); + if (damp < 1.0) + printf("%9.4e ", damp); + else + for (i = 0; i < 11; i++) printf(" "); + printf("%9.4e %9.4e", update_norm, resid_norm); + if (do_time) { + k = label_t; + printf(" %d", k); + } else { + for (i = 0; i < 16; i++) printf(" "); + } + if (label_d >= 0) { + k = label_d; + printf(" %d", k); + } + printf("\n"); + } +#ifdef DEBUG_SOLVEPROB + else if (ioflag > 1) { + + updateMFSolnSP(XMolSolnSP); + printf("\n\t Weighted norm of update = %10.4e\n", update_norm); + + printf("\t Name Prod_Rate XMol Conc " + " Conc_Old wtConc"); + if (damp < 1.0) printf(" UnDamped_Conc"); + printf("\n"); + printf("\t---------------------------------------------------------" + "-----------------------------\n"); + int kindexSP = 0; + for (int isp = 0; isp < m_numSurfPhases; isp++) { + int nsp = m_nSpeciesSurfPhase[isp]; + InterfaceKinetics *m_kin = m_objects[isp]; + //int surfPhaseIndex = m_kinObjPhaseIDSurfPhase[isp]; + m_kin->getNetProductionRates(DATA_PTR(m_numEqn1)); + for (int k = 0; k < nsp; k++, kindexSP++) { + int kspIndex = m_kinSpecIndex[kindexSP]; + nm = m_kin->kineticsSpeciesName(kspIndex); + printf("\t%-16s %10.3e %10.3e %10.3e %10.3e %10.3e ", + nm.c_str(), + m_numEqn1[kspIndex], + XMolSolnSP[kindexSP], + CSolnSP[kindexSP], CSolnSP[kindexSP]+damp*resid[kindexSP], + wtSpecies[kindexSP]); + if (damp < 1.0) { + printf("%10.4e ", CSolnSP[kindexSP]+(damp-1.0)*resid[kindexSP]); + if (label_d == kindexSP) printf(" Damp "); + } + if (label_t == kindexSP) printf(" Tctrl"); + printf("\n"); + } + + } + + printf("\t--------------------------------------------------------" + "------------------------------\n"); + } +#endif + } /* printIteration */ + + //================================================================================================ + void solveProb::printFinal(int ioflag, doublereal damp, int label_d, int label_t, + doublereal inv_t, doublereal t_real, int iter, + doublereal update_norm, doublereal resid_norm, + doublereal netProdRateKinSpecies[], const doublereal CSolnSP[], + const doublereal resid[], + const doublereal wtSpecies[], const doublereal wtRes[], + int dim, bool do_time) + { + int i, k; + string nm; + if (ioflag == 1) { + + printf("\tFIN%3d ", iter); + if (do_time) + printf("%9.4e %9.4e ", t_real, 1.0/inv_t); + else + for (i = 0; i < 22; i++) printf(" "); + if (damp < 1.0) + printf("%9.4e ", damp); + else + for (i = 0; i < 11; i++) printf(" "); + printf("%9.4e %9.4e", update_norm, resid_norm); + if (do_time) { + k = label_t; + printf(" %d", k); + } else { + for (i = 0; i < 16; i++) printf(" "); + } + if (label_d >= 0) { + k = label_d; + + printf(" %d", k); + } + printf(" -- success\n"); + } +#ifdef DEBUG_SOLVEPROB + else if (ioflag > 1) { + + + printf("\n================================== FINAL RESULT =========" + "==================================================\n"); + + printf("\n Weighted norm of solution update = %10.4e\n", update_norm); + printf(" Weighted norm of residual update = %10.4e\n\n", resid_norm); + + printf(" Name Prod_Rate XMol Conc " + " wtConc Resid Resid/wtResid wtResid"); + if (damp < 1.0) printf(" UnDamped_Conc"); + printf("\n"); + printf("---------------------------------------------------------------" + "---------------------------------------------\n"); + + for (int k = 0; k < m_neq; k++, k++) { + printf("%-16s %10.3e %10.3e %10.3e %10.3e %10.3e %10.3e %10.3e", + nm.c_str(), + m_numEqn1[k], + XMolSolnSP[k], + CSolnSP[k], + wtSpecies[k], + resid[k], + resid[k]/wtRes[k], wtRes[k]); + if (damp < 1.0) { + printf("%10.4e ", CSolnSP[k]+(damp-1.0)*resid[k]); + if (label_d == k) printf(" Damp "); + } + if (label_t == k) printf(" Tctrl"); + printf("\n"); + } + + printf("\n"); + printf("===============================================================" + "============================================\n\n"); + } +#endif + } + //================================================================================================ +#ifdef DEBUG_SOLVEPROB + void solveProb:: + printIterationHeader(int ioflag, doublereal damp,doublereal inv_t, doublereal t_real, + int iter, bool do_time) + { + if (ioflag > 1) { + printf("\n===============================Iteration %5d " + "=================================\n", iter); + if (do_time) { + printf(" Transient step with: Real Time_n-1 = %10.4e sec,", t_real); + printf(" Time_n = %10.4e sec\n", t_real + 1.0/inv_t); + printf(" Delta t = %10.4e sec", 1.0/inv_t); + } else { + printf(" Steady Solve "); + } + if (damp < 1.0) { + printf(", Damping value = %10.4e\n", damp); + } else { + printf("\n"); + } + } + } +#endif + //================================================================================================ + void solveProb::setAtol(const doublereal atol[]) { + for (int k = 0; k < m_neq; k++, k++) { + m_atol[k] = atol[k]; + } + } + //================================================================================================ + void solveProb::setAtolConst(const doublereal atolconst) { + for (int k = 0; k < m_neq; k++, k++) { + m_atol[k] = atolconst; + } + } + //================================================================================================ + + +} diff --git a/Cantera/src/numerics/solveProb.h b/Cantera/src/numerics/solveProb.h new file mode 100644 index 000000000..999b700ae --- /dev/null +++ b/Cantera/src/numerics/solveProb.h @@ -0,0 +1,481 @@ +/** + * @file solveProb.h + * Header file for implicit nonlinear solver with the option of a pseudotransient + * (see \ref numerics and class \link Cantera::solveProb solveProb\endlink). + */ +/* + * $Id$ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract + * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government + * retains certain rights in this software. + * See file License.txt for licensing information. + */ + +#ifndef SOLVEPROB_H +#define SOLVEPROB_H +/** + * @defgroup solverGroup Solvers for Equation Systems + */ + + +#include +#include "Array.h" +#include "ResidEval.h" + +//! Solution Methods +/*! + * Flag to specify the solution method + * + * 1: SOLVEPROB_INITIALIZE = This assumes that the initial guess supplied to the + * routine is far from the correct one. Substantial + * work plus transient time-stepping is to be expected + * to find a solution. + * 2: SOLVEPROB_RESIDUAL = Need to solve the surface problem in order to + * calculate the surface fluxes of gas-phase species. + * (Can expect a moderate change in the solution + * vector -> try to solve the system by direct + * methods + * with no damping first -> then, try time-stepping + * if the first method fails) + * A "time_scale" supplied here is used in the + * algorithm to determine when to shut off + * time-stepping. + * 3: SOLVEPROB_JACOBIAN = Calculation of the surface problem is due to the + * need for a numerical jacobian for the gas-problem. + * The solution is expected to be very close to the + * initial guess, and accuracy is needed. + * 4: SOLVEPROB_TRANSIENT = The transient calculation is performed here for an + * amount of time specified by "time_scale". It is + * not garraunted to be time-accurate - just stable + * and fairly fast. The solution after del_t time is + * returned, whether it's converged to a steady + * state or not. + */ +const int SOLVEPROB_INITIALIZE = 1; +const int SOLVEPROB_RESIDUAL = 2; +const int SOLVEPROB_JACOBIAN = 3; +const int SOLVEPROB_TRANSIENT = 4; + + + + +namespace Cantera { + + + //! Method to solve a pseudo steady state of a nonlinear problem + /*! + * The following class handles the solution of a nonlinear problem. + * + * Res_ss(C) = - Res(C) = 0 + * + * Optionally a pseudo transient algorithm may be used to relax the residual if + * it is available. + * + * Res_td(C) = dC/dt - Res(C) = 0; + * + * Res_ss(C) is the steady state residual to be solved. Res_td(C) is the + * time dependent residual which leads to the steady state residual. + * + * + * Solution Method + * + * This routine is typically used within a residual calculation in a large code. + * It's typically invoked millions of times for large calculations, and it must + * work every time. Therefore, requirements demand that it be robust but also + * efficient. + * + * The solution methodology is largely determined by the ifunc<\TT> parameter, + * that is input to the solution object. This parameter may have the following + * 4 values: + * + * + * 1: SOLVEPROB_INITIALIZE = This assumes that the initial guess supplied to the + * routine is far from the correct one. Substantial + * work plus transient time-stepping is to be expected + * to find a solution. + * + * 2: SOLVEPROB_RESIDUAL = Need to solve the nonlinear problem in order to + * calculate quantities for a residual calculation + * (Can expect a moderate change in the solution + * vector -> try to solve the system by direct methods + * with no damping first -> then, try time-stepping + * if the first method fails) + * A "time_scale" supplied here is used in the + * algorithm to determine when to shut off + * time-stepping. + * + * 3: SOLVEPROB_JACOBIAN = Calculation of the surface problem is due to the + * need for a numerical jacobian for the gas-problem. + * The solution is expected to be very close to the + * initial guess, and extra accuracy is needed because + * solution variables have been delta'd from + * nominal values to create jacobian entries. + * + * 4: SOLVEPROB_TRANSIENT = The transient calculation is performed here for an + * amount of time specified by "time_scale". It is + * not garraunted to be time-accurate - just stable + * and fairly fast. The solution after del_t time is + * returned, whether it's converged to a steady + * state or not. This is a poor man's time stepping + * algorithm. + * + * Psuedo time stepping algorithm: + * The time step is determined from sdot[], so that the time step + * doesn't ever change the value of a variable by more than 100%. + * + * This algorithm does use a damped Newton's method to relax the equations. + * Damping is based on a "delta damping" technique. The solution unknowns + * are not allowed to vary too much between iterations. + * + * + * EXTRA_ACCURACY:A constant that is the ratio of the required update norm in + * this Newton iteration compared to that in the nonlinear solver. + * A value of 0.1 is used so surface species are safely overconverged. + * + * Functions called: + *---------------------------------------------------------------------------- + * + * ct_dgetrf -- First half of LAPACK direct solve of a full Matrix + * + * ct_dgetrs -- Second half of LAPACK direct solve of a full matrix. Returns + * solution vector in the right-hand-side vector, resid. + * + *---------------------------------------------------------------------------- + * + * @ingroup solverGroup + */ + class solveProb { + + public: + + //! Constructor for the object + /*! + * @param surfChemPtr Pointer to the ImplicitSurfChem object that + * defines the surface problem to be solved. + * + * @param bulkFunc Integer representing how the bulk phases + * should be handled. Currently, only the + * default value of BULK_ETCH is supported. + */ + solveProb(ResidEval* resid); + + //! Destructor. Deletes the integrator. + ~solveProb(); + + private: + + //! Unimplemented private copy constructor + solveProb(const solveProb &right); + + //! Unimplemented private assignment operator + solveProb& operator=(const solveProb &right); + + public: + + //! Main routine that actually calculates the pseudo steady state + //! of the surface problem + /*! + * The actual converged solution is returned as part of the + * internal state of the InterfaceKinetics objects. + * + * @param ifunc Determines the type of solution algorithm to be + * used. Possible values are SOLVEPROB_INITIALIZE , + * SOLVEPROB_RESIDUAL SOLVEPROB_JACOBIAN SOLVEPROB_TRANSIENT . + * + * @param time_scale Time over which to integrate the surface equations, + * where applicable + * + * @param reltol Relative tolerance to use + * + * @return Returns 1 if the surface problem is successfully solved. + * Returns -1 if the surface problem wasn't solved successfully. + * Note the actual converged solution is returned as part of the + * internal state of the InterfaceKinetics objects. + */ + int solve(int ifunc, doublereal time_scale, doublereal reltol); + + //! Report the current state of the solution + /*! + * @param Report the solution vector for the nonlinear problem + */ + virtual void reportState(doublereal * const CSoln) const; + + //! Set the bottom and top bounds on the solution vector + /*! + * The default is for the bottom is 0.0, while the default for the top is 1.0 + * + * @param botBounds Vector of bottom bounds + * @param topBounds vector of top bounds + */ + virtual void setBounds(const doublereal botBounds[], const doublereal topBounds[]); + + + void setAtol(const doublereal atol[]); + void setAtolConst(const doublereal atolconst); + + private: + + //! Printing routine that gets called at the start of every + //! invocation + virtual void print_header(int ioflag, int ifunc, doublereal time_scale, + doublereal reltol, + doublereal netProdRate[]); + +#ifdef DEBUG_SOLVEPROB + + virtual void printResJac(int ioflag, int neq, const Array2D &Jac, + doublereal resid[], doublereal wtResid[], doublereal norm); +#endif + + //! Printing routine that gets called after every iteration + virtual void printIteration(int ioflag, doublereal damp, int label_d, int label_t, + doublereal inv_t, doublereal t_real, int iter, + doublereal update_norm, doublereal resid_norm, + doublereal netProdRate[], doublereal CSolnSP[], + doublereal resid[], + doublereal wtSpecies[], int dim, bool do_time); + + + //! Print a summary of the solution + /*! + * + */ + virtual void printFinal(int ioflag, doublereal damp, int label_d, int label_t, + doublereal inv_t, doublereal t_real, int iter, + doublereal update_norm, doublereal resid_norm, + doublereal netProdRateKinSpecies[], const doublereal CSolnSP[], + const doublereal resid[], + const doublereal wtSpecies[], const doublereal wtRes[], + int dim, bool do_time); + + //! Calculate a conservative delta T to use in a pseudo-steady state + //! algorithm + /*! + * This routine calculates a pretty conservative 1/del_t based + * on MAX_i(sdot_i/(X_i*SDen0)). This probably guarantees + * diagonal dominance. + * + * Small surface fractions are allowed to intervene in the del_t + * determination, no matter how small. This may be changed. + * Now minimum changed to 1.0e-12, + * + * Maximum time step set to time_scale. + * + * @param netProdRateSolnSP Output variable. Net production rate + * of all of the species in the solution vector. + * @param XMolSolnSP output variable. + * Mole fraction of all of the species in the solution vector + * @param label Output variable. Pointer to the value of the + * species index (kindexSP) that is controlling + * the time step + * @param label_old Output variable. Pointer to the value of the + * species index (kindexSP) that controlled + * the time step at the previous iteration + * @param label_factor Output variable. Pointer to the current + * factor that is used to indicate the same species + * is controlling the time step. + * + * @param ioflag Level of the output requested. + * + * @return Returns the 1. / delta T to be used on the next step + */ + virtual doublereal calc_t(doublereal netProdRateSolnSP[], doublereal Csoln[], + int *label, int *label_old, + doublereal *label_factor, int ioflag); + + //! Calculate the solution and residual weights + /*! + * @param wtSpecies Weights to use for the soln unknowns. These + * are in concentration units + * @param wtResid Weights to sue for the residual unknowns. + * + * @param CSolnSP Solution vector for the surface problem + */ + virtual void calcWeights(doublereal wtSpecies[], doublereal wtResid[], + const doublereal CSolnSP[]); + +#ifdef DEBUG_SOLVEPROB + //! Utility routine to print a header for high lvls of debugging + /*! + * @param ioflag Lvl of debugging + * @param damp lvl of damping + * @param inv_t Inverse of the value of delta T + * @param t_real Value of the time + * @param iter Interation number + * @param do_time boolean indicating whether time stepping is taking + * place + */ + virtual void printIterationHeader(int ioflag, doublereal damp, + doublereal inv_t, doublereal t_real, int iter, + bool do_time); +#endif + + //! Main Function evalulation + /*! + * + * @param resid output Vector of residuals, length = m_neq + * @param CSolnSP Vector of species concentrations, unknowns in the + * problem, length = m_neq + * @param CSolnSPOld Old Vector of species concentrations, unknowns in the + * problem, length = m_neq + * @param do_time Calculate a time dependent residual + * @param deltaT Delta time for time dependent problem. + */ + virtual void fun_eval(doublereal* const resid, const doublereal * const CSolnSP, + const doublereal * const CSolnOldSP, const bool do_time, const doublereal deltaT); + + //! Main routine that calculates the current residual and Jacobian + /*! + * @param JacCol Vector of pointers to the tops of columns of the + * Jacobian to be evalulated. + * @param resid output Vector of residuals, length = m_neq + * @param CSolnSP Vector of species concentrations, unknowns in the + * problem, length = m_neq. These are tweaked in order + * to derive the columns of the jacobian. + * @param CSolnSPOld Old Vector of species concentrations, unknowns in the + * problem, length = m_neq + * @param do_time Calculate a time dependent residual + * @param deltaT Delta time for time dependent problem. + */ + virtual void resjac_eval(std::vector& JacCol, doublereal * resid, + doublereal *CSolnSP, + const doublereal *CSolnSPOld, const bool do_time, + const doublereal deltaT); + + //! This function calculates a damping factor for the Newton iteration update + //! vector, dxneg, to insure that all solution components stay within perscribed bounds + /*! + * The default for this class is that all solution components are bounded between zero and one. + * this is because the original unknowns were mole fractions and surface site fractions. + * + * dxneg[] = negative of the update vector. + * + * The constant "APPROACH" sets the fraction of the distance to the boundary + * that the step can take. If the full step would not force any fraction + * outside of the bounds, then Newton's method is mostly allowed to operate normally. + * There is also some solution damping employed. + * + * @param x Vector of the current solution components + * @param dxneg Vector of the negative of the full solution update vector. + * @param dim Size of the solution vector + * @param label return int, stating which solution component caused the most damping. + */ + virtual doublereal calc_damping(doublereal x[], doublereal dxneg[], int dim, int *label); + + //! residual function pointer to be solved. + ResidEval *m_residFunc; + + //! Total number of equations to solve in the implicit problem. + /*! + * Note, this can be zero, and frequently is + */ + int m_neq; + + //! m_atol is the absolute tolerance in real units. + vector_fp m_atol; + + //! m_rtol is the relative error tolerance. + doublereal m_rtol; + + //! maximum value of the time step + /*! + * units = seconds + */ + doublereal m_maxstep; + + //! Temporary vector with length MAX(1, m_neq) + vector_fp m_netProductionRatesSave; + + //! Temporary vector with length MAX(1, m_neq) + vector_fp m_numEqn1; + + //! Temporary vector with length MAX(1, m_neq) + vector_fp m_numEqn2; + + //! Temporary vector with length MAX(1, m_neq) + vector_fp m_CSolnSave; + + //! Solution vector + /*! + * length MAX(1, m_neq) + */ + vector_fp m_CSolnSP; + + //! Saved inital solution vector + /*! + * length MAX(1, m_neq) + */ + vector_fp m_CSolnSPInit; + + //! Saved solution vector at the old time step + /*! + * length MAX(1, m_neq) + */ + vector_fp m_CSolnSPOld; + + //! Weights for the residual norm calculation + /*! + * length MAX(1, m_neq) + */ + vector_fp m_wtResid; + + //! Weights for the species concentrations norm calculation + /*! + * length MAX(1, m_neq) + */ + vector_fp m_wtSpecies; + + //! Residual for the surface problem + /*! + * The residual vector of length "dim" that, that has the value + * of "sdot" for surface species. The residuals for the bulk + * species are a function of the sdots for all species in the bulk + * phase. The last residual of each phase enforces {Sum(fractions) + * = 1}. After linear solve (dgetrf_ & dgetrs_), resid holds the + * update vector. + * + * length MAX(1, m_neq) + */ + vector_fp m_resid; + + //! pivots + /*! + * length MAX(1, m_neq) + */ + vector_int m_ipiv; + + //! Vector of pointers to the top of the columns of the + //! jacobians + /*! + * The "dim" by "dim" computed Jacobian matrix for the + * local Newton's method. + */ + std::vector m_JacCol; + + //! Jacobian + /*! + * m_neq by m_neq computed Jacobian matrix for the + * local Newton's method. + */ + Array2D m_Jac; + + //! Top bounds for the solution vector + /*! + * This defaults to 1.0 + */ + vector_fp m_topBounds; + + //! Bottom bounds for the solution vector + /*! + * This defaults to 0.0 + */ + vector_fp m_botBounds; + + + public: + int m_ioflag; + }; +} +#endif diff --git a/Cantera/src/numerics/sort.cpp b/Cantera/src/numerics/sort.cpp old mode 100755 new mode 100644 diff --git a/Cantera/src/numerics/sort.h b/Cantera/src/numerics/sort.h old mode 100755 new mode 100644 diff --git a/Cantera/src/oneD/Domain1D.h b/Cantera/src/oneD/Domain1D.h index 4e309aaa8..256432431 100644 --- a/Cantera/src/oneD/Domain1D.h +++ b/Cantera/src/oneD/Domain1D.h @@ -21,501 +21,518 @@ namespace Cantera { - // domain types - const int cFlowType = 50; - const int cConnectorType = 100; - const int cSurfType = 102; - const int cInletType = 104; - const int cSymmType = 105; - const int cOutletType = 106; - const int cEmptyType = 107; - const int cOutletResType = 108; - const int cPorousType = 109; + // domain types + const int cFlowType = 50; + const int cConnectorType = 100; + const int cSurfType = 102; + const int cInletType = 104; + const int cSymmType = 105; + const int cOutletType = 106; + const int cEmptyType = 107; + const int cOutletResType = 108; + const int cPorousType = 109; - class MultiJac; - class OneDim; + class MultiJac; + class OneDim; + + + /** + * Base class for one-dimensional domains. + */ + class Domain1D { + public: + + /** + * Constructor. + * @param nv Number of variables at each grid point. + * @param points Number of grid points. + */ + Domain1D(int nv=1, int points=1, + doublereal time = 0.0) : + m_rdt(0.0), + m_time(time), + m_container(0), + m_index(-1), + m_type(0), + m_iloc(0), + m_jstart(0), + m_left(0), + m_right(0), + m_id(""), m_desc(""), + m_refiner(0), m_bw(-1) { + resize(nv, points); + } + + /// Destructor. Does nothing + virtual ~Domain1D(){ delete m_refiner; } + + /// Domain type flag. + const int domainType() { return m_type; } + + /** + * The left-to-right location of this domain. + */ + const int domainIndex() { return m_index; } + + /** + * True if the domain is a connector domain. + */ + bool isConnector() { return (m_type >= cConnectorType); } + + /** + * The container holding this domain. + */ + const OneDim& container() const { return *m_container; } + + /** + * Specify the container object for this domain, and the + * position of this domain in the list. + */ + void setContainer(OneDim* c, int index){ + m_container = c; + m_index = index; + } + + /* + * Set the Jacobian bandwidth. See the discussion of method bandwidth. + */ + void setBandwidth(int bw = -1) { + m_bw = bw; + } + + /** + * Set the Jacobian bandwith for this domain. When class + * OneDim computes the bandwidth of the overall multi-domain + * problem (in OneDim::resize()), it calls this method for the + * bandwidth of each domain. If setBandwidth has not been + * called, then a negative bandwidth is returned, in which + * case OneDim assumes that this domain is dense -- that is, + * at each point, all components depend on the value of all + * other components at that point. In this case, the bandwidth + * is bw = 2*nComponents() - 1. However, if this domain + * contains some components that are uncoupled from other + * components at the same point, then this default bandwidth + * may greatly overestimate the true bandwidth, with a + * substantial penalty in performance. For such domains, use + * method setBandwidth to specify the bandwidth before passing + * this domain to the Sim1D or OneDim constructor. + */ + int bandwidth() { return m_bw; } + + /** + * Initialize. This method is called by OneDim::init() for + * each domain once at the beginning of a simulation. Base + * class method does nothing, but may be overloaded. + */ + virtual void init(){ } + + virtual void setInitialState(doublereal* xlocal = 0){} + virtual void setState(int point, const doublereal* state, doublereal* x) {} + + /** + * Resize the domain to have nv components and np grid points. + * This method is virtual so that subclasses can perform other + * actions required to resize the domain. + */ + virtual void resize(int nv, int np) { + // if the number of components is being changed, then a + // new grid refiner is required. + if (nv != m_nv || !m_refiner) { + m_nv = nv; + delete m_refiner; + m_refiner = new Refiner(*this); + } + m_nv = nv; + m_td.resize(m_nv, 1); + m_name.resize(m_nv,""); + m_max.resize(m_nv, 0.0); + m_min.resize(m_nv, 0.0); + m_rtol_ss.resize(m_nv, 1.0e-8); + m_atol_ss.resize(m_nv, 1.0e-15); + m_rtol_ts.resize(m_nv, 1.0e-8); + m_atol_ts.resize(m_nv, 1.0e-15); + m_points = np; + m_z.resize(np, 0.0); + m_slast.resize(m_nv * m_points, 0.0); + locate(); + } + + /// Return a reference to the grid refiner. + Refiner& refiner() { return *m_refiner; } + + /// Number of components at each grid point. + int nComponents() const { return m_nv; } + + /// Number of grid points in this domain. + int nPoints() const { return m_points; } + + /// Name of the nth component. May be overloaded. + virtual std::string componentName(int n) const { + if (m_name[n] != "") return m_name[n]; + else return "component " + int2str(n); + } + + void setComponentName(int n, std::string name) { + m_name[n] = name; + } + + void setComponentType(int n, int ctype) { + if (ctype == 0) setAlgebraic(n); + } + + /// index of component with name \a name. + int componentIndex(std::string name) const { + int nc = nComponents(); + for (int n = 0; n < nc; n++) { + if (name == componentName(n)) return n; + } + throw CanteraError("Domain1D::componentIndex", + "no component named "+name); + } + + /** + * Set the lower and upper bounds for each solution component. + */ + void setBounds(int nl, const doublereal* lower, + int nu, const doublereal* upper) { + if (nl < m_nv || nu < m_nv) + throw CanteraError("Domain1D::setBounds", + "wrong array size for solution bounds. " + "Size should be at least "+int2str(m_nv)); + std::copy(upper, upper + m_nv, m_max.begin()); + std::copy(lower, lower + m_nv, m_min.begin()); + } + + void setBounds(int n, doublereal lower, doublereal upper) { + m_min[n] = lower; + m_max[n] = upper; + } + + /// set the error tolerances for all solution components. + void setTolerances(int nr, const doublereal* rtol, + int na, const doublereal* atol, int ts = 0); + + /// set the error tolerances for solution component \a n. + void setTolerances(int n, doublereal rtol, doublereal atol, int ts = 0); + + //added by Karl Meredith + /// set scalar error tolerances. All solution components will + /// have the same relative and absolute error tolerances. + void setTolerances(doublereal rtol, doublereal atol,int ts=0); + + //added by Karl Meredith + void setTolerancesTS(doublereal rtol, doublereal atol); + + //added by Karl Meredith + void setTolerancesSS(doublereal rtol, doublereal atol); + + /// Relative tolerance of the nth component. + doublereal rtol(int n) { return (m_rdt == 0.0 ? m_rtol_ss[n] : m_rtol_ts[n]); } + + /// Absolute tolerance of the nth component. + doublereal atol(int n) { return (m_rdt == 0.0 ? m_atol_ss[n] : m_atol_ts[n]); } + + /// Upper bound on the nth component. + doublereal upperBound(int n) const { return m_max[n]; } + + /// Lower bound on the nth component + doublereal lowerBound(int n) const { return m_min[n]; } /** - * Base class for one-dimensional domains. + * Prepare to do time stepping with time step dt. Copy the + * internally-stored solution at the last time step to array + * x0. */ - class Domain1D { - public: - - /** - * Constructor. - * @param nv Number of variables at each grid point. - * @param points Number of grid points. - */ - Domain1D(int nv=1, int points=1, - doublereal time = 0.0) : - m_rdt(0.0), - m_time(time), - m_container(0), - m_index(-1), - m_type(0), - m_iloc(0), - m_jstart(0), - m_left(0), - m_right(0), - m_id("-"), m_desc("-"), - m_refiner(0), m_bw(-1) { - resize(nv, points); - } - - /// Destructor. Does nothing - virtual ~Domain1D(){ delete m_refiner; } - - /// Domain type flag. - const int domainType() { return m_type; } - - /** - * The left-to-right location of this domain. - */ - const int domainIndex() { return m_index; } - - /** - * True if the domain is a connector domain. - */ - bool isConnector() { return (m_type >= cConnectorType); } - - /** - * The container holding this domain. - */ - const OneDim& container() const { return *m_container; } - - /** - * Specify the container object for this domain, and the - * position of this domain in the list. - */ - void setContainer(OneDim* c, int index){ - m_container = c; - m_index = index; - } - - /* - * Set the Jacobian bandwidth. See the discussion of method bandwidth. - */ - void setBandwidth(int bw = -1) { - m_bw = bw; - } - - /** - * Set the Jacobian bandwith for this domain. When class - * OneDim computes the bandwidth of the overall multi-domain - * problem (in OneDim::resize()), it calls this method for the - * bandwidth of each domain. If setBandwidth has not been - * called, then a negative bandwidth is returned, in which - * case OneDim assumes that this domain is dense -- that is, - * at each point, all components depend on the value of all - * other components at that point. In this case, the bandwidth - * is bw = 2*nComponents() - 1. However, if this domain - * contains some components that are uncoupled from other - * components at the same point, then this default bandwidth - * may greatly overestimate the true bandwidth, with a - * substantial penalty in performance. For such domains, use - * method setBandwidth to specify the bandwidth before passing - * this domain to the Sim1D or OneDim constructor. - */ - int bandwidth() { return m_bw; } - - /** - * Initialize. This method is called by OneDim::init() for - * each domain once at the beginning of a simulation. Base - * class method does nothing, but may be overloaded. - */ - virtual void init(){ } - - virtual void setInitialState(doublereal* xlocal = 0){} - virtual void setState(int point, const doublereal* state, doublereal* x) {} - - /** - * Resize the domain to have nv components and np grid points. - * This method is virtual so that subclasses can perform other - * actions required to resize the domain. - */ - virtual void resize(int nv, int np) { - // if the number of components is being changed, then a - // new grid refiner is required. - if (nv != m_nv || !m_refiner) { - m_nv = nv; - delete m_refiner; - m_refiner = new Refiner(*this); - } - m_nv = nv; - m_td.resize(m_nv, 1); - m_name.resize(m_nv,""); - m_max.resize(m_nv, 0.0); - m_min.resize(m_nv, 0.0); - m_rtol_ss.resize(m_nv, 1.0e-8); - m_atol_ss.resize(m_nv, 1.0e-15); - m_rtol_ts.resize(m_nv, 1.0e-8); - m_atol_ts.resize(m_nv, 1.0e-15); - m_points = np; - m_z.resize(np, 0.0); - m_slast.resize(m_nv * m_points, 0.0); - locate(); - } - - /// Return a reference to the grid refiner. - Refiner& refiner() { return *m_refiner; } - - /// Number of components at each grid point. - int nComponents() const { return m_nv; } - - /// Number of grid points in this domain. - int nPoints() const { return m_points; } - - /// Name of the nth component. May be overloaded. - virtual std::string componentName(int n) const { - if (m_name[n] != "") return m_name[n]; - else return "component " + int2str(n); - } - - void setComponentName(int n, std::string name) { - m_name[n] = name; - } - - void setComponentType(int n, int ctype) { - if (ctype == 0) setAlgebraic(n); - } - - /// index of component with name \a name. - int componentIndex(std::string name) const { - int nc = nComponents(); - for (int n = 0; n < nc; n++) { - if (name == componentName(n)) return n; - } - throw CanteraError("Domain1D::componentIndex", - "no component named "+name); - } - - /** - * Set the lower and upper bounds for each solution component. - */ - void setBounds(int nl, const doublereal* lower, - int nu, const doublereal* upper) { - if (nl < m_nv || nu < m_nv) - throw CanteraError("Domain1D::setBounds", - "wrong array size for solution bounds. " - "Size should be at least "+int2str(m_nv)); - std::copy(upper, upper + m_nv, m_max.begin()); - std::copy(lower, lower + m_nv, m_min.begin()); - } - - void setBounds(int n, doublereal lower, doublereal upper) { - m_min[n] = lower; - m_max[n] = upper; - } - - /// set the error tolerances for all solution components. - void setTolerances(int nr, const doublereal* rtol, - int na, const doublereal* atol, int ts = 0); - - /// set the error tolerances for solution component \a n. - void setTolerances(int n, doublereal rtol, doublereal atol, int ts = 0); - - //added by Karl Meredith - /// set scalar error tolerances. All solution components will - /// have the same relative and absolute error tolerances. - void setTolerances(doublereal rtol, doublereal atol,int ts=0); - - //added by Karl Meredith - void setTolerancesTS(doublereal rtol, doublereal atol); - - //added by Karl Meredith - void setTolerancesSS(doublereal rtol, doublereal atol); - - /// Relative tolerance of the nth component. - doublereal rtol(int n) { return (m_rdt == 0.0 ? m_rtol_ss[n] : m_rtol_ts[n]); } - - /// Absolute tolerance of the nth component. - doublereal atol(int n) { return (m_rdt == 0.0 ? m_atol_ss[n] : m_atol_ts[n]); } - - /// Upper bound on the nth component. - doublereal upperBound(int n) const { return m_max[n]; } - - /// Lower bound on the nth component - doublereal lowerBound(int n) const { return m_min[n]; } - - - /** - * Prepare to do time stepping with time step dt. Copy the - * internally-stored solution at the last time step to array - * x0. - */ - void initTimeInteg(doublereal dt, const doublereal* x0) { - std::copy(x0 + loc(), x0 + loc() + size(), m_slast.begin()); - m_rdt = 1.0/dt; - } - - /** - * Prepare to solve the steady-state problem. - * Set the internally-stored reciprocal of the time step to 0,0 - */ - void setSteadyMode() { m_rdt = 0.0; } - - /// True if in steady-state mode - bool steady() { return (m_rdt == 0.0); } - - /// True if not in steady-state mode - bool transient() { return (m_rdt != 0.0); } - - /** - * Set this if something has changed in the governing - * equations (e.g. the value of a constant has been changed, - * so that the last-computed Jacobian is no longer valid. - * Note: see file OneDim.cpp for the implementation of this method. - */ - void needJacUpdate(); - - /** - * Evaluate the steady-state residual at all points, even if in - * transient mode. Used only to print diagnostic output. - */ - void evalss(doublereal* x, doublereal* r, integer* mask) { - eval(-1,x,r,mask,0.0); - } - - //! Evaluate the residual function at point j. If j < 0, - //! evaluate the residual function at all points. - /*! - * @param j Grid point j - * @param x Soln vector. This is the input. - * @param r residual this is the output. - */ - virtual void eval(int j, doublereal* x, doublereal* r, - integer* mask, doublereal rdt=0.0); - - virtual doublereal residual(doublereal* x, int n, int j) { - throw CanteraError("Domain1D::residual","residual function must be overloaded in derived class "+id()); - } - - int timeDerivativeFlag(int n) { return m_td[n];} - void setAlgebraic(int n) { m_td[n] = 0; } - - /** - * Does nothing. - */ - virtual void update(doublereal* x) {} - - doublereal time() const { return m_time;} - void incrementTime(doublereal dt) { m_time += dt; } - size_t index(int n, int j) const { return m_nv*j + n; } - doublereal value(const doublereal* x, int n, int j) const { - return x[index(n,j)]; - } - - virtual void setJac(MultiJac* jac){} - virtual void save(XML_Node& o, doublereal* sol) { - throw CanteraError("Domain1D::save","base class method called"); - } - - int size() const { return m_nv*m_points; } - - /** - * Find the index of the first grid point in this domain, and - * the start of its variables in the global solution vector. - */ - void locate() { - - if (m_left) { - // there is a domain on the left, so the first grid point - // in this domain is one more than the last one on the left - m_jstart = m_left->lastPoint() + 1; - - // the starting location in the solution vector - m_iloc = m_left->loc() + m_left->size(); - } - else { - // this is the left-most domain - m_jstart = 0; - m_iloc = 0; - } - // if there is a domain to the right of this one, then - // repeat this for it - if (m_right) m_right->locate(); - } - - /** - * Location of the start of the local solution vector in the global - * solution vector, - */ - virtual int loc(int j = 0) const { return m_iloc; } - - /** - * The index of the first (i.e., left-most) grid point - * belonging to this domain. - */ - int firstPoint() const { return m_jstart; } - - /** - * The index of the last (i.e., right-most) grid point - * belonging to this domain. - */ - int lastPoint() const { return m_jstart + m_points - 1; } - - /** - * Set the left neighbor to domain 'left.' Method 'locate' is - * called to update the global positions of this domain and - * all those to its right. - */ - void linkLeft(Domain1D* left) { - m_left = left; - locate(); - } - - /** - * Set the right neighbor to domain 'right.' - */ - void linkRight(Domain1D* right) { m_right = right; } - - /** - * Append domain 'right' to this one, and update all links. - */ - void append(Domain1D* right) { - linkRight(right); - right->linkLeft(this); - } - - /** - * Return a pointer to the left neighbor. - */ - Domain1D* left() const { return m_left; } - - /** - * Return a pointer to the right neighbor. - */ - Domain1D* right() const { return m_right; } - - /** - * Value of component n at point j in the previous solution. - */ - double prevSoln(int n, int j) const { - return m_slast[m_nv*j + n]; - } - - /** - * Specify an identifying tag for this domain. - */ - void setID(const std::string& s) {m_id = s;} - - std::string id() { - if (m_id != "") return m_id; - else return std::string("domain ") + int2str(m_index); - } - - /** - * Specify descriptive text for this domain. - */ - void setDesc(const std::string& s) {m_desc = s;} - const std::string& desc() { return m_desc; } - - virtual void getTransientMask(integer* mask){} - - virtual void showSolution_s(std::ostream& s, const doublereal* x) {} - virtual void showSolution(const doublereal* x); - - virtual void restore(const XML_Node& dom, doublereal* soln) {} - - doublereal z(int jlocal) const { - return m_z[jlocal]; - } - doublereal zmin() const { return m_z[0]; } - doublereal zmax() const { return m_z[m_points - 1]; } - - - void setProfile(std::string name, doublereal* values, doublereal* soln) { - int n, j; - for (n = 0; n < m_nv; n++) { - if (name == componentName(n)) { - for (j = 0; j < m_points; j++) { - soln[index(n, j) + m_iloc] = values[j]; - } - return; - } - } - throw CanteraError("Domain1D::setProfile", - "unknown component: "+name); - } - - vector_fp& grid() { return m_z; } - const vector_fp& grid() const { return m_z; } - doublereal grid(int point) { return m_z[point]; } - - virtual void setupGrid(int n, const doublereal* z); - - void setGrid(int n, const doublereal* z); - - /** - * Writes some or all initial solution values into the global - * solution array, beginning at the location pointed to by - * x. This method is called by the Sim1D constructor, and - * allows default values or ones that have been set locally - * prior to installing this domain into the container to be - * written to the global solution vector. - */ - virtual void _getInitialSoln(doublereal* x); - - /** - * Initial value of solution component \a n at grid point \a j. - */ - virtual doublereal initialValue(int n, int j); - - /** - * In some cases, a domain may need to set parameters that - * depend on the initial solution estimate. In such cases, the - * parameters may be set in method _finalize. This method is - * called just before the Newton solver is called, and the x - * array is guaranteed to be the local solution vector for - * this domain that will be used as the initial guess. If no - * such parameters need to be set, then method _finalize does - * not need to be overloaded. - */ - virtual void _finalize(const doublereal* x) {} - - //added by Karl Meredith - doublereal m_zfixed; - doublereal m_tfixed; - - bool m_adiabatic; - - protected: - - doublereal m_rdt; - int m_nv; - int m_points; - vector_fp m_slast; - doublereal m_time; - vector_fp m_max; - vector_fp m_min; - vector_fp m_rtol_ss, m_rtol_ts; - vector_fp m_atol_ss, m_atol_ts; - vector_fp m_z; - OneDim* m_container; - int m_index; - int m_type; - - //! Starting location within the solution vector for unknowns - //! that correspond to this domain - /*! - * Remember there may be multiple domains associated with - * this problem - */ - int m_iloc; - - int m_jstart; - - Domain1D *m_left, *m_right; - std::string m_id, m_desc; - Refiner* m_refiner; - vector_int m_td; - std::vector m_name; - int m_bw; - - private: - - }; + void initTimeInteg(doublereal dt, const doublereal* x0) { + std::copy(x0 + loc(), x0 + loc() + size(), m_slast.begin()); + m_rdt = 1.0/dt; + } + + /** + * Prepare to solve the steady-state problem. + * Set the internally-stored reciprocal of the time step to 0,0 + */ + void setSteadyMode() { m_rdt = 0.0; } + + /// True if in steady-state mode + bool steady() { return (m_rdt == 0.0); } + + /// True if not in steady-state mode + bool transient() { return (m_rdt != 0.0); } + + /** + * Set this if something has changed in the governing + * equations (e.g. the value of a constant has been changed, + * so that the last-computed Jacobian is no longer valid. + * Note: see file OneDim.cpp for the implementation of this method. + */ + void needJacUpdate(); + + /** + * Evaluate the steady-state residual at all points, even if in + * transient mode. Used only to print diagnostic output. + */ + void evalss(doublereal* x, doublereal* r, integer* mask) { + eval(-1,x,r,mask,0.0); + } + + //! Evaluate the residual function at point j. If j < 0, + //! evaluate the residual function at all points. + /*! + * @param j Grid point j + * @param x Soln vector. This is the input. + * @param r residual this is the output. + */ + virtual void eval(int j, doublereal* x, doublereal* r, + integer* mask, doublereal rdt=0.0); + + virtual doublereal residual(doublereal* x, int n, int j) { + throw CanteraError("Domain1D::residual","residual function must be overloaded in derived class "+id()); + } + + int timeDerivativeFlag(int n) { return m_td[n];} + void setAlgebraic(int n) { m_td[n] = 0; } + + /** + * Does nothing. + */ + virtual void update(doublereal* x) {} + + doublereal time() const { return m_time;} + void incrementTime(doublereal dt) { m_time += dt; } + size_t index(int n, int j) const { return m_nv*j + n; } + doublereal value(const doublereal* x, int n, int j) const { + return x[index(n,j)]; + } + + virtual void setJac(MultiJac* jac){} + + //! Save the current solution for this domain into an XML_Node + /*! + * Base class version of the general domain1D save function. This + * base class version will throw an error condition. Inherited classes + * will know how to save the solution vector. + * + * @param o XML_Node to save the solution to. + * @param sol Current value of the solution vector. + * The object will pick out which part of the solution + * vector pertains to this object. + */ + virtual void save(XML_Node& o, const doublereal * const sol) { + throw CanteraError("Domain1D::save","base class method called"); + } + + int size() const { return m_nv*m_points; } + + /** + * Find the index of the first grid point in this domain, and + * the start of its variables in the global solution vector. + */ + void locate() { + + if (m_left) { + // there is a domain on the left, so the first grid point + // in this domain is one more than the last one on the left + m_jstart = m_left->lastPoint() + 1; + + // the starting location in the solution vector + m_iloc = m_left->loc() + m_left->size(); + } + else { + // this is the left-most domain + m_jstart = 0; + m_iloc = 0; + } + // if there is a domain to the right of this one, then + // repeat this for it + if (m_right) m_right->locate(); + } + + /** + * Location of the start of the local solution vector in the global + * solution vector, + */ + virtual int loc(int j = 0) const { return m_iloc; } + + /** + * The index of the first (i.e., left-most) grid point + * belonging to this domain. + */ + int firstPoint() const { return m_jstart; } + + /** + * The index of the last (i.e., right-most) grid point + * belonging to this domain. + */ + int lastPoint() const { return m_jstart + m_points - 1; } + + /** + * Set the left neighbor to domain 'left.' Method 'locate' is + * called to update the global positions of this domain and + * all those to its right. + */ + void linkLeft(Domain1D* left) { + m_left = left; + locate(); + } + + /** + * Set the right neighbor to domain 'right.' + */ + void linkRight(Domain1D* right) { m_right = right; } + + /** + * Append domain 'right' to this one, and update all links. + */ + void append(Domain1D* right) { + linkRight(right); + right->linkLeft(this); + } + + /** + * Return a pointer to the left neighbor. + */ + Domain1D* left() const { return m_left; } + + /** + * Return a pointer to the right neighbor. + */ + Domain1D* right() const { return m_right; } + + /** + * Value of component n at point j in the previous solution. + */ + double prevSoln(int n, int j) const { + return m_slast[m_nv*j + n]; + } + + /** + * Specify an identifying tag for this domain. + */ + void setID(const std::string& s) {m_id = s;} + + std::string id() const { + if (m_id != "") + return m_id; + else + return std::string("domain ") + int2str(m_index); + } + + /** + * Specify descriptive text for this domain. + */ + void setDesc(const std::string& s) {m_desc = s;} + const std::string& desc() { return m_desc; } + + virtual void getTransientMask(integer* mask){} + + virtual void showSolution_s(std::ostream& s, const doublereal* x) {} + virtual void showSolution(const doublereal* x); + + virtual void restore(const XML_Node& dom, doublereal* soln) {} + + doublereal z(int jlocal) const { + return m_z[jlocal]; + } + doublereal zmin() const { return m_z[0]; } + doublereal zmax() const { return m_z[m_points - 1]; } + + + void setProfile(std::string name, doublereal* values, doublereal* soln) { + int n, j; + for (n = 0; n < m_nv; n++) { + if (name == componentName(n)) { + for (j = 0; j < m_points; j++) { + soln[index(n, j) + m_iloc] = values[j]; + } + return; + } + } + throw CanteraError("Domain1D::setProfile", + "unknown component: "+name); + } + + vector_fp& grid() { return m_z; } + const vector_fp& grid() const { return m_z; } + doublereal grid(int point) { return m_z[point]; } + + virtual void setupGrid(int n, const doublereal* z); + + void setGrid(int n, const doublereal* z); + + /** + * Writes some or all initial solution values into the global + * solution array, beginning at the location pointed to by + * x. This method is called by the Sim1D constructor, and + * allows default values or ones that have been set locally + * prior to installing this domain into the container to be + * written to the global solution vector. + */ + virtual void _getInitialSoln(doublereal* x); + + /** + * Initial value of solution component \a n at grid point \a j. + */ + virtual doublereal initialValue(int n, int j); + + /** + * In some cases, a domain may need to set parameters that + * depend on the initial solution estimate. In such cases, the + * parameters may be set in method _finalize. This method is + * called just before the Newton solver is called, and the x + * array is guaranteed to be the local solution vector for + * this domain that will be used as the initial guess. If no + * such parameters need to be set, then method _finalize does + * not need to be overloaded. + */ + virtual void _finalize(const doublereal* x) {} + + //added by Karl Meredith + doublereal m_zfixed; + doublereal m_tfixed; + + bool m_adiabatic; + + protected: + + doublereal m_rdt; + int m_nv; + int m_points; + vector_fp m_slast; + doublereal m_time; + vector_fp m_max; + vector_fp m_min; + vector_fp m_rtol_ss, m_rtol_ts; + vector_fp m_atol_ss, m_atol_ts; + vector_fp m_z; + OneDim* m_container; + int m_index; + int m_type; + + //! Starting location within the solution vector for unknowns + //! that correspond to this domain + /*! + * Remember there may be multiple domains associated with + * this problem + */ + int m_iloc; + + int m_jstart; + + Domain1D *m_left, *m_right; + + //! Identity tag for the domain + std::string m_id; + std::string m_desc; + Refiner* m_refiner; + vector_int m_td; + std::vector m_name; + int m_bw; + + private: + + }; } #endif diff --git a/Cantera/src/oneD/Inlet1D.h b/Cantera/src/oneD/Inlet1D.h index 309a462a0..373aaafde 100644 --- a/Cantera/src/oneD/Inlet1D.h +++ b/Cantera/src/oneD/Inlet1D.h @@ -162,7 +162,7 @@ namespace Cantera { virtual void init(); virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); protected: @@ -196,7 +196,7 @@ namespace Cantera { virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); virtual void _finalize(const doublereal* x) {} virtual void _getInitialSoln(doublereal* x) { @@ -227,7 +227,7 @@ namespace Cantera { virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); virtual void _finalize(const doublereal* x) { ; //m_temp = x[0]; @@ -259,7 +259,7 @@ namespace Cantera { virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); virtual void _finalize(const doublereal* x) { ; //m_temp = x[0]; @@ -306,7 +306,7 @@ namespace Cantera { virtual void init(); virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); protected: @@ -340,7 +340,7 @@ namespace Cantera { virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); virtual void _getInitialSoln(doublereal* x) { @@ -400,7 +400,7 @@ namespace Cantera { virtual void eval(int jg, doublereal* xg, doublereal* rg, integer* diagg, doublereal rdt); - virtual void save(XML_Node& o, doublereal* soln); + virtual void save(XML_Node& o, const doublereal * const soln); virtual void restore(const XML_Node& dom, doublereal* soln); virtual void _getInitialSoln(doublereal* x) { diff --git a/Cantera/src/oneD/MultiNewton.cpp b/Cantera/src/oneD/MultiNewton.cpp index e85f4da54..1f79e125f 100644 --- a/Cantera/src/oneD/MultiNewton.cpp +++ b/Cantera/src/oneD/MultiNewton.cpp @@ -133,7 +133,7 @@ namespace Cantera { } #endif - iok = jac.solve(sz, step, step); + iok = jac.solve(step, step); // if iok is non-zero, then solve failed if (iok > 0) { diff --git a/Cantera/src/oneD/OneDim.cpp b/Cantera/src/oneD/OneDim.cpp index a54602ce2..545c68cb1 100644 --- a/Cantera/src/oneD/OneDim.cpp +++ b/Cantera/src/oneD/OneDim.cpp @@ -101,20 +101,26 @@ namespace Cantera { MultiJac& OneDim::jacobian() { return *m_jac; } MultiNewton& OneDim::newton() { return *m_newt; } - void OneDim::writeStats() { + //============================================================================================================== + void OneDim::writeStats(int printTime) { saveStats(); char buf[100]; sprintf(buf,"\nStatistics:\n\n Grid Functions Time Jacobians Time \n"); writelog(buf); int n = m_gridpts.size(); for (int i = 0; i < n; i++) { - sprintf(buf,"%5i %5i %9.4f %5i %9.4f \n", - m_gridpts[i], m_funcEvals[i], m_funcElapsed[i], - m_jacEvals[i], m_jacElapsed[i]); - writelog(buf); + if (printTime) { + sprintf(buf,"%5i %5i %9.4f %5i %9.4f \n", + m_gridpts[i], m_funcEvals[i], m_funcElapsed[i], + m_jacEvals[i], m_jacElapsed[i]); + } else { + sprintf(buf,"%5i %5i NA %5i NA \n", + m_gridpts[i], m_funcEvals[i], m_jacEvals[i]); + } + writelog(buf); } } - + //============================================================================================================== /** * Save statistics on function and Jacobiab evaulation, and reset diff --git a/Cantera/src/oneD/OneDim.h b/Cantera/src/oneD/OneDim.h index 3dfac1b15..bd199ec53 100644 --- a/Cantera/src/oneD/OneDim.h +++ b/Cantera/src/oneD/OneDim.h @@ -32,8 +32,8 @@ namespace Cantera { /// Add a domain. void addDomain(Domain1D* d); - /// Return a reference to the Jacobian evaluator. - MultiJac& jacobian(); + //! Return a reference to the Jacobian evaluator. + MultiJac& jacobian(); /// Return a reference to the Newton iterator. MultiNewton& newton(); @@ -137,7 +137,13 @@ namespace Cantera { double timeStep(int nsteps, double dt, double* x, double* r, int loglevel); - void writeStats(); + //! Write statistics about the number of iterations and Jacobians at each grid level + /*! + * @param printTime Boolean that indicates whether time should be printed out + * The default is true. It's turned off for test problems where + * we don't want to print any times + */ + void writeStats(int printTime = 1); void save(std::string fname, std::string id, std::string desc, doublereal* sol); @@ -167,7 +173,10 @@ namespace Cantera { MultiNewton* m_newt; // Newton iterator doublereal m_rdt; // reciprocal of time step bool m_jac_ok; // if true, Jacobian is current - int m_nd; // number of domains + + //! number of domains + int m_nd; + int m_bw; // Jacobian bandwidth int m_size; // solution vector size diff --git a/Cantera/src/oneD/Resid1D.h b/Cantera/src/oneD/Resid1D.h index 417f5a7b3..871d28dfa 100644 --- a/Cantera/src/oneD/Resid1D.h +++ b/Cantera/src/oneD/Resid1D.h @@ -223,7 +223,19 @@ namespace Cantera { } virtual void setJac(MultiJac* jac){} - virtual void save(XML_Node& o, doublereal* sol) { + + //! Save the current solution for this domain into an XML_Node + /*! + * Base class version of the general domain1D save function. This + * base class version will throw an error condition. Inherited classes + * will know how to save the solution vector. + * + * @param o XML_Node to save the solution to. + * @param sol Current value of the solution vector. + * The object will pick out which part of the solution + * vector pertains to this object. + */ + virtual void save(XML_Node& o, const doublereal * const sol) { throw CanteraError("Resid1D::save","base class method called"); } diff --git a/Cantera/src/oneD/Sim1D.cpp b/Cantera/src/oneD/Sim1D.cpp index d804a4564..921e0da72 100644 --- a/Cantera/src/oneD/Sim1D.cpp +++ b/Cantera/src/oneD/Sim1D.cpp @@ -22,12 +22,16 @@ namespace Cantera { s += '\n'; writelog(s.c_str()); } - - Sim1D::Sim1D() : OneDim() { + //==================================================================================================================== + Sim1D::Sim1D() : + OneDim() + { //writelog("Sim1D default constructor\n"); } - - Sim1D::Sim1D(vector& domains) : OneDim(domains) { + //==================================================================================================================== + Sim1D::Sim1D(vector& domains) : + OneDim(domains) + { // resize the internal solution vector and the wprk array, // and perform domain-specific initialization of the @@ -49,7 +53,7 @@ namespace Cantera { m_steps.push_back(10); } - + //==================================================================================================================== // added by Karl Meredith void Sim1D::setInitialGuess(string component, vector_fp& locs, vector_fp& vals){ diff --git a/Cantera/src/oneD/Sim1D.h b/Cantera/src/oneD/Sim1D.h index 8b50cc098..e3717e15b 100644 --- a/Cantera/src/oneD/Sim1D.h +++ b/Cantera/src/oneD/Sim1D.h @@ -23,13 +23,14 @@ namespace Cantera { public: - /** - * Default constructor. This constructor is provided to make - * the class default-constructible, but is not meant to be - * used in most applications. Use the next constructor - * instead. - */ - Sim1D(); + + //! Default constructor. + /*! + * This constructor is provided to make + * the class default-constructible, but is not meant to be + * used in most applications. Use the next constructor + */ + Sim1D(); /** diff --git a/Cantera/src/oneD/Solid1D.cpp b/Cantera/src/oneD/Solid1D.cpp index cfdb5d8a3..4f6be4b61 100644 --- a/Cantera/src/oneD/Solid1D.cpp +++ b/Cantera/src/oneD/Solid1D.cpp @@ -544,7 +544,7 @@ namespace Cantera { - void Solid1D::save(XML_Node& o, doublereal* sol) { + void Solid1D::save(XML_Node& o, const doublereal * const sol) { int k; ArrayViewer soln(m_nv, m_points, sol + loc()); diff --git a/Cantera/src/oneD/Solid1D.h b/Cantera/src/oneD/Solid1D.h index 3bb41f302..c0f32964f 100644 --- a/Cantera/src/oneD/Solid1D.h +++ b/Cantera/src/oneD/Solid1D.h @@ -197,7 +197,15 @@ namespace Cantera { virtual void showSolution(const doublereal* x); - virtual void save(XML_Node& o, doublereal* sol); + //! Save the current solution for this domain into an XML_Node + /*! + * + * @param o XML_Node to save the solution to. + * @param sol Current value of the solution vector. + * The object will pick out which part of the solution + * vector pertains to this object. + */ + virtual void save(XML_Node& o, const doublereal * const sol); virtual void restore(XML_Node& dom, doublereal* soln); diff --git a/Cantera/src/oneD/StFlow.cpp b/Cantera/src/oneD/StFlow.cpp index 5e12b9ef3..16d39d5c4 100644 --- a/Cantera/src/oneD/StFlow.cpp +++ b/Cantera/src/oneD/StFlow.cpp @@ -32,1170 +32,1170 @@ using namespace std; namespace Cantera { - //------------------- importSolution ------------------------ + //------------------- importSolution ------------------------ - /** - * Import a previous solution to use as an initial estimate. The - * previous solution may have been computed using a different - * reaction mechanism. Species in the old and new mechanisms are - * matched by name, and any species in the new mechanism that were - * not in the old one are set to zero. The new solution is created - * with the same number of grid points as in the old solution. - */ - void importSolution(int points, - doublereal* oldSoln, igthermo_t& oldmech, - int size_new, doublereal* newSoln, igthermo_t& newmech) { + /** + * Import a previous solution to use as an initial estimate. The + * previous solution may have been computed using a different + * reaction mechanism. Species in the old and new mechanisms are + * matched by name, and any species in the new mechanism that were + * not in the old one are set to zero. The new solution is created + * with the same number of grid points as in the old solution. + */ + void importSolution(int points, + doublereal* oldSoln, igthermo_t& oldmech, + int size_new, doublereal* newSoln, igthermo_t& newmech) { - // Number of components in old and new solutions - int nv_old = oldmech.nSpecies() + 4; - int nv_new = newmech.nSpecies() + 4; + // Number of components in old and new solutions + int nv_old = oldmech.nSpecies() + 4; + int nv_new = newmech.nSpecies() + 4; - if (size_new < nv_new*points) { - throw CanteraError("importSolution", - "new solution array must have length "+ - int2str(nv_new*points)); - } + if (size_new < nv_new*points) { + throw CanteraError("importSolution", + "new solution array must have length "+ + int2str(nv_new*points)); + } - int n, j, knew; - string nm; + int n, j, knew; + string nm; - // copy u,V,T,lambda - for (j = 0; j < points; j++) - for (n = 0; n < 4; n++) - newSoln[nv_new*j + n] = oldSoln[nv_old*j + n]; + // copy u,V,T,lambda + for (j = 0; j < points; j++) + for (n = 0; n < 4; n++) + newSoln[nv_new*j + n] = oldSoln[nv_old*j + n]; - // copy mass fractions - int nsp0 = oldmech.nSpecies(); - //int nsp1 = newmech.nSpecies(); + // copy mass fractions + int nsp0 = oldmech.nSpecies(); + //int nsp1 = newmech.nSpecies(); - // loop over the species in the old mechanism - for (int k = 0; k < nsp0; k++) { - nm = oldmech.speciesName(k); // name + // loop over the species in the old mechanism + for (int k = 0; k < nsp0; k++) { + nm = oldmech.speciesName(k); // name - // location of this species in the new mechanism. - // If < 0, then the species is not in the new mechanism. - knew = newmech.speciesIndex(nm); + // location of this species in the new mechanism. + // If < 0, then the species is not in the new mechanism. + knew = newmech.speciesIndex(nm); - // copy this species from the old to the new solution vectors - if (knew >= 0) { - for (j = 0; j < points; j++) { - newSoln[nv_new*j + 4 + knew] = oldSoln[nv_old*j + 4 + k]; - } - } - } - - - // normalize mass fractions - for (j = 0; j < points; j++) { - newmech.setMassFractions(&newSoln[nv_new*j + 4]); - newmech.getMassFractions(&newSoln[nv_new*j + 4]); - } + // copy this species from the old to the new solution vectors + if (knew >= 0) { + for (j = 0; j < points; j++) { + newSoln[nv_new*j + 4 + knew] = oldSoln[nv_old*j + 4 + k]; + } + } } - static void st_drawline() { - writelog("\n-------------------------------------" - "------------------------------------------"); + // normalize mass fractions + for (j = 0; j < points; j++) { + newmech.setMassFractions(&newSoln[nv_new*j + 4]); + newmech.getMassFractions(&newSoln[nv_new*j + 4]); + } + } + + + static void st_drawline() { + writelog("\n-------------------------------------" + "------------------------------------------"); + } + + StFlow::StFlow(igthermo_t* ph, int nsp, int points) : + Domain1D(nsp+4, points), + m_inlet_u(0.0), + m_inlet_V(0.0), + m_inlet_T(-1.0), + m_surface_T(-1.0), + m_press(-1.0), + m_nsp(nsp), + m_thermo(0), + m_kin(0), + m_trans(0), + m_jac(0), + m_ok(false), + m_do_soret(false), + m_transport_option(-1), + m_efctr(0.0) + { + m_type = cFlowType; + + m_points = points; + m_thermo = ph; + + if (ph == 0) return; // used to create a dummy object + + int nsp2 = m_thermo->nSpecies(); + if (nsp2 != m_nsp) { + m_nsp = nsp2; + Domain1D::resize(m_nsp+4, points); } - StFlow::StFlow(igthermo_t* ph, int nsp, int points) : - Domain1D(nsp+4, points), - m_inlet_u(0.0), - m_inlet_V(0.0), - m_inlet_T(-1.0), - m_surface_T(-1.0), - m_press(-1.0), - m_nsp(nsp), - m_thermo(0), - m_kin(0), - m_trans(0), - m_jac(0), - m_ok(false), - m_do_soret(false), - m_transport_option(-1), - m_efctr(0.0) - { - m_type = cFlowType; - m_points = points; - m_thermo = ph; + // make a local copy of the species molecular weight vector + m_wt = m_thermo->molecularWeights(); - if (ph == 0) return; // used to create a dummy object + // the species mass fractions are the last components in the solution + // vector, so the total number of components is the number of species + // plus the offset of the first mass fraction. + m_nv = c_offset_Y + m_nsp; - int nsp2 = m_thermo->nSpecies(); - if (nsp2 != m_nsp) { - m_nsp = nsp2; - Domain1D::resize(m_nsp+4, points); - } + // enable all species equations by default + m_do_species.resize(m_nsp, true); + + // but turn off the energy equation at all points + m_do_energy.resize(m_points,false); + + m_diff.resize(m_nsp*m_points); + m_multidiff.resize(m_nsp*m_nsp*m_points); + m_flux.resize(m_nsp,m_points); + m_wdot.resize(m_nsp,m_points, 0.0); + m_surfdot.resize(m_nsp, 0.0); + m_ybar.resize(m_nsp); - // make a local copy of the species molecular weight vector - m_wt = m_thermo->molecularWeights(); + //-------------- default solution bounds -------------------- - // the species mass fractions are the last components in the solution - // vector, so the total number of components is the number of species - // plus the offset of the first mass fraction. - m_nv = c_offset_Y + m_nsp; - - // enable all species equations by default - m_do_species.resize(m_nsp, true); - - // but turn off the energy equation at all points - m_do_energy.resize(m_points,false); - - m_diff.resize(m_nsp*m_points); - m_multidiff.resize(m_nsp*m_nsp*m_points); - m_flux.resize(m_nsp,m_points); - m_wdot.resize(m_nsp,m_points, 0.0); - m_surfdot.resize(m_nsp, 0.0); - m_ybar.resize(m_nsp); - - - //-------------- default solution bounds -------------------- - - vector_fp vmin(m_nv), vmax(m_nv); + vector_fp vmin(m_nv), vmax(m_nv); - // no bounds on u - vmin[0] = -1.e20; - vmax[0] = 1.e20; + // no bounds on u + vmin[0] = -1.e20; + vmax[0] = 1.e20; - // V - vmin[1] = -1.e20; - vmax[1] = 1.e20; + // V + vmin[1] = -1.e20; + vmax[1] = 1.e20; - // temperature bounds - vmin[2] = 200.0; - vmax[2]= 1.e9; + // temperature bounds + vmin[2] = 200.0; + vmax[2]= 1.e9; - // lamda should be negative - vmin[3] = -1.e20; - vmax[3] = 1.e20; + // lamda should be negative + vmin[3] = -1.e20; + vmax[3] = 1.e20; - // mass fraction bounds - int k; - for (k = 0; k < m_nsp; k++) { - vmin[4+k] = -1.0e-5; - vmax[4+k] = 1.0e5; - } - setBounds(vmin.size(), DATA_PTR(vmin), vmax.size(), DATA_PTR(vmax)); - - - //-------------------- default error tolerances ---------------- - vector_fp rtol(m_nv, 1.0e-8); - vector_fp atol(m_nv, 1.0e-15); - setTolerances(rtol.size(), DATA_PTR(rtol), atol.size(), DATA_PTR(atol),false); - setTolerances(rtol.size(), DATA_PTR(rtol), atol.size(), DATA_PTR(atol),true); - - //-------------------- grid refinement ------------------------- - m_refiner->setActive(0, false); - m_refiner->setActive(1, false); - m_refiner->setActive(2, false); - m_refiner->setActive(3, false); - - vector_fp gr; - for (int ng = 0; ng < m_points; ng++) gr.push_back(1.0*ng/m_points); - setupGrid(m_points, DATA_PTR(gr)); - setID("stagnation flow"); + // mass fraction bounds + int k; + for (k = 0; k < m_nsp; k++) { + vmin[4+k] = -1.0e-5; + vmax[4+k] = 1.0e5; } + setBounds(vmin.size(), DATA_PTR(vmin), vmax.size(), DATA_PTR(vmax)); - /** - * Change the grid size. Called after grid refinement. - */ - void StFlow::resize(int ncomponents, int points) { - Domain1D::resize(ncomponents, points); - m_rho.resize(m_points, 0.0); - m_wtm.resize(m_points, 0.0); - m_cp.resize(m_points, 0.0); - m_enth.resize(m_points, 0.0); - m_visc.resize(m_points, 0.0); - m_tcon.resize(m_points, 0.0); + //-------------------- default error tolerances ---------------- + vector_fp rtol(m_nv, 1.0e-8); + vector_fp atol(m_nv, 1.0e-15); + setTolerances(rtol.size(), DATA_PTR(rtol), atol.size(), DATA_PTR(atol),false); + setTolerances(rtol.size(), DATA_PTR(rtol), atol.size(), DATA_PTR(atol),true); - if (m_transport_option == c_Mixav_Transport) { - m_diff.resize(m_nsp*m_points); - } - else { - m_multidiff.resize(m_nsp*m_nsp*m_points); - m_diff.resize(m_nsp*m_points); - } - m_flux.resize(m_nsp,m_points); - m_wdot.resize(m_nsp,m_points, 0.0); - m_do_energy.resize(m_points,false); + //-------------------- grid refinement ------------------------- + m_refiner->setActive(0, false); + m_refiner->setActive(1, false); + m_refiner->setActive(2, false); + m_refiner->setActive(3, false); - m_fixedy.resize(m_nsp, m_points); - m_fixedtemp.resize(m_points); + vector_fp gr; + for (int ng = 0; ng < m_points; ng++) gr.push_back(1.0*ng/m_points); + setupGrid(m_points, DATA_PTR(gr)); + setID("stagnation flow"); + } - m_dz.resize(m_points-1); - m_z.resize(m_points); - } + + /** + * Change the grid size. Called after grid refinement. + */ + void StFlow::resize(int ncomponents, int points) { + Domain1D::resize(ncomponents, points); + m_rho.resize(m_points, 0.0); + m_wtm.resize(m_points, 0.0); + m_cp.resize(m_points, 0.0); + m_enth.resize(m_points, 0.0); + m_visc.resize(m_points, 0.0); + m_tcon.resize(m_points, 0.0); + + if (m_transport_option == c_Mixav_Transport) { + m_diff.resize(m_nsp*m_points); + } + else { + m_multidiff.resize(m_nsp*m_nsp*m_points); + m_diff.resize(m_nsp*m_points); + } + m_flux.resize(m_nsp,m_points); + m_wdot.resize(m_nsp,m_points, 0.0); + m_do_energy.resize(m_points,false); + + m_fixedy.resize(m_nsp, m_points); + m_fixedtemp.resize(m_points); + + m_dz.resize(m_points-1); + m_z.resize(m_points); + } - void StFlow::setupGrid(int n, const doublereal* z) { - resize(m_nv, n); - int j; + void StFlow::setupGrid(int n, const doublereal* z) { + resize(m_nv, n); + int j; - m_z[0] = z[0]; - for (j = 1; j < m_points; j++) { - m_z[j] = z[j]; - m_dz[j-1] = m_z[j] - m_z[j-1]; - } + m_z[0] = z[0]; + for (j = 1; j < m_points; j++) { + m_z[j] = z[j]; + m_dz[j-1] = m_z[j] - m_z[j-1]; } + } - /** - * Install a transport manager. - */ - void StFlow::setTransport(Transport& trans, bool withSoret) { - m_trans = &trans; - m_do_soret = withSoret; + /** + * Install a transport manager. + */ + void StFlow::setTransport(Transport& trans, bool withSoret) { + m_trans = &trans; + m_do_soret = withSoret; - if (m_trans->model() == cMulticomponent) { - m_transport_option = c_Multi_Transport; - m_multidiff.resize(m_nsp*m_nsp*m_points); - m_diff.resize(m_nsp*m_points); - m_dthermal.resize(m_nsp, m_points, 0.0); - } - else if (m_trans->model() == cMixtureAveraged) { - m_transport_option = c_Mixav_Transport; - m_diff.resize(m_nsp*m_points); - if (withSoret) - throw CanteraError("setTransport", - "Thermal diffusion (the Soret effect) " - "requires using a multicomponent transport model."); - } - else - throw CanteraError("setTransport","unknown transport model."); + if (m_trans->model() == cMulticomponent) { + m_transport_option = c_Multi_Transport; + m_multidiff.resize(m_nsp*m_nsp*m_points); + m_diff.resize(m_nsp*m_points); + m_dthermal.resize(m_nsp, m_points, 0.0); } - - void StFlow::enableSoret(bool withSoret) { - if (m_transport_option == c_Multi_Transport) - m_do_soret = withSoret; - else { - throw CanteraError("setTransport", - "Thermal diffusion (the Soret effect) " - "requires using a multicomponent transport model."); - } + else if (m_trans->model() == cMixtureAveraged) { + m_transport_option = c_Mixav_Transport; + m_diff.resize(m_nsp*m_points); + if (withSoret) + throw CanteraError("setTransport", + "Thermal diffusion (the Soret effect) " + "requires using a multicomponent transport model."); } + else + throw CanteraError("setTransport","unknown transport model."); + } - - /** - * Set the gas object state to be consistent with the solution at - * point j. - */ - void StFlow::setGas(const doublereal* x,int j) { - m_thermo->setTemperature(T(x,j)); - const doublereal* yy = x + m_nv*j + c_offset_Y; - m_thermo->setMassFractions_NoNorm(yy); - m_thermo->setPressure(m_press); + void StFlow::enableSoret(bool withSoret) { + if (m_transport_option == c_Multi_Transport) + m_do_soret = withSoret; + else { + throw CanteraError("setTransport", + "Thermal diffusion (the Soret effect) " + "requires using a multicomponent transport model."); } + } - /** - * Set the gas state to be consistent with the solution at the - * midpoint between j and j + 1. - */ - void StFlow::setGasAtMidpoint(const doublereal* x,int j) { - m_thermo->setTemperature(0.5*(T(x,j)+T(x,j+1))); - const doublereal* yyj = x + m_nv*j + c_offset_Y; - const doublereal* yyjp = x + m_nv*(j+1) + c_offset_Y; - for (int k = 0; k < m_nsp; k++) - m_ybar[k] = 0.5*(yyj[k] + yyjp[k]); - m_thermo->setMassFractions_NoNorm(DATA_PTR(m_ybar)); - m_thermo->setPressure(m_press); + /** + * Set the gas object state to be consistent with the solution at + * point j. + */ + void StFlow::setGas(const doublereal* x,int j) { + m_thermo->setTemperature(T(x,j)); + const doublereal* yy = x + m_nv*j + c_offset_Y; + m_thermo->setMassFractions_NoNorm(yy); + m_thermo->setPressure(m_press); + } + + + /** + * Set the gas state to be consistent with the solution at the + * midpoint between j and j + 1. + */ + void StFlow::setGasAtMidpoint(const doublereal* x,int j) { + m_thermo->setTemperature(0.5*(T(x,j)+T(x,j+1))); + const doublereal* yyj = x + m_nv*j + c_offset_Y; + const doublereal* yyjp = x + m_nv*(j+1) + c_offset_Y; + for (int k = 0; k < m_nsp; k++) + m_ybar[k] = 0.5*(yyj[k] + yyjp[k]); + m_thermo->setMassFractions_NoNorm(DATA_PTR(m_ybar)); + m_thermo->setPressure(m_press); + } + + + void StFlow::_finalize(const doublereal* x) { + int k, j; + doublereal zz, tt; + int nz = m_zfix.size(); + bool e = m_do_energy[0]; + for (j = 0; j < m_points; j++) { + if (e || nz == 0) + setTemperature(j, T(x, j)); + else { + zz = (z(j) - z(0))/(z(m_points - 1) - z(0)); + tt = linearInterp(zz, m_zfix, m_tfix); + setTemperature(j, tt); + } + for (k = 0; k < m_nsp; k++) { + setMassFraction(j, k, Y(x, k, j)); + } } + if (e) solveEnergyEqn(); + } - void StFlow::_finalize(const doublereal* x) { - int k, j; - doublereal zz, tt; - int nz = m_zfix.size(); - bool e = m_do_energy[0]; - for (j = 0; j < m_points; j++) { - if (e || nz == 0) - setTemperature(j, T(x, j)); - else { - zz = (z(j) - z(0))/(z(m_points - 1) - z(0)); - tt = linearInterp(zz, m_zfix, m_tfix); - setTemperature(j, tt); - } - for (k = 0; k < m_nsp; k++) { - setMassFraction(j, k, Y(x, k, j)); - } - } - if (e) solveEnergyEqn(); - } + //------------------------------------------------------ + /** + * Evaluate the residual function for axisymmetric stagnation + * flow. If jpt is less than zero, the residual function is + * evaluated at all grid points. If jpt >= 0, then the residual + * function is only evaluated at grid points jpt-1, jpt, and + * jpt+1. This option is used to efficiently evaluate the + * Jacobian numerically. + * + */ - //------------------------------------------------------ + void AxiStagnFlow::eval(int jg, doublereal* xg, + doublereal* rg, integer* diagg, doublereal rdt) { - /** - * Evaluate the residual function for axisymmetric stagnation - * flow. If jpt is less than zero, the residual function is - * evaluated at all grid points. If jpt >= 0, then the residual - * function is only evaluated at grid points jpt-1, jpt, and - * jpt+1. This option is used to efficiently evaluate the - * Jacobian numerically. - * - */ + // if evaluating a Jacobian, and the global point is outside + // the domain of influence for this domain, then skip + // evaluating the residual + if (jg >=0 && (jg < firstPoint() - 1 || jg > lastPoint() + 1)) return; - void AxiStagnFlow::eval(int jg, doublereal* xg, - doublereal* rg, integer* diagg, doublereal rdt) { + // if evaluating a Jacobian, compute the steady-state residual + if (jg >= 0) rdt = 0.0; - // if evaluating a Jacobian, and the global point is outside - // the domain of influence for this domain, then skip - // evaluating the residual - if (jg >=0 && (jg < firstPoint() - 1 || jg > lastPoint() + 1)) return; - - // if evaluating a Jacobian, compute the steady-state residual - if (jg >= 0) rdt = 0.0; - - // start of local part of global arrays - doublereal* x = xg + loc(); - doublereal* rsd = rg + loc(); - integer* diag = diagg + loc(); + // start of local part of global arrays + doublereal* x = xg + loc(); + doublereal* rsd = rg + loc(); + integer* diag = diagg + loc(); - int jmin, jmax, jpt; - jpt = jg - firstPoint(); + int jmin, jmax, jpt; + jpt = jg - firstPoint(); - if (jg < 0) { // evaluate all points - jmin = 0; - jmax = m_points - 1; - } - else { // evaluate points for Jacobian - jmin = max(jpt-1, 0); - jmax = min(jpt+1,m_points-1); - } + if (jg < 0) { // evaluate all points + jmin = 0; + jmax = m_points - 1; + } + else { // evaluate points for Jacobian + jmin = max(jpt-1, 0); + jmax = min(jpt+1,m_points-1); + } - // properties are computed for grid points from j0 to j1 - int j0 = max(jmin-1,0); - int j1 = min(jmax+1,m_points-1); + // properties are computed for grid points from j0 to j1 + int j0 = max(jmin-1,0); + int j1 = min(jmax+1,m_points-1); - int j, k; + int j, k; - //----------------------------------------------------- - // update properties - //----------------------------------------------------- + //----------------------------------------------------- + // update properties + //----------------------------------------------------- - // update thermodynamic properties only if a Jacobian is not - // being evaluated - if (jpt < 0) { //if (jpt < 0 || (m_transport_option == c_Multi_Transport)) { - updateThermo(x, j0, j1); + // update thermodynamic properties only if a Jacobian is not + // being evaluated + if (jpt < 0) { //if (jpt < 0 || (m_transport_option == c_Multi_Transport)) { + updateThermo(x, j0, j1); - // update transport properties only if a Jacobian is not being - // evaluated - updateTransport(x, j0, j1); - } + // update transport properties only if a Jacobian is not being + // evaluated + updateTransport(x, j0, j1); + } - // update the species diffusive mass fluxes whether or not a - // Jacobian is being evaluated - updateDiffFluxes(x, j0, j1); + // update the species diffusive mass fluxes whether or not a + // Jacobian is being evaluated + updateDiffFluxes(x, j0, j1); - //---------------------------------------------------- - // evaluate the residual equations at all required - // grid points - //---------------------------------------------------- + //---------------------------------------------------- + // evaluate the residual equations at all required + // grid points + //---------------------------------------------------- - doublereal sum, sum2, dtdzj; + doublereal sum, sum2, dtdzj; - for (j = jmin; j <= jmax; j++) { + for (j = jmin; j <= jmax; j++) { - //---------------------------------------------- - // left boundary - //---------------------------------------------- + //---------------------------------------------- + // left boundary + //---------------------------------------------- - if (j == 0) { + if (j == 0) { - // these may be modified by a boundary object + // these may be modified by a boundary object - // Continuity. This propagates information right-to-left, - // since rho_u at point 0 is dependent on rho_u at point 1, - // but not on mdot from the inlet. - rsd[index(c_offset_U,0)] = - -(rho_u(x,1) - rho_u(x,0))/m_dz[0] - -(density(1)*V(x,1) + density(0)*V(x,0)); + // Continuity. This propagates information right-to-left, + // since rho_u at point 0 is dependent on rho_u at point 1, + // but not on mdot from the inlet. + rsd[index(c_offset_U,0)] = + -(rho_u(x,1) - rho_u(x,0))/m_dz[0] + -(density(1)*V(x,1) + density(0)*V(x,0)); - // the inlet (or other) object connected to this one - // will modify these equations by subtracting its values - // for V, T, and mdot. As a result, these residual equations - // will force the solution variables to the values for - // the boundary object - rsd[index(c_offset_V,0)] = V(x,0); - rsd[index(c_offset_T,0)] = T(x,0); - rsd[index(c_offset_L,0)] = -rho_u(x,0); + // the inlet (or other) object connected to this one + // will modify these equations by subtracting its values + // for V, T, and mdot. As a result, these residual equations + // will force the solution variables to the values for + // the boundary object + rsd[index(c_offset_V,0)] = V(x,0); + rsd[index(c_offset_T,0)] = T(x,0); + rsd[index(c_offset_L,0)] = -rho_u(x,0); - // The default boundary condition for species is zero - // flux. However, the boundary object may modify - // this. - sum = 0.0; - for (k = 0; k < m_nsp; k++) { - sum += Y(x,k,0); - rsd[index(c_offset_Y + k, 0)] = - -(m_flux(k,0) + rho_u(x,0)* Y(x,k,0)); - } - rsd[index(c_offset_Y, 0)] = 1.0 - sum; - } + // The default boundary condition for species is zero + // flux. However, the boundary object may modify + // this. + sum = 0.0; + for (k = 0; k < m_nsp; k++) { + sum += Y(x,k,0); + rsd[index(c_offset_Y + k, 0)] = + -(m_flux(k,0) + rho_u(x,0)* Y(x,k,0)); + } + rsd[index(c_offset_Y, 0)] = 1.0 - sum; + } - //---------------------------------------------- - // - // right boundary - // - //---------------------------------------------- + //---------------------------------------------- + // + // right boundary + // + //---------------------------------------------- - else if (j == m_points - 1) { + else if (j == m_points - 1) { - // the boundary object connected to the right of this - // one may modify or replace these equations. The - // default boundary conditions are zero u, V, and T, - // and zero diffusive flux for all species. + // the boundary object connected to the right of this + // one may modify or replace these equations. The + // default boundary conditions are zero u, V, and T, + // and zero diffusive flux for all species. - rsd[index(0,j)] = rho_u(x,j); - rsd[index(1,j)] = V(x,j); - rsd[index(2,j)] = T(x,j); - rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); - diag[index(c_offset_L, j)] = 0; - doublereal sum = 0.0; - for (k = 0; k < m_nsp; k++) { - sum += Y(x,k,j); - rsd[index(k+4,j)] = m_flux(k,j-1) + rho_u(x,j)*Y(x,k,j); - } - rsd[index(4,j)] = 1.0 - sum; - diag[index(4,j)] = 0; + rsd[index(0,j)] = rho_u(x,j); + rsd[index(1,j)] = V(x,j); + rsd[index(2,j)] = T(x,j); + rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); + diag[index(c_offset_L, j)] = 0; + doublereal sum = 0.0; + for (k = 0; k < m_nsp; k++) { + sum += Y(x,k,j); + rsd[index(k+4,j)] = m_flux(k,j-1) + rho_u(x,j)*Y(x,k,j); + } + rsd[index(4,j)] = 1.0 - sum; + diag[index(4,j)] = 0; - } + } - //------------------------------------------ - // interior points - //------------------------------------------ + //------------------------------------------ + // interior points + //------------------------------------------ - else { + else { - //---------------------------------------------- - // Continuity equation - // - // Note that this propagates the mass flow rate - // information to the left (j+1 -> j) from the - // value specified at the right boundary. The - // lambda information propagates in the opposite - // direction. - // - // d(\rho u)/dz + 2\rho V = 0 - // - //------------------------------------------------ + //---------------------------------------------- + // Continuity equation + // + // Note that this propagates the mass flow rate + // information to the left (j+1 -> j) from the + // value specified at the right boundary. The + // lambda information propagates in the opposite + // direction. + // + // d(\rho u)/dz + 2\rho V = 0 + // + //------------------------------------------------ - rsd[index(c_offset_U,j)] = - -(rho_u(x,j+1) - rho_u(x,j))/m_dz[j] - -(density(j+1)*V(x,j+1) + density(j)*V(x,j)); + rsd[index(c_offset_U,j)] = + -(rho_u(x,j+1) - rho_u(x,j))/m_dz[j] + -(density(j+1)*V(x,j+1) + density(j)*V(x,j)); - //algebraic constraint - diag[index(c_offset_U, j)] = 0; + //algebraic constraint + diag[index(c_offset_U, j)] = 0; - //------------------------------------------------ - // Radial momentum equation - // - // \rho u dV/dz + \rho V^2 = d(\mu dV/dz)/dz - lambda - // - //------------------------------------------------- - rsd[index(c_offset_V,j)] - = (shear(x,j) - lambda(x,j) - rho_u(x,j)*dVdz(x,j) - - m_rho[j]*V(x,j)*V(x,j))/m_rho[j] - - rdt*(V(x,j) - V_prev(j)); - diag[index(c_offset_V, j)] = 1; + //------------------------------------------------ + // Radial momentum equation + // + // \rho u dV/dz + \rho V^2 = d(\mu dV/dz)/dz - lambda + // + //------------------------------------------------- + rsd[index(c_offset_V,j)] + = (shear(x,j) - lambda(x,j) - rho_u(x,j)*dVdz(x,j) + - m_rho[j]*V(x,j)*V(x,j))/m_rho[j] + - rdt*(V(x,j) - V_prev(j)); + diag[index(c_offset_V, j)] = 1; - //------------------------------------------------- - // Species equations - // - // \rho u dY_k/dz + dJ_k/dz + M_k\omega_k - // - //------------------------------------------------- - getWdot(x,j); + //------------------------------------------------- + // Species equations + // + // \rho u dY_k/dz + dJ_k/dz + M_k\omega_k + // + //------------------------------------------------- + getWdot(x,j); - doublereal convec, diffus; - for (k = 0; k < m_nsp; k++) { - convec = rho_u(x,j)*dYdz(x,k,j); - diffus = 2.0*(m_flux(k,j) - m_flux(k,j-1)) - /(z(j+1) - z(j-1)); - rsd[index(c_offset_Y + k, j)] - = (m_wt[k]*(wdot(k,j) ) - - convec - diffus)/m_rho[j] - - rdt*(Y(x,k,j) - Y_prev(k,j)); - diag[index(c_offset_Y + k, j)] = 1; - } + doublereal convec, diffus; + for (k = 0; k < m_nsp; k++) { + convec = rho_u(x,j)*dYdz(x,k,j); + diffus = 2.0*(m_flux(k,j) - m_flux(k,j-1)) + /(z(j+1) - z(j-1)); + rsd[index(c_offset_Y + k, j)] + = (m_wt[k]*(wdot(k,j) ) + - convec - diffus)/m_rho[j] + - rdt*(Y(x,k,j) - Y_prev(k,j)); + diag[index(c_offset_Y + k, j)] = 1; + } - //----------------------------------------------- - // energy equation - //----------------------------------------------- + //----------------------------------------------- + // energy equation + //----------------------------------------------- - if (m_do_energy[j]) { + if (m_do_energy[j]) { - setGas(x,j); + setGas(x,j); - // heat release term - const vector_fp& h_RT = m_thermo->enthalpy_RT_ref(); - const vector_fp& cp_R = m_thermo->cp_R_ref(); + // heat release term + const vector_fp& h_RT = m_thermo->enthalpy_RT_ref(); + const vector_fp& cp_R = m_thermo->cp_R_ref(); - sum = 0.0; - sum2 = 0.0; - doublereal flxk; - for (k = 0; k < m_nsp; k++) { - flxk = 0.5*(m_flux(k,j-1) + m_flux(k,j)); - sum += wdot(k,j)*h_RT[k]; - sum2 += flxk*cp_R[k]/m_wt[k]; - } - sum *= GasConstant * T(x,j); - dtdzj = dTdz(x,j); - sum2 *= GasConstant * dtdzj; + sum = 0.0; + sum2 = 0.0; + doublereal flxk; + for (k = 0; k < m_nsp; k++) { + flxk = 0.5*(m_flux(k,j-1) + m_flux(k,j)); + sum += wdot(k,j)*h_RT[k]; + sum2 += flxk*cp_R[k]/m_wt[k]; + } + sum *= GasConstant * T(x,j); + dtdzj = dTdz(x,j); + sum2 *= GasConstant * dtdzj; - rsd[index(c_offset_T, j)] = - - m_cp[j]*rho_u(x,j)*dtdzj - - divHeatFlux(x,j) - sum - sum2; - rsd[index(c_offset_T, j)] /= (m_rho[j]*m_cp[j]); + rsd[index(c_offset_T, j)] = + - m_cp[j]*rho_u(x,j)*dtdzj + - divHeatFlux(x,j) - sum - sum2; + rsd[index(c_offset_T, j)] /= (m_rho[j]*m_cp[j]); - rsd[index(c_offset_T, j)] = - rsd[index(c_offset_T, j)] + m_efctr*(T_fixed(j) - T(x,j)); + rsd[index(c_offset_T, j)] = + rsd[index(c_offset_T, j)] + m_efctr*(T_fixed(j) - T(x,j)); - rsd[index(c_offset_T, j)] -= rdt*(T(x,j) - T_prev(j)); - diag[index(c_offset_T, j)] = 1; - } + rsd[index(c_offset_T, j)] -= rdt*(T(x,j) - T_prev(j)); + diag[index(c_offset_T, j)] = 1; + } - // residual equations if the energy equation is disabled + // residual equations if the energy equation is disabled - if (!m_do_energy[j]) { - rsd[index(c_offset_T, j)] = T(x,j) - T_fixed(j); - diag[index(c_offset_T, j)] = 0; - } + if (!m_do_energy[j]) { + rsd[index(c_offset_T, j)] = T(x,j) - T_fixed(j); + diag[index(c_offset_T, j)] = 0; + } - rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); - diag[index(c_offset_L, j)] = 0; - } - } + rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); + diag[index(c_offset_L, j)] = 0; + } } + } - /** - * Update the transport properties at grid points in the range - * from j0 to j1, based on solution x. - */ - void StFlow::updateTransport(doublereal* x,int j0, int j1) { - int j,k,m; + /** + * Update the transport properties at grid points in the range + * from j0 to j1, based on solution x. + */ + void StFlow::updateTransport(doublereal* x,int j0, int j1) { + int j,k,m; - if (m_transport_option == c_Mixav_Transport) { - for (j = j0; j < j1; j++) { - setGasAtMidpoint(x,j); - m_visc[j] = (m_dovisc ? m_trans->viscosity() : 0.0); - m_trans->getMixDiffCoeffs(DATA_PTR(m_diff) + j*m_nsp); - m_tcon[j] = m_trans->thermalConductivity(); - } - } - else if (m_transport_option == c_Multi_Transport) { - doublereal sum, sumx, wtm, dz; - doublereal eps = 1.0e-12; - for (m = j0; m < j1; m++) { - setGasAtMidpoint(x,m); - dz = m_z[m+1] - m_z[m]; - wtm = m_thermo->meanMolecularWeight(); - - m_visc[m] = (m_dovisc ? m_trans->viscosity() : 0.0); - - m_trans->getMultiDiffCoeffs(m_nsp, - DATA_PTR(m_multidiff) + mindex(0,0,m)); - - for (k = 0; k < m_nsp; k++) { - sum = 0.0; - sumx = 0.0; - for (j = 0; j < m_nsp; j++) { - if (j != k) { - sum += m_wt[j]*m_multidiff[mindex(k,j,m)]* - ((X(x,j,m+1) - X(x,j,m))/dz + eps); - sumx += (X(x,j,m+1) - X(x,j,m))/dz; - } - } - m_diff[k + m*m_nsp] = sum/(wtm*(sumx+eps)); - } - - m_tcon[m] = m_trans->thermalConductivity(); - if (m_do_soret) { - m_trans->getThermalDiffCoeffs(m_dthermal.ptrColumn(0) + m*m_nsp); - } - } - } + if (m_transport_option == c_Mixav_Transport) { + for (j = j0; j < j1; j++) { + setGasAtMidpoint(x,j); + m_visc[j] = (m_dovisc ? m_trans->viscosity() : 0.0); + m_trans->getMixDiffCoeffs(DATA_PTR(m_diff) + j*m_nsp); + m_tcon[j] = m_trans->thermalConductivity(); + } } + else if (m_transport_option == c_Multi_Transport) { + doublereal sum, sumx, wtm, dz; + doublereal eps = 1.0e-12; + for (m = j0; m < j1; m++) { + setGasAtMidpoint(x,m); + dz = m_z[m+1] - m_z[m]; + wtm = m_thermo->meanMolecularWeight(); + + m_visc[m] = (m_dovisc ? m_trans->viscosity() : 0.0); + + m_trans->getMultiDiffCoeffs(m_nsp, + DATA_PTR(m_multidiff) + mindex(0,0,m)); + + for (k = 0; k < m_nsp; k++) { + sum = 0.0; + sumx = 0.0; + for (j = 0; j < m_nsp; j++) { + if (j != k) { + sum += m_wt[j]*m_multidiff[mindex(k,j,m)]* + ((X(x,j,m+1) - X(x,j,m))/dz + eps); + sumx += (X(x,j,m+1) - X(x,j,m))/dz; + } + } + m_diff[k + m*m_nsp] = sum/(wtm*(sumx+eps)); + } + + m_tcon[m] = m_trans->thermalConductivity(); + if (m_do_soret) { + m_trans->getThermalDiffCoeffs(m_dthermal.ptrColumn(0) + m*m_nsp); + } + } + } + } - //------------------------------------------------------ + //------------------------------------------------------ - /** - * Evaluate the residual function for axisymmetric stagnation - * flow. If jpt is less than zero, the residual function is - * evaluated at all grid points. If jpt >= 0, then the residual - * function is only evaluated at grid points jpt-1, jpt, and - * jpt+1. This option is used to efficiently evaluate the - * Jacobian numerically. - * - */ + /** + * Evaluate the residual function for axisymmetric stagnation + * flow. If jpt is less than zero, the residual function is + * evaluated at all grid points. If jpt >= 0, then the residual + * function is only evaluated at grid points jpt-1, jpt, and + * jpt+1. This option is used to efficiently evaluate the + * Jacobian numerically. + * + */ - void FreeFlame::eval(int jg, doublereal* xg, - doublereal* rg, integer* diagg, doublereal rdt) { + void FreeFlame::eval(int jg, doublereal* xg, + doublereal* rg, integer* diagg, doublereal rdt) { - // if evaluating a Jacobian, and the global point is outside - // the domain of influence for this domain, then skip - // evaluating the residual - if (jg >=0 && (jg < firstPoint() - 1 || jg > lastPoint() + 1)) return; + // if evaluating a Jacobian, and the global point is outside + // the domain of influence for this domain, then skip + // evaluating the residual + if (jg >=0 && (jg < firstPoint() - 1 || jg > lastPoint() + 1)) return; - // if evaluating a Jacobian, compute the steady-state residual - if (jg >= 0) rdt = 0.0; + // if evaluating a Jacobian, compute the steady-state residual + if (jg >= 0) rdt = 0.0; - // start of local part of global arrays - doublereal* x = xg + loc(); - doublereal* rsd = rg + loc(); - integer* diag = diagg + loc(); + // start of local part of global arrays + doublereal* x = xg + loc(); + doublereal* rsd = rg + loc(); + integer* diag = diagg + loc(); - int jmin, jmax, jpt; - jpt = jg - firstPoint(); + int jmin, jmax, jpt; + jpt = jg - firstPoint(); - if (jg < 0) { // evaluate all points - jmin = 0; - jmax = m_points - 1; - } - else { // evaluate points for Jacobian - jmin = max(jpt-1, 0); - jmax = min(jpt+1,m_points-1); - } + if (jg < 0) { // evaluate all points + jmin = 0; + jmax = m_points - 1; + } + else { // evaluate points for Jacobian + jmin = max(jpt-1, 0); + jmax = min(jpt+1,m_points-1); + } - // properties are computed for grid points from j0 to j1 - int j0 = max(jmin-1,0); - int j1 = min(jmax+1,m_points-1); + // properties are computed for grid points from j0 to j1 + int j0 = max(jmin-1,0); + int j1 = min(jmax+1,m_points-1); - int j, k; + int j, k; - //----------------------------------------------------- - // update properties - //----------------------------------------------------- + //----------------------------------------------------- + // update properties + //----------------------------------------------------- - // update thermodynamic properties only if a Jacobian is not - // being evaluated - if (jpt < 0) { - updateThermo(x, j0, j1); - updateTransport(x, j0, j1); - } + // update thermodynamic properties only if a Jacobian is not + // being evaluated + if (jpt < 0) { + updateThermo(x, j0, j1); + updateTransport(x, j0, j1); + } - // update the species diffusive mass fluxes whether or not a - // Jacobian is being evaluated - updateDiffFluxes(x, j0, j1); + // update the species diffusive mass fluxes whether or not a + // Jacobian is being evaluated + updateDiffFluxes(x, j0, j1); - //---------------------------------------------------- - // evaluate the residual equations at all required - // grid points - //---------------------------------------------------- + //---------------------------------------------------- + // evaluate the residual equations at all required + // grid points + //---------------------------------------------------- - doublereal sum, sum2, dtdzj; + doublereal sum, sum2, dtdzj; - for (j = jmin; j <= jmax; j++) { + for (j = jmin; j <= jmax; j++) { - //---------------------------------------------- - // left boundary - //---------------------------------------------- + //---------------------------------------------- + // left boundary + //---------------------------------------------- - if (j == 0) { + if (j == 0) { - // these may be modified by a boundary object + // these may be modified by a boundary object - // Continuity. This propagates information right-to-left, - // since rho_u at point 0 is dependent on rho_u at point 1, - // but not on mdot from the inlet. - rsd[index(c_offset_U,0)] = - -(rho_u(x,1) - rho_u(x,0))/m_dz[0] - -(density(1)*V(x,1) + density(0)*V(x,0)); + // Continuity. This propagates information right-to-left, + // since rho_u at point 0 is dependent on rho_u at point 1, + // but not on mdot from the inlet. + rsd[index(c_offset_U,0)] = + -(rho_u(x,1) - rho_u(x,0))/m_dz[0] + -(density(1)*V(x,1) + density(0)*V(x,0)); - // the inlet (or other) object connected to this one - // will modify these equations by subtracting its values - // for V, T, and mdot. As a result, these residual equations - // will force the solution variables to the values for - // the boundary object - rsd[index(c_offset_V,0)] = V(x,0); - rsd[index(c_offset_T,0)] = T(x,0); - rsd[index(c_offset_L,0)] = -rho_u(x,0); + // the inlet (or other) object connected to this one + // will modify these equations by subtracting its values + // for V, T, and mdot. As a result, these residual equations + // will force the solution variables to the values for + // the boundary object + rsd[index(c_offset_V,0)] = V(x,0); + rsd[index(c_offset_T,0)] = T(x,0); + rsd[index(c_offset_L,0)] = -rho_u(x,0); - // The default boundary condition for species is zero - // flux - sum = 0.0; - for (k = 0; k < m_nsp; k++) { - sum += Y(x,k,0); - rsd[index(c_offset_Y + k, 0)] = - -(m_flux(k,0) + rho_u(x,0)* Y(x,k,0)); - } - rsd[index(c_offset_Y, 0)] = 1.0 - sum; - } + // The default boundary condition for species is zero + // flux + sum = 0.0; + for (k = 0; k < m_nsp; k++) { + sum += Y(x,k,0); + rsd[index(c_offset_Y + k, 0)] = + -(m_flux(k,0) + rho_u(x,0)* Y(x,k,0)); + } + rsd[index(c_offset_Y, 0)] = 1.0 - sum; + } - //---------------------------------------------- - // - // right boundary - // - //---------------------------------------------- + //---------------------------------------------- + // + // right boundary + // + //---------------------------------------------- - else if (j == m_points - 1) { + else if (j == m_points - 1) { - // the boundary object connected to the right of this - // one may modify or replace these equations. The - // default boundary conditions are zero u, V, and T, - // and zero diffusive flux for all species. + // the boundary object connected to the right of this + // one may modify or replace these equations. The + // default boundary conditions are zero u, V, and T, + // and zero diffusive flux for all species. - // zero gradient - rsd[index(0,j)] = rho_u(x,j) - rho_u(x,j-1); - rsd[index(1,j)] = V(x,j); - rsd[index(2,j)] = T(x,j) - T(x,j-1); - doublereal sum = 0.0; - rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); - diag[index(c_offset_L, j)] = 0; - for (k = 0; k < m_nsp; k++) { - sum += Y(x,k,j); - rsd[index(k+4,j)] = m_flux(k,j-1) + rho_u(x,j)*Y(x,k,j); - } - rsd[index(4,j)] = 1.0 - sum; - diag[index(4,j)] = 0; - } + // zero gradient + rsd[index(0,j)] = rho_u(x,j) - rho_u(x,j-1); + rsd[index(1,j)] = V(x,j); + rsd[index(2,j)] = T(x,j) - T(x,j-1); + doublereal sum = 0.0; + rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); + diag[index(c_offset_L, j)] = 0; + for (k = 0; k < m_nsp; k++) { + sum += Y(x,k,j); + rsd[index(k+4,j)] = m_flux(k,j-1) + rho_u(x,j)*Y(x,k,j); + } + rsd[index(4,j)] = 1.0 - sum; + diag[index(4,j)] = 0; + } - //------------------------------------------ - // interior points - //------------------------------------------ + //------------------------------------------ + // interior points + //------------------------------------------ - else { + else { - //---------------------------------------------- - // Continuity equation - //---------------------------------------------- + //---------------------------------------------- + // Continuity equation + //---------------------------------------------- - if (grid(j) > m_zfixed){ - rsd[index(c_offset_U,j)] = - - (rho_u(x,j) - rho_u(x,j-1))/m_dz[j-1] - - (density(j-1)*V(x,j-1) + density(j)*V(x,j)); - } + if (grid(j) > m_zfixed){ + rsd[index(c_offset_U,j)] = + - (rho_u(x,j) - rho_u(x,j-1))/m_dz[j-1] + - (density(j-1)*V(x,j-1) + density(j)*V(x,j)); + } - else if (grid(j) == m_zfixed){ - if (m_do_energy[j]) { - rsd[index(c_offset_U,j)] = (T(x,j) - m_tfixed); - } - else { - rsd[index(c_offset_U,j)] = (rho_u(x,j) - - m_rho[0]*0.3); - } - } - else if(grid(j) < m_zfixed){ - rsd[index(c_offset_U,j)] = - - (rho_u(x,j+1) - rho_u(x,j))/m_dz[j] - - (density(j+1)*V(x,j+1) + density(j)*V(x,j)); - } - //algebraic constraint - diag[index(c_offset_U, j)] = 0; + else if (grid(j) == m_zfixed){ + if (m_do_energy[j]) { + rsd[index(c_offset_U,j)] = (T(x,j) - m_tfixed); + } + else { + rsd[index(c_offset_U,j)] = (rho_u(x,j) + - m_rho[0]*0.3); + } + } + else if(grid(j) < m_zfixed){ + rsd[index(c_offset_U,j)] = + - (rho_u(x,j+1) - rho_u(x,j))/m_dz[j] + - (density(j+1)*V(x,j+1) + density(j)*V(x,j)); + } + //algebraic constraint + diag[index(c_offset_U, j)] = 0; - //------------------------------------------------ - // Radial momentum equation - // - // \rho u dV/dz + \rho V^2 = d(\mu dV/dz)/dz - lambda - // - //------------------------------------------------- - rsd[index(c_offset_V,j)] - = (shear(x,j) - lambda(x,j) - rho_u(x,j)*dVdz(x,j) - - m_rho[j]*V(x,j)*V(x,j))/m_rho[j] - - rdt*(V(x,j) - V_prev(j)); - diag[index(c_offset_V, j)] = 1; + //------------------------------------------------ + // Radial momentum equation + // + // \rho u dV/dz + \rho V^2 = d(\mu dV/dz)/dz - lambda + // + //------------------------------------------------- + rsd[index(c_offset_V,j)] + = (shear(x,j) - lambda(x,j) - rho_u(x,j)*dVdz(x,j) + - m_rho[j]*V(x,j)*V(x,j))/m_rho[j] + - rdt*(V(x,j) - V_prev(j)); + diag[index(c_offset_V, j)] = 1; - //------------------------------------------------- - // Species equations - // - // \rho u dY_k/dz + dJ_k/dz + M_k\omega_k - // - //------------------------------------------------- - getWdot(x,j); + //------------------------------------------------- + // Species equations + // + // \rho u dY_k/dz + dJ_k/dz + M_k\omega_k + // + //------------------------------------------------- + getWdot(x,j); - doublereal convec, diffus; - for (k = 0; k < m_nsp; k++) { - convec = rho_u(x,j)*dYdz(x,k,j); - diffus = 2.0*(m_flux(k,j) - m_flux(k,j-1)) - /(z(j+1) - z(j-1)); - rsd[index(c_offset_Y + k, j)] - = (m_wt[k]*(wdot(k,j) ) - - convec - diffus)/m_rho[j] - - rdt*(Y(x,k,j) - Y_prev(k,j)); - diag[index(c_offset_Y + k, j)] = 1; - } + doublereal convec, diffus; + for (k = 0; k < m_nsp; k++) { + convec = rho_u(x,j)*dYdz(x,k,j); + diffus = 2.0*(m_flux(k,j) - m_flux(k,j-1)) + /(z(j+1) - z(j-1)); + rsd[index(c_offset_Y + k, j)] + = (m_wt[k]*(wdot(k,j) ) + - convec - diffus)/m_rho[j] + - rdt*(Y(x,k,j) - Y_prev(k,j)); + diag[index(c_offset_Y + k, j)] = 1; + } - //----------------------------------------------- - // energy equation - //----------------------------------------------- + //----------------------------------------------- + // energy equation + //----------------------------------------------- - if (m_do_energy[j]) { + if (m_do_energy[j]) { - setGas(x,j); + setGas(x,j); - // heat release term - const vector_fp& h_RT = m_thermo->enthalpy_RT_ref(); - const vector_fp& cp_R = m_thermo->cp_R_ref(); + // heat release term + const vector_fp& h_RT = m_thermo->enthalpy_RT_ref(); + const vector_fp& cp_R = m_thermo->cp_R_ref(); - sum = 0.0; - sum2 = 0.0; - doublereal flxk; - for (k = 0; k < m_nsp; k++) { - flxk = 0.5*(m_flux(k,j-1) + m_flux(k,j)); - sum += wdot(k,j)*h_RT[k]; - sum2 += flxk*cp_R[k]/m_wt[k]; - } - sum *= GasConstant * T(x,j); - dtdzj = dTdz(x,j); - sum2 *= GasConstant * dtdzj; + sum = 0.0; + sum2 = 0.0; + doublereal flxk; + for (k = 0; k < m_nsp; k++) { + flxk = 0.5*(m_flux(k,j-1) + m_flux(k,j)); + sum += wdot(k,j)*h_RT[k]; + sum2 += flxk*cp_R[k]/m_wt[k]; + } + sum *= GasConstant * T(x,j); + dtdzj = dTdz(x,j); + sum2 *= GasConstant * dtdzj; - rsd[index(c_offset_T, j)] = - - m_cp[j]*rho_u(x,j)*dtdzj - - divHeatFlux(x,j) - sum - sum2; - rsd[index(c_offset_T, j)] /= (m_rho[j]*m_cp[j]); + rsd[index(c_offset_T, j)] = + - m_cp[j]*rho_u(x,j)*dtdzj + - divHeatFlux(x,j) - sum - sum2; + rsd[index(c_offset_T, j)] /= (m_rho[j]*m_cp[j]); - rsd[index(c_offset_T, j)] = - rsd[index(c_offset_T, j)] + m_efctr*(T_fixed(j) - T(x,j)); + rsd[index(c_offset_T, j)] = + rsd[index(c_offset_T, j)] + m_efctr*(T_fixed(j) - T(x,j)); - rsd[index(c_offset_T, j)] -= rdt*(T(x,j) - T_prev(j)); - diag[index(c_offset_T, j)] = 1; - } - // residual equations if the energy equation is disabled - else { - rsd[index(c_offset_T, j)] = T(x,j) - T_fixed(j); - diag[index(c_offset_T, j)] = 0; - } + rsd[index(c_offset_T, j)] -= rdt*(T(x,j) - T_prev(j)); + diag[index(c_offset_T, j)] = 1; + } + // residual equations if the energy equation is disabled + else { + rsd[index(c_offset_T, j)] = T(x,j) - T_fixed(j); + diag[index(c_offset_T, j)] = 0; + } - rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); - diag[index(c_offset_L, j)] = 0; - } - } + rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1); + diag[index(c_offset_L, j)] = 0; + } } + } - /** - * Print the solution. - */ - void StFlow::showSolution(const doublereal* x) { - int nn = m_nv/5; - int i, j, n; - //char* buf = new char[100]; - char buf[100]; + /** + * Print the solution. + */ + void StFlow::showSolution(const doublereal* x) { + int nn = m_nv/5; + int i, j, n; + //char* buf = new char[100]; + char buf[100]; - // The mean molecular weight is needed to convert - updateThermo(x, 0, m_points-1); + // The mean molecular weight is needed to convert + updateThermo(x, 0, m_points-1); - sprintf(buf, " Pressure: %10.4g Pa \n", m_press); - writelog(buf); - for (i = 0; i < nn; i++) { - st_drawline(); - sprintf(buf, "\n z "); - writelog(buf); - for (n = 0; n < 5; n++) { - sprintf(buf, " %10s ",componentName(i*5 + n).c_str()); - writelog(buf); - } - st_drawline(); - for (j = 0; j < m_points; j++) { - sprintf(buf, "\n %10.4g ",m_z[j]); - writelog(buf); - for (n = 0; n < 5; n++) { - sprintf(buf, " %10.4g ",component(x, i*5+n,j)); - writelog(buf); - } - } - writelog("\n"); - } - int nrem = m_nv - 5*nn; - st_drawline(); - sprintf(buf, "\n z "); - writelog(buf); - for (n = 0; n < nrem; n++) { - sprintf(buf, " %10s ", componentName(nn*5 + n).c_str()); - writelog(buf); - } - st_drawline(); - for (j = 0; j < m_points; j++) { - sprintf(buf, "\n %10.4g ",m_z[j]); - writelog(buf); - for (n = 0; n < nrem; n++) { - sprintf(buf, " %10.4g ",component(x, nn*5+n,j)); - writelog(buf); - } - } - writelog("\n"); + sprintf(buf, " Pressure: %10.4g Pa \n", m_press); + writelog(buf); + for (i = 0; i < nn; i++) { + st_drawline(); + sprintf(buf, "\n z "); + writelog(buf); + for (n = 0; n < 5; n++) { + sprintf(buf, " %10s ",componentName(i*5 + n).c_str()); + writelog(buf); + } + st_drawline(); + for (j = 0; j < m_points; j++) { + sprintf(buf, "\n %10.4g ",m_z[j]); + writelog(buf); + for (n = 0; n < 5; n++) { + sprintf(buf, " %10.4g ",component(x, i*5+n,j)); + writelog(buf); + } + } + writelog("\n"); } + int nrem = m_nv - 5*nn; + st_drawline(); + sprintf(buf, "\n z "); + writelog(buf); + for (n = 0; n < nrem; n++) { + sprintf(buf, " %10s ", componentName(nn*5 + n).c_str()); + writelog(buf); + } + st_drawline(); + for (j = 0; j < m_points; j++) { + sprintf(buf, "\n %10.4g ",m_z[j]); + writelog(buf); + for (n = 0; n < nrem; n++) { + sprintf(buf, " %10.4g ",component(x, nn*5+n,j)); + writelog(buf); + } + } + writelog("\n"); + } - /** - * Update the diffusive mass fluxes. - */ - void StFlow::updateDiffFluxes(const doublereal* x, int j0, int j1) { - int j, k, m; - doublereal sum, wtm, rho, dz, gradlogT; + /** + * Update the diffusive mass fluxes. + */ + void StFlow::updateDiffFluxes(const doublereal* x, int j0, int j1) { + int j, k, m; + doublereal sum, wtm, rho, dz, gradlogT; - switch (m_transport_option) { + switch (m_transport_option) { - case c_Mixav_Transport: - case c_Multi_Transport: - for (j = j0; j < j1; j++) { - sum = 0.0; - wtm = m_wtm[j]; - rho = density(j); - dz = z(j+1) - z(j); + case c_Mixav_Transport: + case c_Multi_Transport: + for (j = j0; j < j1; j++) { + sum = 0.0; + wtm = m_wtm[j]; + rho = density(j); + dz = z(j+1) - z(j); - for (k = 0; k < m_nsp; k++) { - m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm); - m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz; - sum -= m_flux(k,j); - } - // correction flux to insure that \sum_k Y_k V_k = 0. - for (k = 0; k < m_nsp; k++) m_flux(k,j) += sum*Y(x,k,j); - } - break; + for (k = 0; k < m_nsp; k++) { + m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm); + m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz; + sum -= m_flux(k,j); + } + // correction flux to insure that \sum_k Y_k V_k = 0. + for (k = 0; k < m_nsp; k++) m_flux(k,j) += sum*Y(x,k,j); + } + break; - default: - throw CanteraError("updateDiffFluxes","unknown transport model"); - } - - if (m_do_soret) { - for (m = j0; m < j1; m++) { - gradlogT = 2.0*(T(x,m+1) - T(x,m))/(T(x,m+1) + T(x,m)); - for (k = 0; k < m_nsp; k++) { - m_flux(k,m) -= m_dthermal(k,m)*gradlogT; - } - } - } + default: + throw CanteraError("updateDiffFluxes","unknown transport model"); } - - string StFlow::componentName(int n) const { - switch(n) { - case 0: return "u"; - case 1: return "V"; - case 2: return "T"; - case 3: return "lambda"; - default: - if (n >= (int) c_offset_Y && n < (int) (c_offset_Y + m_nsp)) { - return m_thermo->speciesName(n - c_offset_Y); - } - else - return ""; - } + if (m_do_soret) { + for (m = j0; m < j1; m++) { + gradlogT = 2.0*(T(x,m+1) - T(x,m))/(T(x,m+1) + T(x,m)); + for (k = 0; k < m_nsp; k++) { + m_flux(k,m) -= m_dthermal(k,m)*gradlogT; + } + } } + } - //added by Karl Meredith - int StFlow::componentIndex(string name) const { + string StFlow::componentName(int n) const { + switch(n) { + case 0: return "u"; + case 1: return "V"; + case 2: return "T"; + case 3: return "lambda"; + default: + if (n >= (int) c_offset_Y && n < (int) (c_offset_Y + m_nsp)) { + return m_thermo->speciesName(n - c_offset_Y); + } + else + return ""; + } + } + + + //added by Karl Meredith + int StFlow::componentIndex(string name) const { - if(name=="u") {return 0;} - else if (name=="V") {return 1;} - else if (name=="T") {return 2;} - else if (name=="lambda") {return 3;} - else { - for (int n=4;n ignored; - int nsp = m_thermo->nSpecies(); - vector_int did_species(nsp, 0); - - vector str; - dom.getChildren("string",str); - int nstr = static_cast(str.size()); - for (int istr = 0; istr < nstr; istr++) { - const XML_Node& nd = *str[istr]; - writelog(nd["title"]+": "+nd.value()+"\n"); - } - - //map params; - double pp = -1.0; - pp = getFloat(dom, "pressure", "pressure"); - setPressure(pp); + return -1; + } - vector d; - dom.child("grid_data").getChildren("floatArray",d); - int nd = static_cast(d.size()); + void StFlow::restore(const XML_Node& dom, doublereal* soln) { - vector_fp x; - int n, np = 0, j, ks, k; - string nm; - bool readgrid = false, wrote_header = false; - for (n = 0; n < nd; n++) { - const XML_Node& fa = *d[n]; - nm = fa["title"]; - if (nm == "z") { - getFloatArray(fa,x,false); - np = x.size(); - writelog("Grid contains "+int2str(np)+ - " points.\n"); - readgrid = true; - setupGrid(np, DATA_PTR(x)); - } - } - if (!readgrid) { - throw CanteraError("StFlow::restore", - "domain contains no grid points."); - } + vector ignored; + int nsp = m_thermo->nSpecies(); + vector_int did_species(nsp, 0); - writelog("Importing datasets:\n"); - for (n = 0; n < nd; n++) { - const XML_Node& fa = *d[n]; - nm = fa["title"]; - getFloatArray(fa,x,false); - if (nm == "u") { - writelog("axial velocity "); - if ((int) x.size() == np) { - for (j = 0; j < np; j++) { - soln[index(0,j)] = x[j]; - } - } - else { - goto error; - } - } - else if (nm == "z") { - ; // already read grid - } - else if (nm == "V") { - writelog("radial velocity "); - if ((int) x.size() == np) { - for (j = 0; j < np; j++) - soln[index(1,j)] = x[j]; - } - else goto error; - } - else if (nm == "T") { - writelog("temperature "); - if ((int) x.size() == np) { - for (j = 0; j < np; j++) - soln[index(2,j)] = x[j]; - - // For fixed-temperature simulations, use the - // imported temperature profile by default. If - // this is not desired, call setFixedTempProfile - // *after* restoring the solution. - - vector_fp zz(np); - for (int jj = 0; jj < np; jj++) - zz[jj] = (grid(jj) - zmin())/(zmax() - zmin()); - setFixedTempProfile(zz, x); - } - else goto error; - } - else if (nm == "L") { - writelog("lambda "); - if ((int) x.size() == np) { - for (j = 0; j < np; j++) - soln[index(3,j)] = x[j]; - } - else goto error; - } - else if (m_thermo->speciesIndex(nm) >= 0) { - writelog(nm+" "); - if ((int) x.size() == np) { - k = m_thermo->speciesIndex(nm); - did_species[k] = 1; - for (j = 0; j < np; j++) - soln[index(k+4,j)] = x[j]; - } - } - else - ignored.push_back(nm); - } - - if (ignored.size() != 0) { - writelog("\n\n"); - writelog("Ignoring datasets:\n"); - int nn = static_cast(ignored.size()); - for (int n = 0; n < nn; n++) { - writelog(ignored[n]+" "); - } - } - - for (ks = 0; ks < nsp; ks++) { - if (did_species[ks] == 0) { - if (!wrote_header) { - writelog("Missing data for species:\n"); - wrote_header = true; - } - writelog(m_thermo->speciesName(ks)+" "); - } - } - - return; - error: - throw CanteraError("StFlow::restore","Data size error"); + vector str; + dom.getChildren("string",str); + int nstr = static_cast(str.size()); + for (int istr = 0; istr < nstr; istr++) { + const XML_Node& nd = *str[istr]; + writelog(nd["title"]+": "+nd.value()+"\n"); } + //map params; + double pp = -1.0; + pp = getFloat(dom, "pressure", "pressure"); + setPressure(pp); - void StFlow::save(XML_Node& o, doublereal* sol) { - int k; + vector d; + dom.child("grid_data").getChildren("floatArray",d); + int nd = static_cast(d.size()); - ArrayViewer soln(m_nv, m_points, sol + loc()); - - XML_Node& flow = (XML_Node&)o.addChild("domain"); - flow.addAttribute("type",flowType()); - flow.addAttribute("id",m_id); - flow.addAttribute("points",m_points); - flow.addAttribute("components",m_nv); - - if (m_desc != "") addString(flow,"description",m_desc); - XML_Node& gv = flow.addChild("grid_data"); - addFloat(flow, "pressure", m_press, "Pa", "pressure"); - addFloatArray(gv,"z",m_z.size(),DATA_PTR(m_z), - "m","length"); - vector_fp x(static_cast(soln.nColumns())); - - soln.getRow(0,DATA_PTR(x)); - addFloatArray(gv,"u",x.size(),DATA_PTR(x),"m/s","velocity"); - - soln.getRow(1,DATA_PTR(x)); - addFloatArray(gv,"V", - x.size(),DATA_PTR(x),"1/s","rate"); - - soln.getRow(2,DATA_PTR(x)); - addFloatArray(gv,"T",x.size(),DATA_PTR(x),"K","temperature",0.0); - - soln.getRow(3,DATA_PTR(x)); - addFloatArray(gv,"L",x.size(),DATA_PTR(x),"N/m^4"); - - for (k = 0; k < m_nsp; k++) { - soln.getRow(4+k,DATA_PTR(x)); - addFloatArray(gv,m_thermo->speciesName(k), - x.size(),DATA_PTR(x),"","massFraction",0.0,1.0); - } + vector_fp x; + int n, np = 0, j, ks, k; + string nm; + bool readgrid = false, wrote_header = false; + for (n = 0; n < nd; n++) { + const XML_Node& fa = *d[n]; + nm = fa["title"]; + if (nm == "z") { + getFloatArray(fa,x,false); + np = x.size(); + writelog("Grid contains "+int2str(np)+ + " points.\n"); + readgrid = true; + setupGrid(np, DATA_PTR(x)); + } + } + if (!readgrid) { + throw CanteraError("StFlow::restore", + "domain contains no grid points."); } + writelog("Importing datasets:\n"); + for (n = 0; n < nd; n++) { + const XML_Node& fa = *d[n]; + nm = fa["title"]; + getFloatArray(fa,x,false); + if (nm == "u") { + writelog("axial velocity "); + if ((int) x.size() == np) { + for (j = 0; j < np; j++) { + soln[index(0,j)] = x[j]; + } + } + else { + goto error; + } + } + else if (nm == "z") { + ; // already read grid + } + else if (nm == "V") { + writelog("radial velocity "); + if ((int) x.size() == np) { + for (j = 0; j < np; j++) + soln[index(1,j)] = x[j]; + } + else goto error; + } + else if (nm == "T") { + writelog("temperature "); + if ((int) x.size() == np) { + for (j = 0; j < np; j++) + soln[index(2,j)] = x[j]; - void StFlow::setJac(MultiJac* jac) { - m_jac = jac; + // For fixed-temperature simulations, use the + // imported temperature profile by default. If + // this is not desired, call setFixedTempProfile + // *after* restoring the solution. + + vector_fp zz(np); + for (int jj = 0; jj < np; jj++) + zz[jj] = (grid(jj) - zmin())/(zmax() - zmin()); + setFixedTempProfile(zz, x); + } + else goto error; + } + else if (nm == "L") { + writelog("lambda "); + if ((int) x.size() == np) { + for (j = 0; j < np; j++) + soln[index(3,j)] = x[j]; + } + else goto error; + } + else if (m_thermo->speciesIndex(nm) >= 0) { + writelog(nm+" "); + if ((int) x.size() == np) { + k = m_thermo->speciesIndex(nm); + did_species[k] = 1; + for (j = 0; j < np; j++) + soln[index(k+4,j)] = x[j]; + } + } + else + ignored.push_back(nm); } + if (ignored.size() != 0) { + writelog("\n\n"); + writelog("Ignoring datasets:\n"); + int nn = static_cast(ignored.size()); + for (int n = 0; n < nn; n++) { + writelog(ignored[n]+" "); + } + } + + for (ks = 0; ks < nsp; ks++) { + if (did_species[ks] == 0) { + if (!wrote_header) { + writelog("Missing data for species:\n"); + wrote_header = true; + } + writelog(m_thermo->speciesName(ks)+" "); + } + } + + return; + error: + throw CanteraError("StFlow::restore","Data size error"); + } + + + + void StFlow::save(XML_Node& o, const doublereal * const sol) { + int k; + + ArrayViewer soln(m_nv, m_points, const_cast(sol) + loc()); + + XML_Node& flow = (XML_Node&)o.addChild("domain"); + flow.addAttribute("type",flowType()); + flow.addAttribute("id",m_id); + flow.addAttribute("points",m_points); + flow.addAttribute("components",m_nv); + + if (m_desc != "") addString(flow,"description",m_desc); + XML_Node& gv = flow.addChild("grid_data"); + addFloat(flow, "pressure", m_press, "Pa", "pressure"); + addFloatArray(gv,"z",m_z.size(),DATA_PTR(m_z), + "m","length"); + vector_fp x(static_cast(soln.nColumns())); + + soln.getRow(0,DATA_PTR(x)); + addFloatArray(gv,"u",x.size(),DATA_PTR(x),"m/s","velocity"); + + soln.getRow(1,DATA_PTR(x)); + addFloatArray(gv,"V", + x.size(),DATA_PTR(x),"1/s","rate"); + + soln.getRow(2,DATA_PTR(x)); + addFloatArray(gv,"T",x.size(),DATA_PTR(x),"K","temperature",0.0); + + soln.getRow(3,DATA_PTR(x)); + addFloatArray(gv,"L",x.size(),DATA_PTR(x),"N/m^4"); + + for (k = 0; k < m_nsp; k++) { + soln.getRow(4+k,DATA_PTR(x)); + addFloatArray(gv,m_thermo->speciesName(k), + x.size(),DATA_PTR(x),"","massFraction",0.0,1.0); + } + } + + + void StFlow::setJac(MultiJac* jac) { + m_jac = jac; + } + } // namespace diff --git a/Cantera/src/oneD/StFlow.h b/Cantera/src/oneD/StFlow.h index c9cb3d482..83437325d 100644 --- a/Cantera/src/oneD/StFlow.h +++ b/Cantera/src/oneD/StFlow.h @@ -182,7 +182,15 @@ namespace Cantera { virtual void showSolution(const doublereal* x); - virtual void save(XML_Node& o, doublereal* sol); + //! Save the current solution for this domain into an XML_Node + /*! + * + * @param o XML_Node to save the solution to. + * @param sol Current value of the solution vector. + * The object will pick out which part of the solution + * vector pertains to this object. + */ + virtual void save(XML_Node& o, const doublereal * const sol); virtual void restore(const XML_Node& dom, doublereal* soln); diff --git a/Cantera/src/oneD/Surf1D.h b/Cantera/src/oneD/Surf1D.h index 44e8013e4..d450253a2 100644 --- a/Cantera/src/oneD/Surf1D.h +++ b/Cantera/src/oneD/Surf1D.h @@ -273,7 +273,7 @@ namespace Cantera { } } - virtual void save(XML_Node& o, doublereal* soln) { + virtual void save(XML_Node& o, const doublereal * const soln) { doublereal* s = soln + loc(); XML_Node& surf = o.addChild("surface"); for (int k = 0; k < m_nsp; k++) { diff --git a/Cantera/src/oneD/boundaries1D.cpp b/Cantera/src/oneD/boundaries1D.cpp index 67bc98e75..b87ab2e79 100644 --- a/Cantera/src/oneD/boundaries1D.cpp +++ b/Cantera/src/oneD/boundaries1D.cpp @@ -246,8 +246,8 @@ namespace Cantera { } void Inlet1D:: - save(XML_Node& o, doublereal* soln) { - doublereal* s = soln + loc(); + save(XML_Node& o, const doublereal* const soln) { + const doublereal* s = soln + loc(); XML_Node& inlt = o.addChild("domain"); inlt.addAttribute("id",id()); inlt.addAttribute("points",1); @@ -262,8 +262,8 @@ namespace Cantera { restore(const XML_Node& dom, doublereal* soln) { //map x; //getFloats(dom, x); - soln[0] = getFloat(dom, "mdot", "massflowrate"); // x["mdot"]; - soln[1] = getFloat(dom, "temperature", "temperature"); // x["temperature"]; + soln[0] = ctml::getFloat(dom, "mdot", "massflowrate"); // x["mdot"]; + soln[1] = ctml::getFloat(dom, "temperature", "temperature"); // x["temperature"]; resize(2,1); } @@ -312,7 +312,7 @@ namespace Cantera { } void Empty1D:: - save(XML_Node& o, doublereal* soln) { + save(XML_Node& o, const doublereal * const soln) { XML_Node& symm = o.addChild("domain"); symm.addAttribute("id",id()); symm.addAttribute("points",1); @@ -395,7 +395,7 @@ namespace Cantera { void Symm1D:: - save(XML_Node& o, doublereal* soln) { + save(XML_Node& o, const doublereal * const soln) { XML_Node& symm = o.addChild("domain"); symm.addAttribute("id",id()); symm.addAttribute("points",1); @@ -493,7 +493,7 @@ namespace Cantera { void Outlet1D:: - save(XML_Node& o, doublereal* soln) { + save(XML_Node& o, const doublereal * const soln) { XML_Node& outlt = o.addChild("domain"); outlt.addAttribute("id",id()); outlt.addAttribute("points",1); @@ -633,7 +633,7 @@ namespace Cantera { void OutletRes1D:: - save(XML_Node& o, doublereal* soln) { + save(XML_Node& o, const doublereal * const soln) { XML_Node& outlt = o.addChild("domain"); outlt.addAttribute("id",id()); outlt.addAttribute("points",1); @@ -710,8 +710,8 @@ namespace Cantera { } void Surf1D:: - save(XML_Node& o, doublereal* soln) { - doublereal* s = soln + loc(); + save(XML_Node& o, const doublereal * const soln) { + const doublereal* s = soln + loc(); //XML_Node& inlt = o.addChild("inlet"); XML_Node& inlt = o.addChild("domain"); inlt.addAttribute("id",id()); @@ -726,7 +726,7 @@ namespace Cantera { void Surf1D:: restore(const XML_Node& dom, doublereal* soln) { map x; - getFloats(dom, x); + ctml::getFloats(dom, x); soln[0] = x["temperature"]; resize(1,1); } @@ -870,8 +870,8 @@ namespace Cantera { } void ReactingSurf1D:: - save(XML_Node& o, doublereal* soln) { - doublereal* s = soln + loc(); + save(XML_Node& o, const doublereal * const soln) { + const doublereal* s = soln + loc(); //XML_Node& inlt = o.addChild("inlet"); XML_Node& inlt = o.addChild("domain"); inlt.addAttribute("id",id()); @@ -886,7 +886,7 @@ namespace Cantera { void ReactingSurf1D:: restore(const XML_Node& dom, doublereal* soln) { map x; - getFloats(dom, x); + ctml::getFloats(dom, x); soln[0] = x["temperature"]; resize(1,1); } diff --git a/Cantera/src/spectra/LineBroadener.cpp b/Cantera/src/spectra/LineBroadener.cpp index 167261e3d..5daa0ae4c 100644 --- a/Cantera/src/spectra/LineBroadener.cpp +++ b/Cantera/src/spectra/LineBroadener.cpp @@ -3,6 +3,7 @@ #include "LineBroadener.h" using namespace std; +using namespace Cantera; namespace CanteraSpectra { @@ -20,7 +21,7 @@ namespace CanteraSpectra { * Units: 1/wavenumber (or cm). */ doublereal Lorentzian::profile(doublereal deltaFreq) { - return (1.0/Pi) *m_hwhm/(deltaFreq*deltaFreq + m_hwhm2); + return (1.0/Cantera::Pi) *m_hwhm/(deltaFreq*deltaFreq + m_hwhm2); } /** @@ -47,7 +48,7 @@ namespace CanteraSpectra { //cout << "entered Gaussian::profile" << endl; //cout << "deltaFreq = " << deltaFreq << endl; //cout << "m_sigma = " << m_sigma << endl; - return 1.0/(m_sigma*SqrtTwo*SqrtPi) * + return 1.0/(m_sigma * Cantera::SqrtTwo *Cantera::SqrtPi) * exp(-deltaFreq*deltaFreq/(2.0*m_sigma2)); } diff --git a/Cantera/src/spectra/LineBroadener.h b/Cantera/src/spectra/LineBroadener.h index 30560d19d..ac7828939 100644 --- a/Cantera/src/spectra/LineBroadener.h +++ b/Cantera/src/spectra/LineBroadener.h @@ -7,7 +7,6 @@ #include "ct_defs.h" #include "ctexceptions.h" -using namespace Cantera; namespace CanteraSpectra { /** @@ -38,7 +37,7 @@ namespace CanteraSpectra { * an exception will be thrown. */ virtual doublereal profile(doublereal deltaFreq) { - throw CanteraError("LineBroadener::profile", + throw Cantera::CanteraError("LineBroadener::profile", "base class method called!"); } @@ -53,7 +52,7 @@ namespace CanteraSpectra { * \f] */ virtual doublereal cumulative(doublereal deltaFreq) { - throw CanteraError("LineBroadener::cumulative", + throw Cantera::CanteraError("LineBroadener::cumulative", "base class method called!"); } diff --git a/Cantera/src/spectra/rotor.cpp b/Cantera/src/spectra/rotor.cpp index ea9d7a31a..9b4770e20 100644 --- a/Cantera/src/spectra/rotor.cpp +++ b/Cantera/src/spectra/rotor.cpp @@ -11,6 +11,7 @@ #include "rotor.h" using namespace std; +using namespace Cantera; namespace CanteraSpectra { diff --git a/Cantera/src/spectra/rotor.h b/Cantera/src/spectra/rotor.h index 70e2ba6ab..b8d6aab18 100644 --- a/Cantera/src/spectra/rotor.h +++ b/Cantera/src/spectra/rotor.h @@ -14,7 +14,6 @@ */ #include "ct_defs.h" -using namespace Cantera; /** * Namespace for spectroscopic functions and classes. @@ -63,24 +62,24 @@ namespace CanteraSpectra { /** convert from Hz to wavenmbers */ inline doublereal hz_to_wnum(doublereal freq) { - return freq/(100.0*lightSpeed); + return freq/(100.0*Cantera::lightSpeed); } /** Convert from wavenumbers to Joules. */ inline doublereal wnum_to_J(doublereal w) { - return Planck * w * 100.0 * lightSpeed; + return Cantera::Planck * w * 100.0 * Cantera::lightSpeed; } inline doublereal J_to_wnum(doublereal e) { - return e /(Planck * 100.0 * lightSpeed); + return e /(Cantera::Planck * 100.0 * Cantera::lightSpeed); } inline doublereal wnum_to_eV(doublereal w) { - return Planck * w * 100.0 * lightSpeed / ElectronCharge; + return Cantera::Planck * w * 100.0 * Cantera::lightSpeed / Cantera::ElectronCharge; } inline doublereal eV_to_wnum(doublereal e) { - return e * ElectronCharge / (Planck * 100.0 * lightSpeed); + return e * Cantera::ElectronCharge / (Cantera::Planck * 100.0 * Cantera::lightSpeed); } } diff --git a/Cantera/src/thermo/ConstDensityThermo.cpp b/Cantera/src/thermo/ConstDensityThermo.cpp index b0adfaca1..f4129d143 100644 --- a/Cantera/src/thermo/ConstDensityThermo.cpp +++ b/Cantera/src/thermo/ConstDensityThermo.cpp @@ -22,6 +22,8 @@ #include +using namespace ctml; + namespace Cantera { ConstDensityThermo::ConstDensityThermo() : m_tlast(0.0) { diff --git a/Cantera/src/thermo/Constituents.cpp b/Cantera/src/thermo/Constituents.cpp index 2d42d9564..ff7446d80 100644 --- a/Cantera/src/thermo/Constituents.cpp +++ b/Cantera/src/thermo/Constituents.cpp @@ -118,6 +118,9 @@ namespace Cantera { return m_Elements->atomicNumber(m); } + int Constituents::elementType(int m) const{ + return m_Elements->elementType(m); + } /* * Add an element to the set. @@ -155,9 +158,9 @@ namespace Cantera { */ void Constituents:: addUniqueElement(const std::string& symbol, doublereal weight, - int atomicNumber, doublereal entropy298) + int atomicNumber, doublereal entropy298, int elem_type) { - m_Elements->addUniqueElement(symbol, weight, atomicNumber, entropy298); + m_Elements->addUniqueElement(symbol, weight, atomicNumber, entropy298, elem_type); } void Constituents:: @@ -291,10 +294,10 @@ namespace Cantera { m_speciesNames.push_back(name); m_speciesCharge.push_back(charge); m_speciesSize.push_back(size); - int m_mm = m_Elements->nElements(); + int ne = m_Elements->nElements(); // Create a changeable copy of the element composition. We now change the charge potentially - vector_fp compNew(m_mm); - for (int m = 0; m < m_mm; m++) { + vector_fp compNew(ne); + for (int m = 0; m < ne; m++) { compNew[m] = comp[m]; } double wt = 0.0; @@ -313,30 +316,17 @@ namespace Cantera { } } } else { - m_Elements->m_elementsFrozen = false; - addUniqueElement("E", 0.000545, 0, 0.0); - m_Elements->m_elementsFrozen = true; - m_mm = m_Elements->nElements(); - if (m_kk > 0) { - vector_fp old(m_speciesComp); - m_speciesComp.resize(m_kk*m_mm, 0.0); - for (int k = 0; k < m_kk; k++) { - int m_old = m_mm - 1; - for (int m = 0; m < m_old; m++) { - m_speciesComp[k * m_mm + m] = old[k * (m_old) + m]; - } - m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0; - } - } + addUniqueElementAfterFreeze("E", 0.000545, 0, 0.0, CT_ELEM_TYPE_ELECTRONCHARGE); + ne = m_Elements->nElements(); eindex = m_Elements->elementIndex("E"); - compNew.resize(m_mm); - compNew[m_mm-1] = - charge; + compNew.resize(ne); + compNew[ne - 1] = - charge; //comp[eindex] = -charge; // throw CanteraError("Constituents::addSpecies", // "Element List doesn't include E, yet this species has charge:" + name); } } - for (int m = 0; m < m_mm; m++) { + for (int m = 0; m < ne; m++) { m_speciesComp.push_back(compNew[m]); wt += compNew[m] * aw[m]; } @@ -470,6 +460,8 @@ namespace Cantera { return m_speciesComp[m_mm * k + m]; } + + //==================================================================================================================== /* * * getAtoms() @@ -485,6 +477,39 @@ namespace Cantera { } } + + + //==================================================================================================================== + int Constituents::addUniqueElementAfterFreeze(const std::string& symbol, doublereal weight, int atomicNumber, + doublereal entropy298, int elem_type) + { + int ii = elementIndex(symbol); + if (ii != -1) { + return ii; + } + // Check to see that the element isn't really in the list + m_Elements->m_elementsFrozen = false; + addUniqueElement(symbol, weight, atomicNumber, entropy298, elem_type); + m_Elements->m_elementsFrozen = true; + int m_mm = m_Elements->nElements(); + ii = elementIndex(symbol); + if (ii != m_mm-1) { + throw CanteraError("Constituents::addElementAfterFreeze()", "confused"); + } + if (m_kk > 0) { + vector_fp old(m_speciesComp); + m_speciesComp.resize(m_kk*m_mm, 0.0); + for (int k = 0; k < m_kk; k++) { + int m_old = m_mm - 1; + for (int m = 0; m < m_old; m++) { + m_speciesComp[k * m_mm + m] = old[k * (m_old) + m]; + } + m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0; + } + } + return ii; + } + //==================================================================================================================== /* * This copy constructor just calls the assignment operator * for this class. diff --git a/Cantera/src/thermo/Constituents.h b/Cantera/src/thermo/Constituents.h index 22028b964..3f4e1b3fd 100644 --- a/Cantera/src/thermo/Constituents.h +++ b/Cantera/src/thermo/Constituents.h @@ -110,7 +110,6 @@ namespace Cantera { /// exception, ElementRangeError, is thrown. std::string elementName(int m) const; - /// Index of element named 'name'. /// The index is an integer /// assigned to each element in the order it was added, @@ -141,6 +140,8 @@ namespace Cantera { */ int atomicNumber(int m) const; + int elementType(int m) const; + /// Return a read-only reference to the vector of element names. const std::vector& elementNames() const; @@ -190,10 +191,12 @@ namespace Cantera { * the value ENTROPY298_UNKNOWN, which is * interpreted as an unknown, and if used * will cause Cantera to throw an error. + * @param elem_type Specifies the type of the element constraint equation. This defaults + * to CT_ELEM_TYPE_ABSPOS, i.e., an element. */ void addUniqueElement(const std::string& symbol, doublereal weight, int atomicNumber = 0, - doublereal entropy298 = ENTROPY298_UNKNOWN); + doublereal entropy298 = ENTROPY298_UNKNOWN, int elem_type = CT_ELEM_TYPE_ABSPOS); //! Adde an element, checking for uniqueness /*! @@ -216,6 +219,25 @@ namespace Cantera { /// True if freezeElements has been called. bool elementsFrozen(); + //! Add an element after the elements have been frozen, checking for uniqueness + /*! + * The uniqueness is checked by comparing the string symbol. If + * not unique, nothing is done. + * + * @param symbol String symbol of the element + * @param weight Atomic weight of the element (kg kmol-1). + * @param atomicNumber Atomic number of the element (unitless) + * @param entropy298 Entropy of the element at 298 K and 1 bar + * in its most stable form. The default is + * the value ENTROPY298_UNKNOWN, which is + * interpreted as an unknown, and if used + * will cause Cantera to throw an error. + * @param elem_type Specifies the type of the element constraint equation. This defaults + * to CT_ELEM_TYPE_ABSPOS, i.e., an element. + */ + int addUniqueElementAfterFreeze(const std::string& symbol, doublereal weight, int atomicNumber, + doublereal entropy298 = ENTROPY298_UNKNOWN, int elem_type = CT_ELEM_TYPE_ABSPOS); + //@} /// Returns the number of species in the phase @@ -280,12 +302,13 @@ namespace Cantera { doublereal charge = 0.0, doublereal size = 1.0); - //! Returns the index of a species named 'name' within the ThermoPhase + //! Returns the index of a species named 'name' within the Constituents object /*! - * The first species added will have index 0, and the last one index nSpecies() - 1. + * The first species in the phase will have an index 0, and the last one in the + * phase will have an index of nSpecies() - 1. * * @param name String name of the species - * @return Returns the index of the species. If the name is not found + * @return Returns the index of the species. If the name is not found, * the value of -1 is returned. */ int speciesIndex(std::string name) const; diff --git a/Cantera/src/thermo/DebyeHuckel.cpp b/Cantera/src/thermo/DebyeHuckel.cpp index 91546cf6d..b2b1f9c81 100644 --- a/Cantera/src/thermo/DebyeHuckel.cpp +++ b/Cantera/src/thermo/DebyeHuckel.cpp @@ -28,6 +28,7 @@ #include using namespace std; +using namespace ctml; namespace Cantera { @@ -915,11 +916,9 @@ namespace Cantera { delete fxml; } - /** - * interp_est() (static) - * - * utility function to assign an integer value from a string - * for the ElectrolyteSpeciesType field. + //! Utility function to assign an integer value from a string for the ElectrolyteSpeciesType field. + /*! + * @param estString input string that will be interpreted */ static int interp_est(std::string estString) { const char *cc = estString.c_str(); diff --git a/Cantera/src/thermo/DebyeHuckel.h b/Cantera/src/thermo/DebyeHuckel.h index 16e3b5dc8..f2ce3d375 100644 --- a/Cantera/src/thermo/DebyeHuckel.h +++ b/Cantera/src/thermo/DebyeHuckel.h @@ -1255,13 +1255,6 @@ namespace Cantera { * -------------- Utilities ------------------------------- */ - - /** - * Return a reference to the species thermodynamic property - * manager. @todo This method will fail if no species thermo - * manager has been installed. - */ - SpeciesThermo& speciesThermo() { return *m_spthermo; } //! Initialize the object's internal lengths after species are set /** diff --git a/Cantera/src/thermo/Elements.cpp b/Cantera/src/thermo/Elements.cpp index 2c9e61bdc..1c0357ec2 100644 --- a/Cantera/src/thermo/Elements.cpp +++ b/Cantera/src/thermo/Elements.cpp @@ -222,6 +222,7 @@ namespace Cantera { Elements::Elements() : m_mm(0), m_elementsFrozen(false), + m_elem_type(0), numSubscribers(0) { } @@ -256,7 +257,7 @@ namespace Cantera { m_atomicNumbers = right.m_atomicNumbers; m_elementNames = right.m_elementNames; m_entropy298 = right.m_entropy298; - + m_elem_type = right.m_elem_type; numSubscribers = 0; return *this; @@ -335,7 +336,43 @@ namespace Cantera { AssertTrace(m >= 0 && m < m_mm); return (m_entropy298[m]); } - + //==================================================================================================================== + //! Return the element constraint type + /*! + * Possible types include: + * + * CT_ELEM_TYPE_TURNEDOFF -1 + * CT_ELEM_TYPE_ABSPOS 0 + * CT_ELEM_TYPE_ELECTRONCHARGE 1 + * CT_ELEM_TYPE_CHARGENEUTRALITY 2 + * CT_ELEM_TYPE_LATTICERATIO 3 + * CT_ELEM_TYPE_KINETICFROZEN 4 + * CT_ELEM_TYPE_SURFACECONSTRAINT 5 + * CT_ELEM_TYPE_OTHERCONSTRAINT 6 + * + * The default is CT_ELEM_TYPE_ABSPOS + */ + int Elements::elementType(int m) const + { + return m_elem_type[m]; + } + //==================================================================================================================== + // Change the element type of the mth constraint + /* + * Reassigns an element type + * + * @param m Element index + * @param elem_type New elem type to be assigned + * + * @return Returns the old element type + */ + int Elements::changeElementType(int m, int elem_type) + { + int old = m_elem_type[m]; + m_elem_type[m] = elem_type; + return old; + } + //==================================================================================================================== /* * * Add an element to the current set of elements in the current object. @@ -367,16 +404,22 @@ namespace Cantera { #ifdef USE_DGG_CODE m_definedElements[symbol] = nElements() + 1; #endif + if (symbol == "E") { + m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE); + } else { + m_elem_type.push_back(CT_ELEM_TYPE_ABSPOS); + } + m_mm++; } - + //=========================================================================================================== void Elements:: addElement(const XML_Node& e) { doublereal weight = atof(e["atomicWt"].c_str()); string symbol = e["name"]; addElement(symbol, weight); } - + //=========================================================================================================== /* * addUniqueElement(): * @@ -393,7 +436,7 @@ namespace Cantera { #ifdef USE_DGG_CODE void Elements:: addUniqueElement(const std::string& symbol, doublereal weight, int atomicNumber, - doublereal entropy298) + doublereal entropy298, int elem_type) { if (m_elementsFrozen) throw ElementsFrozen("addElement"); @@ -413,13 +456,17 @@ namespace Cantera { m_elementNames.push_back(symbol); m_atomicNumbers.push_back(atomicNumber); m_entropy298.push_back(entropy298); + if (symbol == "E") { + m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE); + } else { + m_elem_type.push_back(elem_type); + } m_mm++; } else { if (m_atomicWeights[i] != weight) { throw CanteraError("AddUniqueElement", - "Duplicate Elements (" + symbol + - ") have different weights"); + "Duplicate Elements (" + symbol + ") have different weights"); } } } @@ -427,7 +474,8 @@ namespace Cantera { #else void Elements:: addUniqueElement(const std::string& symbol, - doublereal weight, int atomicNumber, doublereal entropy298) + doublereal weight, int atomicNumber, doublereal entropy298, + int elem_type) { if (weight == -12345.0) { weight = LookupWtElements(symbol); @@ -458,12 +506,16 @@ namespace Cantera { m_elementNames.push_back(symbol); m_atomicNumbers.push_back(atomicNumber); m_entropy298.push_back(entropy298); + if (symbol == "E") { + m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE); + } else { + m_elem_type.push_back(elem_type); + } m_mm++; } else { if (m_atomicWeights[i] != weight) { throw CanteraError("AddUniqueElement", - "Duplicate Elements (" + symbol + - ") have different weights"); + "Duplicate Elements (" + symbol + ") have different weights"); } } } @@ -496,7 +548,13 @@ namespace Cantera { addUniqueElement(symbol); } } - + + // True if freezeElements has been called. + bool Elements::elementsFrozen() const + { + return m_elementsFrozen; + } + /* * clear() * @@ -506,9 +564,11 @@ namespace Cantera { m_mm = 0; m_atomicWeights.resize(0); m_elementNames.resize(0); + m_entropy298.resize(0); + m_elem_type.resize(0); m_elementsFrozen = false; } - + /* * ready(): * diff --git a/Cantera/src/thermo/Elements.h b/Cantera/src/thermo/Elements.h index fa0e5dc2b..c4a3ec499 100644 --- a/Cantera/src/thermo/Elements.h +++ b/Cantera/src/thermo/Elements.h @@ -26,6 +26,73 @@ namespace Cantera { class XML_Node; class ElementRangeError; + /*! + * @name Types of Element Constraint Equations + * + * There may be several different types of element constraints handled + * by the equilibrium program and by Cantera in other contexts. + * These defines are used to assign each constraint to one category. + * @{ + */ + + //! An element constraint that is current turned off +#define CT_ELEM_TYPE_TURNEDOFF -1 + + //! Normal element constraint consisting of positive coefficients for the + //! formula matrix. + /*! + * All species have positive coefficients within the formula matrix. + * With this constraint, we may employ various strategies to handle + * small values of the element number successfully. + */ +#define CT_ELEM_TYPE_ABSPOS 0 + + //! This refers to conservation of electrons + /*! + * Electrons may have positive or negative values in the Formula matrix. + */ +#define CT_ELEM_TYPE_ELECTRONCHARGE 1 + + //! This refers to a charge neutrality of a single phase + /*! + * Charge neutrality may have positive or negative values in the Formula matrix. + */ +#define CT_ELEM_TYPE_CHARGENEUTRALITY 2 + + //! Constraint associated with maintaing a fixed lattice stoichiometry in a solid + /*! + * The constraint may have positive or negative values. The lattice 0 species will + * have negative values while higher lattices will have positive values + */ +#define CT_ELEM_TYPE_LATTICERATIO 3 + + //! Constraint associated with maintaining frozen kinetic equilibria in + //! some functional groups within molecules + /*! + * We seek here to say that some functional groups or ionic states should be + * treated as if they are separate elements given the time scale of the problem. + * This will be abs positive constraint. We have not implemented any examples yet. + * A requirement will be that we must be able to add and subtract these contraints. + */ +#define CT_ELEM_TYPE_KINETICFROZEN 4 + + //! Constraint associated with the maintenance of a surface phase + /*! + * We don't have any examples of this yet either. However, surfaces only exist + * because they are interfaces between bulk layers. If we want to treat surfaces + * within thermodynamic systems we must come up with a way to constrain their total + * number. + */ +#define CT_ELEM_TYPE_SURFACECONSTRAINT 5 + + //! Other constraint equations + /*! + * currently there are none + */ +#define CT_ELEM_TYPE_OTHERCONSTRAINT 6 + //@} + + //! Positive number indicating we don't know the gibbs free energy //! of the element in its most stable state at 298.15 K and 1 bar. //#define GIBSSFE298_UNKNOWN 123456789. @@ -120,6 +187,37 @@ namespace Cantera { */ doublereal entropyElement298(int m) const; + //! Return the element constraint type + /*! + * Possible types include: + * + * CT_ELEM_TYPE_ABSPOS 0 + * CT_ELEM_TYPE_ELECTRONCHARGE 1 + * CT_ELEM_TYPE_CHARGENEUTRALITY 2 + * CT_ELEM_TYPE_LATTICERATIO 3 + * CT_ELEM_TYPE_KINETICFROZEN 4 + * CT_ELEM_TYPE_SURFACECONSTRAINT 5 + * CT_ELEM_TYPE_OTHERCONSTRAINT 6 + * + * The default is CT_ELEM_TYPE_ABSPOS + * + * @param m Element index + * + * @return Returns the element type + */ + int elementType(int m) const; + + //! Change the element type of the mth constraint + /*! + * Reassigns an element type + * + * @param m Element index + * @param elem_type New elem type to be assigned + * + * @return Returns the old element type + */ + int changeElementType(int m, int elem_type); + /// vector of element atomic weights const vector_fp& atomicWeights() const { return m_atomicWeights; } @@ -196,10 +294,12 @@ namespace Cantera { * The default is to specify an ENTROPY298_UNKNOWN value, * which will cause a throw error if its ever * needed. + * @param elem_type New elem type to be assigned. + * The default is a regular element, CT_ELEM_TYPE_ABSPOS */ void addUniqueElement(const std::string& symbol, doublereal weight = -12345.0, int atomicNumber = 0, - doublereal entropy298 = ENTROPY298_UNKNOWN); + doublereal entropy298 = ENTROPY298_UNKNOWN, int elem_type = CT_ELEM_TYPE_ABSPOS); //! Add an element to the current set of elements in the current object. /*! @@ -218,8 +318,8 @@ namespace Cantera { //! Prohibit addition of more elements, and prepare to add species. void freezeElements(); - /// True if freezeElements has been called. - bool elementsFrozen() { return m_elementsFrozen; } + //! True if freezeElements has been called. + bool elementsFrozen() const; /// Remove all elements void clear(); @@ -258,7 +358,7 @@ namespace Cantera { * If this is true, then no elements may be added to the * object. */ - bool m_elementsFrozen; + bool m_elementsFrozen; /** * Vector of element atomic weights: @@ -285,6 +385,9 @@ namespace Cantera { */ vector_fp m_entropy298; + //! Vector of element types + vector_int m_elem_type; + /** * Number of Constituents Objects that use this object * diff --git a/Cantera/src/thermo/FixedChemPotSSTP.cpp b/Cantera/src/thermo/FixedChemPotSSTP.cpp new file mode 100644 index 000000000..0e7f87f4f --- /dev/null +++ b/Cantera/src/thermo/FixedChemPotSSTP.cpp @@ -0,0 +1,544 @@ +/** + * @file FixedChemPotSSTP.cpp + * Definition file for the FixedChemPotSSTP class, which represents a fixed-composition + * incompressible substance with a constant chemical potential (see \ref thermoprops and + * class \link Cantera::FixedChemPotSSTP FixedChemPotSSTP\endlink) + */ + +/* + * 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. + * + */ + +/* + * $Id: FixedChemPotSSTP.cpp 255 2009-11-09 23:36:49Z hkmoffa $ + */ + +#include "ct_defs.h" +#include "mix_defs.h" +#include "FixedChemPotSSTP.h" +#include "SpeciesThermo.h" +#include "ThermoFactory.h" + + +#include +#include "SimpleThermo.h" +namespace Cantera { + //==================================================================================================================== + /* + * ---- Constructors ------- + */ + //==================================================================================================================== + /* + * Default Constructor for the FixedChemPotSSTP class + */ + FixedChemPotSSTP::FixedChemPotSSTP() : + SingleSpeciesTP(), + chemPot_(0.0) + { + } + //==================================================================================================================== + // Create and initialize a FixedChemPotSSTP ThermoPhase object + // from an asci input file + /* + * @param infile name of the input file + * @param id name of the phase id in the file. + * If this is blank, the first phase in the file is used. + */ + FixedChemPotSSTP::FixedChemPotSSTP(std::string infile, std::string id) : + SingleSpeciesTP(), + chemPot_(0.0) + { + XML_Node* root = get_XML_File(infile); + if (id == "-") id = ""; + XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, root); + if (!xphase) { + throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP", + "Couldn't find phase name in file:" + id); + } + // Check the model name to ensure we have compatibility + const XML_Node& th = xphase->child("thermo"); + std::string model = th["model"]; + if (model != "StoichSubstance" && model != "StoichSubstanceSSTP" && model != "FixedChemPot") { + throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP", + "thermo model attribute must be FixedChemPot or StoichSubstance"); + } + importPhase(*xphase, this); + } + //==================================================================================================================== + // Full Constructor. + /* + * @param phaseRef XML node pointing to a FixedChemPotSSTP description + * @param id Id of the phase. + */ + FixedChemPotSSTP::FixedChemPotSSTP(XML_Node& xmlphase, std::string id) : + SingleSpeciesTP(), + chemPot_(0.0) + { + if (id != "") { + std::string idxml = xmlphase["id"]; + if (id != idxml) { + throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP", + "id's don't match"); + } + } + const XML_Node& th = xmlphase.child("thermo"); + std::string model = th["model"]; + if (model != "StoichSubstance" && model != "StoichSubstanceSSTP" && model != "FixedChemPotSSTP") { + throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP", + "thermo model attribute must be StoichSubstance or FixedChemPot"); + } + importPhase(xmlphase, this); + + if (model == "StoichSubstance" || model == "StoichSubstanceSSTP") { + _updateThermo(); + chemPot_ = (m_h0_RT[0] - m_s0_R[0]) * GasConstant * temperature(); + } + } + //==================================================================================================================== + FixedChemPotSSTP::FixedChemPotSSTP(std::string Ename, doublereal val) : + SingleSpeciesTP(), + chemPot_(0.0) + { + + std::string pname = Ename + "Fixed"; + setID(pname); + setName(pname); + setNDim(3); + addUniqueElement(Ename, -12345.); + freezeElements(); + int nel = nElements(); + vector_fp ecomp(nel, 0.0); + ecomp[0] = 1.0; + double chrg = 0.0; + SpeciesThermo* spth = new SimpleThermo(); + setSpeciesThermo(spth); + addUniqueSpecies(pname, &ecomp[0], chrg, 0.0); + double c[4]; + c[0] = 298.15; + c[1] = val; + c[2] = 0.0; + c[3] = 0.0; + m_spthermo->install(pname, 0, SIMPLE, c, 0.0, 1.0E30, OneAtm); + freezeSpecies(); + initThermo(); + m_p0 = OneAtm; + m_tlast = 298.15; + setChemicalPotential(val); + + // Create an XML_Node entry for this species + XML_Node *s = new XML_Node("species", 0); + s->addAttribute("name", pname); + std::string aaS = Ename + ":1"; + s->addChild("atomArray", aaS); + XML_Node &tt = s->addChild("thermo"); + XML_Node &ss = tt.addChild("Simple"); + ss.addAttribute("Pref", "1 bar"); + ss.addAttribute("Tmax", "5000."); + ss.addAttribute("Tmin", "100."); + ss.addChild("t0", "298.15"); + ss.addChild("cp0", "0.0"); + std::string sval = fp2str(val); + ss.addChild("h", sval); + ss.addChild("s", "0.0"); + saveSpeciesData(0, s); + delete s; + s = 0; + } + + //==================================================================================================================== + // Copy constructor + /* + * @param right Object to be copied + */ + FixedChemPotSSTP::FixedChemPotSSTP(const FixedChemPotSSTP &right) : + SingleSpeciesTP() + { + *this = operator=(right); + } + //==================================================================================================================== + // Assignment operator + /* + * @param right Object to be copied + */ + FixedChemPotSSTP & + FixedChemPotSSTP::operator=(const FixedChemPotSSTP & right) { + if (&right != this) { + SingleSpeciesTP::operator=(right); + + chemPot_ = right.chemPot_; + } + return *this; + } + //==================================================================================================================== + /* + * Destructor for the routine (virtual) + * + */ + FixedChemPotSSTP::~FixedChemPotSSTP() + { + } + //==================================================================================================================== + // Duplication function + /* + * This virtual function is used to create a duplicate of the + * current phase. It's used to duplicate the phase when given + * a ThermoPhase pointer to the phase. + * + * @return It returns a ThermoPhase pointer. + */ + ThermoPhase *FixedChemPotSSTP::duplMyselfAsThermoPhase() const { + FixedChemPotSSTP *stp = new FixedChemPotSSTP(*this); + return (ThermoPhase *) stp; + } + //==================================================================================================================== + + /* + * ---- Utilities ----- + */ + + /* + * Equation of state flag. Returns the value cStoichSubstance, + * defined in mix_defs.h. + */ + int FixedChemPotSSTP::eosType() const { + return cFixedChemPot; + } + + /* + * ---- Molar Thermodynamic properties of the solution ---- + */ + + /* + * ----- Mechanical Equation of State ------ + */ + //==================================================================================================================== + /* + * Pressure. Units: Pa. + * For an incompressible substance, the density is independent + * of pressure. This method simply returns the stored + * pressure value. + */ + doublereal FixedChemPotSSTP::pressure() const { + return m_press; + } + //==================================================================================================================== + /* + * Set the pressure at constant temperature. Units: Pa. + * For an incompressible substance, the density is + * independent of pressure. Therefore, this method only + * stores the specified pressure value. It does not + * modify the density. + */ + void FixedChemPotSSTP::setPressure(doublereal p) { + m_press = p; + } + //==================================================================================================================== + /* + * The isothermal compressibility. Units: 1/Pa. + * The isothermal compressibility is defined as + * \f[ + * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T + * \f] + * + * It's equal to zero for this model, since the molar volume + * doesn't change with pressure or temperature. + */ + doublereal FixedChemPotSSTP::isothermalCompressibility() const { + return 0.0; + } + //==================================================================================================================== + /* + * The thermal expansion coefficient. Units: 1/K. + * The thermal expansion coefficient is defined as + * + * \f[ + * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P + * \f] + * + * It's equal to zero for this model, since the molar volume + * doesn't change with pressure or temperature. + */ + doublereal FixedChemPotSSTP::thermalExpansionCoeff() const { + return 0.0; + } + //==================================================================================================================== + /* + * ---- Chemical Potentials and Activities ---- + */ + //==================================================================================================================== + /* + * This method returns the array of generalized + * concentrations. For a stoichiometric substance, there is + * only one species, and the generalized concentration is 1.0. + */ + void FixedChemPotSSTP:: + getActivityConcentrations(doublereal* c) const { + c[0] = 1.0; + } + //==================================================================================================================== + /* + * The standard concentration. This is defined as the concentration + * by which the generalized concentration is normalized to produce + * the activity. + */ + doublereal FixedChemPotSSTP::standardConcentration(int k) const { + return 1.0; + } + //==================================================================================================================== + /* + * Returns the natural logarithm of the standard + * concentration of the kth species + */ + doublereal FixedChemPotSSTP::logStandardConc(int k) const { + return 0.0; + } + //==================================================================================================================== + /* + * Returns the units of the standard and generalized + * concentrations Note they have the same units, as their + * ratio is defined to be equal to the activity of the kth + * species in the solution, which is unitless. + * + * This routine is used in print out applications where the + * units are needed. Usually, MKS units are assumed throughout + * the program and in the XML input files. + * + * uA[0] = kmol units - default = 1 + * uA[1] = m units - default = -nDim(), the number of spatial + * dimensions in the Phase class. + * uA[2] = kg units - default = 0; + * uA[3] = Pa(pressure) units - default = 0; + * uA[4] = Temperature units - default = 0; + * uA[5] = time units - default = 0 + */ + void FixedChemPotSSTP:: + getUnitsStandardConc(doublereal *uA, int k, int sizeUA) const { + for (int i = 0; i < 6; i++) { + uA[i] = 0; + } + } + //==================================================================================================================== + /* + * ---- Partial Molar Properties of the Solution ---- + */ + void FixedChemPotSSTP::getPartialMolarVolumes(doublereal* vbar) const { + vbar[0] = 0.0; + } + //==================================================================================================================== + /* + * ---- Properties of the Standard State of the Species in the Solution + * ---- + */ + //==================================================================================================================== + /* + * Get the array of chemical potentials at unit activity + * \f$ \mu^0_k \f$. + * + * For a stoichiometric substance, there is no activity term in + * the chemical potential expression, and therefore the + * standard chemical potential and the chemical potential + * are both equal to the molar Gibbs function. + */ + void FixedChemPotSSTP:: + getStandardChemPotentials(doublereal* mu0) const { + mu0[0] = chemPot_; + } + //==================================================================================================================== + /* + * Get the nondimensional Enthalpy functions for the species + * at their standard states at the current + * T and P of the solution. + * Molar enthalpy. Units: J/kmol. For an incompressible, + * stoichiometric substance, the internal energy is + * independent of pressure, and therefore the molar enthalpy + * is \f[ \hat h(T, P) = \hat u(T) + P \hat v \f], where the + * molar specific volume is constant. + */ + void FixedChemPotSSTP::getEnthalpy_RT(doublereal* hrt) const { + double rt = _RT(); + hrt[0] = chemPot_ / rt; + } + //==================================================================================================================== + /* + * Get the array of nondimensional Entropy functions for the + * standard state species + * at the current T and P of the solution. + */ + void FixedChemPotSSTP::getEntropy_R(doublereal* sr) const { + sr[0] = 0.0; + } + //==================================================================================================================== + /* + * Get the nondimensional Gibbs functions for the species + * at their standard states of solution at the current T and P + * of the solution + */ + void FixedChemPotSSTP::getGibbs_RT(doublereal* grt) const { + double rt = _RT(); + grt[0] = chemPot_ / rt; + } + //==================================================================================================================== + /* + * Get the nondimensional Gibbs functions for the standard + * state of the species at the current T and P. + */ + void FixedChemPotSSTP::getCp_R(doublereal* cpr) const { + cpr[0] = 0.0; + } + //==================================================================================================================== + /* + * Molar internal energy (J/kmol). + * For an incompressible, + * stoichiometric substance, the molar internal energy is + * independent of pressure. Since the thermodynamic properties + * are specified by giving the standard-state enthalpy, the + * term \f$ P_0 \hat v\f$ is subtracted from the specified molar + * enthalpy to compute the molar internal energy. + */ + void FixedChemPotSSTP::getIntEnergy_RT(doublereal* urt) const { + urt[0] = chemPot_; + } + //==================================================================================================================== + // Get the molar volumes of each species in their standard + // states at the current T and P of the solution. + /* + * units = m^3 / kmol + * + * We set this to zero + * + * @param vbar On output this contains the standard volume of the species + * and phase (m^3/kmol). Vector of length 1 + */ + void FixedChemPotSSTP::getStandardVolumes(doublereal* vbar) const { + vbar[0] = 0.0; + } + //==================================================================================================================== + /* + * ---- Thermodynamic Values for the Species Reference States ---- + */ + //==================================================================================================================== + void FixedChemPotSSTP::getIntEnergy_RT_ref(doublereal* urt) const { + urt[0] = chemPot_; + } + //==================================================================================================================== + void FixedChemPotSSTP::getEnthalpy_RT_ref(doublereal* hrt) const { + double rt = _RT(); + hrt[0] = chemPot_ / rt; + } + //==================================================================================================================== + void FixedChemPotSSTP::getEntropy_R_ref(doublereal* sr) const { + sr[0] = 0.0; + } + //==================================================================================================================== + void FixedChemPotSSTP::getGibbs_RT_ref(doublereal* grt) const { + double rt = _RT(); + grt[0] = chemPot_ / rt; + } + //==================================================================================================================== + void FixedChemPotSSTP::getGibbs_ref(doublereal* g) const { + g[0] = chemPot_; + } + //==================================================================================================================== + void FixedChemPotSSTP::getCp_R_ref(doublereal* cpr) const { + cpr[0] = 0.0; + } + //==================================================================================================================== + /* + * ---- Saturation Properties + */ + //==================================================================================================================== + /* + * ---- Initialization and Internal functions + */ + //==================================================================================================================== + /* + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + void FixedChemPotSSTP::initThermo() { + /* + * Call the base class thermo initializer + */ + SingleSpeciesTP::initThermo(); + } + //==================================================================================================================== + + void FixedChemPotSSTP::initThermoXML(XML_Node& phaseNode, std::string id) { + /* + * Find the Thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("FixedChemPotSSTP::initThermoXML", "no thermo XML node"); + } + XML_Node &tnode = phaseNode.child("thermo"); + std::string model = tnode["model"]; + if (model != "StoichSubstance" && model != "FixedChemPot" && model != "StoichSubstanceSSTP") { + throw CanteraError("FixedChemPotSSTP::initThermoXML()", + "thermo model attribute must be FixedChemPot or StoichSubstance or StoichSubstanceSSTP"); + } + if (model == "FixedChemPot") { + double val = ctml::getFloatDefaultUnits(tnode, "chemicalPotential", "J/kmol"); + chemPot_ = val; + } + SingleSpeciesTP::initThermoXML(phaseNode, id); + + + } + //==================================================================================================================== + /* + * setParameters: + * + * Generic routine that is used to set the parameters used + * by this model. + * C[0] = density of phase [ kg/m3 ] + */ + void FixedChemPotSSTP::setParameters(int n, doublereal * const c) { + chemPot_ = c[0]; + } + //==================================================================================================================== + /* + * getParameters: + * + * Generic routine that is used to get the parameters used + * by this model. + * n = 1 + * C[0] = density of phase [ kg/m3 ] + */ + void FixedChemPotSSTP::getParameters(int &n, doublereal * const c) const { + n = 1; + c[0] = chemPot_; + } + //==================================================================================================================== + void FixedChemPotSSTP::setParametersFromXML(const XML_Node& eosdata) { + std::string model = eosdata["model"]; + if (model != "StoichSubstance" && model != "FixedChemPot" && model != "StoichSubstanceSSTP") { + throw CanteraError("FixedChemPotSSTP::setParametersFromXML", + "thermo model attribute must be FixedChemPot or StoichSubstance or StoichSubstanceSSTP"); + } + if (model == "FixedChemPotSSTP") { + doublereal val = ctml::getFloatDefaultUnits(eosdata, "chemicalPotential", "J/kmol"); + chemPot_ = val; + } + } + //==================================================================================================================== + // Function to set the chemical potential directly + /* + * @param chemPot Value of the chemical potential (units J/kmol) + */ + void FixedChemPotSSTP::setChemicalPotential(doublereal chemPot) { + chemPot_ = chemPot; + } + //==================================================================================================================== +} diff --git a/Cantera/src/thermo/FixedChemPotSSTP.h b/Cantera/src/thermo/FixedChemPotSSTP.h new file mode 100644 index 000000000..8090aac8a --- /dev/null +++ b/Cantera/src/thermo/FixedChemPotSSTP.h @@ -0,0 +1,653 @@ +/** + * @file FixedChemPotSSTP.h + * Header file for the FixedChemPotSSTP class, which represents a fixed-composition + * incompressible substance with a constant chemical potential (see \ref thermoprops and + * class \link Cantera::FixedChemPotSSTP FixedChemPotSSTP\endlink) + */ + +/* + * 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. + */ + +/* + * $Date: 2009-11-09 16:36:49 -0700 (Mon, 09 Nov 2009) $ + * $Revision: 255 $ + */ + +#ifndef CT_FIXEDCHEMPOTSSTP_H +#define CT_FIXEDCHEMPOTSSTP_H + +#include "mix_defs.h" +#include "SingleSpeciesTP.h" +#include "SpeciesThermo.h" + +namespace Cantera { + + //! Class %FixedChemPotSSTP represents a stoichiometric (fixed + //! composition) incompressible substance. + /*! + * This class internally changes the independent degree of freedom from + * density to pressure. This is necessary because the phase is + * incompressible. It uses a zero volume approximation. + * + * + * Specification of Species Standard %State Properties + * + * This class inherits from SingleSpeciesTP. + * It uses a single value for the chemical potential which is assumed to be constant + * with respect to temperature and pressure. + * + * The reference state thermodynamics is inherited from SingleSpeciesTP. However, + * it's only used to set the initial chemical potential to the value + * of the chemical potential at the starting conditions. Thereafter, + * it is ignored. + * + * For a zero volume material, the internal energy and the enthalpy are + * equal to the chemical potential. The entropy, the heat capacity, and the molar volume + * are equal to zero. + * + * + * Specification of Solution Thermodynamic Properties + * + * All solution properties are obtained from the standard state + * species functions, since there is only one species in the phase. + * + * Application within %Kinetics Managers + * + * The standard concentration is equal to 1.0. This means that the + * kinetics operator works on an (activities basis). Since this + * is a stoichiometric substance, this means that the concentration + * of this phase drops out of kinetics expressions. + * + * An example of a reaction using this is a sticking coefficient + * reaction of a substance in an ideal gas phase on a surface with a bulk phase + * species in this phase. In this case, the rate of progress for this + * reaction, \f$ R_s \f$, may be expressed via the following equation: + * \f[ + * R_s = k_s C_{gas} + * \f] + * where the units for \f$ R_s \f$ are kmol m-2 s-1. \f$ C_{gas} \f$ has units + * of kmol m-3. Therefore, the kinetic rate constant, \f$ k_s \f$, has + * units of m s-1. Nowhere does the concentration of the bulk phase + * appear in the rate constant expression, since it's a stoichiometric + * phase, and the activity is always equal to 1.0. + * + * Instanteation of the Class + * + * This phase may be instanteated by calling the default ThermoFactory routine + * for %Cantera. This new %FixedChemPotSSTP object must then have a standalone xml file + * description an example of which is given below. + * + * + * + * It may also be created by the following code snippets. The code + * includes the special member function setChemicalPotential( chempot), which + * sets the chemical potential to a specific value in J / kmol. + * + * @code + * sprintf(file_ID,"%s#Li(Fixed)", iFile); + * XML_Node *xm = get_XML_NameID("phase", file_ID, 0); + * FixedChemPotSSTP *LiFixed = new FixedChemPotSSTP(*xm); + // Set the chemical potential to -2.3E7 J/kmol + * LiFixed->setChemicalPotential(-2.3E7.) + * @endcode + * + * or by the following call to importPhase(): + * + * @code + * sprintf(file_ID,"%s#NaCl(S)", iFile); + * XML_Node *xm = get_XML_NameID("phase", file_ID, 0); + * FixedChemPotSSTP solid; + * importPhase(*xm, &solid); + * @endcode + * + * The phase may also be created by a special constructor so that element + * potentials may be set. The constructor takes the name of the element and + * the value of the element chemical potential. An example is given below. + * + * @code + * FixedChemPotSSTP *LiFixed = new FixedChemPotSSTP("Li", -2.3E7); + * @endcode + * + * XML Example + * + * The phase model name for this is called FixedChemPot. It must be supplied + * as the model attribute of the thermo XML element entry. + * + * + * @verbatim + + + + + + + + Li + + + LiFixed + + + -2.3E7 + + + + + + + + + + Li:1 + + + + 50.72389, 6.672267, -2.517167, + 10.15934, -0.200675, -427.2115, + 130.3973 + + + + + + + @endverbatim + * + * The model attribute, "FixedChemPot", on the thermo element + * identifies the phase as being a FixedChemPotSSTP object. + * + * @ingroup thermoprops + */ + class FixedChemPotSSTP : public SingleSpeciesTP { + + public: + + //! Default constructor for the FixedChemPotSSTP class + FixedChemPotSSTP(); + + //! Construct and initialize a FixedChemPotSSTP ThermoPhase object + //! directly from an asci input file + /*! + * @param infile name of the input file + * @param id name of the phase id in the file. + * If this is blank, the first phase in the file is used. + */ + FixedChemPotSSTP(std::string infile, std::string id = ""); + + //! Construct and initialize a FixedChemPotSSTP ThermoPhase object + //! directly from an XML database + /*! + * @param phaseRef XML node pointing to a FixedChemPotSSTP description + * @param id Id of the phase. + */ + FixedChemPotSSTP(XML_Node& phaseRef, std::string id = ""); + + //! Copy constructor + /*! + * @param right Object to be copied + */ + FixedChemPotSSTP(const FixedChemPotSSTP &right); + + //! Special constructor for the FixecChemPotSSTP class setting an element chemical + //! potential directly + /*! + * This will create a %FixedChemPotSSTP consisting of a single species with the + * stoichiometry of one of the specified atom. It will have a chemical potential + * that is given by the second argument. + * + * @param Ename String name of the element + * @param chemPot Value of the chemical potential of that element (J/kmol) + */ + FixedChemPotSSTP(std::string Ename, doublereal chemPot); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + FixedChemPotSSTP & operator=(const FixedChemPotSSTP & right); + + //! Destructor for the routine (virtual) + virtual ~FixedChemPotSSTP(); + + //! Duplication function + /*! + * This virtual function is used to create a duplicate of the + * current phase. It's used to duplicate the phase when given + * a ThermoPhase pointer to the phase. + * + * @return It returns a ThermoPhase pointer. + */ + ThermoPhase *duplMyselfAsThermoPhase() const; + + /** + * + * @name Utilities + * @{ + */ + + /** + * Equation of state flag. + * + * Returns the value cStoichSubstance, defined in mix_defs.h. + */ + virtual int eosType() const; + + /** + * @} + * @name Molar Thermodynamic Properties of the Solution + * @{ + */ + + /** + * @} + * @name Mechanical Equation of State + * @{ + */ + + + //! Report the Pressure. Units: Pa. + /*! + * For an incompressible substance, the density is independent + * of pressure. This method simply returns the storred + * pressure value. + */ + virtual doublereal pressure() const; + + //! Set the pressure at constant temperature. Units: Pa. + /*! + * For an incompressible substance, the density is + * independent of pressure. Therefore, this method only + * stores the specified pressure value. It does not + * modify the density. + * + * @param p Pressure (units - Pa) + */ + virtual void setPressure(doublereal p); + + //! Returns the isothermal compressibility. Units: 1/Pa. + /*! + * The isothermal compressibility is defined as + * \f[ + * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T + * \f] + */ + virtual doublereal isothermalCompressibility() const; + + //! Return the volumetric thermal expansion coefficient. Units: 1/K. + /*! + * The thermal expansion coefficient is defined as + * \f[ + * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P + * \f] + */ + virtual doublereal thermalExpansionCoeff() const ; + + /** + * @} + * @name Activities, Standard States, and Activity Concentrations + * + * This section is largely handled by parent classes, since there + * is only one species. Therefore, the activity is equal to one. + * @{ + */ + + //! This method returns an array of generalized concentrations + /*! + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used + * by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. + * + * For a stoichiomeetric substance, there is + * only one species, and the generalized concentration is 1.0. + * + * @param c Output array of generalized concentrations. The + * units depend upon the implementation of the + * reaction rate expressions within the phase. + */ + virtual void getActivityConcentrations(doublereal* c) const; + + //! Return the standard concentration for the kth species + /*! + * The standard concentration \f$ C^0_k \f$ used to normalize + * the activity (i.e., generalized) concentration. + * This phase assumes that the kinetics operator works on an + * dimensionless basis. Thus, the standard concentration is + * equal to 1.0. + * + * @param k Optional parameter indicating the species. The default + * is to assume this refers to species 0. + * @return + * Returns The standard Concentration as 1.0 + */ + virtual doublereal standardConcentration(int k=0) const; + + //! Natural logarithm of the standard concentration of the kth species. + /*! + * @param k index of the species (defaults to zero) + */ + virtual doublereal logStandardConc(int k=0) const; + + //! Get the array of chemical potentials at unit activity for the species + //! at their standard states at the current T and P of the solution. + /*! + * For a stoichiometric substance, there is no activity term in + * the chemical potential expression, and therefore the + * standard chemical potential and the chemical potential + * are both equal to the molar Gibbs function. + * + * These are the standard state chemical potentials \f$ \mu^0_k(T,P) + * \f$. The values are evaluated at the current + * temperature and pressure of the solution + * + * @param mu0 Output vector of chemical potentials. + * Length: m_kk. + */ + virtual void getStandardChemPotentials(doublereal* mu0) const; + + //! Returns the units of the standard and generalized concentrations. + /*! + * Note they have the same units, as their + * ratio is defined to be equal to the activity of the kth + * species in the solution, which is unitless. + * + * This routine is used in print out applications where the + * units are needed. Usually, MKS units are assumed throughout + * the program and in the XML input files. + * + * The base %ThermoPhase class assigns thedefault quantities + * of (kmol/m3) for all species. + * Inherited classes are responsible for overriding the default + * values if necessary. + * + * @param uA Output vector containing the units + * uA[0] = kmol units - default = 1 + * uA[1] = m units - default = -nDim(), the number of spatial + * dimensions in the Phase class. + * uA[2] = kg units - default = 0; + * uA[3] = Pa(pressure) units - default = 0; + * uA[4] = Temperature units - default = 0; + * uA[5] = time units - default = 0 + * @param k species index. Defaults to 0. + * @param sizeUA output int containing the size of the vector. + * Currently, this is equal to 6. + */ + virtual void getUnitsStandardConc(doublereal *uA, int k = 0, + int sizeUA = 6) const; + + //@} + /// @name Partial Molar Properties of the Solution + /// + /// These properties are handled by the parent class, + /// SingleSpeciesTP + //@{ + + //! Get the species partial molar volumes. Units: m^3/kmol. + /*! + * This is the phase molar volume. \f$ V(T,P) = V_o(T,P) \f$. + * + * set to zero. + * + * @param vbar On return, contains the molar volume of the single species + * and the phase. Units are m^3 / kmol. Length = 1 + */ + void getPartialMolarVolumes(doublereal* vbar) const; + + //@} + /// @name Properties of the Standard State of the Species in the Solution + //@{ + + //! Get the nondimensional Enthalpy functions for the species + //! at their standard states at the current T and P of the solution. + /*! + * @param hrt Output vector of nondimensional standard state enthalpies. + * Length: m_kk. + */ + virtual void getEnthalpy_RT(doublereal* hrt) const; + + //! Get the array of nondimensional Entropy functions for the + //! standard state species at the current T and P of the solution. + /*! + * @param sr Output vector of nondimensional standard state entropies. + * Length: m_kk. + */ + virtual void getEntropy_R(doublereal* sr) const; + + //! Get the nondimensional Gibbs functions for the species + //! in their standard states at the current T and P of the solution. + /*! + * @param grt Output vector of nondimensional standard state gibbs free energies + * Length: m_kk. + */ + virtual void getGibbs_RT(doublereal* grt) const; + + //! Get the nondimensional Heat Capacities at constant + //! pressure for the species standard states + //! at the current T and P of the solution + /*! + * @param cpr Output vector of nondimensional standard state heat capacities + * Length: m_kk. + */ + virtual void getCp_R(doublereal* cpr) const; + + //! Returns the vector of nondimensional Internal Energies of the standard + //! state species at the current T and P of the solution + /*! + * For an incompressible, + * stoichiometric substance, the molar internal energy is + * independent of pressure. Since the thermodynamic properties + * are specified by giving the standard-state enthalpy, the + * term \f$ P_{ref} \hat v\f$ is subtracted from the specified reference molar + * enthalpy to compute the standard state molar internal energy. + * + * @param urt output vector of nondimensional standard state + * internal energies of the species. Length: m_kk. + */ + virtual void getIntEnergy_RT(doublereal* urt) const; + + //! Get the molar volumes of each species in their standard + //! states at the current T and P of the solution. + /* + * units = m^3 / kmol + * + * We set this to zero + * + * @param vbar On output this contains the standard volume of the species + * and phase (m^3/kmol). Vector of length 1 + */ + virtual void getStandardVolumes(doublereal* vbar) const; + + //@} + /// @name Thermodynamic Values for the Species Reference States + //@{ + + //! Returns the vector of nondimensional + //! internal Energies of the reference state at the current temperature + //! of the solution and the reference pressure for each species. + /*! + * @param urt Output vector of nondimensional reference state + * internal energies of the species. + * Length: m_kk + */ + virtual void getIntEnergy_RT_ref(doublereal *urt) const; + + //@} + /// @name Thermodynamic Values for the Species Reference State + /// + + /*! + * Returns the vector of nondimensional + * enthalpies of the reference state at the current temperature + * of the solution and the reference pressure for the species. + * + * This function is resolved in this class. It is assumed that the m_spthermo species thermo + * pointer is populated and yields the reference state. + * + * @param hrt Output vector containing the nondimensional reference state enthalpies + * Length: m_kk. + */ + virtual void getEnthalpy_RT_ref(doublereal *hrt) const; + + /*! + * Returns the vector of nondimensional + * enthalpies of the reference state at the current temperature + * of the solution and the reference pressure for the species. + * + * This function is resolved in this class. It is assumed that the m_spthermo species thermo + * pointer is populated and yields the reference state. + * + * @param grt Output vector containing the nondimensional reference state + * Gibbs Free energies. Length: m_kk. + */ + virtual void getGibbs_RT_ref(doublereal *grt) const; + + + /*! + * Returns the vector of the + * gibbs function of the reference state at the current temperature + * of the solution and the reference pressure for the species. + * units = J/kmol + * + * This function is resolved in this class. It is assumed that the m_spthermo species thermo + * pointer is populated and yields the reference state. + * + * @param g Output vector containing the reference state + * Gibbs Free energies. Length: m_kk. Units: J/kmol. + */ + virtual void getGibbs_ref(doublereal *g) const; + + /*! + * Returns the vector of nondimensional + * entropies of the reference state at the current temperature + * of the solution and the reference pressure for each species. + * + * This function is resolved in this class. It is assumed that the m_spthermo species thermo + * pointer is populated and yields the reference state. + * + * @param er Output vector containing the nondimensional reference state + * entropies. Length: m_kk. + */ + virtual void getEntropy_R_ref(doublereal *er) const; + + /*! + * Returns the vector of nondimensional + * constant pressure heat capacities of the reference state + * at the current temperature of the solution + * and reference pressure for each species. + * + * This function is resolved in this class. It is assumed that the m_spthermo species thermo + * pointer is populated and yields the reference state. + * + * @param cprt Output vector of nondimensional reference state + * heat capacities at constant pressure for the species. + * Length: m_kk + */ + virtual void getCp_R_ref(doublereal *cprt) const; + + + + + /* + * ---- Critical State Properties + */ + + + /* + * ---- Saturation Properties + */ + + /* + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + + virtual void initThermoXML(XML_Node& phaseNode, std::string id); + + //! Set the equation of state parameters + /*! + * @internal + * The number and meaning of these depends on the subclass. + * + * @param n number of parameters + * @param c array of \a n coefficients + * c[0] = density of phase [ kg/m3 ] + */ + virtual void setParameters(int n, doublereal * const c); + + //! Get the equation of state parameters in a vector + /*! + * @internal + * + * @param n number of parameters + * @param c array of \a n coefficients + * + * For this phase: + * - n = 1 + * - c[0] = density of phase [ kg/m3 ] + */ + virtual void getParameters(int &n, doublereal * const c) const; + + //! Set equation of state parameter values from XML entries. + /*! + * This method is called by function importPhase() in + * file importCTML.cpp when processing a phase definition in + * an input file. It should be overloaded in subclasses to set + * any parameters that are specific to that particular phase + * model. Note, this method is called before the phase is + * initialzed with elements and/or species. + * + * For this phase, the chemical potential is set + * + * @param eosdata An XML_Node object corresponding to + * the "thermo" entry for this phase in the input file. + * + * eosdata points to the thermo block, and looks like this: + * + * @verbatim + + + -2.7E7 + + @endverbatim + * + */ + virtual void setParametersFromXML(const XML_Node& eosdata); + + + //! Function to set the chemical potential directly + /*! + * @param chemPot Value of the chemical potential (units J/kmol) + */ + void setChemicalPotential(doublereal chemPot); + + protected: + + //! Value of the chemical potential of the bath species + /*! + * units are J/kmol + */ + doublereal chemPot_; + + }; + + +} + +#endif diff --git a/Cantera/src/thermo/GibbsExcessVPSSTP.cpp b/Cantera/src/thermo/GibbsExcessVPSSTP.cpp index d0b14221f..feba2c49e 100644 --- a/Cantera/src/thermo/GibbsExcessVPSSTP.cpp +++ b/Cantera/src/thermo/GibbsExcessVPSSTP.cpp @@ -33,7 +33,15 @@ namespace Cantera { * */ GibbsExcessVPSSTP::GibbsExcessVPSSTP() : - VPStandardStateTP() + VPStandardStateTP(), + moleFractions_(0), + lnActCoeff_Scaled_(0), + dlnActCoeffdT_Scaled_(0), + d2lnActCoeffdT2_Scaled_(0), + dlnActCoeffdlnN_diag_(0), + dlnActCoeffdlnX_diag_(0), + dlnActCoeffdlnN_(0,0), + m_pp(0) { } @@ -44,7 +52,15 @@ namespace Cantera { * has a working copy constructor */ GibbsExcessVPSSTP::GibbsExcessVPSSTP(const GibbsExcessVPSSTP &b) : - VPStandardStateTP() + VPStandardStateTP(), + moleFractions_(0), + lnActCoeff_Scaled_(0), + dlnActCoeffdT_Scaled_(0), + d2lnActCoeffdT2_Scaled_(0), + dlnActCoeffdlnN_diag_(0), + dlnActCoeffdlnX_diag_(0), + dlnActCoeffdlnN_(0,0), + m_pp(0) { GibbsExcessVPSSTP::operator=(b); } @@ -66,8 +82,10 @@ namespace Cantera { moleFractions_ = b.moleFractions_; lnActCoeff_Scaled_ = b.lnActCoeff_Scaled_; dlnActCoeffdT_Scaled_ = b.dlnActCoeffdT_Scaled_; - dlnActCoeffdlnX_Scaled_ = b.dlnActCoeffdlnX_Scaled_; - dlnActCoeffdlnN_Scaled_ = b.dlnActCoeffdlnN_Scaled_; + d2lnActCoeffdT2_Scaled_ = b.d2lnActCoeffdT2_Scaled_; + dlnActCoeffdlnX_diag_ = b.dlnActCoeffdlnX_diag_; + dlnActCoeffdlnN_diag_ = b.dlnActCoeffdlnN_diag_; + dlnActCoeffdlnN_ = b.dlnActCoeffdlnN_; m_pp = b.m_pp; return *this; @@ -195,16 +213,17 @@ namespace Cantera { /* * - Activities, Standard States, Activity Concentrations ----------- */ + void GibbsExcessVPSSTP::getActivityConcentrations(doublereal* c) const { + getActivities(c); + } doublereal GibbsExcessVPSSTP::standardConcentration(int k) const { - err("standardConcentration"); - return -1.0; + return 1.0; } doublereal GibbsExcessVPSSTP::logStandardConc(int k) const { - err("logStandardConc"); - return -1.0; + return 0.0; } void GibbsExcessVPSSTP::getActivities(doublereal* ac) const { @@ -215,7 +234,29 @@ namespace Cantera { } } + //==================================================================================================================== + // Get the array of non-dimensional molar-based activity coefficients at + // the current solution temperature, pressure, and solution concentration. + /* + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + void GibbsExcessVPSSTP::getActivityCoefficients(doublereal * const ac) const { + + getLnActivityCoefficients(ac); + // Protect against roundoff when taking exponentials + for (int k = 0; k < m_kk; k++) { + if (ac[k] > 700.) { + ac[k] = exp(700.); + } else if (ac[k] < -700.) { + ac[k] = exp(-700); + } else { + ac[k] = exp(ac[k]); + } + } + } + //==================================================================================================================== + void GibbsExcessVPSSTP::getElectrochemPotentials(doublereal* mu) const { getChemPotentials(mu); double ve = Faraday * electricPotential(); @@ -288,8 +329,8 @@ namespace Cantera { */ void GibbsExcessVPSSTP::getUnitsStandardConc(double *uA, int k, int sizeUA) const { for (int i = 0; i < sizeUA; i++) { - if (i == 0) uA[0] = 1.0; - if (i == 1) uA[1] = -nDim(); + if (i == 0) uA[0] = 0.0; + if (i == 1) uA[1] = 0.0; if (i == 2) uA[2] = 0.0; if (i == 3) uA[3] = 0.0; if (i == 4) uA[4] = 0.0; @@ -314,6 +355,7 @@ namespace Cantera { void GibbsExcessVPSSTP::initThermo() { initLengths(); VPStandardStateTP::initThermo(); + getMoleFractions(DATA_PTR(moleFractions_)); } @@ -324,8 +366,10 @@ namespace Cantera { moleFractions_.resize(m_kk); lnActCoeff_Scaled_.resize(m_kk); dlnActCoeffdT_Scaled_.resize(m_kk); - dlnActCoeffdlnX_Scaled_.resize(m_kk); - dlnActCoeffdlnN_Scaled_.resize(m_kk); + d2lnActCoeffdT2_Scaled_.resize(m_kk); + dlnActCoeffdlnX_diag_.resize(m_kk); + dlnActCoeffdlnN_diag_.resize(m_kk); + dlnActCoeffdlnN_.resize(m_kk, m_kk); m_pp.resize(m_kk); } diff --git a/Cantera/src/thermo/GibbsExcessVPSSTP.h b/Cantera/src/thermo/GibbsExcessVPSSTP.h index a100e5f45..46c7a4369 100644 --- a/Cantera/src/thermo/GibbsExcessVPSSTP.h +++ b/Cantera/src/thermo/GibbsExcessVPSSTP.h @@ -74,7 +74,27 @@ namespace Cantera { * fraction vector. That's one of its primary usages. In order to keep the mole fraction * vector constant, all of the setState functions are redesigned at this layer. * - *

SetState Strategy

+ * + *

+ * Activity Concentrations: Relationship of %ThermoPhase to %Kinetics Expressions + *

+ * + * As explained in a similar discussion in the ThermoPhase class, the actual units used + * in kinetics expressions must be specified in the ThermoPhase class for the corresponding + * species. These units vary with the field of study. %Cantera uses the concept of + * activity concentrations to represent this. Activity concentrations are used directly + * in the expressions for kinetics. Standard concentrations are used as the multiplicative + * constant that takes the activity of a species and turns it into an activity concentration. + * Standard concentrations must not depend on the concentration of the species in the phase. + * + * Here we set a standard for the specification of the standard concentrations for this class + * and all child classes underneath it. We specify here that the standard concentration is + * equal to 1 for all species. Therefore, the activities appear directly in kinetics expressions + * involving species in underlying %GibbsExcessVPSSTP phases. + * + *

+ * SetState Strategy + *

* * All setState functions that set the internal state of the ThermoPhase object are * overloaded at this level, so that a current mole fraction vector is maintained within @@ -223,7 +243,24 @@ namespace Cantera { * @{ */ - + //! This method returns an array of generalized concentrations + /*! + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. Note that they may + * or may not have units of concentration --- they might be + * partial pressures, mole fractions, or surface coverages, + * for example. + * + * @param c Output array of generalized concentrations. The + * units depend upon the implementation of the + * reaction rate expressions within the phase. + */ + virtual void getActivityConcentrations(doublereal* c) const; + /** @@ -237,6 +274,9 @@ namespace Cantera { * different sizes), this method may be called with an * optional parameter indicating the species. * + * The standard concentration for defaulted to 1. In other words + * the activity concentration is assumed to be 1. + * * @param k species index. Defaults to zero. */ virtual doublereal standardConcentration(int k=0) const; @@ -289,6 +329,13 @@ namespace Cantera { */ virtual void getActivities(doublereal* ac) const; + //! Get the array of non-dimensional molar-based ln activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param lnac Output vector of ln activity coefficients. Length: m_kk. + */ + virtual void getActivityCoefficients(doublereal * const ac) const; + //! Get the array of temperature derivatives of the log activity coefficients /*! @@ -304,43 +351,27 @@ namespace Cantera { err("getdlnActCoeffdT"); } - //! Get the array of change in the log activity coefficients w.r.t. change in state (change temp, change mole fractions) + //! Get the array of derivatives of the log activity coefficients with respect to the log of the species mole numbers /*! - * This function is a virtual class, but it first appears in GibbsExcessVPSSTP - * class and derived classes from GibbsExcessVPSSTP. + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * species log mole number (with all other species mole numbers held constant). The default treatment in the + * %ThermoPhase object is to set this vector to zero. + * + * units = 1 / kmol * - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can gradX/X. + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. * - * @param dT Input of temperature change - * @param dX Input vector of changes in mole fraction. length = m_kk - * @param dlnActCoeff Output vector of derivatives of the - * log Activity Coefficients. length = m_kk - */ - virtual void getdlnActCoeff(const doublereal dT, const doublereal * const dX, doublereal *dlnActCoeff) const { - err("getdlnActCoeff"); - } - - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can return zero. - * Implementations should take the derivative of the - * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. mole fraction, - * molality, etc.) that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. - * - * units = dimensionless + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] * + * @param ld Number of rows in the matrix * @param dlnActCoeffdlnN Output vector of derivatives of the - * log Activity Coefficients. length = m_kk + * log Activity Coefficients. length = m_kk * m_kk */ - virtual void getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const { - err("getdlnActCoeffdlnN"); + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) { + err(" getdlnActCoeffdlnN: nonzero and nonimplemented"); } //! Get the array of log concentration-like derivatives of the @@ -365,6 +396,7 @@ namespace Cantera { err("getdlnActCoeffdlnX"); } + //@} /// @name Partial Molar Properties of the Solution //@{ @@ -559,6 +591,8 @@ namespace Cantera { protected: + // HKM get rid of _Scaled_ prefix + //! Storage for the current values of the mole fractions of the species /*! * This vector is kept up-to-date when the setState functions are called. @@ -570,23 +604,35 @@ namespace Cantera { mutable std::vector moleFractions_; //! Storage for the current values of the activity coefficients of the - //! species, divided by RT + //! species mutable std::vector lnActCoeff_Scaled_; //! Storage for the current derivative values of the //! gradients with respect to temperature of the - //! log of theactivity coefficients of the species + //! log of the activity coefficients of the species mutable std::vector dlnActCoeffdT_Scaled_; //! Storage for the current derivative values of the - //! gradients with respect to logarithm of the mole fraction of the - //! log of theactivity coefficients of the species - mutable std::vector dlnActCoeffdlnN_Scaled_; + //! gradients with respect to temperature of the + //! log of the activity coefficients of the species + mutable std::vector d2lnActCoeffdT2_Scaled_; //! Storage for the current derivative values of the //! gradients with respect to logarithm of the mole fraction of the - //! log of theactivity coefficients of the species - mutable std::vector dlnActCoeffdlnX_Scaled_; + //! log of the activity coefficients of the species @deprecated + mutable std::vector dlnActCoeffdlnN_diag_; + + //! Storage for the current derivative values of the + //! gradients with respect to logarithm of the mole fraction of the + //! log of theactivity coefficients of the species @deprecated + mutable std::vector dlnActCoeffdlnX_diag_; + + //! Storage for the current derivative values of the gradients with respect to logarithm of the species mole number of the + //! log of the activity coefficients of the species + /*! + * dlnActCoeffdlnN_(k, m) is the derivative of ln(gamma_k) wrt ln mole number of species m + */ + mutable Array2D dlnActCoeffdlnN_; //! Temporary storage space that is fair game mutable std::vector m_pp; diff --git a/Cantera/src/thermo/HMWSoln.cpp b/Cantera/src/thermo/HMWSoln.cpp index 5147b705d..9059b492b 100644 --- a/Cantera/src/thermo/HMWSoln.cpp +++ b/Cantera/src/thermo/HMWSoln.cpp @@ -738,10 +738,13 @@ namespace Cantera { // Molar heat capacity at constant volume. Units: J/kmol/K. doublereal HMWSoln::cv_mole() const { - //getPartialMolarCv(m_tmpV.begin()); - //return mean_X(m_tmpV.begin()); - err("not implemented"); - return 0.0; + double kappa_t = isothermalCompressibility(); + double beta = thermalExpansionCoeff(); + double cp = cp_mole(); + double tt = temperature(); + double molarV = molarVolume(); + double cv = cp - beta * beta * tt * molarV / kappa_t; + return cv; } // diff --git a/Cantera/src/thermo/HMWSoln.h b/Cantera/src/thermo/HMWSoln.h index 17339386b..2526b9ff9 100644 --- a/Cantera/src/thermo/HMWSoln.h +++ b/Cantera/src/thermo/HMWSoln.h @@ -2053,14 +2053,6 @@ namespace Cantera { * -------------- Utilities ------------------------------- */ - /** - * Return a reference to the species thermodynamic property - * manager. - * - * @todo This method will fail if no species thermo - * manager has been installed. - */ - SpeciesThermo& speciesThermo() { return *m_spthermo; } //! Initialization of a HMWSoln phase using an xml file /*! diff --git a/Cantera/src/thermo/HMWSoln_input.cpp b/Cantera/src/thermo/HMWSoln_input.cpp index bca1ae93f..5faecbca2 100644 --- a/Cantera/src/thermo/HMWSoln_input.cpp +++ b/Cantera/src/thermo/HMWSoln_input.cpp @@ -24,6 +24,7 @@ #include using namespace std; +using namespace ctml; namespace Cantera { @@ -1656,15 +1657,88 @@ namespace Cantera { MolalityVPSSTP::initThermoXML(phaseNode, id); /* - * Lastly set the state + * Lastly calculate the charge balance and then add stuff until the charges compensate */ + + vector_fp mf(m_kk, 0.0); + getMoleFractions(DATA_PTR(mf)); + bool notDone = true; + + do { + double sum = 0.0; + int kMaxC = -1; + double MaxC = 0.0; + for (int k = 0; k < m_kk; k++) { + sum += mf[k] * m_speciesCharge[k]; + if (fabs(mf[k] * m_speciesCharge[k]) > MaxC) { + kMaxC = k; + } + } + int kHp = speciesIndex("H+"); + int kOHm = speciesIndex("OH-"); + + + if (fabs(sum) > 1.0E-30) { + if (kHp >= 0) { + if (mf[kHp] > sum * 1.1) { + mf[kHp] -= sum; + mf[0] += sum; + notDone = false; + } else { + if (sum > 0.0) { + mf[kHp] *= 0.5; + mf[0] += mf[kHp]; + sum -= mf[kHp]; + } + } + } + if (notDone) { + if (kOHm >= 0) { + if (mf[kOHm] > -sum * 1.1) { + mf[kOHm] += sum; + mf[0] -= sum; + notDone = false; + } else { + if (sum < 0.0) { + mf[kOHm] *= 0.5; + mf[0] += mf[kOHm]; + sum += mf[kOHm]; + } + } + } + if (notDone) { + if (kMaxC >= 0) { + if (mf[kMaxC] > (1.1 * sum / m_speciesCharge[kMaxC])) { + mf[kMaxC] -= sum / m_speciesCharge[kMaxC]; + mf[0] += sum / m_speciesCharge[kMaxC]; + } else { + mf[kMaxC] *= 0.5; + mf[0] += mf[kMaxC]; + notDone = true; + } + } + } + } + setMoleFractions(DATA_PTR(mf)); + } else { + notDone = false; + } + } while (notDone); + + + + + + + + // if (phaseNode.hasChild("state")) { // XML_Node& stateNode = phaseNode.child("state"); // setStateFromXML(stateNode); //} } - + //==================================================================================================================== // Precalculate the IMS Cutoff parameters for typeCutoff = 2 void HMWSoln::calcIMSCutoffParams_() { IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_); diff --git a/Cantera/src/thermo/IdealMolalSoln.cpp b/Cantera/src/thermo/IdealMolalSoln.cpp index 0c560636a..9a60d5da1 100644 --- a/Cantera/src/thermo/IdealMolalSoln.cpp +++ b/Cantera/src/thermo/IdealMolalSoln.cpp @@ -33,11 +33,14 @@ #endif //@} +using namespace ctml; + namespace Cantera { - + //! Small value to be used in cutoff expressions with logs static double xxSmall = 1.0E-150; - /** + + /* * Default constructor */ IdealMolalSoln::IdealMolalSoln() : diff --git a/Cantera/src/thermo/IdealMolalSoln.h b/Cantera/src/thermo/IdealMolalSoln.h index 737fe349a..151eb3083 100644 --- a/Cantera/src/thermo/IdealMolalSoln.h +++ b/Cantera/src/thermo/IdealMolalSoln.h @@ -777,14 +777,6 @@ namespace Cantera { /* * -------------- Utilities ------------------------------- */ - - /*! - * Return a reference to the species thermodynamic property - * manager. @todo This method will fail if no species thermo - * manager has been installed. - */ - SpeciesThermo& speciesThermo() { return *m_spthermo; } - //! Initialization routine for an IdealMolalSoln phase. /*! diff --git a/Cantera/src/thermo/IdealSolidSolnPhase.cpp b/Cantera/src/thermo/IdealSolidSolnPhase.cpp index 08fcbd784..4425531a7 100644 --- a/Cantera/src/thermo/IdealSolidSolnPhase.cpp +++ b/Cantera/src/thermo/IdealSolidSolnPhase.cpp @@ -57,7 +57,7 @@ namespace Cantera { } constructPhaseFile(inputFile, id); } - + //==================================================================================================================== IdealSolidSolnPhase::IdealSolidSolnPhase(XML_Node& root, std::string id, int formGC) : ThermoPhase(), @@ -75,12 +75,12 @@ namespace Cantera { } constructPhaseXML(root, id); } - + //==================================================================================================================== IdealSolidSolnPhase::IdealSolidSolnPhase(const IdealSolidSolnPhase &b) { *this = b; } - + //==================================================================================================================== IdealSolidSolnPhase& IdealSolidSolnPhase:: operator=(const IdealSolidSolnPhase &b) { @@ -117,7 +117,7 @@ namespace Cantera { IdealSolidSolnPhase *ii = new IdealSolidSolnPhase(*this); return (ThermoPhase*) ii; } - + //==================================================================================================================== /** * Equation of state flag. Returns the value cIdealGas, defined * in mix_defs.h. @@ -679,8 +679,7 @@ namespace Cantera { * property manager. They are polynomial functions of temperature. * @see SpeciesThermo */ - void IdealSolidSolnPhase:: - getPartialMolarEnthalpies(doublereal* hbar) const { + void IdealSolidSolnPhase::getPartialMolarEnthalpies(doublereal* hbar) const { const array_fp& _h = enthalpy_RT_ref(); doublereal rt = GasConstant * temperature(); scale(_h.begin(), _h.end(), hbar, rt); @@ -892,8 +891,7 @@ namespace Cantera { * units = m^3 / kmol */ void IdealSolidSolnPhase::getStandardVolumes(doublereal *vol) const { - copy(m_speciesMolarVolume.begin(), - m_speciesMolarVolume.end(), vol); + copy(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), vol); } @@ -1227,8 +1225,7 @@ namespace Cantera { "Unknown standardConc model: " + formStringa); } } else { - throw CanteraError(subname.c_str(), - "Unspecified standardConc model"); + throw CanteraError(subname.c_str(), "Unspecified standardConc model"); } /* @@ -1247,7 +1244,7 @@ namespace Cantera { for (int k = 0; k < m_kk; k++) { XML_Node* s = speciesDB->findByAttr("name", sss[k]); XML_Node *ss = s->findByName("standardState"); - m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI"); + m_speciesMolarVolume[k] = ctml::getFloat(*ss, "molarVolume", "toSI"); } /* diff --git a/Cantera/src/thermo/IdealSolidSolnPhase.h b/Cantera/src/thermo/IdealSolidSolnPhase.h index a9f87b29c..279463915 100644 --- a/Cantera/src/thermo/IdealSolidSolnPhase.h +++ b/Cantera/src/thermo/IdealSolidSolnPhase.h @@ -579,9 +579,9 @@ namespace Cantera { /// @name Partial Molar Properties of the Solution ----------------------------- //@{ - /** - * Returns an array of partial molar enthalpies for the species - * in the mixture. + + //! Returns an array of partial molar enthalpies for the species in the mixture. + /*! * Units (J/kmol) * For this phase, the partial molar enthalpies are equal to the * pure species enthalpies @@ -1057,8 +1057,9 @@ namespace Cantera { */ doublereal m_Pcurrent; + //! Vector of molar volumes for each species in the solution /** - * Species molar volume \f$ m^3 kmol^-1 \f$ + * Species molar volumes \f$ m^3 kmol^-1 \f$ */ array_fp m_speciesMolarVolume; diff --git a/Cantera/src/thermo/IonsFromNeutralVPSSTP.cpp b/Cantera/src/thermo/IonsFromNeutralVPSSTP.cpp index 5beb7725f..029fd29cd 100644 --- a/Cantera/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/Cantera/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -33,13 +33,14 @@ using namespace std; #ifndef MIN +//! standard MIN function # define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) #endif namespace Cantera { static const double xxSmall = 1.0E-150; - + //==================================================================================================================== /* * Default constructor. * @@ -54,11 +55,14 @@ namespace Cantera { numAnionSpecies_(0), numPassThroughSpecies_(0), neutralMoleculePhase_(0), - IOwnNThermoPhase_(true) + IOwnNThermoPhase_(true), + moleFractionsTmp_(0), + muNeutralMolecule_(0), + lnActCoeff_NeutralMolecule_(0) { } - + //==================================================================================================================== // Construct and initialize an IonsFromNeutralVPSSTP object // directly from an asci input file /* @@ -95,14 +99,17 @@ namespace Cantera { numAnionSpecies_(0), numPassThroughSpecies_(0), neutralMoleculePhase_(neutralPhase), - IOwnNThermoPhase_(true) + IOwnNThermoPhase_(true), + moleFractionsTmp_(0), + muNeutralMolecule_(0), + lnActCoeff_NeutralMolecule_(0) { if (neutralPhase) { IOwnNThermoPhase_ = false; } constructPhaseFile(inputFile, id); } - + //==================================================================================================================== IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP(XML_Node& phaseRoot, std::string id, ThermoPhase *neutralPhase) : GibbsExcessVPSSTP(), @@ -114,7 +121,11 @@ namespace Cantera { numAnionSpecies_(0), numPassThroughSpecies_(0), neutralMoleculePhase_(neutralPhase), - IOwnNThermoPhase_(true) + IOwnNThermoPhase_(true), + moleFractionsTmp_(0), + muNeutralMolecule_(0), + + lnActCoeff_NeutralMolecule_(0) { if (neutralPhase) { IOwnNThermoPhase_ = false; @@ -122,7 +133,7 @@ namespace Cantera { constructPhaseXML(phaseRoot, id); } - + //==================================================================================================================== /* * Copy Constructor: @@ -140,11 +151,15 @@ namespace Cantera { numAnionSpecies_(0), numPassThroughSpecies_(0), neutralMoleculePhase_(0), - IOwnNThermoPhase_(true) + IOwnNThermoPhase_(true), + moleFractionsTmp_(0), + muNeutralMolecule_(0), + + lnActCoeff_NeutralMolecule_(0) { IonsFromNeutralVPSSTP::operator=(b); } - + //==================================================================================================================== /* * operator=() * @@ -196,9 +211,11 @@ namespace Cantera { IOwnNThermoPhase_ = b.IOwnNThermoPhase_; moleFractionsTmp_ = b.moleFractionsTmp_; muNeutralMolecule_ = b.muNeutralMolecule_; - gammaNeutralMolecule_ = b.gammaNeutralMolecule_; + // gammaNeutralMolecule_ = b.gammaNeutralMolecule_; + lnActCoeff_NeutralMolecule_ = b.lnActCoeff_NeutralMolecule_; dlnActCoeffdT_NeutralMolecule_ = b.dlnActCoeffdT_NeutralMolecule_; - dlnActCoeffdlnX_NeutralMolecule_ = b.dlnActCoeffdlnX_NeutralMolecule_; + dlnActCoeffdlnX_diag_NeutralMolecule_ = b.dlnActCoeffdlnX_diag_NeutralMolecule_; + dlnActCoeffdlnN_diag_NeutralMolecule_ = b.dlnActCoeffdlnN_diag_NeutralMolecule_; dlnActCoeffdlnN_NeutralMolecule_ = b.dlnActCoeffdlnN_NeutralMolecule_; return *this; @@ -306,110 +323,18 @@ namespace Cantera { //err("not implemented"); //return 0.0; } - + //=========================================================================================================== /* * - Activities, Standard States, Activity Concentrations ----------- */ - - // This method returns an array of generalized concentrations - /* - * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / - * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration - * defined below and \f$ a_k \f$ are activities used in the - * thermodynamic functions. These activity (or generalized) - * concentrations are used - * by kinetics manager classes to compute the forward and - * reverse rates of elementary reactions. Note that they may - * or may not have units of concentration --- they might be - * partial pressures, mole fractions, or surface coverages, - * for example. - * - * Here we define the activity concentrations as equal - * to the activities, because the standard concentration is 1. - * - * @param c Output array of generalized concentrations. The - * units depend upon the implementation of the - * reaction rate expressions within the phase. - */ - void IonsFromNeutralVPSSTP::getActivityConcentrations(doublereal* c) const { - getActivities(c); - } - - void IonsFromNeutralVPSSTP::getDissociationCoeffs(vector_fp& coeffs,vector_fp& charges, std::vector& neutMolIndex){ + //=========================================================================================================== + void IonsFromNeutralVPSSTP::getDissociationCoeffs(vector_fp& coeffs, + vector_fp& charges, std::vector& neutMolIndex) const { coeffs = fm_neutralMolec_ions_; charges = m_speciesCharge; neutMolIndex = fm_invert_ionForNeutral; - //for ( int k = 0; k < fm_neutralMolec_ions_[k]; k++ ) - // coeffs.push_back(fm_neutralMolec_ions_[k]); } - - // Return the standard concentration for the kth species - /* - * The standard concentration \f$ C^0_k \f$ used to normalize - * the activity (i.e., generalized) concentration. In many cases, this quantity - * will be the same for all species in a phase - for example, - * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this - * reason, this method returns a single value, instead of an - * array. However, for phases in which the standard - * concentration is species-specific (e.g. surface species of - * different sizes), this method may be called with an - * optional parameter indicating the species. - * - * @param k Optional parameter indicating the species. The default - * is to assume this refers to species 0. - * @return - * Returns the standard concentration. The units are by definition - * dependent on the ThermoPhase and kinetics manager representation. - */ - doublereal IonsFromNeutralVPSSTP::standardConcentration(int k) const { - return 1.0; - } - - // Natural logarithm of the standard concentration of the kth species. - /* - * @param k index of the species (defaults to zero) - */ - doublereal IonsFromNeutralVPSSTP::logStandardConc(int k) const { - return 0.0; - } - - // Returns the units of the standard and generalized concentrations. - /* - * Note they have the same units, as their - * ratio is defined to be equal to the activity of the kth - * species in the solution, which is unitless. - * - * This routine is used in print out applications where the - * units are needed. Usually, MKS units are assumed throughout - * the program and in the XML input files. - * - * The base %ThermoPhase class assigns the default quantities - * of (kmol/m3) for all species. - * Inherited classes are responsible for overriding the default - * values if necessary. - * - * @param uA Output vector containing the units - * uA[0] = kmol units - default = 1 - * uA[1] = m units - default = -nDim(), the number of spatial - * dimensions in the Phase class. - * uA[2] = kg units - default = 0; - * uA[3] = Pa(pressure) units - default = 0; - * uA[4] = Temperature units - default = 0; - * uA[5] = time units - default = 0 - * @param k species index. Defaults to 0. - * @param sizeUA output int containing the size of the vector. - * Currently, this is equal to 6. - */ - void IonsFromNeutralVPSSTP::getUnitsStandardConc(double *uA, int k, - int sizeUA) const { - uA[0] = 0; - uA[1] = 0; - uA[2] = 0; - uA[3] = 0; - uA[4] = 0; - uA[5] = 0; - } - + //=========================================================================================================== // Get the array of non-dimensional molar-based activity coefficients at // the current solution temperature, pressure, and solution concentration. /* @@ -472,7 +397,8 @@ namespace Cantera { neutralMoleculePhase_->getChemPotentials(mu); break; case cIonSolnType_SINGLEANION: - neutralMoleculePhase_->getActivityCoefficients(DATA_PTR(gammaNeutralMolecule_)); + // neutralMoleculePhase_->getActivityCoefficients(DATA_PTR(gammaNeutralMolecule_)); + neutralMoleculePhase_->getLnActivityCoefficients(DATA_PTR(lnActCoeff_NeutralMolecule_)); fact2 = 2.0 * RT_ * log(2.0); @@ -482,7 +408,7 @@ namespace Cantera { icat = cationList_[k]; jNeut = fm_invert_ionForNeutral[icat]; xx = fmaxx(SmallNumber, moleFractions_[icat]); - mu[icat] = muNeutralMolecule_[jNeut] + fact2 + RT_ * log(gammaNeutralMolecule_[jNeut] * xx); + mu[icat] = muNeutralMolecule_[jNeut] + fact2 + RT_ * (lnActCoeff_NeutralMolecule_[jNeut] + log(xx)); } // Do the anion list @@ -496,7 +422,7 @@ namespace Cantera { icat = passThroughList_[k]; jNeut = fm_invert_ionForNeutral[icat]; xx = fmaxx(SmallNumber, moleFractions_[icat]); - mu[icat] = muNeutralMolecule_[jNeut] + RT_ * log( gammaNeutralMolecule_[jNeut] * xx); + mu[icat] = muNeutralMolecule_[jNeut] + RT_ * (lnActCoeff_NeutralMolecule_[jNeut] + log(xx)); } break; @@ -593,9 +519,9 @@ namespace Cantera { } - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! + // Get the array of log concentration-like derivatives of the + // log activity coefficients + /* * This function is a virtual method. For ideal mixtures * (unity activity coefficients), this can return zero. * Implementations should take the derivative of the @@ -612,55 +538,64 @@ namespace Cantera { * derivatives of the log Activity Coefficients. * length = m_kk */ - void IonsFromNeutralVPSSTP::getdlnActCoeffdlnX(doublereal *dlnActCoeffdlnX) const { + void IonsFromNeutralVPSSTP::getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const { s_update_lnActCoeff(); - s_update_dlnActCoeff_dlnX(); + s_update_dlnActCoeff_dlnX_diag(); for (int k = 0; k < m_kk; k++) { - dlnActCoeffdlnX[k] = dlnActCoeffdlnX_Scaled_[k]; + dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k]; } } - - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can return zero. - * Implementations should take the derivative of the - * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. moles) - * that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. - * - * units = dimensionless - * - * @param dlnActCoeffdlnN Output vector of log(mole fraction) - * derivatives of the log Activity Coefficients. - * length = m_kk - */ - void IonsFromNeutralVPSSTP::getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const { + //==================================================================================================================== + // Get the array of log concentration-like derivatives of the + // log activity coefficients + /* + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. moles) + * that represents the standard state. + * This quantity is to be used in conjunction with derivatives of + * that concentration-like variable when the derivative of the chemical + * potential is taken. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + void IonsFromNeutralVPSSTP::getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { s_update_lnActCoeff(); - s_update_dlnActCoeff_dlnN(); + s_update_dlnActCoeff_dlnN_diag(); for (int k = 0; k < m_kk; k++) { - dlnActCoeffdlnN[k] = dlnActCoeffdlnN_Scaled_[k]; + dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k]; } } - - // This is temporary. We will get rid of this + //==================================================================================================================== + void IonsFromNeutralVPSSTP::getdlnActCoeffdlnN(const int ld, doublereal *dlnActCoeffdlnN) { + s_update_lnActCoeff(); + s_update_dlnActCoeff_dlnN(); + double *data = & dlnActCoeffdlnN_(0,0); + for (int k = 0; k < m_kk; k++) { + for (int m = 0; m < m_kk; m++) { + dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m]; + } + } + } + //==================================================================================================================== void IonsFromNeutralVPSSTP::setTemperature(const doublereal temp) { double p = pressure(); IonsFromNeutralVPSSTP::setState_TP(temp, p); } - - // This is temporary. We will get rid of this + //==================================================================================================================== void IonsFromNeutralVPSSTP::setPressure(doublereal p) { double t = temperature(); IonsFromNeutralVPSSTP::setState_TP(t, p); } - + //==================================================================================================================== // Set the temperature (K) and pressure (Pa) /* * Setting the pressure may involve the solution of a nonlinear equation. @@ -724,7 +659,7 @@ namespace Cantera { } } - + //==================================================================================================================== // Calculate neutral molecule mole fractions /* * This routine calculates the neutral molecule mole @@ -852,8 +787,8 @@ namespace Cantera { } } - -// Calculate neutral molecule mole fractions + //==================================================================================================================== + // Calculate neutral molecule mole fractions /* * This routine calculates the neutral molecule mole * fraction given the vector of ion mole fractions, @@ -867,7 +802,7 @@ namespace Cantera { * is followed, while the difference in charge neutrality * is dumped into the anion mole number to fix the imbalance. */ - void IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads(const doublereal * const dx, doublereal *dy) const { + void IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads(const doublereal * const dx, doublereal * const dy) const { int k, icat, jNeut; doublereal sumCat; doublereal sumAnion; @@ -1156,7 +1091,7 @@ namespace Cantera { } - + //==================================================================================================================== /* * @internal Initialize. This method is provided to allow * subclasses to perform any initialization required after all @@ -1174,7 +1109,7 @@ namespace Cantera { initLengths(); GibbsExcessVPSSTP::initThermo(); } - + //==================================================================================================================== // Initialize lengths of local variables after all species have // been identified. @@ -1190,12 +1125,23 @@ namespace Cantera { passThroughList_.resize(m_kk); moleFractionsTmp_.resize(m_kk); muNeutralMolecule_.resize(numNeutralMoleculeSpecies_); - gammaNeutralMolecule_.resize(numNeutralMoleculeSpecies_); + lnActCoeff_NeutralMolecule_.resize(numNeutralMoleculeSpecies_); dlnActCoeffdT_NeutralMolecule_.resize(numNeutralMoleculeSpecies_); - dlnActCoeffdlnX_NeutralMolecule_.resize(numNeutralMoleculeSpecies_); - dlnActCoeffdlnN_NeutralMolecule_.resize(numNeutralMoleculeSpecies_); + dlnActCoeffdlnX_diag_NeutralMolecule_.resize(numNeutralMoleculeSpecies_); + dlnActCoeffdlnN_diag_NeutralMolecule_.resize(numNeutralMoleculeSpecies_); + dlnActCoeffdlnN_NeutralMolecule_.resize(numNeutralMoleculeSpecies_, numNeutralMoleculeSpecies_, 0.0); } - + //==================================================================================================================== + //! Return the factor overlap + /*! + * @param elnamesVN + * @param elemVectorN + * @param nElementsN + * @param elnamesVI + * @param elemVectorI + * @param nElementsI + * + */ static double factorOverlap(const std::vector& elnamesVN , const std::vector& elemVectorN, const int nElementsN, @@ -1221,7 +1167,7 @@ namespace Cantera { } return fMax; } - + //==================================================================================================================== /* * initThermoXML() (virtual from ThermoPhase) * Import and initialize a ThermoPhase object @@ -1386,13 +1332,12 @@ namespace Cantera { * have charge conservation. */ } - + //==================================================================================================================== // Update the activity coefficients /* * This function will be called to update the internally storred * natural logarithm of the activity coefficients * - * he = X_A X_B(B + C(X_A - X_B)) */ void IonsFromNeutralVPSSTP::s_update_lnActCoeff() const { int k, icat, jNeut; @@ -1400,7 +1345,7 @@ namespace Cantera { /* * Get the activity coefficiens of the neutral molecules */ - neutralMoleculePhase_->getActivityCoefficients(DATA_PTR(gammaNeutralMolecule_)); + neutralMoleculePhase_->getLnActivityCoefficients(DATA_PTR(lnActCoeff_NeutralMolecule_)); switch (ionSolnType_) { case cIonSolnType_PASSTHROUGH: @@ -1413,7 +1358,7 @@ namespace Cantera { icat = cationList_[k]; jNeut = fm_invert_ionForNeutral[icat]; fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk]; - lnActCoeff_Scaled_[icat] = log(gammaNeutralMolecule_[jNeut])/fmij; + lnActCoeff_Scaled_[icat] = lnActCoeff_NeutralMolecule_[jNeut] / fmij; } // Do the anion list @@ -1425,7 +1370,7 @@ namespace Cantera { for (k = 0; k < numPassThroughSpecies_; k++) { icat = passThroughList_[k]; jNeut = fm_invert_ionForNeutral[icat]; - lnActCoeff_Scaled_[icat] = log(gammaNeutralMolecule_[jNeut]); + lnActCoeff_Scaled_[icat] = lnActCoeff_NeutralMolecule_[jNeut]; } break; @@ -1441,12 +1386,19 @@ namespace Cantera { } } - - - - // get the gradient in the activity coefficients - - void IonsFromNeutralVPSSTP::getdlnActCoeff(const doublereal dT, const doublereal * const dX, doublereal *dlnActCoeff) const { + //==================================================================================================================== + // Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + // a line in parameter space or along a line in physical space + /* + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + */ + void IonsFromNeutralVPSSTP::getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const { int k, icat, jNeut; doublereal fmij; int numNeutMolSpec; @@ -1456,7 +1408,7 @@ namespace Cantera { GibbsExcessVPSSTP *geThermo = dynamic_cast(neutralMoleculePhase_); if (!geThermo) { for ( k = 0; k < m_kk; k++ ){ - dlnActCoeff[k] = dX[k]/moleFractions_[k]; + dlnActCoeffds[k] = dXds[k] / moleFractions_[k]; } return; } @@ -1466,11 +1418,11 @@ namespace Cantera { vector_fp dX_NeutralMolecule(numNeutMolSpec); - getNeutralMoleculeMoleGrads(DATA_PTR(dX),DATA_PTR(dX_NeutralMolecule)); + getNeutralMoleculeMoleGrads(DATA_PTR(dXds),DATA_PTR(dX_NeutralMolecule)); // All mole fractions returned to normal - geThermo->getdlnActCoeff(dT, DATA_PTR(dX_NeutralMolecule), DATA_PTR(dlnActCoeff_NeutralMolecule)); + geThermo->getdlnActCoeffds(dTds, DATA_PTR(dX_NeutralMolecule), DATA_PTR(dlnActCoeff_NeutralMolecule)); switch (ionSolnType_) { case cIonSolnType_PASSTHROUGH: @@ -1483,36 +1435,36 @@ namespace Cantera { icat = cationList_[k]; jNeut = fm_invert_ionForNeutral[icat]; fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk]; - dlnActCoeff[icat] = dlnActCoeff_NeutralMolecule[jNeut]/fmij; + dlnActCoeffds[icat] = dlnActCoeff_NeutralMolecule[jNeut]/fmij; } // Do the anion list icat = anionList_[0]; jNeut = fm_invert_ionForNeutral[icat]; - dlnActCoeff[icat]= 0.0; + dlnActCoeffds[icat]= 0.0; // Do the list of neutral molecules for (k = 0; k < numPassThroughSpecies_; k++) { icat = passThroughList_[k]; jNeut = fm_invert_ionForNeutral[icat]; - dlnActCoeff[icat] = dlnActCoeff_NeutralMolecule[jNeut]; + dlnActCoeffds[icat] = dlnActCoeff_NeutralMolecule[jNeut]; } break; case cIonSolnType_SINGLECATION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffds", "Unimplemented type"); break; case cIonSolnType_MULTICATIONANION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffds", "Unimplemented type"); break; default: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffds", "Unimplemented type"); break; } } - - // Update the temperatture derivative of the ln activity coefficients + //==================================================================================================================== + // Update the temperature derivative of the ln activity coefficients /* * This function will be called to update the internally storred * temperature derivative of the natural logarithm of the activity coefficients @@ -1559,23 +1511,23 @@ namespace Cantera { break; case cIonSolnType_SINGLECATION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffdT", "Unimplemented type"); break; case cIonSolnType_MULTICATIONANION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffdT", "Unimplemented type"); break; default: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffdT", "Unimplemented type"); break; } } - + //==================================================================================================================== /* * This function will be called to update the internally storred * temperature derivative of the natural logarithm of the activity coefficients */ - void IonsFromNeutralVPSSTP::s_update_dlnActCoeff_dlnX() const { + void IonsFromNeutralVPSSTP::s_update_dlnActCoeff_dlnX_diag() const { int k, icat, jNeut; doublereal fmij; /* @@ -1583,11 +1535,11 @@ namespace Cantera { */ GibbsExcessVPSSTP *geThermo = dynamic_cast(neutralMoleculePhase_); if (!geThermo) { - fvo_zero_dbl_1(dlnActCoeffdlnX_Scaled_, m_kk); + fvo_zero_dbl_1(dlnActCoeffdlnX_diag_, m_kk); return; } - geThermo->getdlnActCoeffdlnX(DATA_PTR(dlnActCoeffdlnX_NeutralMolecule_)); + geThermo->getdlnActCoeffdlnX_diag(DATA_PTR(dlnActCoeffdlnX_diag_NeutralMolecule_)); switch (ionSolnType_) { case cIonSolnType_PASSTHROUGH: @@ -1600,52 +1552,113 @@ namespace Cantera { icat = cationList_[k]; jNeut = fm_invert_ionForNeutral[icat]; fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk]; - dlnActCoeffdlnX_Scaled_[icat] = dlnActCoeffdlnX_NeutralMolecule_[jNeut]/fmij; + dlnActCoeffdlnX_diag_[icat] = dlnActCoeffdlnX_diag_NeutralMolecule_[jNeut]/fmij; } // Do the anion list icat = anionList_[0]; jNeut = fm_invert_ionForNeutral[icat]; - dlnActCoeffdlnX_Scaled_[icat]= 0.0; + dlnActCoeffdlnX_diag_[icat]= 0.0; // Do the list of neutral molecules for (k = 0; k < numPassThroughSpecies_; k++) { icat = passThroughList_[k]; jNeut = fm_invert_ionForNeutral[icat]; - dlnActCoeffdlnX_Scaled_[icat] = dlnActCoeffdlnX_NeutralMolecule_[jNeut]; + dlnActCoeffdlnX_diag_[icat] = dlnActCoeffdlnX_diag_NeutralMolecule_[jNeut]; } break; case cIonSolnType_SINGLECATION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnX_diag()", "Unimplemented type"); break; case cIonSolnType_MULTICATIONANION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnX_diag()", "Unimplemented type"); break; default: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnX_diag()", "Unimplemented type"); break; } } - + //==================================================================================================================== /* * This function will be called to update the internally storred * temperature derivative of the natural logarithm of the activity coefficients */ + void IonsFromNeutralVPSSTP::s_update_dlnActCoeff_dlnN_diag() const { + int k, icat, jNeut; + doublereal fmij; + /* + * Get the activity coefficients of the neutral molecules + */ + GibbsExcessVPSSTP *geThermo = dynamic_cast(neutralMoleculePhase_); + if (!geThermo) { + fvo_zero_dbl_1(dlnActCoeffdlnN_diag_, m_kk); + return; + } + + geThermo->getdlnActCoeffdlnN_diag(DATA_PTR(dlnActCoeffdlnN_diag_NeutralMolecule_)); + + switch (ionSolnType_) { + case cIonSolnType_PASSTHROUGH: + break; + case cIonSolnType_SINGLEANION: + + // Do the cation list + for (k = 0; k < (int) cationList_.size(); k++) { + //! Get the id for the next cation + icat = cationList_[k]; + jNeut = fm_invert_ionForNeutral[icat]; + fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk]; + dlnActCoeffdlnN_diag_[icat] = dlnActCoeffdlnN_diag_NeutralMolecule_[jNeut]/fmij; + } + + // Do the anion list + icat = anionList_[0]; + jNeut = fm_invert_ionForNeutral[icat]; + dlnActCoeffdlnN_diag_[icat]= 0.0; + + // Do the list of neutral molecules + for (k = 0; k < numPassThroughSpecies_; k++) { + icat = passThroughList_[k]; + jNeut = fm_invert_ionForNeutral[icat]; + dlnActCoeffdlnN_diag_[icat] = dlnActCoeffdlnN_diag_NeutralMolecule_[jNeut]; + } + break; + + case cIonSolnType_SINGLECATION: + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN_diag()", "Unimplemented type"); + break; + case cIonSolnType_MULTICATIONANION: + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN_diag()", "Unimplemented type"); + break; + default: + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN_diag()", "Unimplemented type"); + break; + } + + } + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients + // wrt log(number of moles) - diagonal components + /* + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the number of moles of given species. + */ void IonsFromNeutralVPSSTP::s_update_dlnActCoeff_dlnN() const { - int k, icat, jNeut; - doublereal fmij; + int k, m, kcat, kNeut, mcat, mNeut; + doublereal fmij, mfmij; + dlnActCoeffdlnN_.zero(); /* * Get the activity coefficients of the neutral molecules */ - GibbsExcessVPSSTP *geThermo = dynamic_cast(neutralMoleculePhase_); + GibbsExcessVPSSTP *geThermo = dynamic_cast(neutralMoleculePhase_); if (!geThermo) { - fvo_zero_dbl_1(dlnActCoeffdlnN_Scaled_, m_kk); - return; + throw CanteraError("IonsFromNeutralVPSSTP::s_update_dlnActCoeff_dlnN()", "dynamic cast failed"); } - - geThermo->getdlnActCoeffdlnN(DATA_PTR(dlnActCoeffdlnN_NeutralMolecule_)); + int nsp_ge = geThermo->nSpecies(); + geThermo->getdlnActCoeffdlnN(nsp_ge, &(dlnActCoeffdlnN_NeutralMolecule_(0,0))); switch (ionSolnType_) { case cIonSolnType_PASSTHROUGH: @@ -1654,39 +1667,69 @@ namespace Cantera { // Do the cation list for (k = 0; k < (int) cationList_.size(); k++) { - //! Get the id for the next cation - icat = cationList_[k]; - jNeut = fm_invert_ionForNeutral[icat]; - fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk]; - dlnActCoeffdlnN_Scaled_[icat] = dlnActCoeffdlnN_NeutralMolecule_[jNeut]/fmij; + for (m = 0; m < (int) cationList_.size(); m++) { + kcat = cationList_[k]; + + kNeut = fm_invert_ionForNeutral[kcat]; + fmij = fm_neutralMolec_ions_[kcat + kNeut * m_kk]; + dlnActCoeffdlnN_diag_[kcat] = dlnActCoeffdlnN_diag_NeutralMolecule_[kNeut]/fmij; + + mcat = cationList_[m]; + mNeut = fm_invert_ionForNeutral[mcat]; + mfmij = fm_neutralMolec_ions_[mcat + mNeut * m_kk]; + + dlnActCoeffdlnN_(kcat,mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut,mNeut) * mfmij / fmij; + + } + for (m = 0; m < numPassThroughSpecies_; m++) { + mcat = passThroughList_[m]; + mNeut = fm_invert_ionForNeutral[mcat]; + dlnActCoeffdlnN_(kcat, mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut, mNeut) / fmij; + } } - // Do the anion list - icat = anionList_[0]; - jNeut = fm_invert_ionForNeutral[icat]; - dlnActCoeffdlnN_Scaled_[icat]= 0.0; + // Do the anion list -> anion activity coefficient is one + kcat = anionList_[0]; + kNeut = fm_invert_ionForNeutral[kcat]; + for (k = 0; k < m_kk; k++) { + dlnActCoeffdlnN_(kcat, k) = 0.0; + dlnActCoeffdlnN_(k, kcat) = 0.0; + } // Do the list of neutral molecules for (k = 0; k < numPassThroughSpecies_; k++) { - icat = passThroughList_[k]; - jNeut = fm_invert_ionForNeutral[icat]; - dlnActCoeffdlnN_Scaled_[icat] = dlnActCoeffdlnN_NeutralMolecule_[jNeut]; + kcat = passThroughList_[k]; + kNeut = fm_invert_ionForNeutral[kcat]; + dlnActCoeffdlnN_diag_[kcat] = dlnActCoeffdlnN_diag_NeutralMolecule_[kNeut]; + + for (m = 0; m < m_kk; m++) { + mcat = passThroughList_[m]; + mNeut = fm_invert_ionForNeutral[mcat]; + dlnActCoeffdlnN_(kcat, mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut, mNeut); + } + + + for (m = 0; m < (int) cationList_.size(); m++) { + mcat = cationList_[m]; + mNeut = fm_invert_ionForNeutral[mcat]; + mfmij = fm_neutralMolec_ions_[mcat + mNeut * m_kk]; + dlnActCoeffdlnN_(kcat, mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut,mNeut); + } + } break; case cIonSolnType_SINGLECATION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN", "Unimplemented type"); break; case cIonSolnType_MULTICATIONANION: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN", "Unimplemented type"); break; default: - throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type"); + throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN", "Unimplemented type"); break; } - } - - + //==================================================================================================================== } - +//====================================================================================================================== diff --git a/Cantera/src/thermo/IonsFromNeutralVPSSTP.h b/Cantera/src/thermo/IonsFromNeutralVPSSTP.h index 2aa23319b..33b6d5d8c 100644 --- a/Cantera/src/thermo/IonsFromNeutralVPSSTP.h +++ b/Cantera/src/thermo/IonsFromNeutralVPSSTP.h @@ -264,88 +264,6 @@ namespace Cantera { * @{ */ - //! This method returns an array of generalized concentrations - /*! - * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / - * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration - * defined below and \f$ a_k \f$ are activities used in the - * thermodynamic functions. These activity (or generalized) - * concentrations are used - * by kinetics manager classes to compute the forward and - * reverse rates of elementary reactions. Note that they may - * or may not have units of concentration --- they might be - * partial pressures, mole fractions, or surface coverages, - * for example. - * - * @param c Output array of generalized concentrations. The - * units depend upon the implementation of the - * reaction rate expressions within the phase. - */ - virtual void getActivityConcentrations(doublereal* c) const; - - //! Return the standard concentration for the kth species - /*! - * The standard concentration \f$ C^0_k \f$ used to normalize - * the activity (i.e., generalized) concentration. In many cases, this quantity - * will be the same for all species in a phase - for example, - * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this - * reason, this method returns a single value, instead of an - * array. However, for phases in which the standard - * concentration is species-specific (e.g. surface species of - * different sizes), this method may be called with an - * optional parameter indicating the species. - * - * Here we define the standard concentration as being equal to 1.0. - * Therefore, the kinetics operators will be dealing in unitless - * activities for all kinetics expressions involving the molten - * salts. This assignment is subject to further assessment. - * - * @param k Optional parameter indicating the species. The default - * is to assume this refers to species 0. - * @return - * Returns the standard concentration. The units are by definition - * dependent on the ThermoPhase and kinetics manager representation. - */ - virtual doublereal standardConcentration(int k=0) const; - - - //! Natural logarithm of the standard concentration of the kth species. - /*! - * @param k index of the species (defaults to zero) - */ - virtual doublereal logStandardConc(int k=0) const; - - //! Returns the units of the standard and generalized concentrations. - /*! - * Note they have the same units, as their - * ratio is defined to be equal to the activity of the kth - * species in the solution, which is unitless. - * - * This routine is used in print out applications where the - * units are needed. Usually, MKS units are assumed throughout - * the program and in the XML input files. - * - * The base %ThermoPhase class assigns the default quantities - * of (kmol/m3) for all species. - * Inherited classes are responsible for overriding the default - * values if necessary. - * - * @param uA Output vector containing the units - * uA[0] = kmol units - default = 1 - * uA[1] = m units - default = -nDim(), the number of spatial - * dimensions in the Phase class. - * uA[2] = kg units - default = 0; - * uA[3] = Pa(pressure) units - default = 0; - * uA[4] = Temperature units - default = 0; - * uA[5] = time units - default = 0 - * @param k species index. Defaults to 0. - * @param sizeUA output int containing the size of the vector. - * Currently, this is equal to 6. - */ - virtual void getUnitsStandardConc(double *uA, int k = 0, - int sizeUA = 6) const; - - //! Get the array of non-dimensional molar-based activity coefficients at //! the current solution temperature, pressure, and solution concentration. /*! @@ -353,7 +271,6 @@ namespace Cantera { */ virtual void getActivityCoefficients(doublereal* ac) const; - //@} /// @name Partial Molar Properties of the Solution @@ -384,6 +301,8 @@ namespace Cantera { * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} * \f] * + * @param hbar Output vector of species partial molar enthalpies. + * Length: m_kk. Units: J/kmol */ virtual void getPartialMolarEnthalpies(doublereal* hbar) const; @@ -401,71 +320,101 @@ namespace Cantera { * - R \ln( \gamma_k X_k) * - R T \frac{d \ln(\gamma_k) }{dT} * \f] + * + * + * @param sbar Output vector of species partial molar entropies. + * Length: m_kk. Units: J/kmol/K */ virtual void getPartialMolarEntropies(doublereal* sbar) const; - //! Get the array of change in the log activity coefficients w.r.t. change in state (change temp, change mole fractions) + + //! Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + //! a line in parameter space or along a line in physical space /*! - * This function is a virtual class, but it first appears in GibbsExcessVPSSTP - * class and derived classes from GibbsExcessVPSSTP. * - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can gradX/X. - * - * @param dT Input of temperature change - * @param dX Input vector of changes in mole fraction. length = m_kk - * @param dlnActCoeff Output vector of derivatives of the - * log Activity Coefficients. length = m_kk + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk */ - virtual void getdlnActCoeff(const doublereal dT, const doublereal * const dX, doublereal *dlnActCoeff) const; + virtual void getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const; //! Get the array of log concentration-like derivatives of the - //! log activity coefficients + //! log activity coefficients - diagonal component /*! * This function is a virtual method. For ideal mixtures * (unity activity coefficients), this can return zero. * Implementations should take the derivative of the * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. mole fraction) - * that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. + * logarithm of the mole fraction. * * units = dimensionless * - * @param dlnActCoeffdlnX Output vector of log(mole fraction) + * @param dlnActCoeffdlnX_diag Output vector of log(mole fraction) * derivatives of the log Activity Coefficients. * length = m_kk */ - virtual void getdlnActCoeffdlnX(doublereal *dlnActCoeffdlnX) const; + virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const; //! Get the array of log concentration-like derivatives of the - //! log activity coefficients + //! log activity coefficients - diagonal components /*! * This function is a virtual method. For ideal mixtures * (unity activity coefficients), this can return zero. * Implementations should take the derivative of the * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. number of moles) - * that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. + * logarithm of the species mole numbe. This routine just does the diagonal entries. * * units = dimensionless * - * @param dlnActCoeffdlnN Output vector of log(mole fraction) + * @param dlnActCoeffdlnN_diag Output vector of diagonal components of the log(mole fraction) * derivatives of the log Activity Coefficients. * length = m_kk */ - virtual void getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const; + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const; + + //! Get the array of derivatives of the ln activity coefficients with respect to the ln species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * log of a species mole number (with all other species mole numbers held constant) + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) ; + //! Get the Salt Dissociation Coefficients //! Returns the vector of dissociation coefficients and vector of charges - virtual void getDissociationCoeffs(vector_fp& coeffs, vector_fp& charges, std::vector& neutMolIndex); + /*! + * @param fm_neutralMolec_ions Returns the formula matrix for the composition of neutral molecules + * in terms of the ions. + * @param charges Returns a vector containing the charges of all species in this phase + * @param neutMolIndex Returns the vector fm_invert_ionForNeutral + * This is the mapping between ion species and neutral molecule for quick invert. + */ + void getDissociationCoeffs(vector_fp& fm_neutralMolec_ions, vector_fp& charges, std::vector& neutMolIndex) const; - virtual void getNeutralMolecMoleFractions(vector_fp& fracs){fracs=NeutralMolecMoleFractions_;} + + //! Return the current value of the neutral mole fraction vector + /*! + * @param neutralMoleculeMoleFractions Vector of neutral molecule mole fractions. + */ + void getNeutralMolecMoleFractions(vector_fp& neutralMoleculeMoleFractions) const { + neutralMoleculeMoleFractions = NeutralMolecMoleFractions_; + } //! Calculate neutral molecule mole fractions /*! @@ -480,14 +429,29 @@ namespace Cantera { * in the charge neutrality is allowed. The cation number * is followed, while the difference in charge neutrality * is dumped into the anion mole number to fix the imbalance. + * + * @param dx input vector of ion mole fraction gradients + * @param dy output Vector of neutral molecule mole fraction gradients */ - virtual void getNeutralMoleculeMoleGrads(const doublereal * const x, doublereal *y) const; + void getNeutralMoleculeMoleGrads(const doublereal * const dx, doublereal *const dy) const; - virtual void getCationList(std::vector& cation){cation=cationList_;} - virtual void getAnionList(std::vector& anion){anion=anionList_;} - virtual void getSpeciesNames(std::vector& names){names=m_speciesNames;} + //! Get the list of cations in this object + /*! + * @param cation List of cations + */ + void getCationList(std::vector& cation) const { + cation=cationList_; + } + //! Get the list of anions in this object + /*! + * @param anion List of anions + */ + void getAnionList(std::vector& anion) const { + anion=anionList_; + } + //@} /// @name Properties of the Standard State of the Species in the Solution //@{ @@ -749,10 +713,19 @@ namespace Cantera { * derivative of the natural logarithm of the activity coefficients * wrt logarithm of the mole fractions. */ - void s_update_dlnActCoeff_dlnX() const; + void s_update_dlnActCoeff_dlnX_diag() const; //! Update the derivative of the log of the activity coefficients - //! wrt log(number of moles) + //! wrt log(number of moles) - diagonal components + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the number of moles of given species. + */ + void s_update_dlnActCoeff_dlnN_diag() const; + + //! Update the derivative of the log of the activity coefficients + //! wrt log(number of moles) - diagonal components /*! * This function will be called to update the internally storred * derivative of the natural logarithm of the activity coefficients @@ -876,28 +849,66 @@ namespace Cantera { * as a shallow pointer. */ bool IOwnNThermoPhase_; - - //! ThermoPhase for the cation lattice - /*! - * Currently this is unimplemented and may be deleted - */ - // ThermoPhase *cationPhase_; - - //! ThermoPhase for the anion lattice - /*! - * Currently this is unimplemented and may be deleted - */ - //ThermoPhase *anionPhase_; //! Temporary mole fraction vector mutable std::vector moleFractionsTmp_; + //! Storage vector for the neutral molecule chemical potentials + /*! + * This vector is used as a temporary storage area when calculating the ion chemical + * potentials. + * + * Units = Joules/kmol + * Length = numNeutralMoleculeSpecies_ + */ mutable std::vector muNeutralMolecule_; - mutable std::vector gammaNeutralMolecule_; - mutable std::vector dlnActCoeff_NeutralMolecule_; + + //! Storage vector for the neutral molecule ln activity coefficients + /*! + * This vector is used as a temporary storage area when calculating the ion chemical + * potentials and activity coefficients + * + * Units = none + * Length = numNeutralMoleculeSpecies_ + */ + mutable std::vector lnActCoeff_NeutralMolecule_; + + //! Storage vector for the neutral molecule d ln activity coefficients dT + /*! + * This vector is used as a temporary storage area when calculating the ion derivatives + + * + * Units = 1/Kelvin + * Length = numNeutralMoleculeSpecies_ + */ mutable std::vector dlnActCoeffdT_NeutralMolecule_; - mutable std::vector dlnActCoeffdlnX_NeutralMolecule_; - mutable std::vector dlnActCoeffdlnN_NeutralMolecule_; + + //! Storage vector for the neutral molecule d ln activity coefficients dX - diagonal component + /*! + * This vector is used as a temporary storage area when calculating the ion derivatives + * + * Units = none + * Length = numNeutralMoleculeSpecies_ + */ + mutable std::vector dlnActCoeffdlnX_diag_NeutralMolecule_; + + //! Storage vector for the neutral molecule d ln activity coefficients dlnN - diagonal component + /*! + * This vector is used as a temporary storage area when calculating the ion derivatives + * + * Units = none + * Length = numNeutralMoleculeSpecies_ + */ + mutable std::vector dlnActCoeffdlnN_diag_NeutralMolecule_; + + //! Storage vector for the neutral molecule d ln activity coefficients dlnN + /*! + * This vector is used as a temporary storage area when calculating the ion derivatives + * + * Units = none + * Length = numNeutralMoleculeSpecies_ + */ + mutable Array2D dlnActCoeffdlnN_NeutralMolecule_; }; diff --git a/Cantera/src/thermo/LatticePhase.cpp b/Cantera/src/thermo/LatticePhase.cpp index 00942edfb..f23b5b009 100644 --- a/Cantera/src/thermo/LatticePhase.cpp +++ b/Cantera/src/thermo/LatticePhase.cpp @@ -23,14 +23,25 @@ #include "mix_defs.h" #include "LatticePhase.h" #include "SpeciesThermo.h" +#include "ThermoFactory.h" #include +#include + +using namespace std; namespace Cantera { // Base Empty constructor LatticePhase::LatticePhase() : - m_tlast(0.0) + m_mm(0), + m_tmin(0.0), + m_tmax(0.0), + m_Pref(OneAtm), + m_Pcurrent(OneAtm), + m_tlast(0.0), + m_speciesMolarVolume(0), + m_site_density(0.0) { } @@ -39,7 +50,14 @@ namespace Cantera { * @param right Object to be copied */ LatticePhase::LatticePhase(const LatticePhase &right) : - m_tlast(0.0) + m_mm(0), + m_tmin(0.0), + m_tmax(0.0), + m_Pref(OneAtm), + m_Pcurrent(OneAtm), + m_tlast(0.0), + m_speciesMolarVolume(0), + m_site_density(0.0) { *this = operator=(right); } @@ -54,15 +72,16 @@ namespace Cantera { m_mm = right.m_mm; m_tmin = right.m_tmin; m_tmax = right.m_tmax; - m_p0 = right.m_p0; + m_Pref = right.m_Pref; + m_Pcurrent = right.m_Pcurrent; m_tlast = right.m_tlast; m_h0_RT = right.m_h0_RT; m_cp0_R = right.m_cp0_R; m_g0_RT = right.m_g0_RT; m_s0_R = right.m_s0_R; - m_press = right.m_press; m_vacancy = right.m_vacancy; - m_molar_density = right.m_molar_density; + m_speciesMolarVolume = right.m_speciesMolarVolume; + m_site_density = right.m_site_density; } return *this; } @@ -70,7 +89,27 @@ namespace Cantera { // Destructor LatticePhase::~LatticePhase() { } + + + // Full constructor for a lattice phase + /* + * @param inputFile String name of the input file + * @param id string id of the phase name + */ + LatticePhase::LatticePhase(std::string inputFile, std::string id) { + constructPhaseFile(inputFile, id); + } + // Full constructor for a water phase + /* + * @param phaseRef XML node referencing the lattice phase. + * @param id string id of the phase name + */ + LatticePhase::LatticePhase(XML_Node& phaseRef, std::string id) { + constructPhaseXML(phaseRef, id); + } + + // Duplication function /* * This virtual function is used to create a duplicate of the @@ -84,6 +123,75 @@ namespace Cantera { return (ThermoPhase *) igp; } + /* + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void LatticePhase::constructPhaseXML(XML_Node& phaseNode, std::string idTarget) { + std::string idattrib = phaseNode.id(); + if (idTarget != idattrib) { + throw CanteraError("LatticePhase::constructPhaseXML","ids don't match"); + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the solvent and solute standard states. + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("LatticePhase::constructPhaseXML","importPhase failed "); + } + } + + /* + * constructPhaseFile + * + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void LatticePhase::constructPhaseFile(std::string inputFile, std::string id) { + + if (inputFile.size() == 0) { + throw CanteraError("LatticePhase::constructPhaseFile", + "input file is null"); + } + std::string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("LatticePhase::constructPhaseFile","could not open " + +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("LatticePhase::constructPhaseFile", + "ERROR: Can not find phase named " + + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; + } + doublereal LatticePhase:: enthalpy_mole() const { @@ -104,101 +212,240 @@ namespace Cantera { return GasConstant * (mean_X(&entropy_R_ref()[0]) - sum_xlogx()); } - + //==================================================================================================================== doublereal LatticePhase::gibbs_mole() const { return enthalpy_mole() - temperature() * entropy_mole(); } - + //==================================================================================================================== doublereal LatticePhase::cp_mole() const { return GasConstant * mean_X(&cp_R_ref()[0]); } - + //==================================================================================================================== doublereal LatticePhase::cv_mole() const { return cp_mole(); } - - - - void LatticePhase::setPressure(doublereal p) { - m_press = p; - setMolarDensity(m_molar_density); + //==================================================================================================================== + doublereal LatticePhase::calcDensity() { + setMolarDensity(m_site_density); + doublereal mw = meanMolecularWeight(); + doublereal dens = mw * m_site_density; + /* + * Calculate the molarVolume of the solution (m**3 kmol-1) + */ + // const doublereal * const dtmp = moleFractdivMMW(); + // doublereal invDens = dot(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), dtmp); + /* + * Set the density in the parent State object directly, + * by calling the State::setDensity() function. + */ + // doublereal dens = 1.0/invDens; + // State::setDensity(dens); + return dens; } - + //==================================================================================================================== + void LatticePhase::setPressure(doublereal p) { + m_Pcurrent = p; + calcDensity(); + } + //==================================================================================================================== + void LatticePhase::setMoleFractions(const doublereal * const x) { + State::setMoleFractions(x); + calcDensity(); + } + //==================================================================================================================== + void LatticePhase::setMoleFractions_NoNorm(const doublereal * const x) { + State::setMoleFractions(x); + calcDensity(); + } + //==================================================================================================================== + void LatticePhase::setMassFractions(const doublereal * const y) { + State::setMassFractions(y); + calcDensity(); + } + //==================================================================================================================== + void LatticePhase::setMassFractions_NoNorm(const doublereal * const y) { + State::setMassFractions_NoNorm(y); + calcDensity(); + } + //==================================================================================================================== + void LatticePhase::setConcentrations(const doublereal * const c) { + State::setConcentrations(c); + calcDensity(); + } + //==================================================================================================================== void LatticePhase::getActivityConcentrations(doublereal* c) const { getMoleFractions(c); } - + //==================================================================================================================== void LatticePhase::getActivityCoefficients(doublereal* ac) const { for (int k = 0; k < m_kk; k++) { ac[k] = 1.0; } } - + //==================================================================================================================== doublereal LatticePhase::standardConcentration(int k) const { return 1.0; } - + //==================================================================================================================== doublereal LatticePhase::logStandardConc(int k) const { return 0.0; } - + //==================================================================================================================== void LatticePhase::getChemPotentials(doublereal* mu) const { - doublereal vdp = ((pressure() - m_spthermo->refPressure())/ - molarDensity()); + doublereal delta_p = m_Pcurrent - m_Pref; doublereal xx; - doublereal rt = temperature() * GasConstant; + doublereal RT = temperature() * GasConstant; const array_fp& g_RT = gibbs_RT_ref(); for (int k = 0; k < m_kk; k++) { xx = fmaxx(SmallNumber, moleFraction(k)); - mu[k] = rt*(g_RT[k] + log(xx)) + vdp; + mu[k] = RT * (g_RT[k] + log(xx)) + + delta_p * m_speciesMolarVolume[k]; + } + + } + //==================================================================================================================== + void LatticePhase::getPartialMolarEnthalpies(doublereal* hbar) const { + const array_fp& _h = enthalpy_RT_ref(); + doublereal rt = GasConstant * temperature(); + scale(_h.begin(), _h.end(), hbar, rt); + } + //==================================================================================================================== + void LatticePhase::getPartialMolarEntropies(doublereal* sbar) const { + const array_fp& _s = entropy_R_ref(); + doublereal r = GasConstant; + doublereal xx; + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(SmallNumber, moleFraction(k)); + sbar[k] = r * (_s[k] - log(xx)); } } - + //==================================================================================================================== + void LatticePhase::getPartialMolarCp(doublereal* cpbar) const { + getCp_R(cpbar); + for (int k = 0; k < m_kk; k++) { + cpbar[k] *= GasConstant; + } + } + //==================================================================================================================== void LatticePhase::getPartialMolarVolumes(doublereal* vbar) const { getStandardVolumes(vbar); } - + //==================================================================================================================== void LatticePhase::getStandardChemPotentials(doublereal* mu0) const { const array_fp& gibbsrt = gibbs_RT_ref(); scale(gibbsrt.begin(), gibbsrt.end(), mu0, _RT()); } - + //==================================================================================================================== void LatticePhase::getPureGibbs(doublereal* gpure) const { const array_fp& gibbsrt = gibbs_RT_ref(); - scale(gibbsrt.begin(), gibbsrt.end(), gpure, _RT()); - } - - void LatticePhase::getEnthalpy_RT(doublereal* hrt) const { - const array_fp& _h = enthalpy_RT_ref(); - std::copy(_h.begin(), _h.end(), hrt); - doublereal tmp = (pressure() - m_p0) / (molarDensity() * GasConstant * temperature()); + doublereal delta_p = (m_Pcurrent - m_Pref); + double RT = GasConstant * temperature(); for (int k = 0; k < m_kk; k++) { - hrt[k] += tmp; + gpure[k] = RT * gibbsrt[k] + delta_p * m_speciesMolarVolume[k]; } } - + //==================================================================================================================== + void LatticePhase::getEnthalpy_RT(doublereal* hrt) const { + const array_fp& _h = enthalpy_RT_ref(); + doublereal delta_prt = ((m_Pcurrent - m_Pref) / (GasConstant * temperature())); + for (int k = 0; k < m_kk; k++) { + hrt[k] = _h[k] + delta_prt * m_speciesMolarVolume[k]; + } + } + //==================================================================================================================== void LatticePhase::getEntropy_R(doublereal* sr) const { const array_fp& _s = entropy_R_ref(); std::copy(_s.begin(), _s.end(), sr); } - + //==================================================================================================================== void LatticePhase::getGibbs_RT(doublereal* grt) const { const array_fp& gibbsrt = gibbs_RT_ref(); - std::copy(gibbsrt.begin(), gibbsrt.end(), grt); + doublereal RT = _RT(); + doublereal delta_prt = (m_Pcurrent - m_Pref)/ RT; + for (int k = 0; k < m_kk; k++) { + grt[k] = gibbsrt[k] + delta_prt * m_speciesMolarVolume[k]; + } } + //==================================================================================================================== + void LatticePhase::getGibbs_ref(doublereal *g) const { + getGibbs_RT_ref(g); + for (int k = 0; k < m_kk; k++) { + g[k] *= GasConstant * temperature(); + } + } + //=================================================================================================================== void LatticePhase::getCp_R(doublereal* cpr) const { const array_fp& _cpr = cp_R_ref(); std::copy(_cpr.begin(), _cpr.end(), cpr); } - + //=================================================================================================================== void LatticePhase::getStandardVolumes(doublereal* vbar) const { - doublereal vv = 1.0/m_molar_density; + copy(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), vbar); + } + //======================================================================================================= + // Returns the vector of nondimensional Enthalpies of the reference state at the current temperature + // of the solution and the reference pressure for the phase. + /* + * @return Output vector of nondimensional reference state Enthalpies of the species. + * Length: m_kk + */ + const array_fp& LatticePhase::enthalpy_RT_ref() const { + _updateThermo(); + return m_h0_RT; + } + //======================================================================================================= + // Returns a reference to the dimensionless reference state Gibbs free energy vector. + /* + * This function is part of the layer that checks/recalculates the reference + * state thermo functions. + */ + const array_fp& LatticePhase::gibbs_RT_ref() const { + _updateThermo(); + return m_g0_RT; + } + //==================================================================================================================== + void LatticePhase::getGibbs_RT_ref(doublereal *grt) const { + _updateThermo(); for (int k = 0; k < m_kk; k++) { - vbar[k] = vv; + grt[k] = m_g0_RT[k]; } } - + //======================================================================================================= + // Returns a reference to the dimensionless reference state Entropy vector. + /* + * This function is part of the layer that checks/recalculates the reference + * state thermo functions. + */ + const array_fp& LatticePhase::entropy_R_ref() const { + _updateThermo(); + return m_s0_R; + } + //======================================================================================================= + // Returns a reference to the dimensionless reference state Heat Capacity vector. + /* + * This function is part of the layer that checks/recalculates the reference + * state thermo functions. + */ + const array_fp& LatticePhase::cp_R_ref() const { + _updateThermo(); + return m_cp0_R; + } + //==================================================================================================================== + // Initialize the ThermoPhase object after all species have been set up + /* + * @internal Initialize. + * + * This method performs any initialization required after all + * species have been added. For example, it is used to + * resize internal work arrays that must have an entry for + * each species. + * This method is called from ThermoPhase::initThermoXML(), + * which is called from importPhase(), + * just prior to returning from the function, importPhase(). + * + * @see importCTML.cpp + */ void LatticePhase::initThermo() { m_kk = nSpecies(); m_mm = nElements(); @@ -206,51 +453,99 @@ namespace Cantera { doublereal tmax = m_spthermo->maxTemp(); if (tmin > 0.0) m_tmin = tmin; if (tmax > 0.0) m_tmax = tmax; - m_p0 = refPressure(); + m_Pref = refPressure(); int leng = m_kk; m_h0_RT.resize(leng); m_g0_RT.resize(leng); m_cp0_R.resize(leng); m_s0_R.resize(leng); - setMolarDensity(m_molar_density); + m_speciesMolarVolume.resize(leng, 0.0); + + ThermoPhase::initThermo(); } + //==================================================================================================================== + void LatticePhase::initThermoXML(XML_Node& phaseNode, std::string id) { + std::string subname = "LatticePhase::initThermoXML"; + /* + * Check on the thermo field. Must have: + * + */ + if (phaseNode.hasChild("thermo")) { + XML_Node& thNode = phaseNode.child("thermo"); + std::string mStringa = thNode.attrib("model"); + std::string mString = lowercase(mStringa); + if (mString != "lattice") { + throw CanteraError(subname.c_str(), + "Unknown thermo model: " + mStringa); + } + } else { + throw CanteraError(subname.c_str(), + "Unspecified thermo model"); + } + /* + * Now go get the molar volumes. use the default if not found + */ + XML_Node& speciesList = phaseNode.child("speciesArray"); + XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"], &phaseNode.root()); + const std::vector &sss = speciesNames(); + + for (int k = 0; k < m_kk; k++) { + m_speciesMolarVolume[k] = m_site_density; + XML_Node* s = speciesDB->findByAttr("name", sss[k]); + if (!s) { + throw CanteraError(" LatticePhase::initThermoXML", "database problems"); + } + XML_Node *ss = s->findByName("standardState"); + if (ss) { + if (ss->findByName("molarVolume")) { + m_speciesMolarVolume[k] = ctml::getFloat(*ss, "molarVolume", "toSI"); + } + } + } - + /* + * Call the base initThermo, which handles setting the initial + * state. + */ + ThermoPhase::initThermoXML(phaseNode, id); + } + //===================================================================================================== + // Update the species reference state thermodynamic functions + /* + * The polynomials for the standard state functions are only + * reevalulated if the temperature has changed. + */ void LatticePhase::_updateThermo() const { doublereal tnow = temperature(); - if (fabs(molarDensity() - m_molar_density)/m_molar_density > 0.0001) { - throw CanteraError("_updateThermo","molar density changed from " - +fp2str(m_molar_density)+" to "+fp2str(molarDensity())); - } if (m_tlast != tnow) { - m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0], - &m_s0_R[0]); + m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0], &m_s0_R[0]); m_tlast = tnow; - int k; - for (k = 0; k < m_kk; k++) { + for (int k = 0; k < m_kk; k++) { m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k]; } m_tlast = tnow; } } - + //===================================================================================================== void LatticePhase::setParameters(int n, doublereal* const c) { - m_molar_density = c[0]; - setMolarDensity(m_molar_density); + m_site_density = c[0]; + setMolarDensity(m_site_density); } - + //===================================================================================================== void LatticePhase::getParameters(int &n, doublereal * const c) const { double d = molarDensity(); c[0] = d; n = 1; } - + //===================================================================================================== void LatticePhase::setParametersFromXML(const XML_Node& eosdata) { - eosdata._require("model","Lattice"); - m_molar_density = getFloat(eosdata, "site_density", "toSI"); - m_vacancy = getChildValue(eosdata, "vacancy_species"); + eosdata._require("model", "Lattice"); + m_site_density = ctml::getFloat(eosdata, "site_density", "toSI"); + m_vacancy = ctml::getChildValue(eosdata, "vacancy_species"); } + //===================================================================================================== } - +//======================================================================================================= #endif + diff --git a/Cantera/src/thermo/LatticePhase.h b/Cantera/src/thermo/LatticePhase.h index 111848b09..eabde4c25 100644 --- a/Cantera/src/thermo/LatticePhase.h +++ b/Cantera/src/thermo/LatticePhase.h @@ -1,7 +1,6 @@ /** * @file LatticePhase.h - * Header for a simple thermodynamics model of a bulk phase - * derived from ThermoPhase, + * Header for a simple thermodynamics model of a bulk phase derived from ThermoPhase, * assuming a lattice of solid atoms * (see \ref thermoprops and class \link Cantera::LatticePhase LatticePhase\endlink). * @@ -255,7 +254,7 @@ namespace Cantera { * @ingroup thermoprops * */ - class LatticePhase : public ThermoPhase { + class LatticePhase : public ThermoPhase { public: @@ -274,6 +273,20 @@ namespace Cantera { */ LatticePhase& operator=(const LatticePhase& right); + //! Full constructor for a lattice phase + /*! + * @param inputFile String name of the input file + * @param id string id of the phase name + */ + LatticePhase(std::string inputFile, std::string id = ""); + + //! Full constructor for a water phase + /*! + * @param phaseRef XML node referencing the lattice phase. + * @param id string id of the phase name + */ + LatticePhase(XML_Node& phaseRef, std::string id = ""); + //! Destructor virtual ~LatticePhase(); @@ -287,9 +300,33 @@ namespace Cantera { */ ThermoPhase *duplMyselfAsThermoPhase() const; + //! Import and initialize a %LatticePhase phase specification from an XML tree into the current object. + /*! + * @param phaseNode XML file containing the description of the phase + * + * @param idTarget Optional parameter identifying the name of the + * phase. If none is given, the first XML phase element is used. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string idTarget); + + //! Initialization of a %LatticePhase phase using an xml file + /*! + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); //! Equation of state flag. Returns the value cLattice - virtual int eosType() const { return cLattice; } + virtual int eosType() const { + return cLattice; + } /** * @name Molar Thermodynamic Properties of the Solution ------------------------ @@ -416,7 +453,7 @@ namespace Cantera { * independent value of the pressure. */ virtual doublereal pressure() const { - return m_press; + return m_Pcurrent; } //! Set the internally storred pressure (Pa) at constant @@ -428,7 +465,67 @@ namespace Cantera { * @param p Input Pressure (Pa) */ virtual void setPressure(doublereal p); - + + //! Calculate the density of the mixture using the partial + //! molar volumes and mole fractions as input + /*! + * The formula for this is + * + * \f[ + * \rho = \frac{\sum_k{X_k W_k}}{\sum_k{X_k V_k}} + * \f] + * + * where \f$X_k\f$ are the mole fractions, \f$W_k\f$ are + * the molecular weights, and \f$V_k\f$ are the pure species + * molar volumes. + * + * Note, the basis behind this formula is that in an ideal + * solution the partial molar volumes are equal to the pure + * species molar volumes. We have additionally specified + * in this class that the pure species molar volumes are + * independent of temperature and pressure. + * + * NOTE: This is a non-virtual function, which is not a + * member of the ThermoPhase base class. + */ + doublereal calcDensity(); + + //! Set the mole fractions + /*! + * @param x Input vector of mole fractions. + * Length: m_kk. + */ + virtual void setMoleFractions(const doublereal * const x); + + //! Set the mole fractions, but don't normalize them to one. + /*! + * @param x Input vector of mole fractions. + * Length: m_kk. + */ + virtual void setMoleFractions_NoNorm(const doublereal * const x); + + //! Set the mass fractions, and normalize them to one. + /*! + * @param y Input vector of mass fractions. + * Length: m_kk. + */ + virtual void setMassFractions(const doublereal * const y); + + //! Set the mass fractions, but don't normalize them to one + /*! + * @param y Input vector of mass fractions. + * Length: m_kk. + */ + virtual void setMassFractions_NoNorm(const doublereal * const y); + + //! Set the concentration, + /*! + * @param c Input vector of concentrations. + * Length: m_kk. + */ + virtual void setConcentrations(const doublereal * const c); + + //@} /// @name Activities, Standard States, and Activity Concentrations /** @@ -510,6 +607,71 @@ namespace Cantera { */ virtual void getChemPotentials(doublereal* mu) const; + + //@} + /// @name Partial Molar Properties of the Solution ----------------------------- + //@{ + + + /** + * Returns an array of partial molar enthalpies for the species + * in the mixture. + * Units (J/kmol) + * For this phase, the partial molar enthalpies are equal to the + * pure species enthalpies + * \f[ + * \bar h_k(T,P) = \hat h^{ref}_k(T) + (P - P_{ref}) \hat V^0_k + * \f] + * The reference-state pure-species enthalpies, \f$ \hat h^{ref}_k(T) \f$, + * at the reference pressure,\f$ P_{ref} \f$, + * are computed by the species thermodynamic + * property manager. They are polynomial functions of temperature. + * @see SpeciesThermo + * + * @param hbar Output vector containing partial molar enthalpies. + * Length: m_kk. + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + /** + * Returns an array of partial molar entropies of the species in the + * solution. Units: J/kmol/K. + * For this phase, the partial molar entropies are equal to the + * pure species entropies plus the ideal solution contribution. + * \f[ + * \bar s_k(T,P) = \hat s^0_k(T) - R log(X_k) + * \f] + * The reference-state pure-species entropies,\f$ \hat s^{ref}_k(T) \f$, + * at the reference pressure, \f$ P_{ref} \f$, are computed by the + * species thermodynamic + * property manager. They are polynomial functions of temperature. + * @see SpeciesThermo + * + * @param sbar Output vector containing partial molar entropies. + * Length: m_kk. + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + /** + * Returns an array of partial molar Heat Capacities at constant + * pressure of the species in the + * solution. Units: J/kmol/K. + * For this phase, the partial molar heat capacities are equal + * to the standard state heat capacities. + * + * @param cpbar Output vector of partial heat capacities. Length: m_kk. + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + //! Return an array of partial molar volumes for the + //! species in the mixture. Units: m^3/kmol. + /*! + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //! Get the array of chemical potentials at unit activity for the //! species standard states at the current T and P of the solution. /*! @@ -531,14 +693,7 @@ namespace Cantera { */ virtual void getPureGibbs(doublereal* gpure) const; - //! Return an array of partial molar volumes for the - //! species in the mixture. Units: m^3/kmol. - /*! - * @param vbar Output vector of speciar partial molar volumes. - * Length = m_kk. units are m^3/kmol. - */ - virtual void getPartialMolarVolumes(doublereal* vbar) const; - + //@} /// @name Properties of the Standard State of the Species in the Solution //@{ @@ -656,40 +811,47 @@ namespace Cantera { * Enthalpies of the species. * Length: m_kk */ - const array_fp& enthalpy_RT_ref() const { - _updateThermo(); - return m_h0_RT; - } + const array_fp& enthalpy_RT_ref() const; //! Returns a reference to the dimensionless reference state Gibbs free energy vector. /*! * This function is part of the layer that checks/recalculates the reference * state thermo functions. */ - const array_fp& gibbs_RT_ref() const { - _updateThermo(); - return m_g0_RT; - } + const array_fp& gibbs_RT_ref() const; + + //! Returns the vector of nondimensional + //! Gibbs Free Energies of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * @param grt Output vector containing the nondimensional reference state + * Gibbs Free energies. Length: m_kk. + */ + virtual void getGibbs_RT_ref(doublereal *grt) const; + + //! Returns the vector of the gibbs function of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * units = J/kmol + * + * @param g Output vector containing the reference state + * Gibbs Free energies. Length: m_kk. Units: J/kmol. + */ + virtual void getGibbs_ref(doublereal *g) const; //! Returns a reference to the dimensionless reference state Entropy vector. /*! * This function is part of the layer that checks/recalculates the reference * state thermo functions. */ - const array_fp& entropy_R_ref() const { - _updateThermo(); - return m_s0_R; - } + const array_fp& entropy_R_ref() const; //! Returns a reference to the dimensionless reference state Heat Capacity vector. /*! * This function is part of the layer that checks/recalculates the reference * state thermo functions. */ - const array_fp& cp_R_ref() const { - _updateThermo(); - return m_cp0_R; - } + const array_fp& cp_R_ref() const; //@} /// @name Utilities for Initialization of the Object @@ -711,6 +873,33 @@ namespace Cantera { */ virtual void initThermo(); + + //! Import and initialize a ThermoPhase object using an XML tree. + /*! + * Here we read extra information about the XML description + * of a phase. Regular information about elements and species + * and their reference state thermodynamic information + * have already been read at this point. + * For example, we do not need to call this function for + * ideal gas equations of state. + * This function is called from importPhase() + * after the elements and the + * species are initialized with default ideal solution + * level data. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + virtual void initThermoXML(XML_Node& phaseNode, std::string id); + //! Set the equation of state parameters from the argument list /*! * @internal @@ -767,6 +956,7 @@ namespace Cantera { protected: + //! Number of elements int m_mm; @@ -785,38 +975,56 @@ namespace Cantera { doublereal m_tmax; //! Reference state pressure - doublereal m_p0; + doublereal m_Pref; + + + //! The current pressure + /*! + * Since the density isn't a function of pressure, but only of the + * mole fractions, we need to independently specify the pressure. + * The density variable which is inherited as part of the State class, + * m_dens, is always kept current whenever T, P, or X[] change. + */ + doublereal m_Pcurrent; //! Current value of the temperature (Kelvin) - mutable doublereal m_tlast; + mutable doublereal m_tlast; //! Reference state enthalpies / RT - mutable array_fp m_h0_RT; + mutable array_fp m_h0_RT; //! Temporary storage for the reference state heat capacities - mutable array_fp m_cp0_R; + mutable array_fp m_cp0_R; //! Temporary storage for the reference state gibbs energies - mutable array_fp m_g0_RT; + mutable array_fp m_g0_RT; - //! Temporary storage for the reference state entropies - mutable array_fp m_s0_R; + //! Temporary storage for the reference state entropies at the current temperature + mutable array_fp m_s0_R; - //! Current value of the pressure (Pa) - doublereal m_press; //! String name for the species which represents a vacency //! in the lattice /*! * This string is currently unused */ - std::string m_vacancy; + std::string m_vacancy; - //! Molar density of the lattice solid + //! Vector of molar volumes for each species in the solution + /** + * Species molar volumes \f$ m^3 kmol^-1 \f$ + */ + array_fp m_speciesMolarVolume; + + //! Site Density of the lattice solid /*! + * Currently, this is imposed as a function of T, P or composition + * * units are kmol m-3 */ - doublereal m_molar_density; + doublereal m_site_density; + + // doublereal m_molar_lattice_volume; private: diff --git a/Cantera/src/thermo/LatticeSolidPhase.cpp b/Cantera/src/thermo/LatticeSolidPhase.cpp index e9671db02..4a024cfc9 100644 --- a/Cantera/src/thermo/LatticeSolidPhase.cpp +++ b/Cantera/src/thermo/LatticeSolidPhase.cpp @@ -1,7 +1,11 @@ /** - * - * @file LatticeSolidPhase.cpp - * + * @file LatticeSolidPhase.h + * Definitions for a simple thermodynamics model of a bulk solid phase + * derived from %ThermoPhase, + * assuming an ideal solution model based on a lattice of solid atoms + * (see \ref thermoprops and class \link Cantera::LatticeSolidPhase LatticeSolidPhase\endlink). + */ +/* * $Id$ */ @@ -10,39 +14,63 @@ #pragma warning(disable:4503) #endif -#include "config.h" -#ifdef WITH_LATTICE_SOLID #include "ct_defs.h" +#ifdef WITH_LATTICE_SOLID + #include "mix_defs.h" #include "LatticeSolidPhase.h" #include "LatticePhase.h" #include "SpeciesThermo.h" #include "ThermoFactory.h" -//#include "importCTML.h" +#include "SpeciesThermoFactory.h" +#include "GeneralSpeciesThermo.h" #include -using namespace std; +#ifndef MIN +# define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) +#endif +#ifndef MAX +# define MAX(x,y) (( (x) > (y) ) ? (x) : (y)) +#endif +using namespace std; +//====================================================================================================================== namespace Cantera { - + //==================================================================================================================== // Base empty constructor LatticeSolidPhase::LatticeSolidPhase() : - m_tlast(0.0) + m_mm(0), + m_tlast(0.0), + m_press(-1.0), + m_molar_density(0.0), + m_nlattice(0), + m_lattice(0), + m_x(0), + theta_(0), + tmpV_(0) { } - + //==================================================================================================================== // Copy Constructor /* * @param right Object to be copied */ LatticeSolidPhase::LatticeSolidPhase(const LatticeSolidPhase &right) : - m_tlast(0.0) + m_mm(0), + m_tlast(0.0), + m_press(-1.0), + m_molar_density(0.0), + m_nlattice(0), + m_lattice(0), + m_x(0), + theta_(0), + tmpV_(0) { *this = operator=(right); } - + //==================================================================================================================== // Assignment operator /* * @param right Object to be copied @@ -51,21 +79,28 @@ namespace Cantera { LatticeSolidPhase::operator=(const LatticeSolidPhase& right) { if (&right != this) { ThermoPhase::operator=(right); - m_mm = right.m_mm; - m_kk = right.m_kk; - m_tlast = right.m_tlast; - m_press = right.m_press; + m_mm = right.m_mm; + m_tlast = right.m_tlast; + m_press = right.m_press; m_molar_density = right.m_molar_density; - m_nlattice = right.m_nlattice; - m_x = right.m_x; + m_nlattice = right.m_nlattice; + deepStdVectorPointerCopy(right.m_lattice, m_lattice); + m_x = right.m_x; + theta_ = right.theta_; + tmpV_ = right.tmpV_; } return *this; } - - //! Destructor + //==================================================================================================================== + // Destructor LatticeSolidPhase::~LatticeSolidPhase() { + // We own the sublattices. So we have to delete the sublattices + for (int n = 0; n < m_nlattice; n++) { + delete m_lattice[n]; + m_lattice[n] = 0; + } } - + //==================================================================================================================== // Duplication function /* * This virtual function is used to create a duplicate of the @@ -78,212 +113,608 @@ namespace Cantera { LatticeSolidPhase *igp = new LatticeSolidPhase(*this); return (ThermoPhase *) igp; } - + + //==================================================================================================================== + // Minimum temperature for which the thermodynamic data for the species + // or phase are valid. + /* + * If no argument is supplied, the + * value returned will be the lowest temperature at which the + * data for \e all species are valid. Otherwise, the value + * will be only for species \a k. This function is a wrapper + * that calls the species thermo minTemp function. + * + * @param k index of the species. Default is -1, which will return the max of the min value + * over all species. + */ + doublereal LatticeSolidPhase::minTemp(int k) const { + if (k >= 0) { + for (int n = 0; n < m_nlattice; n++) { + if (lkstart_[n+1] < k) { + double ml = (m_lattice[n])->minTemp(k-lkstart_[n]); + return ml; + } + } + } + doublereal mm = 1.0E300; + for (int n = 0; n < m_nlattice; n++) { + double ml = (m_lattice[n])->minTemp(-1); + mm = MIN(mm, ml); + } + return mm; + } + //==================================================================================================================== + // Maximum temperature for which the thermodynamic data for the species + // or phase are valid. + /* + * If no argument is supplied, the + * value returned will be the lowest temperature at which the + * data for \e all species are valid. Otherwise, the value + * will be only for species \a k. This function is a wrapper + * that calls the species thermo minTemp function. + * + * @param k index of the species. Default is -1, which will return the max of the min value + * over all species. + */ + doublereal LatticeSolidPhase::maxTemp(int k) const { + if (k >= 0) { + for (int n = 0; n < m_nlattice; n++) { + if (lkstart_[n+1] < k) { + double ml = (m_lattice[n])->maxTemp(k - lkstart_[n]); + return ml; + } + } + } + doublereal mm = -1.0E300; + for (int n = 0; n < m_nlattice; n++) { + double ml = (m_lattice[n])->maxTemp(-1); + mm = MAX(mm, ml); + } + return mm; + } + //==================================================================================================================== + /* + * Returns the reference pressure in Pa. This function is a wrapper + * that calls the species thermo refPressure function. + */ + doublereal LatticeSolidPhase::refPressure() const { + return m_lattice[0]->refPressure(); + } + //==================================================================================================================== doublereal LatticeSolidPhase:: enthalpy_mole() const { _updateThermo(); - doublereal ndens, sum = 0.0; + doublereal sum = 0.0; int n; for (n = 0; n < m_nlattice; n++) { - ndens = m_lattice[n]->molarDensity(); - sum += ndens * m_lattice[n]->enthalpy_mole(); + sum += theta_[n] * m_lattice[n]->enthalpy_mole(); } - return sum/molarDensity(); + return sum; + } + //==================================================================================================================== + doublereal LatticeSolidPhase::intEnergy_mole() const { + _updateThermo(); + doublereal sum = 0.0; + int n; + for (n = 0; n < m_nlattice; n++) { + sum += theta_[n] * m_lattice[n]->intEnergy_mole(); + } + return sum; + } + //==================================================================================================================== + doublereal LatticeSolidPhase::entropy_mole() const { + _updateThermo(); + doublereal sum = 0.0; + int n; + for (n = 0; n < m_nlattice; n++) { + sum += theta_[n] * m_lattice[n]->entropy_mole(); + } + return sum; + } + //==================================================================================================================== + doublereal LatticeSolidPhase::gibbs_mole() const { + _updateThermo(); + doublereal sum = 0.0; + for (int n = 0; n < m_nlattice; n++) { + sum += theta_[n] * m_lattice[n]->gibbs_mole(); + } + return sum; + } + //==================================================================================================================== + doublereal LatticeSolidPhase::cp_mole() const { + _updateThermo(); + doublereal sum = 0.0; + for (int n = 0; n < m_nlattice; n++) { + sum += theta_[n] * m_lattice[n]->cp_mole(); + } + return sum; + } + //==================================================================================================================== + void LatticeSolidPhase::getActivityConcentrations(doublereal* c) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + m_lattice[n]->getMoleFractions(c+strt); + strt += m_lattice[n]->nSpecies(); + } + } + //==================================================================================================================== + void LatticeSolidPhase::getActivityCoefficients(doublereal* ac) const { + for (int k = 0; k < m_kk; k++) { + ac[k] = 1.0; + } + } + //==================================================================================================================== + doublereal LatticeSolidPhase::standardConcentration(int k) const { + return 1.0; + } + //==================================================================================================================== + doublereal LatticeSolidPhase::logStandardConc(int k) const { + return 0.0; } - doublereal LatticeSolidPhase::intEnergy_mole() const { - _updateThermo(); - doublereal ndens, sum = 0.0; - int n; - for (n = 0; n < m_nlattice; n++) { - ndens = m_lattice[n]->molarDensity(); - sum += ndens * m_lattice[n]->intEnergy_mole(); - } - return sum/molarDensity(); + //==================================================================================================================== + // Set the pressure at constant temperature. Units: Pa. + /* + * + * @param p Pressure (units - Pa) + */ + void LatticeSolidPhase::setPressure(doublereal p) { + m_press = p; + for (int n = 0; n < m_nlattice; n++) { + m_lattice[n]->setPressure(m_press); } - - doublereal LatticeSolidPhase::entropy_mole() const { - _updateThermo(); - doublereal ndens, sum = 0.0; - int n; - for (n = 0; n < m_nlattice; n++) { - ndens = m_lattice[n]->molarDensity(); - sum += ndens * m_lattice[n]->entropy_mole(); - } - return sum/molarDensity(); + calcDensity(); + } + //==================================================================================================================== + // Calculate the density of the solid mixture + /* + * The formula for this is + * + * \f[ + * \rho = \sum_n{ \rho_n \theta_n } + * \f] + * + * where \f$ \rho_n \f$ is the density of the nth sublattice + * + * Note this is a nonvirtual function. + */ + doublereal LatticeSolidPhase::calcDensity() { + double sum = 0.0; + for (int n = 0; n < m_nlattice; n++) { + sum += theta_[n] * m_lattice[n]->density(); } - - doublereal LatticeSolidPhase::gibbs_mole() const { - _updateThermo(); - doublereal ndens, sum = 0.0; - int n; - for (n = 0; n < m_nlattice; n++) { - ndens = m_lattice[n]->molarDensity(); - sum += ndens * m_lattice[n]->gibbs_mole(); - } - return sum/molarDensity(); + State::setDensity(sum); + return sum; + } + //==================================================================================================================== + // Set the mole fractions to the specified values, and then + // normalize them so that they sum to 1.0 for each of the subphases + /* + * On input, the mole fraction vector is assumed to sum to one for each of the sublattices. The sublattices + * are updated with this mole fraction vector. The mole fractions are also storred within this object, after + * they are normalized to one by dividing by the number of sublattices. + * + * @param x Input vector of mole fractions. There is no restriction + * on the sum of the mole fraction vector. Internally, + * this object will pass portions of this vector to the sublattices which assume that the portions + * individually sum to one. + * Length is m_kk. + */ + void LatticeSolidPhase::setMoleFractions(const doublereal* const x) { + int nsp, strt = 0; + for (int n = 0; n < m_nlattice; n++) { + nsp = m_lattice[n]->nSpecies(); + m_lattice[n]->setMoleFractions(x + strt); + strt += nsp; } - - doublereal LatticeSolidPhase::cp_mole() const { - _updateThermo(); - doublereal ndens, sum = 0.0; - int n; - for (n = 0; n < m_nlattice; n++) { - ndens = m_lattice[n]->molarDensity(); - sum += ndens * m_lattice[n]->cp_mole(); - } - return sum/molarDensity(); + for (int k = 0; k < strt; k++) { + m_x[k] = x[k] / m_nlattice; } - - void LatticeSolidPhase::getActivityConcentrations(doublereal* c) const { - _updateThermo(); - int n; - int strt = 0; - for (n = 0; n < m_nlattice; n++) { - m_lattice[n]->getMoleFractions(c+strt); - strt += m_lattice[n]->nSpecies(); - } - } - - void LatticeSolidPhase::getActivityCoefficients(doublereal* ac) const { - for (int k = 0; k < m_kk; k++) { - ac[k] = 1.0; + State::setMoleFractions(DATA_PTR(m_x)); + calcDensity(); + } + //==================================================================================================================== + // Get the species mole fraction vector. + /* + * On output the mole fraction vector will sum to one for each of the subphases which make up this phase. + * + * @param x On return, x contains the mole fractions. Must have a + * length greater than or equal to the number of species. + */ + void LatticeSolidPhase::getMoleFractions(doublereal* const x) const { + int nsp, strt = 0; + // the ifdef block should be the way we calculate this.!!!!! + State::getMoleFractions(x); + doublereal sum; + for (int n = 0; n < m_nlattice; n++) { + nsp = m_lattice[n]->nSpecies(); + sum = 0.0; + for (int k = 0; k < nsp; k++) { + sum += (x + strt)[k]; + } + for (int k = 0; k < nsp; k++) { + (x + strt)[k] /= sum; + } + /* + * At this point we can check against the mole fraction vector of the underlying LatticePhase objects and + * get the same answer. + */ +#ifdef DEBUG_MODE + m_lattice[n]->getMoleFractions(&(m_x[strt])); + for (int k = 0; k < nsp; k++) { + if (fabs((x + strt)[k] - m_x[strt+k]) > 1.0E-14) { + throw CanteraError("LatticeSolidPhase::getMoleFractions()", + "internal error"); } - } - - doublereal LatticeSolidPhase::standardConcentration(int k) const { - return 1.0; - } - - doublereal LatticeSolidPhase::logStandardConc(int k) const { - return 0.0; - } - - void LatticeSolidPhase::getChemPotentials(doublereal* mu) const { - _updateThermo(); - int n; - int strt = 0; - double dratio; - for (n = 0; n < m_nlattice; n++) { - dratio = m_lattice[n]->molarDensity()/molarDensity(); - m_lattice[n]->getChemPotentials(mu+strt); - scale(mu + strt, mu + strt + m_lattice[n]->nSpecies(), mu + strt, dratio); - strt += m_lattice[n]->nSpecies(); - } - } - - void LatticeSolidPhase::getStandardChemPotentials(doublereal* mu0) const { - _updateThermo(); - int n; - int strt = 0; - double dratio; - for (n = 0; n < m_nlattice; n++) { - dratio = m_lattice[n]->molarDensity()/molarDensity(); - m_lattice[n]->getStandardChemPotentials(mu0+strt); - scale(mu0 + strt, mu0 + strt + m_lattice[n]->nSpecies(), mu0 + strt, dratio); - strt += m_lattice[n]->nSpecies(); - } - } - - void LatticeSolidPhase::initThermo() { - m_kk = nSpecies(); - m_mm = nElements(); - m_x.resize(m_kk); - int n, nsp, k, loc = 0; - doublereal ndens; - m_molar_density = 0.0; - for (n = 0; n < m_nlattice; n++) { - nsp = m_lattice[n]->nSpecies(); - ndens = m_lattice[n]->molarDensity(); - for (k = 0; k < nsp; k++) { - m_x[loc] = ndens * m_lattice[n]->moleFraction(k); - loc++; - } - m_molar_density += ndens; - } - setMoleFractions(DATA_PTR(m_x)); - -// const vector& spnames = speciesNames(); -// int n, k, kl, namesize; -// int nl = m_sitedens.size(); -// string s; -// m_lattice.resize(m_kk,-1); -// vector_fp conc(m_kk, 0.0); - -// compositionMap xx; -// for (n = 0; n < nl; n++) { -// for (k = 0; k < m_kk; k++) { -// xx[speciesName(k)] = -1.0; -// } -// parseCompString(m_sp[n], xx); -// for (k = 0; k < m_kk; k++) { -// if (xx[speciesName(k)] != -1.0) { -// conc[k] = m_sitedens[n]*xx[speciesName(k)]; -// m_lattice[k] = n; -// } -// } - -// } -// for (k = 0; k < m_kk; k++) { -// if (m_lattice[k] == -1) { -// throw CanteraError("LatticeSolidPhase::" -// "setParametersFromXML","Species "+speciesName(k) -// +" not a member of any lattice."); -// } -// } -// setMoleFractions(DATA_PTR(conc)); - } - - - void LatticeSolidPhase::_updateThermo() const { - doublereal tnow = temperature(); - // if (fabs(molarDensity() - m_molar_density)/m_molar_density > 0.0001) { - // throw CanteraError("_updateThermo","molar density changed from " - // +fp2str(m_molar_density)+" to "+fp2str(molarDensity())); - //} - if (m_tlast != tnow) { - int n; - getMoleFractions(DATA_PTR(m_x)); - int strt = 0; - for (n = 0; n < m_nlattice; n++) { - m_lattice[n]->setTemperature(tnow); - m_lattice[n]->setMoleFractions(DATA_PTR(m_x) + strt); - m_lattice[n]->setPressure(m_press); - strt += m_lattice[n]->nSpecies(); - } - m_tlast = tnow; - } - } - - void LatticeSolidPhase::setLatticeMoleFractions(int nn, - string x) { - m_lattice[nn]->setMoleFractionsByName(x); - int n, k, loc=0, nsp; - doublereal ndens; - for (n = 0; n < m_nlattice; n++) { - nsp = m_lattice[n]->nSpecies(); - ndens = m_lattice[n]->molarDensity(); - for (k = 0; k < nsp; k++) { - m_x[loc] = ndens * m_lattice[n]->moleFraction(k); - loc++; - } - } - setMoleFractions(DATA_PTR(m_x)); - } - - void LatticeSolidPhase::setParametersFromXML(const XML_Node& eosdata) { - eosdata._require("model","LatticeSolid"); - XML_Node& la = eosdata.child("LatticeArray"); - vector lattices; - la.getChildren("phase",lattices); - int n; - int nl = lattices.size(); - m_nlattice = nl; - for (n = 0; n < nl; n++) { - XML_Node& i = *lattices[n]; - m_lattice.push_back((LatticePhase*)newPhase(i)); - } - } -} - + } #endif + strt += nsp; + } + } + //==================================================================================================================== + // Get the species chemical potentials. Units: J/kmol. + /* + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * This returns the underlying lattice chemical potentials + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ + void LatticeSolidPhase::getChemPotentials(doublereal* mu) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + int nlsp = m_lattice[n]->nSpecies(); + m_lattice[n]->getChemPotentials(mu+strt); + strt += nlsp; + } + } + //==================================================================================================================== + void LatticeSolidPhase::getPartialMolarEnthalpies(doublereal* hbar) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + int nlsp = m_lattice[n]->nSpecies(); + m_lattice[n]->getPartialMolarEnthalpies(hbar + strt); + strt += nlsp; + } + } + //==================================================================================================================== + void LatticeSolidPhase::getPartialMolarEntropies(doublereal* sbar) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + int nlsp = m_lattice[n]->nSpecies(); + m_lattice[n]->getPartialMolarEntropies(sbar + strt); + strt += nlsp; + } + } + //==================================================================================================================== + void LatticeSolidPhase::getPartialMolarCp(doublereal* cpbar) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + int nlsp = m_lattice[n]->nSpecies(); + m_lattice[n]->getPartialMolarCp(cpbar + strt); + strt += nlsp; + } + } + //==================================================================================================================== + void LatticeSolidPhase::getPartialMolarVolumes(doublereal* vbar) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + int nlsp = m_lattice[n]->nSpecies(); + m_lattice[n]->getPartialMolarVolumes(vbar + strt); + strt += nlsp; + } + } + //==================================================================================================================== + // Get the array of standard state chemical potentials at unit activity for the species + // at their standard states at the current T and P of the solution. + /* + * These are the standard state chemical potentials \f$ \mu^0_k(T,P) + * \f$. The values are evaluated at the current + * temperature and pressure of the solution. + * + * This returns the underlying lattice standard chemical potentials, as the units are kmol-1 of + * the sublattice species. + * + * @param mu0 Output vector of chemical potentials. + * Length: m_kk. Units: J/kmol + */ + void LatticeSolidPhase::getStandardChemPotentials(doublereal* mu0) const { + _updateThermo(); + int strt = 0; + for (int n = 0; n < m_nlattice; n++) { + m_lattice[n]->getStandardChemPotentials(mu0+strt); + strt += m_lattice[n]->nSpecies(); + } + } + //==================================================================================================================== + void LatticeSolidPhase::getGibbs_RT_ref(doublereal *grt) const { + _updateThermo(); + for (int n = 0; n < m_nlattice; n++) { + m_lattice[n]->getGibbs_RT_ref(grt + lkstart_[n]); + } + } + //==================================================================================================================== + void LatticeSolidPhase::getGibbs_ref(doublereal *g) const { + getGibbs_RT_ref(g); + for (int k = 0; k < m_kk; k++) { + g[k] *= GasConstant * temperature(); + } + } + //==================================================================================================================== + // Add in species from Slave phases + /* + * This hook is used for cSS_CONVENTION_SLAVE phases + * + * @param phaseNode XML_Node for the current phase + */ + void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode) + { + int m, k; + int kk = 0; + int kstart = 0; + SpeciesThermoFactory* spFactory = SpeciesThermoFactory::factory(); + SpeciesThermo * spthermo_ptr = new GeneralSpeciesThermo(); + setSpeciesThermo(spthermo_ptr); + m_speciesData.clear(); + + XML_Node& eosdata = phaseNode->child("thermo"); + XML_Node& la = eosdata.child("LatticeArray"); + std::vector lattices; + la.getChildren("phase",lattices); + for (int n = 0; n < m_nlattice; n++) { + LatticePhase *lp = m_lattice[n]; + XML_Node* phaseNode_ptr = lattices[n]; + int nsp = lp->nSpecies(); + vector constArr(lp->nElements()); + const vector_fp& aws = lp->atomicWeights(); + for (int es = 0; es < lp->nElements(); es++) { + string esName = lp->elementName(es); + double wt = aws[es]; + int an = lp->atomicNumber(es); + int e298 = lp->entropyElement298(es); + int et = lp->elementType(es); + addUniqueElementAfterFreeze(esName, wt, an, e298, et); + } + const std::vector & spNode = lp->speciesData(); + kstart = kk; + + + for (k = 0; k < nsp; k++) { + std::string sname = lp->speciesName(k); + std::map comp; + lp->getAtoms(k, DATA_PTR(constArr)); + int nel = nElements(); + vector_fp ecomp(nel, 0.0); + for (m = 0; m < lp->nElements(); m++) { + if (constArr[m] != 0.0) { + std::string oldEname = lp->elementName(m); + int newIndex = elementIndex(oldEname); + if (newIndex < 0) { + throw CanteraError("LatticeSolidPhase::installSlavePhases", "confused"); + } + ecomp[newIndex] = constArr[m]; + } + } + double chrg = lp->charge(k); + double sz = lp->size(k); + addUniqueSpecies(sname, &ecomp[0], chrg, sz); + spFactory->installThermoForSpecies(kk, *(spNode[k]), this, *m_spthermo, phaseNode_ptr); + + m_speciesData.push_back(new XML_Node(*(spNode[k]))); + kk++; + } + /* + * Add in the lattice stoichiometry constraint + */ + if (n > 0) { + string econ = "LC_"; + econ += int2str(n); + econ += "_" + id(); + int m = addUniqueElementAfterFreeze(econ, 0.0, 0, 0.0, CT_ELEM_TYPE_LATTICERATIO); + m_mm = nElements(); + LatticePhase *lp0 = m_lattice[0]; + int nsp0 = lp0->nSpecies(); + for (k = 0; k < nsp0; k++) { + m_speciesComp[k * m_mm + m] = -theta_[0]; + } + for (k = 0; k < nsp; k++) { + int ks = kstart + k; + m_speciesComp[ks * m_mm + m] = theta_[n]; + } + } + } + } + + //==================================================================================================================== + // Initialize the ThermoPhase object after all species have been set up + /* + * @internal Initialize. + * + * This method is provided to allow subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called from ThermoPhase::initThermoXML(), + * which is called from importPhase(), just prior to returning from function importPhase(). + * + * @see importCTML.cpp + */ + void LatticeSolidPhase::initThermo() { + m_kk = nSpecies(); + m_mm = nElements(); + initLengths(); + int nsp, k, loc = 0; + for (int n = 0; n < m_nlattice; n++) { + nsp = m_lattice[n]->nSpecies(); + lkstart_[n] = loc; + nspLattice_[n] = nsp; + for (k = 0; k < nsp; k++) { + m_x[loc] =m_lattice[n]->moleFraction(k) / (double) m_nlattice; + loc++; + } + lkstart_[n+1] = loc; + } + setMoleFractions(DATA_PTR(m_x)); + ThermoPhase::initThermo(); + } + //==================================================================================================================== + // Initialize vectors that depend on the number of species and sublattices + /* + * + */ + void LatticeSolidPhase::initLengths() { + theta_.resize(m_nlattice,0); + nspLattice_.resize(m_nlattice); + lkstart_.resize(m_nlattice+1); + m_x.resize(m_kk, 0.0); + tmpV_.resize(m_kk, 0.0); + } + //==================================================================================================================== + void LatticeSolidPhase::_updateThermo() const { + doublereal tnow = temperature(); + // if (fabs(molarDensity() - m_molar_density)/m_molar_density > 0.0001) { + // throw CanteraError("_updateThermo","molar density changed from " + // +fp2str(m_molar_density)+" to "+fp2str(molarDensity())); + //} + if (m_tlast != tnow) { + int n; + getMoleFractions(DATA_PTR(m_x)); + int strt = 0; + for (n = 0; n < m_nlattice; n++) { + m_lattice[n]->setTemperature(tnow); + m_lattice[n]->setMoleFractions(DATA_PTR(m_x) + strt); + m_lattice[n]->setPressure(m_press); + strt += m_lattice[n]->nSpecies(); + } + m_tlast = tnow; + } + } + //==================================================================================================================== + void LatticeSolidPhase::setLatticeMoleFractionsByName(int nn, std::string x) { + m_lattice[nn]->setMoleFractionsByName(x); + int n, k, loc=0, nsp; + doublereal ndens; + for (n = 0; n < m_nlattice; n++) { + nsp = m_lattice[n]->nSpecies(); + ndens = m_lattice[n]->molarDensity(); + for (k = 0; k < nsp; k++) { + m_x[loc] = ndens * m_lattice[n]->moleFraction(k); + loc++; + } + } + setMoleFractions(DATA_PTR(m_x)); + } + //==================================================================================================================== + + + //==================================================================================================================== + // Set the parameters from the XML file + /*! + * Currently, this is the spot that we read in all of the sublattice phases. + * The SetParametersFromXML() call is carried out at + */ + void LatticeSolidPhase::setParametersFromXML(const XML_Node& eosdata) { + eosdata._require("model","LatticeSolid"); + XML_Node& la = eosdata.child("LatticeArray"); + std::vector lattices; + la.getChildren("phase",lattices); + int n; + int nl = lattices.size(); + m_nlattice = nl; + for (n = 0; n < nl; n++) { + XML_Node& i = *lattices[n]; + m_lattice.push_back((LatticePhase*)newPhase(i)); + } + std::vector pnam; + std::vector pval; + XML_Node& ls = eosdata.child("LatticeStoichiometry"); + int np = ctml::getPairs(ls, pnam, pval); + theta_.resize(nl); + for (int i = 0; i < np; i++) { + double val = fpValueCheck(pval[i]); + bool found = false; + for (int j = 0; j < nl; j++) { + ThermoPhase &tp = *(m_lattice[j]); + string idj = tp.id(); + if (idj == pnam[i]) { + theta_[j] = val; + found = true; + break; + } + } + if (!found) { + throw CanteraError("", "not found"); + } + } + + } + //==================================================================================================================== + // Return a changeable reference to the calculation manager + // for species reference-state thermodynamic properties + /* + * + * @param k Speices id. The default is -1, meaning return the default + * + * @internal + */ + SpeciesThermo& LatticeSolidPhase::speciesThermo(int k) { + return *m_spthermo; + /* + int kk; + if (k >= 0) { + for (int n = 0; n < m_nlattice; n++) { + if (lkstart_[n+1] < k) { + kk = k - lkstart_[n]; + return m_lattice[n]->speciesThermo(kk); + } + } + } + return m_lattice[0]->speciesThermo(-1); + */ + } + //==================================================================================================================== + +#ifdef H298MODIFY_CAPABILITY + + //! Modify the value of the 298 K Heat of Formation of one species in the phase (J kmol-1) + /*! + * The 298K heat of formation is defined as the enthalpy change to create the standard state + * of the species from its constituent elements in their standard states at 298 K and 1 bar. + * + * @param k Species k + * @param Hf298New Specify the new value of the Heat of Formation at 298K and 1 bar + */ + void LatticeSolidPhase::modifyOneHf298SS(const int k, const doublereal Hf298New) { + for (int n = 0; n < m_nlattice; n++) { + if (lkstart_[n+1] < k) { + int kk = k-lkstart_[n]; + SpeciesThermo& l_spthermo = m_lattice[n]->speciesThermo(); + l_spthermo.modifyOneHf298(kk, Hf298New); + } + } + m_tlast += 0.0001234; + _updateThermo(); + } +#endif + //==================================================================================================================== + + doublereal LatticeSolidPhase::err(std::string msg) const { + throw CanteraError("LatticeSolidPhase","Unimplemented " + msg); + return 0.0; + } + +} // End namespace Cantera +//====================================================================================================================== +#endif // End #define WITH_LATTICE_SOLID +//====================================================================================================================== diff --git a/Cantera/src/thermo/LatticeSolidPhase.h b/Cantera/src/thermo/LatticeSolidPhase.h index 16f1bc4a7..c9c7c47fa 100644 --- a/Cantera/src/thermo/LatticeSolidPhase.h +++ b/Cantera/src/thermo/LatticeSolidPhase.h @@ -27,19 +27,98 @@ #include "mix_defs.h" #include "ThermoPhase.h" #include "SpeciesThermo.h" +#include "LatticePhase.h" #include "utilities.h" namespace Cantera { - class LatticePhase; - - //! Additive combination of lattice phases + //! A phase that is comprised of a fixed additive combination of other lattice phases /*! + * This is the main way %Cantera describes semiconductors and other solid phases. + * This %ThermoPhase object calculates its properties as a sum over other %LatticePhase objects. Each of the %LatticePhase + * objects is a %ThermoPhase object by itself. + * + * The results from this LatticeSolidPhase model reduces to the LatticePhase model when there is one + * lattice phase and the molar densities of the sublattice and the molar density within the LatticeSolidPhase + * have the same values. * + * + * The mole fraction vector is redefined witin the the LatticeSolidPhase object. Each of the mole + * fractions sum to one on each of the sublattices. The routine getMoleFraction() and setMoleFraction() + * have been redefined to use this convention. + * + *
+ *

Specification of Species Standard %State Properties

+ *
+ * + * The standard state properties are calculated in the normal way for each of the sublattices. The normal way + * here means that a thermodynamic polynomial in temperature is developed. Also, a constant volume approximation + * for the pressure dependence is assumed. All of these properties are on a Joules per kmol of sublattice + * constituent basis. + * + *
+ *

Specification of Solution Thermodynamic Properties

+ *
+ + * The sum over the %LatticePhase objects is carried out by weighting each %LatticePhase object + * value with the molar density (kmol m-3) of its %LatticePhase. Then the resulting quantity is divided by + * the molar density of the total compound. The LatticeSolidPhase object therefore only contains a + * listing of the number of %LatticePhase object + * that comprises the solid, and it contains a value for the molar density of the entire mixture. + * This is the same thing as saying that + * + * \f[ + * L_i = L^{solid} \theta_i + * \f] + * + * \f$ L_i \f$ is the molar volume of the ith lattice. \f$ L^{solid} \f$ is the molar volume of the entire + * solid. \f$ \theta_i \f$ is a fixed weighting factor for the ith lattice representing the lattice + * stoichiometric coefficient. For this object the \f$ \theta_i \f$ values are fixed. + * + * + * Let's take FeS2 as an example, which may be thought of as a combination of two lattices: Fe and S lattice. + * The Fe sublattice has a molar density of 1 gmol cm-3. The S sublattice has a molar density of 2 gmol cm-3. + * We then define the LatticeSolidPhase object as having a nominal composition of FeS2, and having a + * molar density of 1 gmol cm-3. All quantities pertaining to the FeS2 compound will be have weights + * associated with the sublattices. The Fe sublattice will have a weight of 1.0 associated with it. The + * S sublattice will have a weight of 2.0 associated with it. + * + * + *
+ *

Specification of Solution Density Properties

+ *
+ * + * Currently, molar density is not a constant within the object, even though the species molar volumes are a + * constant. The basic idea is that a swelling of one of the sublattices will result in a swelling of + * of all of the lattices. Therefore, the molar volumes of the individual lattices are not independent of + * one another. + * + * The molar volume of the Lattice solid is calculated from the following formula + * + * \f[ + * V = \sum_i{ \theta_i V_i^{lattice}} + * \f] + * + * where \f$ V_i^{lattice} \f$ is the molar volume of the ith sublattice. This is calculated from the + * following standard formula. + * + * + * \f[ + * V_i = \sum_k{ X_k V_k} + * \f] + * + * where k is a species in the ith sublattice. + * + * The mole fraction vector is redefined witin the the LatticeSolidPhase object. Each of the mole + * fractions sum to one on each of the sublattices. The routine getMoleFraction() and setMoleFraction() + * have been redefined to use this convention. + * + * (This object is still under construction) + * */ - class LatticeSolidPhase : public ThermoPhase { + class LatticeSolidPhase : public ThermoPhase { public: @@ -77,57 +156,512 @@ namespace Cantera { */ virtual int eosType() const { return cLatticeSolid; } + //! Minimum temperature for which the thermodynamic data for the species + //! or phase are valid. + /*! + * If no argument is supplied, the + * value returned will be the lowest temperature at which the + * data for \e all species are valid. Otherwise, the value + * will be only for species \a k. This function is a wrapper + * that calls the species thermo minTemp function. + * + * @param k index of the species. Default is -1, which will return the max of the min value + * over all species. + */ + virtual doublereal minTemp(int k = -1) const; + + //! Maximum temperature for which the thermodynamic data for the species + //! are valid. + /*! + * If no argument is supplied, the + * value returned will be the highest temperature at which the + * data for \e all species are valid. Otherwise, the value + * will be only for species \a k. This function is a wrapper + * that calls the species thermo maxTemp function. + * + * @param k index of the species. Default is -1, which will return the min of the max value + * over all species. + */ + virtual doublereal maxTemp(int k = -1) const; + + + //! Returns the reference pressure in Pa. This function is a wrapper + //! that calls the species thermo refPressure function. + virtual doublereal refPressure() const ; + + //! This method returns the convention used in specification + //! of the standard state, of which there are currently two, + //! temperature based, and variable pressure based. + /*! + * All of the thermo is determined by slave %ThermoPhase routines. + */ + virtual int standardStateConvention() const { + return cSS_CONVENTION_SLAVE; + } + //! Return the Molar Enthalpy. Units: J/kmol. /*! - * For an ideal solution, - * \f[ - * \hat h(T,P) = \sum_k X_k \hat h^0_k(T), - * \f] - * and is a function only of temperature. - * The standard-state pure-species Enthalpies - * \f$ \hat h^0_k(T) \f$ are computed by the species thermodynamic - * property manager. + * The molar enthalpy is determined by the following formula, where \f$ \theta_n \f$ is the + * lattice stoichiometric coefficient of the nth lattice * - * \see SpeciesThermo + * \f[ + * \tilde h(T,P) = {\sum_n \theta_n \tilde h_n(T,P) } + * \f] + * + * \f$ \tilde h_n(T,P) \f$ is the enthalpy of the nth lattice. + * + * units J/kmol */ virtual doublereal enthalpy_mole() const; + + //! Return the Molar Internal Energy. Units: J/kmol. + /*! + * The molar enthalpy is determined by the following formula, where \f$ \theta_n \f$ is the + * lattice stoichiometric coefficient of the nth lattice + * + * \f[ + * \tilde u(T,P) = {\sum_n \theta_n \tilde u_n(T,P) } + * \f] + * + * \f$ \tilde u_n(T,P) \f$ is the internal energy of the nth lattice. + * + * units J/kmol + */ virtual doublereal intEnergy_mole() const; + //! Return the Molar Entropy. Units: J/kmol/K. + /*! + * The molar enthalpy is determined by the following formula, where \f$ \theta_n \f$ is the + * lattice stoichiometric coefficient of the nth lattice + * + * \f[ + * \tilde s(T,P) = \sum_n \theta_n \tilde s_n(T,P) + * \f] + * + * \f$ \tilde s_n(T,P) \f$ is the molar entropy of the nth lattice. + * + * units J/kmol/K + */ virtual doublereal entropy_mole() const; + //! Return the Molar Gibbs energy. Units: J/kmol. + /*! + * The molar gibbs free energy is determined by the following formula, where \f$ \theta_n \f$ is the + * lattice stoichiometric coefficient of the nth lattice + * + * \f[ + * \tilde h(T,P) = {\sum_n \theta_n \tilde h_n(T,P) } + * \f] + * + * \f$ \tilde h_n(T,P) \f$ is the enthalpy of the nth lattice. + * + * units J/kmol + */ virtual doublereal gibbs_mole() const; + //! Return the constant pressure heat capacity. Units: J/kmol/K + /*! + * The molar constant pressure heat capacity is determined by the following formula, where \f$ C_n \f$ is the + * lattice molar density of the nth lattice, and \f$ C_T \f$ is the molar density + * of the solid compound. + * + * \f[ + * \tilde c_{p,n}(T,P) = \frac{\sum_n C_n \tilde c_{p,n}(T,P) }{C_T}, + * \f] + * + * \f$ \tilde c_{p,n}(T,P) \f$ is the heat capacity of the nth lattice. + * + * units J/kmol/K + */ virtual doublereal cp_mole() const; + //! Return the constant volume heat capacity. Units: J/kmol/K + /*! + * The molar constant volume heat capacity is determined by the following formula, where \f$ C_n \f$ is the + * lattice molar density of the nth lattice, and \f$ C_T \f$ is the molar density + * of the solid compound. + * + * \f[ + * \tilde c_{v,n}(T,P) = \frac{\sum_n C_n \tilde c_{v,n}(T,P) }{C_T}, + * \f] + * + * \f$ \tilde c_{v,n}(T,P) \f$ is the heat capacity of the nth lattice. + * + * units J/kmol/K + */ virtual doublereal cv_mole() const { return cp_mole(); } + //! Report the Pressure. Units: Pa. + /*! + * This method simply returns the storred pressure value. + */ virtual doublereal pressure() const { return m_press; } - virtual void setPressure(doublereal p) { - m_press = p; - setMolarDensity(m_molar_density); + //! Set the pressure at constant temperature. Units: Pa. + /*! + * + * @param p Pressure (units - Pa) + */ + virtual void setPressure(doublereal p); + + //! Calculate the density of the solid mixture + /*! + * The formula for this is + * + * \f[ + * \rho = \sum_n{ \rho_n \theta_n } + * \f] + * + * where \f$ \rho_n \f$ is the density of the nth sublattice + * + * Note this is a nonvirtual function. + */ + doublereal calcDensity(); + + //! Set the mole fractions to the specified values, and then + //! normalize them so that they sum to 1.0 for each of the subphases + /*! + * On input, the mole fraction vector is assumed to sum to one for each of the sublattices. The sublattices + * are updated with this mole fraction vector. The mole fractions are also storred within this object, after + * they are normalized to one by dividing by the number of sublattices. + * + * @param x Input vector of mole fractions. There is no restriction + * on the sum of the mole fraction vector. Internally, + * this object will pass portions of this vector to the sublattices which assume that the portions + * individually sum to one. + * Length is m_kk. + */ + virtual void setMoleFractions(const doublereal * const x); + + //! Get the species mole fraction vector. + /*! + * On output the mole fraction vector will sum to one for each of the subphases which make up this phase. + * + * @param x On return, x contains the mole fractions. Must have a + * length greater than or equal to the number of species. + */ + virtual void getMoleFractions(doublereal * const x) const; + + //! The mole fraction of species k. + /*! + * If k is ouside the valid + * range, an exception will be thrown. Note that it is + * somewhat more efficent to call getMoleFractions if the + * mole fractions of all species are desired. + * @param k species index + */ + doublereal moleFraction(const int k) const { + return err("not implemented"); + } + + //! Get the species mass fractions. + /*! + * @param y On return, y contains the mass fractions. Array \a y must have a length + * greater than or equal to the number of species. + */ + void getMassFractions(doublereal* const y) const { + err("not implemented"); + } + + //! Mass fraction of species k. + /*! + * If k is outside the valid range, an exception will be thrown. Note that it is + * somewhat more efficent to call getMassFractions if the mass fractions of all species are desired. + * + * @param k species index + */ + doublereal massFraction(const int k) const { + return err("not implemented"); } + + //! Set the mass fractions to the specified values, and then + //! normalize them so that they sum to 1.0. + /*! + * @param y Array of unnormalized mass fraction values (input). + * Must have a length greater than or equal to the number of species. + * Input vector of mass fractions. There is no restriction + * on the sum of the mass fraction vector. Internally, + * the State object will normalize this vector before + * storring its contents. + * Length is m_kk. + */ + virtual void setMassFractions(const doublereal * const y) { + err("not implemented"); + } + + + //! Set the mass fractions to the specified values without normalizing. + /*! + * This is useful when the normalization + * condition is being handled by some other means, for example + * by a constraint equation as part of a larger set of equations. + * + * @param y Input vector of mass fractions. + * Length is m_kk. + */ + virtual void setMassFractions_NoNorm(const doublereal* const y) { + err("not implemented"); + } + + void getConcentrations(doublereal* const c) const { + err("not implemented"); + } + + doublereal concentration(int k) const { + return err("not implemented"); + } + + virtual void setConcentrations(const doublereal* const conc) { + err("not implemented"); + } + + //! This method returns an array of generalized activity concentrations + /*! + * The generalized activity concentrations, + * \f$ C^a_k \f$, are defined such that \f$ a_k = C^a_k / + * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. Note that they may + * or may not have units of concentration --- they might be + * partial pressures, mole fractions, or surface coverages, + * for example. + * + * @param c Output array of generalized concentrations. The + * units depend upon the implementation of the + * reaction rate expressions within the phase. + */ virtual void getActivityConcentrations(doublereal* c) const; + //! Get the array of non-dimensional molar-based activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param ac Output vector of activity coefficients. Length: m_kk. + */ virtual void getActivityCoefficients(doublereal* ac) const; + //! Get the species chemical potentials. Units: J/kmol. + /*! + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * This returns the underlying lattice chemical potentials, as the units are kmol-1 of + * the sublattice species. + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ virtual void getChemPotentials(doublereal* mu) const; - virtual void getStandardChemPotentials(doublereal* mu0) const; - virtual doublereal standardConcentration(int k=0) const; - virtual doublereal logStandardConc(int k=0) const; + + //! Returns an array of partial molar enthalpies for the species in the mixture. + /*! + * Units (J/kmol) + * For this phase, the partial molar enthalpies are equal to the + * pure species enthalpies + * \f[ + * \bar h_k(T,P) = \hat h^{ref}_k(T) + (P - P_{ref}) \hat V^0_k + * \f] + * The reference-state pure-species enthalpies, \f$ \hat h^{ref}_k(T) \f$, + * at the reference pressure,\f$ P_{ref} \f$, + * are computed by the species thermodynamic + * property manager. They are polynomial functions of temperature. + * @see SpeciesThermo + * + * @param hbar Output vector containing partial molar enthalpies. + * Length: m_kk. + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + /** + * Returns an array of partial molar entropies of the species in the + * solution. Units: J/kmol/K. + * For this phase, the partial molar entropies are equal to the + * pure species entropies plus the ideal solution contribution. + * \f[ + * \bar s_k(T,P) = \hat s^0_k(T) - R log(X_k) + * \f] + * The reference-state pure-species entropies,\f$ \hat s^{ref}_k(T) \f$, + * at the reference pressure, \f$ P_{ref} \f$, are computed by the + * species thermodynamic + * property manager. They are polynomial functions of temperature. + * @see SpeciesThermo + * + * @param sbar Output vector containing partial molar entropies. + * Length: m_kk. + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + /** + * Returns an array of partial molar Heat Capacities at constant + * pressure of the species in the + * solution. Units: J/kmol/K. + * For this phase, the partial molar heat capacities are equal + * to the standard state heat capacities. + * + * @param cpbar Output vector of partial heat capacities. Length: m_kk. + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + /** + * returns an array of partial molar volumes of the species + * in the solution. Units: m^3 kmol-1. + * + * For this solution, thepartial molar volumes are equal to the + * constant species molar volumes. + * + * @param vbar Output vector of partial molar volumes. Length: m_kk. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //! Get the array of standard state chemical potentials at unit activity for the species + //! at their standard states at the current T and P of the solution. + /*! + * These are the standard state chemical potentials \f$ \mu^0_k(T,P) + * \f$. The values are evaluated at the current + * temperature and pressure of the solution. + * + * + * This returns the underlying lattice standard chemical potentials, as the units are kmol-1 of + * the sublattice species. + * + * @param mu0 Output vector of chemical potentials. + * Length: m_kk. Units: J/kmol + */ + virtual void getStandardChemPotentials(doublereal* mu0) const; + + //! Return the standard concentration for the kth species + /*! + * The standard concentration \f$ C^0_k \f$ used to normalize + * the activity (i.e., generalized) concentration. In many cases, this quantity + * will be the same for all species in a phase - for example, + * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this + * reason, this method returns a single value, instead of an + * array. However, for phases in which the standard + * concentration is species-specific (e.g. surface species of + * different sizes), this method may be called with an + * optional parameter indicating the species. + * + * @param k Optional parameter indicating the species. The default + * is to assume this refers to species 0. + * @return + * Returns the standard concentration. The units are by definition + * dependent on the ThermoPhase and kinetics manager representation. + */ + virtual doublereal standardConcentration(int k=0) const; + + //! Natural logarithm of the standard concentration of the kth species. + /*! + * @param k index of the species (defaults to zero) + */ + virtual doublereal logStandardConc(int k=0) const; + //@} + /// @name Thermodynamic Values for the Species Reference States -------------------- + //@{ + + //! Returns the vector of nondimensional enthalpies of the reference state at the current + //! temperature of the solution and the reference pressure for the species. + /*! + * This function fills in its one entry in hrt[] by calling + * the underlying species thermo function for the + * dimensionless gibbs free energy, calculated from the + * dimensionless enthalpy and entropy. + * + * @param grt Vector of dimensionless Gibbs free energies of the reference state + * length = m_kk + */ + virtual void getGibbs_RT_ref(doublereal *grt) const; + + + //! Returns the vector of the gibbs function of the reference state at the current + //! temperatureof the solution and the reference pressure for the species. + /*! + * units = J/kmol + * + * This function fills in its one entry in g[] by calling the underlying species thermo + * functions for the gibbs free energy, calculated from enthalpy and the + * entropy, and the multiplying by RT. + * + * @param g Vector of Gibbs free energies of the reference state. + * length = m_kk + */ + virtual void getGibbs_ref(doublereal *g) const; + + + //! Initialize the ThermoPhase object after all species have been set up + /*! + * @internal Initialize. + * + * This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called from ThermoPhase::initThermoXML(), + * which is called from importPhase(), + * just prior to returning from function importPhase(). + * + * @see importCTML.cpp + */ virtual void initThermo(); + //! Initialize vectors that depend on the number of species and sublattices + void initLengths(); + + //! Add in species from Slave phases + /*! + * This hook is used for cSS_CONVENTION_SLAVE phases + * + * @param phaseNode XML_Node for the current phase + */ + virtual void installSlavePhases(Cantera::XML_Node* phaseNode); + + + //! Set equation of state parameter values from XML entries. + /*! + * + * This method is called by function importPhase() in + * file importCTML.cpp when processing a phase definition in + * an input file. It should be overloaded in subclasses to set + * any parameters that are specific to that particular phase + * model. Note, this method is called before the phase is + * initialzed with elements and/or species. + * + * @param eosdata An XML_Node object corresponding to + * the "thermo" entry for this phase in the input file. + */ virtual void setParametersFromXML(const XML_Node& eosdata); - void setLatticeMoleFractions(int n, std::string x); + //! Set the Lattice mole fractions using a string + /*! + * + * @param n Integer value of the lattice whose mole fractions are being set + * @param x string comtaining Name:value pairs that will specify the mole fractions + * of species on a particular lattice + */ + void setLatticeMoleFractionsByName(int n, std::string x); + + //! Return a changeable reference to the calculation manager + //! for species reference-state thermodynamic properties + /*! + * This routine returns the calculation manager for the sublattice + * + * @param k Speices id. The default is -1, meaning return the default + * + * @internal + */ + virtual SpeciesThermo& speciesThermo(int k = -1); #ifdef H298MODIFY_CAPABILITY @@ -137,32 +671,64 @@ namespace Cantera { * of the species from its constituent elements in their standard states at 298 K and 1 bar. * * @param k Species k - * @param HF298New Specify the new value of the Heat of Formation at 298K and 1 bar + * @param Hf298New Specify the new value of the Heat of Formation at 298K and 1 bar */ - virtual void modifyOneHf298SS(const int k, const doublereal Hf298New) { - m_spthermo->modifyOneHf298(k, Hf298New); - m_tlast += 0.0001234; - } + virtual void modifyOneHf298SS(const int k, const doublereal Hf298New); #endif + private: + //! error routine + /*! + * @param msg Message + * + * @return nothing + */ + doublereal err(std::string msg) const; + protected: - + + //! Number of elements int m_mm; - int m_kk; - mutable doublereal m_tlast; - doublereal m_press; - doublereal m_molar_density; + //! Last temperature at which the reference thermo was calculated + mutable doublereal m_tlast; - int m_nlattice; - std::vector m_lattice; - mutable vector_fp m_x; + //! Current value of the pressure + doublereal m_press; + + //! Current value of the molar density + doublereal m_molar_density; + + //! Number of sublattice phases + int m_nlattice; + + //! Vector of sublattic ThermoPhase objects + std::vector m_lattice; + + //! Vector of mole fractions + /*! + * Note these mole fractions sum to one when summed over all phases. + * However, this is not what's passed down to the lower m_lattice objects. + */ + mutable vector_fp m_x; + + //! Lattice stoichiometric coefficients + std::vector theta_; + + //! Temporary vector + mutable vector_fp tmpV_; + + std::vector nspLattice_; + + std::vector lkstart_; private: + //! Update the reference thermodynamic functions void _updateThermo() const; }; } -#endif +#endif // #ifdef WITH_LATTICE_SOLID + #endif diff --git a/Cantera/src/thermo/Makefile.in b/Cantera/src/thermo/Makefile.in index 73669357e..a7f87e4ec 100644 --- a/Cantera/src/thermo/Makefile.in +++ b/Cantera/src/thermo/Makefile.in @@ -40,7 +40,7 @@ THERMO_OBJ = State.o Elements.o Constituents.o Phase.o \ ThermoFactory.o phasereport.o SpeciesThermoInterpType.o \ VPSSMgr.o VPSSMgrFactory.o VPSSMgr_General.o IdealSolnGasVPSS.o \ VPSSMgr_IdealGas.o VPSSMgr_ConstVol.o PDSS_ConstVol.o PDSS_IdealGas.o \ - PDSS_SSVol.o @phase_object_files@ + PDSS_SSVol.o MixtureFugacityTP.o RedlichKwongMFTP.o @phase_object_files@ THERMO_H = State.h Elements.h Constituents.h Phase.h mix_defs.h \ ThermoPhase.h IdealGasPhase.h ConstDensityThermo.h \ @@ -54,7 +54,7 @@ THERMO_H = State.h Elements.h Constituents.h Phase.h mix_defs.h \ EdgePhase.h \ VPSSMgr.h VPSSMgrFactory.h VPSSMgr_General.h IdealSolnGasVPSS.h \ VPSSMgr_IdealGas.h VPSSMgr_ConstVol.h PDSS_ConstVol.h PDSS_IdealGas.h \ - PDSS_SSVol.h @phase_header_files@ + PDSS_SSVol.h MixtureFugacityTP.h RedlichKwongMFTP.h @phase_header_files@ # Extended Cantera Thermodynamics Object Files @@ -67,7 +67,7 @@ ELECTRO_OBJ = MolalityVPSSTP.o VPStandardStateTP.o \ PDSS.o PDSS_Water.o PDSS_HKFT.o \ HMWSoln.o HMWSoln_input.o DebyeHuckel.o \ WaterSSTP.o MetalSHEelectrons.o \ - VPSSMgr_Water_ConstVol.o VPSSMgr_Water_HKFT.o + VPSSMgr_Water_ConstVol.o VPSSMgr_Water_HKFT.o PhaseCombo_Interaction.o ELECTRO_H = MolalityVPSSTP.h VPStandardStateTP.h \ IdealMolalSoln.h \ @@ -75,15 +75,17 @@ ELECTRO_H = MolalityVPSSTP.h VPStandardStateTP.h \ PDSS.h PDSS_Water.h PDSS_HKFT.h \ HMWSoln.h electrolytes.h \ DebyeHuckel.h WaterSSTP.h MetalSHEelectrons.h VPSSMgr_Water_HKFT.h \ - VPSSMgr_Water_ConstVol.h + VPSSMgr_Water_ConstVol.h PhaseCombo_Interaction.h endif ifeq ($(do_issp),1) ISSP_OBJ = IdealSolidSolnPhase.o StoichSubstanceSSTP.o SingleSpeciesTP.o MineralEQ3.o \ - GibbsExcessVPSSTP.o PseudoBinaryVPSSTP.o MargulesVPSSTP.o \ - IonsFromNeutralVPSSTP.o PDSS_IonsFromNeutral.o + GibbsExcessVPSSTP.o MolarityIonicVPSSTP.o MargulesVPSSTP.o \ + IonsFromNeutralVPSSTP.o PDSS_IonsFromNeutral.o FixedChemPotSSTP.o \ + MixedSolventElectrolyte.o RedlichKisterVPSSTP.o ISSP_H = IdealSolidSolnPhase.h StoichSubstanceSSTP.h SingleSpeciesTP.h MineralEQ3.h \ - GibbsExcessVPSSTP.h PseudoBinaryVPSSTP.h MargulesVPSSTP.h \ - IonsFromNeutralVPSSTP.h PDSS_IonsFromNeutral.h + GibbsExcessVPSSTP.h MolarityIonicVPSSTP.h MargulesVPSSTP.h \ + IonsFromNeutralVPSSTP.h PDSS_IonsFromNeutral.h FixedChemPotSSTP.h \ + MixedSolventElectrolyte.h RedlichKisterVPSSTP.h endif CATHERMO_OBJ = $(THERMO_OBJ) $(ELECTRO_OBJ) $(ISSP_OBJ) @@ -91,7 +93,7 @@ CATHERMO_OBJ = $(THERMO_OBJ) $(ELECTRO_OBJ) $(ISSP_OBJ) CATHERMO_H = $(THERMO_H) $(ELECTRO_H) $(ISSP_H) -CXX_INCLUDES = -I../base @CXX_INCLUDES@ +CXX_INCLUDES = -I../base -I../numerics @CXX_INCLUDES@ LIB = @buildlib@/libthermo.a DEPENDS = $(CATHERMO_OBJ:.o=.d) diff --git a/Cantera/src/thermo/MargulesVPSSTP.cpp b/Cantera/src/thermo/MargulesVPSSTP.cpp index 0d1ab06dc..2af8706cb 100644 --- a/Cantera/src/thermo/MargulesVPSSTP.cpp +++ b/Cantera/src/thermo/MargulesVPSSTP.cpp @@ -341,22 +341,13 @@ namespace Cantera { */ - doublereal MargulesVPSSTP::standardConcentration(int k) const { - err("standardConcentration"); - return -1.0; - } - - doublereal MargulesVPSSTP::logStandardConc(int k) const { - err("logStandardConc"); - return -1.0; - } - - // Get the array of non-dimensional molar-based activity coefficients at + //==================================================================================================================== + // Get the array of non-dimensional molar-based ln activity coefficients at // the current solution temperature, pressure, and solution concentration. /* - * @param ac Output vector of activity coefficients. Length: m_kk. + * @param lnac Output vector of ln activity coefficients. Length: m_kk. */ - void MargulesVPSSTP::getActivityCoefficients(doublereal* ac) const { + void MargulesVPSSTP::getLnActivityCoefficients(doublereal* lnac) const { /* * Update the activity coefficients */ @@ -366,10 +357,10 @@ namespace Cantera { * take the exp of the internally storred coefficients. */ for (int k = 0; k < m_kk; k++) { - ac[k] = exp(lnActCoeff_Scaled_[k]); + lnac[k] = lnActCoeff_Scaled_[k]; } } - + //==================================================================================================================== /* * ------------ Partial Molar Properties of the Solution ------------ */ @@ -408,6 +399,43 @@ namespace Cantera { } } + /// Molar enthalpy. Units: J/kmol. + doublereal MargulesVPSSTP::enthalpy_mole() const { + int kk = nSpecies(); + double hbar[kk], h = 0; + getPartialMolarEnthalpies(hbar); + for (int i = 0; i < kk; i++){ + h += moleFractions_[i]*hbar[i]; + } + return h; + } + + /// Molar entropy. Units: J/kmol. + doublereal MargulesVPSSTP::entropy_mole() const { + int kk = nSpecies(); + double sbar[kk], s = 0; + getPartialMolarEntropies(sbar); + for (int i = 0; i < kk; i++){ + s += moleFractions_[i]*sbar[i]; + } + return s; + } + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + doublereal MargulesVPSSTP::cp_mole() const { + int kk = nSpecies(); + double cpbar[kk], cp = 0; + getPartialMolarCp(cpbar); + for (int i = 0; i < kk; i++){ + cp += moleFractions_[i]*cpbar[i]; + } + return cp; + } + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + doublereal MargulesVPSSTP::cv_mole() const { + return cp_mole() - GasConstant; + } // Returns an array of partial molar enthalpies for the species // in the mixture. @@ -448,6 +476,44 @@ namespace Cantera { } } + // Returns an array of partial molar heat capacities for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????? \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MargulesVPSSTP::getPartialMolarCp(doublereal* cpbar) const { + /* + * Get the nondimensional standard state entropies + */ + getCp_R(cpbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + cpbar[k] *= GasConstant; + } + } + // Returns an array of partial molar entropies for the species // in the mixture. /* @@ -512,9 +578,7 @@ namespace Cantera { * Get the standard state values in m^3 kmol-1 */ getStandardVolumes(vbar); - //cout << "species name(0) = " << speciesName(0) << endl; - //cout << "iA = " << speciesName(m_pSpecies_A_ij[0]) << endl; - //cout << "iB = " << speciesName(m_pSpecies_B_ij[0]) << endl; + for ( iK = 0; iK < m_kk; iK++ ){ delAK = 0; @@ -569,7 +633,7 @@ namespace Cantera { // been identified. void MargulesVPSSTP::initLengths() { m_kk = nSpecies(); - + dlnActCoeffdlnN_.resize(m_kk, m_kk); } /* @@ -617,7 +681,7 @@ namespace Cantera { if (thermoNode.hasChild("activityCoefficients")) { XML_Node& acNode = thermoNode.child("activityCoefficients"); acNodePtr = &acNode; - string mStringa = thermoNode.attrib("model"); + string mStringa = acNode.attrib("model"); string mString = lowercase(mStringa); if (mString != "margules") { throw CanteraError(subname.c_str(), @@ -647,7 +711,7 @@ namespace Cantera { } - + //=================================================================================================================== // Update the activity coefficients /* @@ -661,64 +725,25 @@ namespace Cantera { double XA, XB, XK, g0 , g1; double T = temperature(); double RT = GasConstant*T; - fvo_zero_dbl_1(lnActCoeff_Scaled_, m_kk); - - for ( iK = 0; iK < m_kk; iK++ ){ - + for (iK = 0; iK < m_kk; iK++) { XK = moleFractions_[iK]; - for (int i = 0; i < numBinaryInteractions_; i++) { - iA = m_pSpecies_A_ij[i]; iB = m_pSpecies_B_ij[i]; - delAK = 0; delBK = 0; - - if (iA==iK) delAK = 1; + if (iA==iK) delAK = 1; else if (iB==iK) delBK = 1; - XA = moleFractions_[iA]; XB = moleFractions_[iB]; - g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; - - lnActCoeff_Scaled_[iK] += (delAK*XB+XA*delBK-XA*XB)*(g0+g1*XB)+XA*XB*(delBK-XB)*g1; - //lnActCoeff_Scaled_[iK] += XA*XB*(g0+g1*XB)+((delAK-XA)*XB+XA*(delBK-XB))*(g0+g1*XB)+XA*XB*(delBK-XB)*g1; + lnActCoeff_Scaled_[iK] += (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1; } } } - - - /* - // Not Right??? - void MargulesVPSSTP::s_update_lnActCoeff() const { - - int iA, iB; - double XA, XB, g0 , g1; - double T = temperature(); - - fvo_zero_dbl_1(lnActCoeff_Scaled_, m_kk); - - double RT = GasConstant * temperature(); - for (int i = 0; i < numBinaryInteractions_; i++) { - iA = m_pSpecies_A_ij[i]; - iB = m_pSpecies_B_ij[i]; - - XA = moleFractions_[iA]; - XB = moleFractions_[iB]; - - g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT ; - g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; - - lnActCoeff_Scaled_[iA] += XB * XB * (g0 + g1 * (XB - XA)); - lnActCoeff_Scaled_[iB] += XA * XA * g0 + XA * XB * g1 * (2 * XA); - } - } - */ - + //=================================================================================================================== // Update the derivative of the log of the activity coefficients wrt T /* * This function will be called to update the internally storred @@ -728,79 +753,60 @@ namespace Cantera { */ void MargulesVPSSTP::s_update_dlnActCoeff_dT() const { int iA, iB, iK, delAK, delBK; - double XA, XB, XK, g0 , g1; - double T = temperature(); - double RTT = GasConstant*T*T; - + doublereal XA, XB, g0, g1; + doublereal T = temperature(); + doublereal RTT = GasConstant*T*T; fvo_zero_dbl_1(dlnActCoeffdT_Scaled_, m_kk); - - for ( iK = 0; iK < m_kk; iK++ ){ - - XK = moleFractions_[iK]; - + fvo_zero_dbl_1(d2lnActCoeffdT2_Scaled_, m_kk); + for (iK = 0; iK < m_kk; iK++) { for (int i = 0; i < numBinaryInteractions_; i++) { - iA = m_pSpecies_A_ij[i]; iB = m_pSpecies_B_ij[i]; - delAK = 0; delBK = 0; - - if (iA==iK) delAK = 1; + if (iA==iK) delAK = 1; else if (iB==iK) delBK = 1; - XA = moleFractions_[iA]; XB = moleFractions_[iB]; - g0 = -m_HE_b_ij[i] / RTT; g1 = -m_HE_c_ij[i] / RTT; - - dlnActCoeffdT_Scaled_[iK] += (delAK*XB+XA*delBK-XA*XB)*(g0+g1*XB)+XA*XB*(delBK-XB)*g1; + double temp = (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1; + dlnActCoeffdT_Scaled_[iK] += temp; + d2lnActCoeffdT2_Scaled_[iK] -= 2.0 * temp / T; } } } - - /* Not Right??? - void MargulesVPSSTP::s_update_dlnActCoeff_dT() const {} - - int iA, iB; - doublereal XA, XB, h0 , h1; - doublereal T = temperature(); - - fvo_zero_dbl_1(dlnActCoeffdT_Scaled_, m_kk); - - doublereal RTT = GasConstant * T * T; - for (int i = 0; i < numBinaryInteractions_; i++) { - iA = m_pSpecies_A_ij[i]; - iB = m_pSpecies_B_ij[i]; - - XA = moleFractions_[iA]; - XB = moleFractions_[iB]; - - h0 = m_HE_b_ij[i]; - h1 = m_HE_c_ij[i]; - - dlnActCoeffdT_Scaled_[iA] += -(XB * XB * (h0 + h1 * (XB - XA))) / RTT; - dlnActCoeffdT_Scaled_[iB] += -(XA * XA * h0 + XA * XB * h1 * (2 * XA))/RTT; - } - } - */ - + //==================================================================================================================== void MargulesVPSSTP::getdlnActCoeffdT(doublereal *dlnActCoeffdT) const { s_update_dlnActCoeff_dT(); for (int k = 0; k < m_kk; k++) { dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k]; } } + //==================================================================================================================== + void MargulesVPSSTP::getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k]; + } + } + //==================================================================================================================== - // calculate the change of the log of the activity coefficients wrt change in state: dT, dX + // Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + // a line in parameter space or along a line in physical space /* - * This function will be called to calculate gradient of the - * logarithm of the activity coefficients based on gradients in temperature and mole fraction. * - * he = X_A X_B(B + C X_B) + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. */ - void MargulesVPSSTP::getdlnActCoeff(const doublereal dT, const doublereal * const dX, doublereal* dlnActCoeff) const { + void MargulesVPSSTP::getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const { + + int iA, iB, iK, delAK, delBK; double XA, XB, XK, g0 , g1, dXA, dXB; double T = temperature(); @@ -812,7 +818,7 @@ namespace Cantera { for ( iK = 0; iK < m_kk; iK++ ){ XK = moleFractions_[iK]; - dlnActCoeff[iK] = 0.0; + dlnActCoeffds[iK] = 0.0; for (int i = 0; i < numBinaryInteractions_; i++) { @@ -828,18 +834,19 @@ namespace Cantera { XA = moleFractions_[iA]; XB = moleFractions_[iB]; - dXA = dX[iA]; - dXB = dX[iB]; + dXA = dXds[iA]; + dXB = dXds[iB]; g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; - dlnActCoeff[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB + dlnActCoeffdT_Scaled_[iK]*dT; + dlnActCoeffds[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB + + dlnActCoeffdT_Scaled_[iK]*dTds; } } } - - // Update the derivative of the log of the activity coefficients wrt ln(X) + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt dlnN /* * This function will be called to update the internally stored gradients of the * logarithm of the activity coefficients. These are used in the determination @@ -847,13 +854,13 @@ namespace Cantera { * * he = X_A X_B(B + C X_B) */ - void MargulesVPSSTP::s_update_dlnActCoeff_dlnN() const { + void MargulesVPSSTP::s_update_dlnActCoeff_dlnN_diag() const { int iA, iB, iK, delAK, delBK; double XA, XB, XK, g0 , g1; double T = temperature(); double RT = GasConstant*T; - fvo_zero_dbl_1(dlnActCoeffdlnN_Scaled_, m_kk); + fvo_zero_dbl_1(dlnActCoeffdlnN_diag_, m_kk); for ( iK = 0; iK < m_kk; iK++ ){ @@ -876,19 +883,105 @@ namespace Cantera { g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; - dlnActCoeffdlnN_Scaled_[iK] += 2*(delBK-XB) * (g0*(delAK-XA) + g1*(2*(delAK-XA)*XB + XA*(delBK-XB))); + dlnActCoeffdlnN_diag_[iK] += 2*(delBK-XB)*(g0*(delAK-XA)+g1*(2*(delAK-XA)*XB+XA*(delBK-XB))); + +// double gfac = g0 + g1 * XB; +// double gggg = (delBK - XB) * g1; + + +// dlnActCoeffdlnN_diag_[iK] += gfac * delAK * ( - XB + delBK); + +// dlnActCoeffdlnN_diag_[iK] += gfac * delBK * ( - XA + delAK); + +// dlnActCoeffdlnN_diag_[iK] += gfac * (2.0 * XA * XB - delAK * XB - XA * delBK); + +// dlnActCoeffdlnN_diag_[iK] += (delAK * XB + XA * delBK - XA * XB) * g1 * (-XB + delBK); + +// dlnActCoeffdlnN_diag_[iK] += gggg * ( - 2.0 * XA * XB + delAK * XB + XA * delBK); + +// dlnActCoeffdlnN_diag_[iK] += - g1 * XA * XB * (- XB + delBK); } - dlnActCoeffdlnN_Scaled_[iK] = XK*dlnActCoeffdlnN_Scaled_[iK]-XK; + dlnActCoeffdlnN_diag_[iK] = XK*dlnActCoeffdlnN_diag_[iK];//-XK; } } - void MargulesVPSSTP::s_update_dlnActCoeff_dlnX() const { + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt dlnN + /* + * This function will be called to update the internally stored gradients of the + * logarithm of the activity coefficients. These are used in the determination + * of the diffusion coefficients. + * + */ + void MargulesVPSSTP::s_update_dlnActCoeff_dlnN() const { + int iA, iB; + doublereal delAK, delBK; + double XA, XB, g0 , g1, XK,XM; + double T = temperature(); + double RT = GasConstant*T; + + doublereal delAM, delBM; + + dlnActCoeffdlnN_.zero(); + + /* + * Loop over the activity coefficient gamma_k + */ + for (int iK = 0; iK < m_kk; iK++) { + XK = moleFractions_[iK]; + for (int iM = 0; iM < m_kk; iM++) { + XM = moleFractions_[iM]; + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0.0; + delBK = 0.0; + delAM = 0.0; + delBM = 0.0; + if (iA==iK) delAK = 1.0; + else if (iB==iK) delBK = 1.0; + if (iA==iM) delAM = 1.0; + else if (iB==iM) delBM = 1.0; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnN_(iK,iM) += g0*((delAM-XA)*(delBK-XB)+(delAK-XA)*(delBM-XB)); + dlnActCoeffdlnN_(iK,iM) += 2*g1*((delAM-XA)*(delBK-XB)*XB+(delAK-XA)*(delBM-XB)*XB+(delBM-XB)*(delBK-XB)*XA); + +// double gfac = g0 + g1 * XB; +// double gggg = (delBK - XB) * g1; + + +// dlnActCoeffdlnN_(iK, iM) += gfac * delAK * ( - XB + delBM); + +// dlnActCoeffdlnN_(iK, iM) += gfac * delBK * ( - XA + delAM); + +// dlnActCoeffdlnN_(iK, iM) += gfac * (2.0 * XA * XB - delAM * XB - XA * delBM); + +// dlnActCoeffdlnN_(iK, iM) += (delAK * XB + XA * delBK - XA * XB) * g1 * (-XB + delBM); + +// dlnActCoeffdlnN_(iK, iM) += gggg * ( - 2.0 * XA * XB + delAM * XB + XA * delBM); + +// dlnActCoeffdlnN_(iK, iM) += - g1 * XA * XB * (- XB + delBM); + } + dlnActCoeffdlnN_(iK,iM) = XM*dlnActCoeffdlnN_(iK,iM); + } + } + } + //==================================================================================================================== + void MargulesVPSSTP::s_update_dlnActCoeff_dlnX_diag() const { int iA, iB; doublereal XA, XB, g0 , g1; doublereal T = temperature(); - fvo_zero_dbl_1(dlnActCoeffdlnX_Scaled_, m_kk); + fvo_zero_dbl_1(dlnActCoeffdlnX_diag_, m_kk); doublereal RT = GasConstant * T; @@ -904,45 +997,36 @@ namespace Cantera { g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; - dlnActCoeffdlnX_Scaled_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB); - dlnActCoeffdlnX_Scaled_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB); + dlnActCoeffdlnX_diag_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB); + dlnActCoeffdlnX_diag_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB); } - - /* - // Wrong!!! - for (int i = 0; i < numBinaryInteractions_; i++) { - iA = m_pSpecies_A_ij[i]; - iB = m_pSpecies_B_ij[i]; - - XA = moleFractions_[iA]; - XB = moleFractions_[iB]; - - g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT ; - g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; - - dlnActCoeffdlnX_Scaled_[iA] += XA * ( ( - 2.0 + 2.0 * XA ) * g0 - + ( - 4.0 + 10.0 * XA - 6.0 * XA*XA ) * g1 ) ; - dlnActCoeffdlnX_Scaled_[iB] += XB * ( ( - 2.0 + 2.0 * XB ) * g0 - + ( 2.0 - 8.0 * XB + 6.0 * XB*XB ) * g1 ) ; - } - */ } - - void MargulesVPSSTP::getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const { + //==================================================================================================================== + void MargulesVPSSTP::getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + s_update_dlnActCoeff_dlnN_diag(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k]; + } + } + //==================================================================================================================== + void MargulesVPSSTP::getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const { + s_update_dlnActCoeff_dlnX_diag(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k]; + } + } + //==================================================================================================================== + void MargulesVPSSTP::getdlnActCoeffdlnN(const int ld, doublereal *dlnActCoeffdlnN) { s_update_dlnActCoeff_dlnN(); + double *data = & dlnActCoeffdlnN_(0,0); for (int k = 0; k < m_kk; k++) { - dlnActCoeffdlnN[k] = dlnActCoeffdlnN_Scaled_[k]; + for (int m = 0; m < m_kk; m++) { + dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m]; + } } } - void MargulesVPSSTP::getdlnActCoeffdlnX(doublereal *dlnActCoeffdlnX) const { - s_update_dlnActCoeff_dlnX(); - for (int k = 0; k < m_kk; k++) { - dlnActCoeffdlnX[k] = dlnActCoeffdlnX_Scaled_[k]; - } - } - - + //==================================================================================================================== void MargulesVPSSTP::resizeNumInteractions(const int num) { numBinaryInteractions_ = num; m_HE_b_ij.resize(num, 0.0); @@ -962,7 +1046,7 @@ namespace Cantera { m_pSpecies_B_ij.resize(num, -1); } - + //==================================================================================================================== /* * Process an XML node called "binaryNeutralSpeciesParameters" @@ -1027,13 +1111,13 @@ namespace Cantera { /* * Get the string containing all of the values */ - getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy"); + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies::excessEnthalpy for " + ispName + "::" + jspName, - "wrong number of params found"); + "wrong number of params found. Need 2"); } m_HE_b_ij[iSpot] = vParams[0]; m_HE_c_ij[iSpot] = vParams[1]; @@ -1043,13 +1127,13 @@ namespace Cantera { /* * Get the string containing all of the values */ - getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy"); + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies::excessEntropy for " + ispName + "::" + jspName, - "wrong number of params found"); + "wrong number of params found. Need 2"); } m_SE_b_ij[iSpot] = vParams[0]; m_SE_c_ij[iSpot] = vParams[1]; @@ -1059,13 +1143,13 @@ namespace Cantera { /* * Get the string containing all of the values */ - getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy"); + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName + "::" + jspName, - "wrong number of params found"); + "wrong number of params found. Need 2"); } m_VHE_b_ij[iSpot] = vParams[0]; m_VHE_c_ij[iSpot] = vParams[1]; @@ -1075,13 +1159,13 @@ namespace Cantera { /* * Get the string containing all of the values */ - getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy"); + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies::excessVolume_Entropy for " + ispName + "::" + jspName, - "wrong number of params found"); + "wrong number of params found. Need 2"); } m_VSE_b_ij[iSpot] = vParams[0]; m_VSE_c_ij[iSpot] = vParams[1]; diff --git a/Cantera/src/thermo/MargulesVPSSTP.h b/Cantera/src/thermo/MargulesVPSSTP.h index b75594c76..6b38baa33 100644 --- a/Cantera/src/thermo/MargulesVPSSTP.h +++ b/Cantera/src/thermo/MargulesVPSSTP.h @@ -23,7 +23,7 @@ #ifndef CT_MARGULESVPSSTP_H #define CT_MARGULESVPSSTP_H -#include "PseudoBinaryVPSSTP.h" +#include "GibbsExcessVPSSTP.h" namespace Cantera { @@ -78,8 +78,11 @@ namespace Cantera { *

Specification of Solution Thermodynamic Properties

*
* - * The excess Gibbs free energy (expressed as an extrinsic thermodynamic - * variable) is given by the following formula: + * The molar excess Gibbs free energy is given by the following formula which is a sum over interactions i. + * Each of the interactions are binary interactions involving two of the species in the phase, denoted, Ai + * and Bi. + * This is the generalization of the Margules formulation for a phase + * that has more than 2 species. * * \f[ * G^E = \sum_i \left( H_{Ei} - T S_{Ei} \right) @@ -100,42 +103,56 @@ namespace Cantera { * a_k = \gamma_k X_k * \f] * - * where \f$ X_k \f$ is the mole fraction of species k. + * where + * + * \f[ + * R T \ln( \gamma_k )= \frac{d(n G^E)}{d(n_k)}\Bigg|_{n_i} + * \f] + * + * Taking the derivatives results in the following expression + * + * \f[ + * R T \ln( \gamma_k )= \sum_i \left( \left( \delta_{Ai,k} X_{Bi} + \delta_{Bi,k} X_{Ai} - X_{Ai} X_{Bi} \right) + * \left( g^E_{o,i} + g^E_{1,i} X_{Bi} \right) + + * \left( \delta_{Bi,k} - X_{Bi} \right) X_{Ai} X_{Bi} g^E_{1,i} \right) + * \f] + * where + * \f$ g^E_{o,i} = h_{o,i} - T s_{o,i} \f$ and \f$ g^E_{1,i} = h_{1,i} - T s_{1,i} \f$ + * and where \f$ X_k \f$ is the mole fraction of species k. + * + * This object inherits from the class VPStandardStateTP. Therefore, the specification and + * calculation of all standard state and reference state values are handled at that level. Various functional + * forms for the standard state are permissible. * The chemical potential for species k is equal to * * \f[ - * \mu_k(T,P) = \mu^o_k(T, P) + R T \log(\gamma_k X_k) - * \f] - * - * In terms of the reference state, the above can be rewritten - * - * - * \f[ - * \mu_k(T,P) = \mu^{ref}_k(T, P) + R T \log(\frac{P X_k}{P_{ref}}) + * \mu_k(T,P) = \mu^o_k(T, P) + R T \ln(\gamma_k X_k) * \f] * * The partial molar entropy for species k is given by the following relation, * * \f[ - * \tilde{s}_k(T,P) = s^o_k(T,P) - R \log(X_k) = s^{ref}_k(T) - R \log(\frac{P X_k}{P_{ref}}) + * \tilde{s}_k(T,P) = s^o_k(T,P) - R \ln( \gamma_k X_k ) + * - R T \frac{d \ln(\gamma_k) }{dT} * \f] * - * The partial molar enthalpy for species k is + * The partial molar enthalpy for species k is given by * * \f[ - * \tilde{h}_k(T,P) = h^o_k(T,P) = h^{ref}_k(T) + * \tilde{h}_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} * \f] * - * The partial molar Internal Energy for species k is + * The partial molar volume for species k is * * \f[ - * \tilde{u}_k(T,P) = u^o_k(T,P) = u^{ref}_k(T) + * \tilde V_k(T,P) = V^o_k(T,P) + R T \frac{d \ln(\gamma_k) }{dP} * \f] * * The partial molar Heat Capacity for species k is * * \f[ - * \tilde{Cp}_k(T,P) = Cp^o_k(T,P) = Cp^{ref}_k(T) + * \tilde{C}_{p,k}(T,P) = C^o_{p,k}(T,P) - 2 R T \frac{d \ln( \gamma_k )}{dT} + * - R T^2 \frac{d^2 \ln(\gamma_k) }{{dT}^2} * \f] * *
@@ -476,41 +493,14 @@ namespace Cantera { * @{ */ - - - /** - * The standard concentration \f$ C^0_k \f$ used to normalize - * the generalized concentration. In many cases, this quantity - * will be the same for all species in a phase - for example, - * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this - * reason, this method returns a single value, instead of an - * array. However, for phases in which the standard - * concentration is species-specific (e.g. surface species of - * different sizes), this method may be called with an - * optional parameter indicating the species. - * - * @param k species index. Defaults to zero. - */ - virtual doublereal standardConcentration(int k=0) const; - - /** - * Returns the natural logarithm of the standard - * concentration of the kth species - * - * @param k species index - */ - virtual doublereal logStandardConc(int k=0) const; - - //! Get the array of non-dimensional molar-based activity coefficients at + //! Get the array of non-dimensional molar-based ln activity coefficients at //! the current solution temperature, pressure, and solution concentration. /*! - * @param ac Output vector of activity coefficients. Length: m_kk. + * @param ac Output vector of ln activity coefficients. Length: m_kk. */ - virtual void getActivityCoefficients(doublereal* ac) const; + virtual void getLnActivityCoefficients(doublereal* lnac) const; - - //@} /// @name Partial Molar Properties of the Solution @@ -527,7 +517,18 @@ namespace Cantera { */ virtual void getChemPotentials(doublereal* mu) const; - + /// Molar enthalpy. Units: J/kmol. + virtual doublereal enthalpy_mole() const; + + /// Molar entropy. Units: J/kmol. + virtual doublereal entropy_mole() const; + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + virtual doublereal cp_mole() const; + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + virtual doublereal cv_mole() const; + //! Returns an array of partial molar enthalpies for the species //! in the mixture. /*! @@ -566,6 +567,28 @@ namespace Cantera { */ virtual void getPartialMolarEntropies(doublereal* sbar) const; + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????????? + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * ??????????????? + * \f] + * + * @param cpbar Vector of returned partial molar heat capacities + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + //! Return an array of partial molar volumes for the //! species in the mixture. Units: m^3/kmol. @@ -592,19 +615,18 @@ namespace Cantera { */ void getElectrochemPotentials(doublereal* mu) const; - - //! Get the array of change in the log activity coefficients with change in state (change temp, change mole fractions) + //! Get the array of temperature second derivatives of the log activity coefficients /*! * This function is a virtual class, but it first appears in GibbsExcessVPSSTP * class and derived classes from GibbsExcessVPSSTP. * * units = 1/Kelvin * - * @param dlnActCoeff Output vector of temperature derivatives of the + * @param d2lnActCoeffdT2 Output vector of temperature 2nd derivatives of the * log Activity Coefficients. length = m_kk * */ - virtual void getdlnActCoeff(const doublereal dT, const doublereal * const dX, doublereal *dlnActCoeffdT) const; + virtual void getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const; //! Get the array of temperature derivatives of the log activity coefficients /*! @@ -619,28 +641,6 @@ namespace Cantera { */ virtual void getdlnActCoeffdT(doublereal *dlnActCoeffdT) const; - - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can return zero. - * Implementations should take the derivative of the - * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. mole fraction, - * molality, etc.) that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - j that concentration-like variable when the derivative of the chemical - * potential is taken. - * - * units = dimensionless - * - * @param dlnActCoeffdlnX Output vector of log(mole fraction) - * derivatives of the log Activity Coefficients. - * length = m_kk - */ - virtual void getdlnActCoeffdlnX(doublereal *dlnActCoeffdlnX) const; - virtual void getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const; //@} @@ -731,6 +731,81 @@ namespace Cantera { */ void initThermoXML(XML_Node& phaseNode, std::string id); + /** + * @} + * @name Derivatives of Thermodynamic Variables needed for Applications + * @{ + */ + + //! Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + //! a line in parameter space or along a line in physical space + /*! + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + virtual void getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, doublereal *dlnActCoeffds) const; + + //! Get the array of log concentration-like derivatives of the + //! log activity coefficients - diagonal component + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the mole fraction. + * + * units = dimensionless + * + * @param dlnActCoeffdlnX_diag Output vector of the diagonal component of the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const; + + //! Get the array of derivatives of the log activity coefficients wrt mole numbers - diagonal only + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. mole fraction, + * molality, etc.) that represents the standard state. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of the diagonal entries for the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const; + + + //! Get the array of derivatives of the ln activity coefficients with respect to the ln species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * log of a species mole number (with all other species mole numbers held constant) + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) ; + + //@} private: @@ -780,14 +855,22 @@ namespace Cantera { * derivative of the natural logarithm of the activity coefficients * wrt logarithm of the mole fractions. */ - void s_update_dlnActCoeff_dlnX() const; + void s_update_dlnActCoeff_dlnX_diag() const; //! Update the derivative of the log of the activity coefficients - //! wrt log(moles) + //! wrt log(moles) - diagonal only + /*! + * This function will be called to update the internally storred diagonal entries for the + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the moles. + */ + void s_update_dlnActCoeff_dlnN_diag() const; + + //! Update the derivative of the log of the activity coefficients wrt log(moles_m) /*! * This function will be called to update the internally storred * derivative of the natural logarithm of the activity coefficients - * wrt logarithm of the moles. + * wrt logarithm of the mole number of species */ void s_update_dlnActCoeff_dlnN() const; @@ -854,6 +937,8 @@ namespace Cantera { //! Entropy term for the quaternary mole fraction interaction of the //! excess gibbs free energy expression mutable vector_fp m_VSE_d_ij; + + //! vector of species indices representing species A in the interaction /*! diff --git a/Cantera/src/thermo/MetalPhase.h b/Cantera/src/thermo/MetalPhase.h index 32ad3431d..315e4c344 100644 --- a/Cantera/src/thermo/MetalPhase.h +++ b/Cantera/src/thermo/MetalPhase.h @@ -104,7 +104,7 @@ namespace Cantera { virtual void setParametersFromXML(const XML_Node& eosdata) { eosdata._require("model","Metal"); - doublereal rho = getFloat(eosdata, "density", "density"); + doublereal rho = ctml::getFloat(eosdata, "density", "density"); setDensity(rho); } diff --git a/Cantera/src/thermo/MetalSHEelectrons.cpp b/Cantera/src/thermo/MetalSHEelectrons.cpp index 221fa5ae9..d9ef37ec5 100644 --- a/Cantera/src/thermo/MetalSHEelectrons.cpp +++ b/Cantera/src/thermo/MetalSHEelectrons.cpp @@ -433,7 +433,7 @@ namespace Cantera { XML_Node &tnode = phaseNode.child("thermo"); doublereal dens = 2.65E3; if (tnode.hasChild("density")) { - dens = getFloatDefaultUnits(tnode, "density", "kg/m3"); + dens = ctml::getFloatDefaultUnits(tnode, "density", "kg/m3"); } setDensity(dens); SingleSpeciesTP::initThermoXML(phaseNode, id); @@ -537,7 +537,7 @@ namespace Cantera { } doublereal rho = 2.65E3; if (eosdata.hasChild("density")) { - rho = getFloat(eosdata, "density", "toSI"); + rho = ctml::getFloat(eosdata, "density", "toSI"); } setDensity(rho); } diff --git a/Cantera/src/thermo/MineralEQ3.cpp b/Cantera/src/thermo/MineralEQ3.cpp index 1758f95de..e97c8f9e2 100644 --- a/Cantera/src/thermo/MineralEQ3.cpp +++ b/Cantera/src/thermo/MineralEQ3.cpp @@ -493,7 +493,7 @@ namespace Cantera { Aunits = aV.attrib("units"); Afactor = toSI(Aunits); } - volVal = getFloat(*aStandardState, "V0_Pr_Tr"); + volVal = ctml::getFloat(*aStandardState, "V0_Pr_Tr"); m_V0_pr_tr= volVal; volVal *= Afactor; m_speciesSize[0] = volVal; @@ -509,13 +509,13 @@ namespace Cantera { m_deltaG_formation_pr_tr = - getFloatDefaultUnits(MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy"); + ctml::getFloatDefaultUnits(MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy"); m_deltaH_formation_pr_tr = - getFloatDefaultUnits(MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy"); - m_Entrop_pr_tr = getFloatDefaultUnits(MinEQ3node, "S0_Pr_Tr", "cal/gmol/K"); - m_a = getFloatDefaultUnits(MinEQ3node, "a", "cal/gmol/K"); - m_b = getFloatDefaultUnits(MinEQ3node, "b", "cal/gmol/K2"); - m_c = getFloatDefaultUnits(MinEQ3node, "c", "cal-K/gmol"); + ctml::getFloatDefaultUnits(MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy"); + m_Entrop_pr_tr = ctml::getFloatDefaultUnits(MinEQ3node, "S0_Pr_Tr", "cal/gmol/K"); + m_a = ctml::getFloatDefaultUnits(MinEQ3node, "a", "cal/gmol/K"); + m_b = ctml::getFloatDefaultUnits(MinEQ3node, "b", "cal/gmol/K2"); + m_c = ctml::getFloatDefaultUnits(MinEQ3node, "c", "cal-K/gmol"); convertDGFormation(); diff --git a/Cantera/src/thermo/MixedSolventElectrolyte.cpp b/Cantera/src/thermo/MixedSolventElectrolyte.cpp new file mode 100644 index 000000000..922a40bfa --- /dev/null +++ b/Cantera/src/thermo/MixedSolventElectrolyte.cpp @@ -0,0 +1,1176 @@ +/** + * @file MargulesVPSSTP.cpp + * Definitions for ThermoPhase object for phases which + * employ excess gibbs free energy formulations related to Margules + * expansions (see \ref thermoprops + * and class \link Cantera::MargulesVPSSTP MargulesVPSSTP\endlink). + * + */ +/* + * Copywrite (2009) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ +/* + * $Date: 2011-04-14 12:24:13 -0600 (Thu, 14 Apr 2011) $ + * $Revision: 713 $ + */ + + +#include "MixedSolventElectrolyte.h" +#include "ThermoFactory.h" +#include + +using namespace std; + +namespace Cantera { + + static const double xxSmall = 1.0E-150; + /* + * Default constructor. + * + */ + MixedSolventElectrolyte::MixedSolventElectrolyte() : + MolarityIonicVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + } + + /* + * Working constructors + * + * The two constructors below are the normal way + * the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + + */ + MixedSolventElectrolyte::MixedSolventElectrolyte(std::string inputFile, std::string id) : + MolarityIonicVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + constructPhaseFile(inputFile, id); + } + + MixedSolventElectrolyte::MixedSolventElectrolyte(XML_Node& phaseRoot, std::string id) : + MolarityIonicVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + constructPhaseXML(phaseRoot, id); + } + + + /* + * Copy Constructor: + * + * Note this stuff will not work until the underlying phase + * has a working copy constructor + */ + MixedSolventElectrolyte::MixedSolventElectrolyte(const MixedSolventElectrolyte &b) : + MolarityIonicVPSSTP() + { + MixedSolventElectrolyte::operator=(b); + } + + /* + * operator=() + * + * Note this stuff will not work until the underlying phase + * has a working assignment operator + */ + MixedSolventElectrolyte& MixedSolventElectrolyte:: + operator=(const MixedSolventElectrolyte &b) { + if (&b == this) { + return *this; + } + + MolarityIonicVPSSTP::operator=(b); + + numBinaryInteractions_ = b.numBinaryInteractions_ ; + m_HE_b_ij = b.m_HE_b_ij; + m_HE_c_ij = b.m_HE_c_ij; + m_HE_d_ij = b.m_HE_d_ij; + m_SE_b_ij = b.m_SE_b_ij; + m_SE_c_ij = b.m_SE_c_ij; + m_SE_d_ij = b.m_SE_d_ij; + m_VHE_b_ij = b.m_VHE_b_ij; + m_VHE_c_ij = b.m_VHE_c_ij; + m_VHE_d_ij = b.m_VHE_d_ij; + m_VSE_b_ij = b.m_VSE_b_ij; + m_VSE_c_ij = b.m_VSE_c_ij; + m_VSE_d_ij = b.m_VSE_d_ij; + m_pSpecies_A_ij = b.m_pSpecies_A_ij; + m_pSpecies_B_ij = b.m_pSpecies_B_ij; + formMargules_ = b.formMargules_; + formTempModel_ = b.formTempModel_; + + return *this; + } + + /** + * + * ~MixedSolventElectrolyte(): (virtual) + * + * Destructor: does nothing: + * + */ + MixedSolventElectrolyte::~MixedSolventElectrolyte() { + } + + /* + * This routine duplicates the current object and returns + * a pointer to ThermoPhase. + */ + ThermoPhase* + MixedSolventElectrolyte::duplMyselfAsThermoPhase() const { + MixedSolventElectrolyte* mtp = new MixedSolventElectrolyte(*this); + return (ThermoPhase *) mtp; + } + + // Special constructor for a hard-coded problem + /* + * + * LiKCl treating the PseudoBinary layer as passthrough. + * -> test to predict the eutectic and liquidus correctly. + * + */ + MixedSolventElectrolyte::MixedSolventElectrolyte(int testProb) : + MolarityIonicVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + + + constructPhaseFile("LiKCl_liquid.xml", ""); + + + numBinaryInteractions_ = 1; + + m_HE_b_ij.resize(1); + m_HE_c_ij.resize(1); + m_HE_d_ij.resize(1); + + m_SE_b_ij.resize(1); + m_SE_c_ij.resize(1); + m_SE_d_ij.resize(1); + + m_VHE_b_ij.resize(1); + m_VHE_c_ij.resize(1); + m_VHE_d_ij.resize(1); + + m_VSE_b_ij.resize(1); + m_VSE_c_ij.resize(1); + m_VSE_d_ij.resize(1); + + m_pSpecies_A_ij.resize(1); + m_pSpecies_B_ij.resize(1); + + + + m_HE_b_ij[0] = -17570E3; + m_HE_c_ij[0] = -377.0E3; + m_HE_d_ij[0] = 0.0; + + m_SE_b_ij[0] = -7.627E3; + m_SE_c_ij[0] = 4.958E3; + m_SE_d_ij[0] = 0.0; + + + int iLiCl = speciesIndex("LiCl(L)"); + if (iLiCl < 0) { + throw CanteraError("MixedSolventElectrolyte test1 constructor", + "Unable to find LiCl(L)"); + } + m_pSpecies_B_ij[0] = iLiCl; + + + int iKCl = speciesIndex("KCl(L)"); + if (iKCl < 0) { + throw CanteraError("MixedSolventElectrolyte test1 constructor", + "Unable to find KCl(L)"); + } + m_pSpecies_A_ij[0] = iKCl; + } + + + /* + * -------------- Utilities ------------------------------- + */ + + + // Equation of state type flag. + /* + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The MixedSolventElectrolyte class also returns + * zero, as it is a non-complete class. + */ + int MixedSolventElectrolyte::eosType() const { + return 0; + } + + /* + * Import, construct, and initialize a phase + * specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void MixedSolventElectrolyte::constructPhaseFile(std::string inputFile, std::string id) { + + if ((int) inputFile.size() == 0) { + throw CanteraError("MixedSolventElectrolyte:constructPhaseFile", + "input file is null"); + } + string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("MixedSolventElectrolyte:constructPhaseFile","could not open " + +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("MixedSolventElectrolyte:constructPhaseFile", + "ERROR: Can not find phase named " + + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; + } + + /* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * Most of the work is carried out by the cantera base + * routine, importPhase(). That routine imports all of the + * species and element data, including the standard states + * of the species. + * + * Then, In this routine, we read the information + * particular to the specification of the activity + * coefficient model for the Pitzer parameterization. + * + * We also read information about the molar volumes of the + * standard states if present in the XML file. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void MixedSolventElectrolyte::constructPhaseXML(XML_Node& phaseNode, std::string id) { + string stemp; + if ((int) id.size() > 0) { + string idp = phaseNode.id(); + if (idp != id) { + throw CanteraError("MixedSolventElectrolyte::constructPhaseXML", + "phasenode and Id are incompatible"); + } + } + + /* + * Find the Thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("MixedSolventElectrolyte::constructPhaseXML", + "no thermo XML node"); + } + XML_Node& thermoNode = phaseNode.child("thermo"); + + /* + * Make sure that the thermo model is Margules + */ + stemp = thermoNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "margules") { + throw CanteraError("MixedSolventElectrolyte::constructPhaseXML", + "model name isn't Margules: " + formString); + + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the solvent and solute standard states + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("MixedSolventElectrolyte::constructPhaseXML","importPhase failed "); + } + + } + //==================================================================================================================== + /* + * ------------ Molar Thermodynamic Properties ---------------------- + */ + //==================================================================================================================== + /* + * - Activities, Standard States, Activity Concentrations ----------- + */ + //==================================================================================================================== + // Get the array of non-dimensional molar-based activity coefficients at + // the current solution temperature, pressure, and solution concentration. + /* + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + void MixedSolventElectrolyte::getActivityCoefficients(doublereal* ac) const { + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + + /* + * take the exp of the internally storred coefficients. + */ + for (int k = 0; k < m_kk; k++) { + ac[k] = exp(lnActCoeff_Scaled_[k]); + } + } + //==================================================================================================================== + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + + + + void MixedSolventElectrolyte::getElectrochemPotentials(doublereal* mu) const { + getChemPotentials(mu); + double ve = Faraday * electricPotential(); + for (int k = 0; k < m_kk; k++) { + mu[k] += ve*charge(k); + } + } + + + void MixedSolventElectrolyte::getChemPotentials(doublereal* mu) const { + doublereal xx; + /* + * First get the standard chemical potentials in + * molar form. + * -> this requires updates of standard state as a function + * of T and P + */ + getStandardChemPotentials(mu); + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + /* + * + */ + doublereal RT = GasConstant * temperature(); + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + mu[k] += RT * (log(xx) + lnActCoeff_Scaled_[k]); + } + } + + /// Molar enthalpy. Units: J/kmol. + doublereal MixedSolventElectrolyte::enthalpy_mole() const { + int kk = nSpecies(); + double hbar[kk], h = 0; + getPartialMolarEnthalpies(hbar); + for (int i = 0; i < kk; i++){ + h += moleFractions_[i]*hbar[i]; + } + return h; + } + + /// Molar entropy. Units: J/kmol. + doublereal MixedSolventElectrolyte::entropy_mole() const { + int kk = nSpecies(); + double sbar[kk], s = 0; + getPartialMolarEntropies(sbar); + for (int i = 0; i < kk; i++){ + s += moleFractions_[i]*sbar[i]; + } + return s; + } + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + doublereal MixedSolventElectrolyte::cp_mole() const { + int kk = nSpecies(); + double cpbar[kk], cp = 0; + getPartialMolarCp(cpbar); + for (int i = 0; i < kk; i++){ + cp += moleFractions_[i]*cpbar[i]; + } + return cp; + } + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + doublereal MixedSolventElectrolyte::cv_mole() const { + return cp_mole() - GasConstant; + } + + // Returns an array of partial molar enthalpies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MixedSolventElectrolyte::getPartialMolarEnthalpies(doublereal* hbar) const { + /* + * Get the nondimensional standard state enthalpies + */ + getEnthalpy_RT(hbar); + /* + * dimensionalize it. + */ + double T = temperature(); + double RT = GasConstant * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] *= RT; + } + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + double RTT = RT * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] -= RTT * dlnActCoeffdT_Scaled_[k]; + } + } + + // Returns an array of partial molar heat capacities for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????? \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MixedSolventElectrolyte::getPartialMolarCp(doublereal* cpbar) const { + /* + * Get the nondimensional standard state entropies + */ + getCp_R(cpbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + cpbar[k] *= GasConstant; + } + } + + // Returns an array of partial molar entropies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MixedSolventElectrolyte::getPartialMolarEntropies(doublereal* sbar) const { + double xx; + /* + * Get the nondimensional standard state entropies + */ + getEntropy_R(sbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + sbar[k] *= GasConstant; + } + } + + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + + // Return an array of partial molar volumes for the + // species in the mixture. Units: m^3/kmol. + /* + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + void MixedSolventElectrolyte::getPartialMolarVolumes(doublereal* vbar) const { + + int iA, iB, iK, delAK, delBK; + double XA, XB, XK, g0 , g1; + double T = temperature(); + + /* + * Get the standard state values in m^3 kmol-1 + */ + getStandardVolumes(vbar); + + + for ( iK = 0; iK < m_kk; iK++ ){ + delAK = 0; + delBK = 0; + XK = moleFractions_[iK]; + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_VHE_b_ij[i] - T * m_VSE_b_ij[i]); + g1 = (m_VHE_c_ij[i] - T * m_VSE_c_ij[i]); + + vbar[iK] += XA*XB*(g0+g1*XB)+((delAK-XA)*XB+XA*(delBK-XB))*(g0+g1*XB)+XA*XB*(delBK-XB)*g1; + } + } + } + + doublereal MixedSolventElectrolyte::err(std::string msg) const { + throw CanteraError("MixedSolventElectrolyte","Base class method " + +msg+" called. Equation of state type: "+int2str(eosType())); + return 0; + } + + + /* + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + void MixedSolventElectrolyte::initThermo() { + initLengths(); + MolarityIonicVPSSTP::initThermo(); + } + + + // Initialize lengths of local variables after all species have + // been identified. + void MixedSolventElectrolyte::initLengths() { + m_kk = nSpecies(); + dlnActCoeffdlnN_.resize(m_kk, m_kk); + } + + /* + * initThermoXML() (virtual from ThermoPhase) + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void MixedSolventElectrolyte::initThermoXML(XML_Node& phaseNode, std::string id) { + string subname = "MixedSolventElectrolyte::initThermoXML"; + string stemp; + + /* + * Check on the thermo field. Must have: + * + */ + + XML_Node& thermoNode = phaseNode.child("thermo"); + string mStringa = thermoNode.attrib("model"); + string mString = lowercase(mStringa); + if (mString != "margules") { + throw CanteraError(subname.c_str(), + "Unknown thermo model: " + mStringa); + } + + + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + XML_Node *acNodePtr = 0; + if (thermoNode.hasChild("activityCoefficients")) { + XML_Node& acNode = thermoNode.child("activityCoefficients"); + acNodePtr = &acNode; + string mStringa = acNode.attrib("model"); + string mString = lowercase(mStringa); + if (mString != "margules") { + throw CanteraError(subname.c_str(), + "Unknown activity coefficient model: " + mStringa); + } + int n = acNodePtr->nChildren(); + for (int i = 0; i < n; i++) { + XML_Node &xmlACChild = acNodePtr->child(i); + stemp = xmlACChild.name(); + string nodeName = lowercase(stemp); + /* + * Process a binary salt field, or any of the other XML fields + * that make up the Pitzer Database. Entries will be ignored + * if any of the species in the entry isn't in the solution. + */ + if (nodeName == "binaryneutralspeciesparameters") { + readXMLBinarySpecies(xmlACChild); + + } + } + } + + /* + * Go down the chain + */ + MolarityIonicVPSSTP::initThermoXML(phaseNode, id); + + + } + //=================================================================================================================== + + // Update the activity coefficients + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + * he = X_A X_B(B + C X_B) + */ + void MixedSolventElectrolyte::s_update_lnActCoeff() const { + int iA, iB, iK, delAK, delBK; + double XA, XB, XK, g0 , g1; + double T = temperature(); + double RT = GasConstant*T; + fvo_zero_dbl_1(lnActCoeff_Scaled_, m_kk); + for (iK = 0; iK < m_kk; iK++) { + XK = moleFractions_[iK]; + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + delAK = 0; + delBK = 0; + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + lnActCoeff_Scaled_[iK] += (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1; + } + } + } + //=================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt T + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + * he = X_A X_B(B + C X_B) + */ + void MixedSolventElectrolyte::s_update_dlnActCoeff_dT() const { + int iA, iB, iK, delAK, delBK; + doublereal XA, XB, g0, g1; + doublereal T = temperature(); + doublereal RTT = GasConstant*T*T; + fvo_zero_dbl_1(dlnActCoeffdT_Scaled_, m_kk); + fvo_zero_dbl_1(d2lnActCoeffdT2_Scaled_, m_kk); + for (iK = 0; iK < m_kk; iK++) { + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + delAK = 0; + delBK = 0; + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + g0 = -m_HE_b_ij[i] / RTT; + g1 = -m_HE_c_ij[i] / RTT; + double temp = (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1; + dlnActCoeffdT_Scaled_[iK] += temp; + d2lnActCoeffdT2_Scaled_[iK] -= 2.0 * temp / T; + } + } + } + //==================================================================================================================== + void MixedSolventElectrolyte::getdlnActCoeffdT(doublereal *dlnActCoeffdT) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k]; + } + } + //==================================================================================================================== + void MixedSolventElectrolyte::getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k]; + } + } + //==================================================================================================================== + + // Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + // a line in parameter space or along a line in physical space + /* + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + void MixedSolventElectrolyte::getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const { + + + int iA, iB, iK, delAK, delBK; + double XA, XB, XK, g0 , g1, dXA, dXB; + double T = temperature(); + double RT = GasConstant*T; + + //fvo_zero_dbl_1(dlnActCoeff, m_kk); + s_update_dlnActCoeff_dT(); + + for ( iK = 0; iK < m_kk; iK++ ){ + + XK = moleFractions_[iK]; + dlnActCoeffds[iK] = 0.0; + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0; + delBK = 0; + + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + dXA = dXds[iA]; + dXB = dXds[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffds[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB + + dlnActCoeffdT_Scaled_[iK]*dTds; + } + } + } + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt dlnN + /* + * This function will be called to update the internally stored gradients of the + * logarithm of the activity coefficients. These are used in the determination + * of the diffusion coefficients. + * + * he = X_A X_B(B + C X_B) + */ + void MixedSolventElectrolyte::s_update_dlnActCoeff_dlnN_diag() const { + int iA, iB, iK, delAK, delBK; + double XA, XB, XK, g0 , g1; + double T = temperature(); + double RT = GasConstant*T; + + fvo_zero_dbl_1(dlnActCoeffdlnN_diag_, m_kk); + + for ( iK = 0; iK < m_kk; iK++ ){ + + XK = moleFractions_[iK]; + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0; + delBK = 0; + + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnN_diag_[iK] += 2*(delBK-XB)*(g0*(delAK-XA)+g1*(2*(delAK-XA)*XB+XA*(delBK-XB))); + +// double gfac = g0 + g1 * XB; +// double gggg = (delBK - XB) * g1; + + +// dlnActCoeffdlnN_diag_[iK] += gfac * delAK * ( - XB + delBK); + +// dlnActCoeffdlnN_diag_[iK] += gfac * delBK * ( - XA + delAK); + +// dlnActCoeffdlnN_diag_[iK] += gfac * (2.0 * XA * XB - delAK * XB - XA * delBK); + +// dlnActCoeffdlnN_diag_[iK] += (delAK * XB + XA * delBK - XA * XB) * g1 * (-XB + delBK); + +// dlnActCoeffdlnN_diag_[iK] += gggg * ( - 2.0 * XA * XB + delAK * XB + XA * delBK); + +// dlnActCoeffdlnN_diag_[iK] += - g1 * XA * XB * (- XB + delBK); + } + dlnActCoeffdlnN_diag_[iK] = XK*dlnActCoeffdlnN_diag_[iK];//-XK; + } + } + + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt dlnN + /* + * This function will be called to update the internally stored gradients of the + * logarithm of the activity coefficients. These are used in the determination + * of the diffusion coefficients. + * + */ + void MixedSolventElectrolyte::s_update_dlnActCoeff_dlnN() const { + int iA, iB; + doublereal delAK, delBK; + double XA, XB, g0 , g1, XK,XM; + double T = temperature(); + double RT = GasConstant*T; + + doublereal delAM, delBM; + + dlnActCoeffdlnN_.zero(); + + /* + * Loop over the activity coefficient gamma_k + */ + for (int iK = 0; iK < m_kk; iK++) { + XK = moleFractions_[iK]; + for (int iM = 0; iM < m_kk; iM++) { + XM = moleFractions_[iM]; + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0.0; + delBK = 0.0; + delAM = 0.0; + delBM = 0.0; + if (iA==iK) delAK = 1.0; + else if (iB==iK) delBK = 1.0; + if (iA==iM) delAM = 1.0; + else if (iB==iM) delBM = 1.0; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnN_(iK,iM) += g0*((delAM-XA)*(delBK-XB)+(delAK-XA)*(delBM-XB)); + dlnActCoeffdlnN_(iK,iM) += 2*g1*((delAM-XA)*(delBK-XB)*XB+(delAK-XA)*(delBM-XB)*XB+(delBM-XB)*(delBK-XB)*XA); + +// double gfac = g0 + g1 * XB; +// double gggg = (delBK - XB) * g1; + + +// dlnActCoeffdlnN_(iK, iM) += gfac * delAK * ( - XB + delBM); + +// dlnActCoeffdlnN_(iK, iM) += gfac * delBK * ( - XA + delAM); + +// dlnActCoeffdlnN_(iK, iM) += gfac * (2.0 * XA * XB - delAM * XB - XA * delBM); + +// dlnActCoeffdlnN_(iK, iM) += (delAK * XB + XA * delBK - XA * XB) * g1 * (-XB + delBM); + +// dlnActCoeffdlnN_(iK, iM) += gggg * ( - 2.0 * XA * XB + delAM * XB + XA * delBM); + +// dlnActCoeffdlnN_(iK, iM) += - g1 * XA * XB * (- XB + delBM); + } + dlnActCoeffdlnN_(iK,iM) = XM*dlnActCoeffdlnN_(iK,iM); + } + } + } + //==================================================================================================================== + void MixedSolventElectrolyte::s_update_dlnActCoeff_dlnX_diag() const { + + int iA, iB; + doublereal XA, XB, g0 , g1; + doublereal T = temperature(); + + fvo_zero_dbl_1(dlnActCoeffdlnX_diag_, m_kk); + + doublereal RT = GasConstant * T; + + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnX_diag_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB); + dlnActCoeffdlnX_diag_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB); + } + } + + //==================================================================================================================== + void MixedSolventElectrolyte::getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + s_update_dlnActCoeff_dlnN_diag(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k]; + } + } + //==================================================================================================================== + void MixedSolventElectrolyte::getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const { + s_update_dlnActCoeff_dlnX_diag(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k]; + } + } + //==================================================================================================================== + void MixedSolventElectrolyte::getdlnActCoeffdlnN(const int ld, doublereal *dlnActCoeffdlnN) { + s_update_dlnActCoeff_dlnN(); + double *data = & dlnActCoeffdlnN_(0,0); + for (int k = 0; k < m_kk; k++) { + for (int m = 0; m < m_kk; m++) { + dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m]; + } + } + } + //==================================================================================================================== + void MixedSolventElectrolyte::resizeNumInteractions(const int num) { + numBinaryInteractions_ = num; + m_HE_b_ij.resize(num, 0.0); + m_HE_c_ij.resize(num, 0.0); + m_HE_d_ij.resize(num, 0.0); + m_SE_b_ij.resize(num, 0.0); + m_SE_c_ij.resize(num, 0.0); + m_SE_d_ij.resize(num, 0.0); + m_VHE_b_ij.resize(num, 0.0); + m_VHE_c_ij.resize(num, 0.0); + m_VHE_d_ij.resize(num, 0.0); + m_VSE_b_ij.resize(num, 0.0); + m_VSE_c_ij.resize(num, 0.0); + m_VSE_d_ij.resize(num, 0.0); + + m_pSpecies_A_ij.resize(num, -1); + m_pSpecies_B_ij.resize(num, -1); + + } + //==================================================================================================================== + + /* + * Process an XML node called "binaryNeutralSpeciesParameters" + * This node contains all of the parameters necessary to describe + * the Margules Interaction for a single binary interaction + * This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + */ + void MixedSolventElectrolyte::readXMLBinarySpecies(XML_Node &xmLBinarySpecies) { + string xname = xmLBinarySpecies.name(); + if (xname != "binaryNeutralSpeciesParameters") { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", + "Incorrect name for processing this routine: " + xname); + } + double *charge = DATA_PTR(m_speciesCharge); + string stemp; + int nParamsFound; + vector_fp vParams; + string iName = xmLBinarySpecies.attrib("speciesA"); + if (iName == "") { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesA attrib"); + } + string jName = xmLBinarySpecies.attrib("speciesB"); + if (jName == "") { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesB attrib"); + } + /* + * Find the index of the species in the current phase. It's not + * an error to not find the species + */ + int iSpecies = speciesIndex(iName); + if (iSpecies < 0) { + return; + } + string ispName = speciesName(iSpecies); + if (charge[iSpecies] != 0) { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesA charge problem"); + } + int jSpecies = speciesIndex(jName); + if (jSpecies < 0) { + return; + } + string jspName = speciesName(jSpecies); + if (charge[jSpecies] != 0) { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesB charge problem"); + } + + resizeNumInteractions(numBinaryInteractions_ + 1); + int iSpot = numBinaryInteractions_ - 1; + m_pSpecies_A_ij[iSpot] = iSpecies; + m_pSpecies_B_ij[iSpot] = jSpecies; + + int num = xmLBinarySpecies.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = xmLBinarySpecies.child(iChild); + stemp = xmlChild.name(); + string nodeName = lowercase(stemp); + /* + * Process the binary species interaction child elements + */ + if (nodeName == "excessenthalpy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEnthalpy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_HE_b_ij[iSpot] = vParams[0]; + m_HE_c_ij[iSpot] = vParams[1]; + } + + if (nodeName == "excessentropy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEntropy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_SE_b_ij[iSpot] = vParams[0]; + m_SE_c_ij[iSpot] = vParams[1]; + } + + if (nodeName == "excessvolume_enthalpy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_VHE_b_ij[iSpot] = vParams[0]; + m_VHE_c_ij[iSpot] = vParams[1]; + } + + if (nodeName == "excessvolume_entropy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Entropy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_VSE_b_ij[iSpot] = vParams[0]; + m_VSE_c_ij[iSpot] = vParams[1]; + } + + + } + + } + +} + diff --git a/Cantera/src/thermo/MixedSolventElectrolyte.h b/Cantera/src/thermo/MixedSolventElectrolyte.h new file mode 100644 index 000000000..21a33cde8 --- /dev/null +++ b/Cantera/src/thermo/MixedSolventElectrolyte.h @@ -0,0 +1,982 @@ +/** + * @file MargulesVPSSTP.h + * Header for intermediate ThermoPhase object for phases which + * employ gibbs excess free energy based formulations + * (see \ref thermoprops + * and class \link Cantera::MargulesVPSSTP MargulesVPSSTP\endlink). + * + * Header file for a derived class of ThermoPhase that handles + * variable pressure standard state methods for calculating + * thermodynamic properties that are further based upon activities + * based on the molality scale. These include most of the methods for + * calculating liquid electrolyte thermodynamics. + */ +/* + * 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. + */ +/* + * $Id: MargulesVPSSTP.h 713 2011-04-14 18:24:13Z hkmoffa $ + */ + +#ifndef CT_MIXEDSOLVENTELECTROLYTEVPSSTP_H +#define CT_MIXEDSOLVENTELECTROLYTEVPSSTP_H + +#include "MolarityIonicVPSSTP.h" + +namespace Cantera { + + /** + * @ingroup thermoprops + */ + + + //! MixedSolventElectrolyte is a derived class of GibbsExcessVPSSTP that employs + //! the DH and local Marguless approximations for the excess gibbs free energy + /*! + * + * %MargulesVPSSTP derives from class GibbsExcessVPSSTP which is derived + * from VPStandardStateTP, + * and overloads the virtual methods defined there with ones that + * use expressions appropriate for the Margules Excess gibbs free energy + * approximation. + * + * The independent unknowns are pressure, temperature, and mass fraction. + * + * Several concepts are introduced. The first concept is there are temporary + * variables for holding the species standard state values + * of Cp, H, S, G, and V at the + * last temperature and pressure called. These functions are not recalculated + * if a new call is made using the previous temperature and pressure. Currently, + * these variables and the calculation method are handled by the VPSSMgr class, + * for which VPStandardStateTP owns a pointer to. + * + * To support the above functionality, pressure and temperature variables, + * m_plast_ss and m_tlast_ss, are kept which store the last pressure and temperature + * used in the evaluation of standard state properties. + * + * This class is usually used for nearly incompressible phases. For those phases, it + * makes sense to change the equation of state independent variable from + * density to pressure. The variable m_Pcurrent contains the current value of the + * pressure within the phase. + * + * + *
+ *

Specification of Species Standard %State Properties

+ *
+ * + * All species are defined to have standard states that depend upon both + * the temperature and the pressure. The Margules approximation assumes + * symmetric standard states, where all of the standard state assume + * that the species are in pure component states at the temperatue + * and pressure of the solution. I don't think it prevents, however, + * some species from being dilute in the solution. + * + * + *
+ *

Specification of Solution Thermodynamic Properties

+ *
+ * + * The molar excess Gibbs free energy is given by the following formula which is a sum over interactions i. + * Each of the interactions are binary interactions involving two of the species in the phase, denoted, Ai + * and Bi. + * This is the generalization of the Margules formulation for a phase + * that has more than 2 species. + * + * \f[ + * G^E = \sum_i \left( H_{Ei} - T S_{Ei} \right) + * \f] + * \f[ + * H^E_i = n X_{Ai} X_{Bi} \left( h_{o,i} + h_{1,i} X_{Bi} \right) + * \f] + * \f[ + * S^E_i = n X_{Ai} X_{Bi} \left( s_{o,i} + s_{1,i} X_{Bi} \right) + * \f] + * + * where n is the total moles in the solution. + * + * The activity of a species defined in the phase is given by an excess + * Gibbs free energy formulation. + * + * \f[ + * a_k = \gamma_k X_k + * \f] + * + * where + * + * \f[ + * R T \ln( \gamma_k )= \frac{d(n G^E)}{d(n_k)}\Bigg|_{n_i} + * \f] + * + * Taking the derivatives results in the following expression + * + * \f[ + * R T \ln( \gamma_k )= \sum_i \left( \left( \delta_{Ai,k} X_{Bi} + \delta_{Bi,k} X_{Ai} - X_{Ai} X_{Bi} \right) + * \left( g^E_{o,i} + g^E_{1,i} X_{Bi} \right) + + * \left( \delta_{Bi,k} - X_{Bi} \right) X_{Ai} X_{Bi} g^E_{1,i} \right) + * \f] + * where + * \f$ g^E_{o,i} = h_{o,i} - T s_{o,i} \f$ and \f$ g^E_{1,i} = h_{1,i} - T s_{1,i} \f$ + * and where \f$ X_k \f$ is the mole fraction of species k. + * + * This object inherits from the class VPStandardStateTP. Therefore, the specification and + * calculation of all standard state and reference state values are handled at that level. Various functional + * forms for the standard state are permissible. + * The chemical potential for species k is equal to + * + * \f[ + * \mu_k(T,P) = \mu^o_k(T, P) + R T \ln(\gamma_k X_k) + * \f] + * + * The partial molar entropy for species k is given by the following relation, + * + * \f[ + * \tilde{s}_k(T,P) = s^o_k(T,P) - R \ln( \gamma_k X_k ) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * The partial molar enthalpy for species k is given by + * + * \f[ + * \tilde{h}_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * The partial molar volume for species k is + * + * \f[ + * \tilde V_k(T,P) = V^o_k(T,P) + R T \frac{d \ln(\gamma_k) }{dP} + * \f] + * + * The partial molar Heat Capacity for species k is + * + * \f[ + * \tilde{C}_{p,k}(T,P) = C^o_{p,k}(T,P) - 2 R T \frac{d \ln( \gamma_k )}{dT} + * - R T^2 \frac{d^2 \ln(\gamma_k) }{{dT}^2} + * \f] + * + *
+ *

%Application within %Kinetics Managers

+ *
+ * + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^s_k, \f$ where \f$ C^s_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used + * by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. + * The activity concentration,\f$ C^a_k \f$,is given by the following expression. + * + * \f[ + * C^a_k = C^s_k X_k = \frac{P}{R T} X_k + * \f] + * + * The standard concentration for species k is independent of k and equal to + * + * \f[ + * C^s_k = C^s = \frac{P}{R T} + * \f] + * + * For example, a bulk-phase binary gas reaction between species j and k, producing + * a new gas species l would have the + * following equation for its rate of progress variable, \f$ R^1 \f$, which has + * units of kmol m-3 s-1. + * + * \f[ + * R^1 = k^1 C_j^a C_k^a = k^1 (C^s a_j) (C^s a_k) + * \f] + * where + * \f[ + * C_j^a = C^s a_j \mbox{\quad and \quad} C_k^a = C^s a_k + * \f] + * + * + * \f$ C_j^a \f$ is the activity concentration of species j, and + * \f$ C_k^a \f$ is the activity concentration of species k. \f$ C^s \f$ + * is the standard concentration. \f$ a_j \f$ is + * the activity of species j which is equal to the mole fraction of j. + * + * The reverse rate constant can then be obtained from the law of microscopic reversibility + * and the equilibrium expression for the system. + * + * \f[ + * \frac{a_j a_k}{ a_l} = K_a^{o,1} = \exp(\frac{\mu^o_l - \mu^o_j - \mu^o_k}{R T} ) + * \f] + * + * \f$ K_a^{o,1} \f$ is the dimensionless form of the equilibrium constant, associated with + * the pressure dependent standard states \f$ \mu^o_l(T,P) \f$ and their associated activities, + * \f$ a_l \f$, repeated here: + * + * \f[ + * \mu_l(T,P) = \mu^o_l(T, P) + R T \log(a_l) + * \f] + * + * We can switch over to expressing the equilibrium constant in terms of the reference + * state chemical potentials + * + * \f[ + * K_a^{o,1} = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{P} + * \f] + * + * The concentration equilibrium constant, \f$ K_c \f$, may be obtained by changing over + * to activity concentrations. When this is done: + * + * \f[ + * \frac{C^a_j C^a_k}{ C^a_l} = C^o K_a^{o,1} = K_c^1 = + * \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{RT} + * \f] + * + * %Kinetics managers will calculate the concentration equilibrium constant, \f$ K_c \f$, + * using the second and third part of the above expression as a definition for the concentration + * equilibrium constant. + * + * For completeness, the pressure equilibrium constant may be obtained as well + * + * \f[ + * \frac{P_j P_k}{ P_l P_{ref}} = K_p^1 = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) + * \f] + * + * \f$ K_p \f$ is the simplest form of the equilibrium constant for ideal gases. However, it isn't + * necessarily the simplest form of the equilibrium constant for other types of phases; \f$ K_c \f$ is + * used instead because it is completely general. + * + * The reverse rate of progress may be written down as + * \f[ + * R^{-1} = k^{-1} C_l^a = k^{-1} (C^o a_l) + * \f] + * + * where we can use the concept of microscopic reversibility to + * write the reverse rate constant in terms of the + * forward reate constant and the concentration equilibrium + * constant, \f$ K_c \f$. + * + * \f[ + * k^{-1} = k^1 K^1_c + * \f] + * + * \f$k^{-1} \f$ has units of s-1. + * + * + *
+ *

Instantiation of the Class

+ *
+ * + * + * The constructor for this phase is located in the default ThermoFactory + * for %Cantera. A new %IdealGasPhase may be created by the following code + * snippet: + * + * @code + * XML_Node *xc = get_XML_File("silane.xml"); + * XML_Node * const xs = xc->findNameID("phase", "silane"); + * ThermoPhase *silane_tp = newPhase(*xs); + * IdealGasPhase *silaneGas = dynamic_cast (silane_tp); + * @endcode + * + * or by the following constructor: + * + * @code + * XML_Node *xc = get_XML_File("silane.xml"); + * XML_Node * const xs = xc->findNameID("phase", "silane"); + * IdealGasPhase *silaneGas = new IdealGasPhase(*xs); + * @endcode + * + *
+ *

XML Example

+ *
+ * An example of an XML Element named phase setting up a IdealGasPhase + * object named silane is given below. + * + * + * @verbatim + + + Si H He + + H2 H HE SIH4 SI SIH SIH2 SIH3 H3SISIH SI2H6 + H2SISIH2 SI3H8 SI2 SI3 + + + + + + + @endverbatim + * + * The model attribute "IdealGas" of the thermo XML element identifies the phase as + * being of the type handled by the IdealGasPhase object. + * + * @ingroup thermoprops + * + + */ + class MixedSolventElectrolyte : public MolarityIonicVPSSTP { + + public: + + //! Constructor + /*! + * This doesn't do much more than initialize constants with + * default values for water at 25C. Water molecular weight + * comes from the default elements.xml file. It actually + * differs slightly from the IAPWS95 value of 18.015268. However, + * density conservation and therefore element conservation + * is the more important principle to follow. + */ + MixedSolventElectrolyte(); + + //! Construct and initialize a MixedSolventElectrolyte ThermoPhase object + //! directly from an xml input file + /*! + * Working constructors + * + * The two constructors below are the normal way + * the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + * + * @param inputFile Name of the input file containing the phase XML data + * to set up the object + * @param id ID of the phase in the input file. Defaults to the + * empty string. + */ + MixedSolventElectrolyte(std::string inputFile, std::string id = ""); + + //! Construct and initialize a MixedSolventElectrolyte ThermoPhase object + //! directly from an XML database + /*! + * @param phaseRef XML phase node containing the description of the phase + * @param id id attribute containing the name of the phase. + * (default is the empty string) + */ + MixedSolventElectrolyte(XML_Node& phaseRef, std::string id = ""); + + + //! Special constructor for a hard-coded problem + /*! + * + * @param testProb Hard-coded value. Only the value of 1 is + * used. It's for + * a LiKCl system + * -> test to predict the eutectic and liquidus correctly. + */ + MixedSolventElectrolyte(int testProb); + + //! Copy constructor + /*! + * Note this stuff will not work until the underlying phase + * has a working copy constructor + * + * @param b class to be copied + */ + MixedSolventElectrolyte(const MixedSolventElectrolyte& b); + + //! Assignment operator + /*! + * + * @param b class to be copied. + */ + MixedSolventElectrolyte& operator=(const MixedSolventElectrolyte &b); + + //! Destructor + virtual ~MixedSolventElectrolyte(); + + //! Duplication routine for objects which inherit from ThermoPhase. + /*! + * This virtual routine can be used to duplicate thermophase objects + * inherited from ThermoPhase even if the application only has + * a pointer to ThermoPhase to work with. + */ + virtual ThermoPhase *duplMyselfAsThermoPhase() const; + + /** + * + * @name Utilities + * @{ + */ + + + //! Equation of state type flag. + /*! + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The MolalityVPSSTP class also returns + * zero, as it is a non-complete class. + */ + virtual int eosType() const; + + //! Initialization of a phase using an xml file + /*! + * This routine is a precursor to + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); + + //! Import and initialize a phase + //! specification in an XML tree into the current object. + /*! + * Here we read an XML description of the phase. + * We import descriptions of the elements that make up the + * species in a phase. + * We import information about the species, including their + * reference state thermodynamic polynomials. We then freeze + * the state of the species. + * + * Then, we read the species molar volumes from the xml + * tree to finish the initialization. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Molar Thermodynamic Properties + * @{ + */ + + + /** + * @} + * @name Utilities for Solvent ID and Molality + * @{ + */ + + + + + /** + * @} + * @name Mechanical Properties + * @{ + */ + + /** + * @} + * @name Potential Energy + * + * Species may have an additional potential energy due to the + * presence of external gravitation or electric fields. These + * methods allow specifying a potential energy for individual + * species. + * @{ + */ + + /** + * @} + * @name Activities, Standard States, and Activity Concentrations + * + * The activity \f$a_k\f$ of a species in solution is + * related to the chemical potential by \f[ \mu_k = \mu_k^0(T) + * + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is + * the chemical potential at unit activity, which depends only + * on temperature and pressure. + * @{ + */ + + //! Get the array of non-dimensional molar-based activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + virtual void getActivityCoefficients(doublereal* ac) const; + + + + + //@} + /// @name Partial Molar Properties of the Solution + //@{ + + //! Get the species chemical potentials. Units: J/kmol. + /*! + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ + virtual void getChemPotentials(doublereal* mu) const; + + /// Molar enthalpy. Units: J/kmol. + virtual doublereal enthalpy_mole() const; + + /// Molar entropy. Units: J/kmol. + virtual doublereal entropy_mole() const; + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + virtual doublereal cp_mole() const; + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + virtual doublereal cv_mole() const; + + //! Returns an array of partial molar enthalpies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * @param hbar Vector of returned partial molar enthalpies + * (length m_kk, units = J/kmol) + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * @param sbar Vector of returned partial molar entropies + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????????? + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * ??????????????? + * \f] + * + * @param cpbar Vector of returned partial molar heat capacities + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + + //! Return an array of partial molar volumes for the + //! species in the mixture. Units: m^3/kmol. + /*! + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //! Get the species electrochemical potentials. + /*! + * These are partial molar quantities. + * This method adds a term \f$ Fz_k \phi_k \f$ to the + * to each chemical potential. + * + * Units: J/kmol + * + * @param mu output vector containing the species electrochemical potentials. + * Length: m_kk., units = J/kmol + */ + void getElectrochemPotentials(doublereal* mu) const; + + //! Get the array of temperature second derivatives of the log activity coefficients + /*! + * This function is a virtual class, but it first appears in GibbsExcessVPSSTP + * class and derived classes from GibbsExcessVPSSTP. + * + * units = 1/Kelvin + * + * @param d2lnActCoeffdT2 Output vector of temperature 2nd derivatives of the + * log Activity Coefficients. length = m_kk + * + */ + virtual void getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const; + + //! Get the array of temperature derivatives of the log activity coefficients + /*! + * This function is a virtual class, but it first appears in GibbsExcessVPSSTP + * class and derived classes from GibbsExcessVPSSTP. + * + * units = 1/Kelvin + * + * @param dlnActCoeffdT Output vector of temperature derivatives of the + * log Activity Coefficients. length = m_kk + * + */ + virtual void getdlnActCoeffdT(doublereal *dlnActCoeffdT) const; + + + + //@} + /// @name Properties of the Standard State of the Species in the Solution + //@{ + + + + //@} + /// @name Thermodynamic Values for the Species Reference States + //@{ + + + /////////////////////////////////////////////////////// + // + // The methods below are not virtual, and should not + // be overloaded. + // + ////////////////////////////////////////////////////// + + /** + * @name Specific Properties + * @{ + */ + + + /** + * @name Setting the State + * + * These methods set all or part of the thermodynamic + * state. + * @{ + */ + + + + //@} + + /** + * @name Chemical Equilibrium + * Routines that implement the Chemical equilibrium capability + * for a single phase, based on the element-potential method. + * @{ + */ + + + + //@} + + + + /// The following methods are used in the process of constructing + /// the phase and setting its parameters from a specification in an + /// input file. They are not normally used in application programs. + /// To see how they are used, see files importCTML.cpp and + /// ThermoFactory.cpp. + + + /*! + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + + /** + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void initThermoXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Derivatives of Thermodynamic Variables needed for Applications + * @{ + */ + + //! Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + //! a line in parameter space or along a line in physical space + /*! + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + virtual void getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, doublereal *dlnActCoeffds) const; + + //! Get the array of log concentration-like derivatives of the + //! log activity coefficients - diagonal component + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the mole fraction. + * + * units = dimensionless + * + * @param dlnActCoeffdlnX_diag Output vector of the diagonal component of the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const; + + //! Get the array of derivatives of the log activity coefficients wrt mole numbers - diagonal only + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. mole fraction, + * molality, etc.) that represents the standard state. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of the diagonal entries for the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const; + + + //! Get the array of derivatives of the log activity coefficients with respect to the ln species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * log of a species mole number (with all other species mole numbers held constant) + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) ; + + //@} + + private: + + //! Process an XML node called "binaryNeutralSpeciesParameters" + /*! + * This node contains all of the parameters necessary to describe + * the Margules model for a particular binary interaction. + * This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + * + * @param xmlBinarySpecies Reference to the XML_Node named "binaryNeutralSpeciesParameters" + * containing the binary interaction + */ + void readXMLBinarySpecies(XML_Node &xmlBinarySpecies); + + //! Resize internal arrays within the object that depend upon the number + //! of binary Margules interaction terms + /*! + * @param num Number of binary Margules interaction terms + */ + void resizeNumInteractions(const int num); + + + //! Initialize lengths of local variables after all species have + //! been identified. + void initLengths(); + + //! Update the activity coefficients + /*! + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + */ + void s_update_lnActCoeff() const; + + //! Update the derivative of the log of the activity coefficients wrt T + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt temperature. + */ + void s_update_dlnActCoeff_dT() const; + + //! Update the derivative of the log of the activity coefficients + //! wrt log(mole fraction) + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the mole fractions. + */ + void s_update_dlnActCoeff_dlnX_diag() const; + + //! Update the derivative of the log of the activity coefficients + //! wrt log(moles) - diagonal only + /*! + * This function will be called to update the internally storred diagonal entries for the + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the moles. + */ + void s_update_dlnActCoeff_dlnN_diag() const; + + //! Update the derivative of the log of the activity coefficients wrt log(moles_m) + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the mole number of species + */ + void s_update_dlnActCoeff_dlnN() const; + + + private: + //! Error function + /*! + * Print an error string and exit + * + * @param msg Message to be printed + */ + doublereal err(std::string msg) const; + + protected: + + + //! number of binary interaction expressions + int numBinaryInteractions_; + + //! Enthalpy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_HE_b_ij; + + //! Enthalpy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_HE_c_ij; + + //! Enthalpy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_HE_d_ij; + + //! Entropy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_SE_b_ij; + + //! Entropy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_SE_c_ij; + + //! Entropy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_SE_d_ij; + + //! Enthalpy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VHE_b_ij; + + //! Enthalpy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VHE_c_ij; + + //! Enthalpy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VHE_d_ij; + + //! Entropy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VSE_b_ij; + + //! Entropy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VSE_c_ij; + + //! Entropy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VSE_d_ij; + + + + //! vector of species indices representing species A in the interaction + /*! + * Each Margules excess Gibbs free energy term involves two species, A and B. + * This vector identifies species A. + */ + vector_int m_pSpecies_A_ij; + + //! vector of species indices representing species B in the interaction + /*! + * Each Margules excess Gibbs free energy term involves two species, A and B. + * This vector identifies species B. + */ + vector_int m_pSpecies_B_ij; + + //! form of the Margules interaction expression + /*! + * Currently there is only one form. + */ + int formMargules_; + + //! form of the temperatuer dependence of the Margules interaction expression + /*! + * Currently there is only one form -> constant wrt temperature. + */ + int formTempModel_; + + + }; + + + +} + +#endif + + + + + diff --git a/Cantera/src/thermo/MixtureFugacityTP.cpp b/Cantera/src/thermo/MixtureFugacityTP.cpp new file mode 100644 index 000000000..901daa9c9 --- /dev/null +++ b/Cantera/src/thermo/MixtureFugacityTP.cpp @@ -0,0 +1,1367 @@ +/** + * @file MixtureFugacityTP.cpp + * Methods file for a derived class of ThermoPhase that handles + * non-ideal mixtures based on the fugacity models (see \ref thermoprops and + * class \link Cantera::MixtureFugacityTP MixtureFugacityTP\endlink). + * + */ +/* + * 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. + */ +/* + * $Author: hkmoffa $ + * $Date: 2010-01-17 12:08:00 -0700 (Sun, 17 Jan 2010) $ + * $Revision: 388 $ + */ + +// turn off warnings under Windows +#ifdef WIN32 +#pragma warning(disable:4786) +#pragma warning(disable:4503) +#endif + +#include "MixtureFugacityTP.h" +#include "VPSSMgr.h" +#include "PDSS.h" + + +#ifndef MIN +# define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) +#endif +using namespace std; + +namespace Cantera { + + + + //==================================================================================================================== + /* + * Default constructor + */ + MixtureFugacityTP::MixtureFugacityTP() : + ThermoPhase(), + m_Pcurrent(-1.0), + moleFractions_(0), + iState_(FLUID_GAS), + forcedState_(FLUID_UNDEFINED), + m_Tlast_ref(-1.0), + m_logc0(0.0), + m_h0_RT(0), + m_cp0_R(0), + m_g0_RT(0), + m_s0_R(0) + { + } + //==================================================================================================================== + /* + * Copy Constructor: + * + * Note this stuff will not work until the underlying phase + * has a working copy constructor. + * + * The copy constructor just calls the assignment operator + * to do the heavy lifting. + */ + MixtureFugacityTP::MixtureFugacityTP(const MixtureFugacityTP &b) : + ThermoPhase(), + m_Pcurrent(-1.0), + moleFractions_(0), + iState_(FLUID_GAS), + forcedState_(FLUID_UNDEFINED), + m_Tlast_ref(-1.0), + m_logc0(0.0), + m_h0_RT(0), + m_cp0_R(0), + m_g0_RT(0), + m_s0_R(0) + { + MixtureFugacityTP::operator=(b); + } + //==================================================================================================================== + /* + * operator=() + * + * Note this stuff will not work until the underlying phase + * has a working assignment operator + */ + MixtureFugacityTP& + MixtureFugacityTP::operator=(const MixtureFugacityTP &b) { + if (&b != this) { + /* + * Mostly, this is a passthrough to the underlying + * assignment operator for the ThermoPhase parent object. + */ + ThermoPhase::operator=(b); + /* + * However, we have to handle data that we own. + */ + m_Pcurrent = b.m_Pcurrent; + moleFractions_ = b.moleFractions_; + iState_ = b.iState_; + forcedState_ = b.forcedState_; + m_Tlast_ref = b.m_Tlast_ref; + m_logc0 = b.m_logc0; + m_h0_RT = b.m_h0_RT; + m_cp0_R = b.m_cp0_R; + m_g0_RT = b.m_g0_RT; + m_s0_R = b.m_s0_R; + /* + * The VPSSMgr object contains shallow pointers. Whenever you have shallow + * pointers, they have to be fixed up to point to the correct objects refering + * back to this ThermoPhase's properties. + */ + //m_VPSS_ptr->initAllPtrs(this, m_spthermo); + /* + * The PDSS objects contains shallow pointers. Whenever you have shallow + * pointers, they have to be fixed up to point to the correct objects refering + * back to this ThermoPhase's properties. This function also sets m_VPSS_ptr + * so it occurs after m_VPSS_ptr is set. + */ + + /* + * Ok, the VPSSMgr object is ready for business. + * We need to resync the temperature and the pressure of the new standard states + * with what is storred in this object. + */ + // m_VPSS_ptr->setState_TP(m_Tlast_ss, m_Plast_ss); + } + return *this; + } + //==================================================================================================================== + /* + * ~MixtureFugacityTP(): (virtual) + * + */ + MixtureFugacityTP::~MixtureFugacityTP() { + + } + + /* + * Duplication function. + * This calls the copy constructor for this object. + */ + ThermoPhase* MixtureFugacityTP::duplMyselfAsThermoPhase() const { + MixtureFugacityTP* vptp = new MixtureFugacityTP(*this); + return (ThermoPhase *) vptp; + } + //==================================================================================================================== + // This method returns the convention used in specification + // of the standard state, of which there are currently two, + // temperature based, and variable pressure based. + /* + * Currently, there are two standard state conventions: + * - Temperature-based activities + * cSS_CONVENTION_TEMPERATURE 0 + * - default + * + * - Variable Pressure and Temperature -based activities + * cSS_CONVENTION_VPSS 1 + */ + int MixtureFugacityTP::standardStateConvention() const { + return cSS_CONVENTION_TEMPERATURE; + } + //==================================================================================================================== + // Set the solution branch to force the ThermoPhase to exist on one branch or another + /* + * @param solnBranch Branch that the solution is restricted to. + * the value -1 means gas. The value -2 means unrestricted. + * Values of zero or greater refer to species dominated condensed phases. + */ + void MixtureFugacityTP::setForcedSolutionBranch(int solnBranch) { + forcedState_ = solnBranch; + } + //==================================================================================================================== + // Report the solution branch which the solution is restricted to + /* + * @return Branch that the solution is restricted to. + * the value -1 means gas. The value -2 means unrestricted. + * Values of zero or greater refer to species dominated condensed phases. + */ + int MixtureFugacityTP::forcedSolutionBranch() const { + return forcedState_; + } + //==================================================================================================================== + // Report the solution branch which the solution is actually on + /* + * @return Branch that the solution is restricted to. + * the value -1 means gas. The value -2 means superfluid.. + * Values of zero or greater refer to species dominated condensed phases. + */ + int MixtureFugacityTP::reportSolnBranchActual() const { + return iState_; + } + //==================================================================================================================== + + /* + * ------------Molar Thermodynamic Properties ------------------------- + */ + //==================================================================================================================== + + doublereal MixtureFugacityTP::err(std::string msg) const { + throw CanteraError("MixtureFugacityTP","Base class method " + +msg+" called. Equation of state type: "+int2str(eosType())); + return 0; + } + //==================================================================================================================== + /* + * ---- Partial Molar Properties of the Solution ----------------- + */ + //==================================================================================================================== + /* + * Get the array of non-dimensional species chemical potentials + * These are partial molar Gibbs free energies. + * \f$ \mu_k / \hat R T \f$. + * Units: unitless + * + * We close the loop on this function, here, calling + * getChemPotentials() and then dividing by RT. + */ + void MixtureFugacityTP::getChemPotentials_RT(doublereal* muRT) const{ + getChemPotentials(muRT); + doublereal invRT = 1.0 / _RT(); + for (int k = 0; k < m_kk; k++) { + muRT[k] *= invRT; + } + } + //==================================================================================================================== + /* + * ----- Thermodynamic Values for the Species Standard States States ---- + */ + void MixtureFugacityTP::getStandardChemPotentials(doublereal* g) const { + _updateReferenceStateThermo(); + copy(m_g0_RT.begin(), m_g0_RT.end(), g); + doublereal RT = _RT(); + double tmp = log (pressure() /m_spthermo->refPressure()); + for (int k = 0; k < m_kk; k++) { + g[k] = RT * (g[k] + tmp); + } + } + //==================================================================================================================== + void MixtureFugacityTP::getEnthalpy_RT(doublereal* hrt) const { + getEnthalpy_RT_ref(hrt); + } + //================================================================================================ +#ifdef H298MODIFY_CAPABILITY + // Modify the value of the 298 K Heat of Formation of one species in the phase (J kmol-1) + /* + * The 298K heat of formation is defined as the enthalpy change to create the standard state + * of the species from its constituent elements in their standard states at 298 K and 1 bar. + * + * @param k Species k + * @param Hf298New Specify the new value of the Heat of Formation at 298K and 1 bar + */ + void MixtureFugacityTP::modifyOneHf298SS(const int k, const doublereal Hf298New) { + m_spthermo->modifyOneHf298(k, Hf298New); + m_Tlast_ref += 0.0001234; + } +#endif + //==================================================================================================================== + /* + * Get the array of nondimensional entropy functions for the + * standard state species + * at the current T and P of the solution. + */ + void MixtureFugacityTP::getEntropy_R(doublereal* sr) const { + _updateReferenceStateThermo(); + copy(m_s0_R.begin(), m_s0_R.end(), sr); + double tmp = log (pressure() /m_spthermo->refPressure()); + for (int k = 0; k < m_kk; k++) { + sr[k] -= tmp; + } + } + //==================================================================================================================== + /* + * Get the nondimensional gibbs function for the species + * standard states at the current T and P of the solution. + */ + void MixtureFugacityTP::getGibbs_RT(doublereal* grt) const { + _updateReferenceStateThermo(); + copy(m_g0_RT.begin(), m_g0_RT.end(), grt); + double tmp = log (pressure() /m_spthermo->refPressure()); + for (int k = 0; k < m_kk; k++) { + grt[k] += tmp; + } + } + //==================================================================================================================== + /* + * get the pure Gibbs free energies of each species assuming + * it is in its standard state. This is the same as + * getStandardChemPotentials(). + */ + void MixtureFugacityTP::getPureGibbs(doublereal* g) const { + _updateReferenceStateThermo(); + scale(m_g0_RT.begin(), m_g0_RT.end(), g, _RT()); + double tmp = log (pressure() /m_spthermo->refPressure()); + tmp *= _RT(); + for (int k = 0; k < m_kk; k++) { + g[k] += tmp; + } + } + //==================================================================================================================== + /* + * Returns the vector of nondimensional + * internal Energies of the standard state at the current temperature + * and pressure of the solution for each species. + */ + void MixtureFugacityTP::getIntEnergy_RT(doublereal* urt) const { + _updateReferenceStateThermo(); + copy(m_h0_RT.begin(), m_h0_RT.end(), urt); + doublereal p = pressure(); + doublereal tmp = p / _RT(); + doublereal v0 = _RT() / p; + for (int i = 0; i < m_kk; i++) { + urt[i] -= tmp * v0; + } + } + //==================================================================================================================== + /* + * Get the nondimensional heat capacity at constant pressure + * function for the species + * standard states at the current T and P of the solution. + */ + void MixtureFugacityTP::getCp_R(doublereal* cpr) const { + _updateReferenceStateThermo(); + copy(m_cp0_R.begin(), m_cp0_R.end(), cpr); + } + //==================================================================================================================== + /* + * Get the molar volumes of the species standard states at the current + * T and P of the solution. + * units = m^3 / kmol + * + * @param vol Output vector containing the standard state volumes. + * Length: m_kk. + */ + void MixtureFugacityTP::getStandardVolumes(doublereal *vol) const { + _updateReferenceStateThermo(); + doublereal v0 = _RT() / pressure(); + for (int i = 0; i < m_kk; i++) { + vol[i]= v0; + } + } + //==================================================================================================================== + /* + * ----- Thermodynamic Values for the Species Reference States ---- + */ + + /* + * Returns the vector of nondimensional enthalpies of the + * reference state at the current temperature of the solution and + * the reference pressure for the species. + */ + void MixtureFugacityTP::getEnthalpy_RT_ref(doublereal *hrt) const { + _updateReferenceStateThermo(); + copy(m_h0_RT.begin(), m_h0_RT.end(), hrt); + } + //==================================================================================================================== + /* + * Returns the vector of nondimensional + * enthalpies of the reference state at the current temperature + * of the solution and the reference pressure for the species. + */ + void MixtureFugacityTP::getGibbs_RT_ref(doublereal *grt) const { + _updateReferenceStateThermo(); + copy(m_g0_RT.begin(), m_g0_RT.end(), grt); + } + //==================================================================================================================== + /* + * Returns the vector of the + * gibbs function of the reference state at the current temperature + * of the solution and the reference pressure for the species. + * units = J/kmol + * + * This is filled in here so that derived classes don't have to + * take care of it. + */ + void MixtureFugacityTP::getGibbs_ref(doublereal *g) const { + const array_fp& gibbsrt = gibbs_RT_ref(); + scale(gibbsrt.begin(), gibbsrt.end(), g, _RT()); + } + //==================================================================================================================== + const vector_fp & MixtureFugacityTP::gibbs_RT_ref() const { + _updateReferenceStateThermo(); + return m_g0_RT; + } + //==================================================================================================================== + /* + * Returns the vector of nondimensional + * entropies of the reference state at the current temperature + * of the solution and the reference pressure for the species. + */ + void MixtureFugacityTP::getEntropy_R_ref(doublereal *er) const { + _updateReferenceStateThermo(); + copy(m_s0_R.begin(), m_s0_R.end(), er); + return; + } + //==================================================================================================================== + /* + * Returns the vector of nondimensional + * constant pressure heat capacities of the reference state + * at the current temperature of the solution + * and reference pressure for the species. + */ + void MixtureFugacityTP::getCp_R_ref(doublereal *cpr) const { + _updateReferenceStateThermo(); + copy(m_cp0_R.begin(), m_cp0_R.end(), cpr); + } + //==================================================================================================================== + /* + * Get the molar volumes of the species reference states at the current + * T and reference pressure of the solution. + * + * units = m^3 / kmol + */ + void MixtureFugacityTP::getStandardVolumes_ref(doublereal *vol) const { + _updateReferenceStateThermo(); + double pp = refPressure(); + doublereal v0 = _RT() / pp; + for (int i = 0; i < m_kk; i++) { + vol[i]= v0; + } + } + //==================================================================================================================== + // Set the initial state of the phase to the conditions specified in the state XML element. + /* + * + * This method sets the temperature, pressure, and mole fraction vector to a set default value. + * We modify the default behavior here so that TP is evaluated at the same time. + * + * @param state AN XML_Node object corresponding to + * the "state" entry for this phase in the + * input file. + */ + void MixtureFugacityTP::setStateFromXML(const XML_Node& state) { + int doTP = 0; + string comp = ctml::getChildValue(state,"moleFractions"); + if (comp != "") { + // not overloaded in current object -> phase state is not calculated. + setMoleFractionsByName(comp); + doTP = 1; + } else { + comp = ctml::getChildValue(state,"massFractions"); + if (comp != "") { + // not overloaded in current object -> phase state is not calculated. + setMassFractionsByName(comp); + doTP = 1; + } + } + double t = temperature(); + if (state.hasChild("temperature")) { + t = ctml::getFloat(state, "temperature", "temperature"); + doTP = 1; + } + if (state.hasChild("pressure")) { + double p = ctml::getFloat(state, "pressure", "pressure"); + setState_TP(t, p); + } else if (state.hasChild("density")) { + double rho = ctml::getFloat(state, "density", "density"); + setState_TR(t, rho); + } else if (doTP) { + double rho = State::density(); + setState_TR(t, rho); + } + } + //==================================================================================================================== + /* + * Perform initializations after all species have been + * added. + */ + void MixtureFugacityTP::initThermo() { + initLengths(); + ThermoPhase::initThermo(); + } + //==================================================================================================================== + /* + * Initialize the internal lengths. + * (this is not a virtual function) + */ + void MixtureFugacityTP::initLengths() { + m_kk = nSpecies(); + moleFractions_.resize(m_kk, 0.0); + moleFractions_[0] = 1.0; + m_h0_RT.resize(m_kk, 0.0); + m_cp0_R.resize(m_kk, 0.0); + m_g0_RT.resize(m_kk, 0.0); + m_s0_R.resize(m_kk, 0.0); + } + //==================================================================================================================== + void MixtureFugacityTP::setTemperature(const doublereal temp) { + _updateReferenceStateThermo(); + setState_TR(temperature(), density()); + } + //==================================================================================================================== + void MixtureFugacityTP::setPressure(doublereal p) { + setState_TP(temperature(), p); + // double chemPot[5], mf[5]; + // getMoleFractions(mf); + // getChemPotentials(chemPot); + // for (int i = 0; i < m_kk; i++) { + // printf(" MixFug:setPres: mu(%d = %g) = %18.8g\n", i, mf[i], chemPot[i]); + // } + } + //==================================================================================================================== + void MixtureFugacityTP::setMassFractions(const doublereal* const y) { + State::setMassFractions(y); + getMoleFractions(DATA_PTR(moleFractions_)); + } + //==================================================================================================================== + void MixtureFugacityTP::setMassFractions_NoNorm(const doublereal* const y) { + State::setMassFractions_NoNorm(y); + getMoleFractions(DATA_PTR(moleFractions_)); + } + //==================================================================================================================== + void MixtureFugacityTP::setMoleFractions(const doublereal* const x) { + State::setMoleFractions(x); + getMoleFractions(DATA_PTR(moleFractions_)); + } + //==================================================================================================================== + void MixtureFugacityTP::setMoleFractions_NoNorm(const doublereal* const x) { + State::setMoleFractions_NoNorm(x); + getMoleFractions(DATA_PTR(moleFractions_)); + } + //==================================================================================================================== + void MixtureFugacityTP::setConcentrations(const doublereal* const c) { + State::setConcentrations(c); + getMoleFractions(DATA_PTR(moleFractions_)); + } + //==================================================================================================================== + void MixtureFugacityTP::setMoleFractions_NoState(const doublereal* const x) { + State::setMoleFractions(x); + getMoleFractions(DATA_PTR(moleFractions_)); + updateMixingExpressions(); + } + //==================================================================================================================== + void MixtureFugacityTP::calcDensity() { + err("MixtureFugacityTP::calcDensity() called, but EOS for phase is not known"); + } + //==================================================================================================================== + + void MixtureFugacityTP::setState_TP(doublereal t, doublereal pres) { + /* + * A pretty tricky algorithm is needed here, due to problems involving + * standard states of real fluids. For those cases you need + * to combine the T and P specification for the standard state, or else + * you may venture into the forbidden zone, especially when nearing the + * triple point. + * Therefore, we need to do the standard state thermo calc with the + * (t, pres) combo. + */ + getMoleFractions(DATA_PTR(moleFractions_)); + + + State::setTemperature(t); + _updateReferenceStateThermo(); + // Depends on the mole fractions and the temperature + updateMixingExpressions(); + // setPressure(pres); + m_Pcurrent = pres; + // double mmw = meanMolecularWeight(); + + if (forcedState_ == FLUID_UNDEFINED) { + double rhoNow = State::density(); + double rho = densityCalc(t, pres, iState_, rhoNow); + if (rho > 0.0) { + State::setDensity(rho); + m_Pcurrent = pres; + iState_ = phaseState(true); + } else { + if (rho < -1.5) { + rho = densityCalc(t, pres, FLUID_UNDEFINED , rhoNow); + if (rho > 0.0) { + State::setDensity(rho); + m_Pcurrent = pres; + iState_ = phaseState(true); + } else { + throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho"); + } + } else { + throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho"); + } + } + + + + } else if (forcedState_ == FLUID_GAS) { + // Normal density calculation + if (iState_ < FLUID_LIQUID_0) { + double rhoNow = State::density(); + double rho = densityCalc(t, pres, iState_, rhoNow); + if (rho > 0.0) { + State::setDensity(rho); + m_Pcurrent = pres; + iState_ = phaseState(true); + if (iState_ >= FLUID_LIQUID_0) { + throw CanteraError("MixtureFugacityTP::setState_TP()", "wrong state"); + } + } else { + throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho"); + } + + } + + + } else if (forcedState_ > FLUID_LIQUID_0) { + if (iState_ >= FLUID_LIQUID_0) { + double rhoNow = State::density(); + double rho = densityCalc(t, pres, iState_, rhoNow); + if (rho > 0.0) { + State::setDensity(rho); + m_Pcurrent = pres; + iState_ = phaseState(true); + if (iState_ == FLUID_GAS) { + throw CanteraError("MixtureFugacityTP::setState_TP()", "wrong state"); + } + } else { + throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho"); + } + + } + } + + + + //setTemperature(t); + //setPressure(pres); + //calcDensity(); + } + //==================================================================================================================== + // Set the internally storred temperature (K) and density (kg/m^3) + /* + * This overrides the default behavior. In addition to just storring the state in the object, we need to do + * an equation of state calculation and figure out what phase state we are in. + * + * @param t Temperature in kelvin + * @param rho Density (kg/m^3) + */ + void MixtureFugacityTP::setState_TR(doublereal T, doublereal rho) { + getMoleFractions(DATA_PTR(moleFractions_)); + State::setTemperature(T); + _updateReferenceStateThermo(); + State::setDensity(rho); + doublereal mv = molarVolume(); + // depends on mole fraction and temperature + updateMixingExpressions(); + + m_Pcurrent = pressureCalc(T, mv); + iState_ = phaseState(true); + + // printf("setState_TR: state at T = %g, rho = %g, mv = %g, P = %20.13g, iState = %d\n", T, rho, mv, m_Pcurrent, iState_); + } + + //==================================================================================================================== + // Set the temperature (K), pressure (Pa), and mole fractions. + /* + * Note, the mole fractions are set first before the pressure is set. + * Setting the pressure may involve the solution of a nonlinear equation. + * + * @param t Temperature (K) + * @param p Pressure (Pa) + * @param x Vector of mole fractions. + * Length is equal to m_kk. + */ + void MixtureFugacityTP::setState_TPX(doublereal t, doublereal p, const doublereal* x) { + setMoleFractions_NoState(x); + setState_TP(t,p); + } + //==================================================================================================================== + /* + * Import and initialize a ThermoPhase object + * + * param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + * + * This routine initializes the lengths in the current object and + * then calls the parent routine. + */ + void MixtureFugacityTP::initThermoXML(XML_Node& phaseNode, std::string id) { + MixtureFugacityTP::initLengths(); + + //m_VPSS_ptr->initThermo(); + + // m_VPSS_ptr->initThermoXML(phaseNode, id); + ThermoPhase::initThermoXML(phaseNode, id); + } + //==================================================================================================================== + doublereal MixtureFugacityTP::z() const { + doublereal p = pressure(); + doublereal rho = density(); + doublereal mmw = meanMolecularWeight(); + doublereal molarV = mmw / rho; + doublereal rt = _RT(); + doublereal zz = p * molarV / rt; + return zz; + } + //==================================================================================================================== + doublereal MixtureFugacityTP::sresid() const { + throw CanteraError("MixtureFugacityTP::sresid()", "Base Class: not implemented"); + return 0.0; + } + //==================================================================================================================== + doublereal MixtureFugacityTP::hresid() const { + throw CanteraError("MixtureFugacityTP::hresid()", "Base Class: not implemented"); + return 0.0; + } + //==================================================================================================================== + doublereal MixtureFugacityTP::psatEst(doublereal TKelvin) const { + doublereal tcrit = critTemperature(); + doublereal pcrit = critPressure(); + doublereal tt = tcrit/TKelvin; + if (tt < 1.0) { + return pcrit; + } + doublereal lpr = -0.8734*tt*tt - 3.4522*tt + 4.2918; + return pcrit*exp(lpr); + } + //==================================================================================================================== + doublereal MixtureFugacityTP::liquidVolEst(doublereal TKelvin, doublereal &pres) const { + throw CanteraError("MixtureFugacityTP::liquidVolEst()", "unimplemented"); + return 0.0; + } + //==================================================================================================================== + /* + * Calculates the density given the temperature and the pressure, + * and a guess at the density. Note, below T_c, this is a + * multivalued function. This function assumes that the phase is on one side of the vapor dome + * or the other. It does not allow for crosses of the vapor dome. + * + * parameters: + * temperature: Kelvin + * pressure : Pressure in Pascals (Newton/m**2) + * phase : guessed phase of water + * : -1: no guessed phase + * rhoguess : guessed density of the water + * + * -1.0 no guessed density + * + * If a problem is encountered, a negative 1 is returned. + * + * @TODO make this a const function + */ + doublereal MixtureFugacityTP::densityCalc(doublereal TKelvin, doublereal presPa, + int phase, doublereal rhoguess) { + double tcrit = critTemperature(); + doublereal mmw = meanMolecularWeight(); + // double pcrit = critPressure(); + // doublereal deltaGuess = 0.0; + if (rhoguess == -1.0) { + if (phase != -1) { + if (TKelvin > tcrit) { + rhoguess = presPa * mmw / (GasConstant * TKelvin); + } else { + if (phase == FLUID_GAS || phase == FLUID_SUPERCRIT) { + rhoguess = presPa * mmw / (GasConstant * TKelvin); + } else if (phase >= FLUID_LIQUID_0) { + double lqvol = liquidVolEst(TKelvin, presPa); + rhoguess = mmw / lqvol; + } + } + } else { + /* + * Assume the Gas phase initial guess, if nothing is + * specified to the routine + */ + rhoguess = presPa * mmw / (GasConstant * TKelvin); + } + + } + + double molarVolBase = mmw / rhoguess; + double molarVolLast = molarVolBase; + double vc = mmw / critDensity(); + /* + * molar volume of the spinodal at the current temperature and mole fractions. this will + * be updated as we go. + */ + double molarVolSpinodal = vc; + doublereal pcheck = 1.0E-30 + 1.0E-8 * presPa; + doublereal presBase, dpdVBase, delMV; + bool conv = false; + /* + * We start on one side of the vc and stick with that side + */ + bool gasSide = molarVolBase > vc; + if (gasSide) { + molarVolLast = (GasConstant * TKelvin)/presPa; + } else { + molarVolLast = liquidVolEst(TKelvin, presPa); + } + + /* + * OK, now we do a small solve to calculate the molar volume given the T,P value. + * The algorithm is taken from dfind() + */ + for (int n = 0; n < 200; n++) { + + /* + * Calculate the predicted reduced pressure, pred0, based on the + * current tau and dd. + */ + + /* + * Calculate the derivative of the predicted pressure + * wrt the molar volume. + * This routine also returns the pressure, presBase + */ + dpdVBase = dpdVCalc(TKelvin, molarVolBase, presBase); + + /* + * If dpdV is positve, then we are in the middle of the + * 2 phase region and beyond the spinodal stability curve. We need to adjust + * the initial guess outwards and start a new iteration. + */ + if (dpdVBase >= 0.0) { + if (TKelvin > tcrit) { + throw CanteraError("", "confused"); + } + /* + * TODO Spawn a calculation for the value of the spinodal point that is + * very accurate. Answer the question as to wethera solution is + * possible on the current side of the vapor dome. + */ + if (gasSide) { + if (molarVolBase >= vc) { + molarVolSpinodal = molarVolBase; + molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal); + } else { + molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal); + } + } else { + if (molarVolBase <= vc) { + molarVolSpinodal = molarVolBase; + molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal); + } else { + molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal); + } + } + continue; + } + + /* + * Check for convergence + */ + if (fabs(presBase-presPa) < pcheck) { + conv = true; + break; + } + + /* + * Dampen and crop the update + */ + doublereal dpdV = dpdVBase; + if (n < 10) { + dpdV = dpdVBase * 1.5; + } + // if (dpdV > -0.001) dpdV = -0.001; + + /* + * Formulate the update to the molar volume by + * Newton's method. Then, crop it to a max value + * of 0.1 times the current volume + */ + delMV = - (presBase - presPa) / dpdV; + if (!gasSide || delMV < 0.0) { + if (fabs(delMV) > 0.2 * molarVolBase) { + delMV = delMV / fabs(delMV) * 0.2 * molarVolBase; + } + } + /* + * Only go 1/10 the way towards the spinodal at any one time. + */ + if (TKelvin < tcrit) { + if (gasSide) { + if (delMV < 0.0) { + if (-delMV > 0.5 * (molarVolBase - molarVolSpinodal)) { + delMV = - 0.5 * (molarVolBase - molarVolSpinodal); + } + } + } else { + if (delMV > 0.0) { + if (delMV > 0.5 * (molarVolSpinodal - molarVolBase)) { + delMV = 0.5 * (molarVolSpinodal - molarVolBase); + } + } + } + } + /* + * updated the molar volume value + */ + molarVolLast = molarVolBase; + molarVolBase += delMV; + + + if (fabs(delMV/molarVolBase) < 1.0E-14) { + conv = true; + break; + } + + /* + * Check for negative molar volumes + */ + if (molarVolBase <= 0.0) { + molarVolBase = MIN(1.0E-30, fabs(delMV*1.0E-4)); + } + + } + + + /* + * Check for convergence, and return 0.0 if it wasn't achieved. + */ + double densBase = 0.0; + if (! conv) { + molarVolBase = 0.0; + throw CanteraError("MixtureFugacityTP::densityCalc()", "Process didnot converge"); + } else { + densBase = mmw / molarVolBase; + } + return densBase; + } + //==================================================================================================================== + void MixtureFugacityTP::updateMixingExpressions() { + + } + //==================================================================================================================== + MixtureFugacityTP::spinodalFunc::spinodalFunc(MixtureFugacityTP *tp) : + ResidEval(), + m_tp(tp) + { + } + //==================================================================================================================== + int MixtureFugacityTP::spinodalFunc::evalSS(const doublereal t, const doublereal * const y, + doublereal * const r) { + int status = 0; + doublereal molarVol = y[0]; + doublereal tt = m_tp->temperature(); + doublereal pp; + doublereal val = m_tp->dpdVCalc(tt, molarVol, pp); + r[0] = val; + return status; + } + //==================================================================================================================== + // Utility routine in the calculation of the saturation pressure + /* + * Private routine + * + * @param TKelvin temperature (kelvin) + * @param pres pressure (Pascal) + * @param densLiq Output density of liquid + * @param densGas output density of gas + * @param delGRT output delGRT + * + * @return Returns zero if both the gas and the liquid states are found for a given pressure. + + */ + int MixtureFugacityTP::corr0(doublereal TKelvin, doublereal pres, doublereal &densLiqGuess, + doublereal &densGasGuess, doublereal &liqGRT, doublereal &gasGRT) { + + int retn = 0; + doublereal densLiq = densityCalc(TKelvin, pres, FLUID_LIQUID_0, densLiqGuess); + if (densLiq <= 0.0) { + // throw Cantera::CanteraError("MixtureFugacityTP::corr0", + // "Error occurred trying to find liquid density at (T,P) = " + // + Cantera::fp2str(TKelvin) + " " + Cantera::fp2str(pres)); + retn = -1; + } else { + densLiqGuess = densLiq; + setState_TR(TKelvin, densLiq); + liqGRT = gibbs_mole() / _RT(); + } + + doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, densGasGuess); + if (densGas <= 0.0) { + //throw Cantera::CanteraError("MixtureFugacityTP::corr0", + // "Error occurred trying to find gas density at (T,P) = " + // + Cantera::fp2str(TKelvin) + " " + Cantera::fp2str(pres)); + if (retn == -1) { + throw Cantera::CanteraError("MixtureFugacityTP::corr0", + "Error occurred trying to find gas density at (T,P) = " + + Cantera::fp2str(TKelvin) + " " + Cantera::fp2str(pres)); + } + retn = -2; + } else { + densGasGuess = densGas; + setState_TR(TKelvin, densGas); + gasGRT = gibbs_mole() / _RT(); + } + // delGRT = gibbsLiqRT - gibbsGasRT; + return retn; + } + //==================================================================================================================== + // Returns the Phase State flag for the current state of the object + /* + * @param checkState If true, this function does a complete check to see where + * in paramters space we are + * + * There are three values: + * WATER_GAS below the critical temperature but below the critical density + * WATER_LIQUID below the critical temperature but above the critical density + * WATER_SUPERCRIT above the critical temperature + */ + int MixtureFugacityTP::phaseState(bool checkState) const { + int state = iState_; + if (checkState) { + double t = temperature(); + double tcrit = critTemperature(); + double rhocrit = critDensity(); + if (t >= tcrit) { + state = FLUID_SUPERCRIT; + return state; + } + double tmid = tcrit - 100.; + if (tmid < 0.0) { + tmid = tcrit / 2.0; + } + double pp = psatEst(tmid); + double mmw = meanMolecularWeight(); + double molVolLiqTmid = liquidVolEst(tmid, pp); + double molVolGasTmid = GasConstant * tmid / (pp); + double densLiqTmid = mmw / molVolLiqTmid; + double densGasTmid = mmw / molVolGasTmid; + double densMidTmid = 0.5 * (densLiqTmid + densGasTmid); + doublereal rhoMid = rhocrit + (t - tcrit) * (rhocrit - densMidTmid) / (tcrit - tmid); + + double rho = density(); + int iStateGuess = FLUID_LIQUID_0; + if (rho < rhoMid) { + iStateGuess = FLUID_GAS; + } + double molarVol = mmw / rho; + double presCalc; + + double dpdv = dpdVCalc(t, molarVol, presCalc); + if (dpdv < 0.0) { + state = iStateGuess; + } else { + state = FLUID_UNSTABLE; + } + + } + return state; + } + //==================================================================================================================== + // Return the value of the density at the liquid spinodal point (on the liquid side) + // for the current temperature. + /* + * @return returns the density with units of kg m-3 + */ + doublereal MixtureFugacityTP::densSpinodalLiquid() const { + throw CanteraError("", "unimplmented"); + return 0.0; + } + //==================================================================================================================== + // Return the value of the density at the gas spinodal point (on the gas side) + // for the current temperature. + /* + * @return returns the density with units of kg m-3 + */ + doublereal MixtureFugacityTP::densSpinodalGas() const { + throw CanteraError("", "unimplmented"); + return 0.0; + } + //==================================================================================================================== + // Calculate the saturation pressure at the current mixture content for the given temperature + /* + * This is a non-const routine that is public. + * + * The algorithm for this routine has undergone quite a bit of work. It probably needs more work. + * However, it seems now to be fairly robust. + * The key requirement is to find an initial pressure where both the liquid and the gas exist. This + * is not as easy as it sounds, and it gets exceedingly hard as the critical temperature is approached + * from below. + * Once we have this initial state, then we seek to equilibrate the gibbs free energies of the + * gas and liquid and use the formula + * + * dp = VdG + * + * to create an update condition for deltaP using + * + * - (Gliq - Ggas) = (Vliq - Vgas) (deltaP) + * + * + * + * @param TKelvin (input) Temperature (Kelvin) + * @param molarVolGas (return) Molar volume of the gas + * @param molarVolLiquid (return) Molar volume of the liquid + * + * @return Returns the saturation pressure at the given temperature + * + * @TODO Suggestions for the future would be to switch it to an algorithm that uses the gas molar volume + * and the liquid molar volumes as the fundamental unknowns. + * + */ + doublereal MixtureFugacityTP::calculatePsat(doublereal TKelvin, doublereal &molarVolGas, + doublereal &molarVolLiquid) { + // we need this because this is a non-const routine that is public + setTemperature(TKelvin); + double tcrit = critTemperature(); + double RhoLiquid, RhoGas; + double RhoLiquidGood, RhoGasGood; + double densSave = density(); + double tempSave = temperature(); + double pres; + doublereal mw = meanMolecularWeight(); + bool conv = false; + if (TKelvin < tcrit) { + + pres = psatEst(TKelvin); + // trial value = Psat from correlation + int i; + doublereal volLiquid = liquidVolEst(TKelvin, pres); + RhoLiquidGood = mw / volLiquid; + RhoGasGood = pres * mw / (GasConstant * TKelvin); + doublereal delGRT, liqGRT, gasGRT; + int stab; + doublereal presLast = pres; + + +#ifdef DDDD + double pVec[100]; + int n = 0; + for (int i = 0; i < 50; i++) { + pVec[n++] = 3.40E6 + 0.01E5 * i; + } + + for (int i = 0; i < 50; i++) { + stab = corr0(TKelvin, pVec[i], RhoLiquid, RhoGas, liqGRT, gasGRT); + printf ("p = %g, T = %g, stab = %d, Rl = %g Rg = %g, Gl = %g, Gg = %g\n", + pVec[i], TKelvin, stab, RhoLiquid, RhoGas,liqGRT, gasGRT); + } +#endif + + /* + * First part of the calculation involves finding a pressure at which the + * gas and the liquid state coexists. + */ + doublereal presLiquid; + doublereal presGas; + doublereal presBase = pres; + bool foundLiquid = false; + bool foundGas = false; + + doublereal densLiquid = densityCalc(TKelvin, presBase, FLUID_LIQUID_0, RhoLiquidGood); + if (densLiquid > 0.0) { + foundLiquid = true; + presLiquid = pres; + RhoLiquidGood = densLiquid; + } + if (!foundLiquid) { + for (int i = 0; i < 50; i++) { + pres = 1.1 * pres; + densLiquid = densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood); + if (densLiquid > 0.0) { + foundLiquid = true; + presLiquid = pres; + RhoLiquidGood = densLiquid; + break; + } + } + } + + pres = presBase; + doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood); + if (densGas <= 0.0) { + foundGas = false; + } else { + foundGas = true; + presGas = pres; + RhoGasGood = densGas; + } + if (!foundGas) { + for (int i = 0; i < 50; i++) { + pres = 0.9 * pres; + densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood); + if (densGas > 0.0) { + foundGas = true; + presGas = pres; + RhoGasGood = densGas; + break; + } + } + } + + if (foundGas && foundLiquid) { + if (presGas == presLiquid) { + pres = presGas; + goto startIteration; + } + pres = 0.5 * (presLiquid + presGas); + bool goodLiq; + bool goodGas; + for (int i = 0; i < 50; i++) { + + doublereal densLiquid = densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood); + if (densLiquid <= 0.0) { + goodLiq = false; + } else { + goodLiq = true; + RhoLiquidGood = densLiquid; + presLiquid = pres; + } + doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood); + if (densGas <= 0.0) { + goodGas = false; + } else { + goodGas = true; + RhoGasGood = densGas; + presGas = pres; + } + if (goodGas && goodLiq) { + break; + } + if (!goodLiq && !goodGas) { + pres = 0.5 * (pres + presLiquid); + } + if (goodLiq || goodGas) { + pres = 0.5 * (presLiquid + presGas); + } + + } + } + if (!foundGas || !foundLiquid) { + printf("error coundn't find a starting pressure\n"); + return (0.0); + } + if (presGas != presLiquid) { + printf("error coundn't find a starting pressure\n"); + return (0.0); + } + + startIteration: + pres = presGas; + presLast = pres; + RhoGas = RhoGasGood; + RhoLiquid = RhoLiquidGood; + + + /* + * Now that we have found a good pressure we can proceed with the algorithm. + */ + + for (i = 0; i < 20; i++) { + + stab = corr0(TKelvin, pres, RhoLiquid, RhoGas, liqGRT, gasGRT); + if (stab == 0) { + presLast = pres; + delGRT = liqGRT - gasGRT; + doublereal delV = mw * (1.0/RhoLiquid - 1.0/RhoGas); + doublereal dp = - delGRT * GasConstant * TKelvin / delV; + + if (fabs(dp) > 0.1 * pres) { + if (dp > 0.0) { + dp = 0.1 * pres; + } else { + dp = -0.1 * pres; + } + } + pres += dp; + + } else if (stab == -1) { + delGRT = 1.0E6; + if (presLast > pres) { + pres = 0.5 * (presLast + pres); + } else { + // we are stuck here - try this + pres = 1.1 * pres; + } + } else if (stab == -2) { + if (presLast < pres) { + pres = 0.5 * (presLast + pres); + } else { + // we are stuck here - try this + pres = 0.9 * pres; + } + } + molarVolGas = mw / RhoGas; + molarVolLiquid = mw / RhoLiquid; + + + if (fabs(delGRT) < 1.0E-8) { + conv = true; + break; + } + } + + molarVolGas = mw / RhoGas; + molarVolLiquid = mw / RhoLiquid; + // Put the fluid in the desired end condition + setState_TR(tempSave, densSave); + + return pres; + + + } else { + pres = critPressure(); + setState_TP(TKelvin, pres); + RhoGas = density(); + molarVolGas = mw / RhoGas; + molarVolLiquid = molarVolGas; + setState_TR(tempSave, densSave); + } + return pres; + } + + //==================================================================================================================== + // Calculate the pressure given the temperature and the molar volume + doublereal MixtureFugacityTP::pressureCalc(doublereal TKelvin, doublereal molarVol) const { + throw CanteraError("MixtureFugacityTP::pressureCalc", "unimplemented"); + return 0.0; + } + //==================================================================================================================== + // Calculate the pressure given the temperature and the molar volume + doublereal MixtureFugacityTP::dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal &presCalc) const { + throw CanteraError("MixtureFugacityTP::dpdVCalc", "unimplemented"); + return 0.0; + } + //==================================================================================================================== + + /* + * void _updateStandardStateThermo() (protected, virtual, const) + * + * If m_useTmpStandardStateStorage is true, + * This function must be called for every call to functions in this + * class that need standard state properties. + * Child classes may require that it be called even if m_useTmpStandardStateStorage + * is not true. + * It checks to see whether the temperature has changed and + * thus the ss thermodynamics functions for all of the species + * must be recalculated. + * + * This + */ + void MixtureFugacityTP::_updateReferenceStateThermo() const { + double Tnow = temperature(); + + // If the temperature has changed since the last time these + // properties were computed, recompute them. + if (m_Tlast_ref != Tnow) { + m_spthermo->update(Tnow, &m_cp0_R[0], &m_h0_RT[0], &m_s0_R[0]); + m_Tlast_ref = Tnow; + + // update the species Gibbs functions + int k; + for (k = 0; k < m_kk; k++) { + m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k]; + } + doublereal pref = refPressure(); + if (pref <= 0.0) { + throw CanteraError("MixtureFugacityTP::_updateReferenceStateThermo()", "neg ref pressure"); + } + m_logc0 = log(pref/(GasConstant * Tnow)); + } + } + //==================================================================================================================== + + +} + + diff --git a/Cantera/src/thermo/MixtureFugacityTP.h b/Cantera/src/thermo/MixtureFugacityTP.h new file mode 100644 index 000000000..5aa9f7c3a --- /dev/null +++ b/Cantera/src/thermo/MixtureFugacityTP.h @@ -0,0 +1,968 @@ +/** + * @file MixtureFugacityTP.h + * Header file for a derived class of ThermoPhase that handles + * non-ideal mixtures based on the fugacity models (see \ref thermoprops and + * class \link Cantera::MixtureFugacityTP MixtureFugacityTP\endlink). + * + */ +/* + * 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. + */ +/* + * $Date: 2010-08-04 10:06:14 -0600 (Wed, 04 Aug 2010) $ + * $Revision: 547 $ + */ + +#ifndef CT_MIXTUREFUGACITYTP_H +#define CT_MIXTUREFUGACITYTP_H + +#include "ThermoPhase.h" +#include "VPSSMgr.h" +#include "ResidEval.h" + +namespace Cantera { + + class XML_Node; + class PDSS; + + + //! Various states of the Fugacity object. In general there can be multiple liquid + //! objects for a single phase identified with each species. + +#define FLUID_UNSTABLE -4 +#define FLUID_UNDEFINED -3 +#define FLUID_SUPERCRIT -2 +#define FLUID_GAS -1 +#define FLUID_LIQUID_0 0 +#define FLUID_LIQUID_1 1 +#define FLUID_LIQUID_2 2 +#define FLUID_LIQUID_3 3 +#define FLUID_LIQUID_4 4 +#define FLUID_LIQUID_5 5 +#define FLUID_LIQUID_6 6 +#define FLUID_LIQUID_7 7 +#define FLUID_LIQUID_8 8 +#define FLUID_LIQUID_9 9 + + + + /** + * @ingroup thermoprops + * + * This is a filter class for ThermoPhase that implements some prepatory + * steps for efficiently handling mixture of gases that whose standard states + * are defined as ideal gases, but which describe also non-ideal solutions. + * In addition a multicomponent liquid phase below the critical temperature of the + * mixture is also allowed. The main subclass is currently a mixture Redlich-Kwong class. + * + * Several concepts are introduced. The first concept is there are temporary + * variables for holding the species standard state values + * of Cp, H, S, G, and V at the last temperature and pressure called. These functions are not recalculated + * if a new call is made using the previous temperature and pressure. + * + * The other concept is that the current state of the mixture is tracked. + * The state variable is either GAS, LIQUID, or SUPERCRIT fluid. Additionally, + * the variable LiquidContent is used and may vary between 0 and 1. + * + * To support the above functionality, pressure and temperature variables, + * m_Plast_ss and m_Tlast_ss, are kept which store the last pressure and temperature + * used in the evaluation of standard state properties. + * + * Typically, only one liquid phase is allowed to be formed within these classes. + * Additionally, there is an inherent contradiction between three phase models and + * the ThermoPhase class. The ThermoPhase class is really only meant to represent a + * single instanteation of a phase. The three phase models may be in equilibrium with + * multiple phases of the fluid in equilibrium with each other. This has yet to be resolved. + * + * This class is usually used for non-ideal gases. + * + * + * @nosubgrouping + */ + class MixtureFugacityTP : public ThermoPhase { + + public: + + /*! + * + * @name Constructors and Duplicators for %MixtureFugacityTP + * + */ + //! Constructor. + MixtureFugacityTP(); + + //! Copy Constructor. + /*! + * @param b Object to be copied + */ + MixtureFugacityTP(const MixtureFugacityTP &b); + + //! Assignment operator + /*! + * @param b Object to be copied + */ + MixtureFugacityTP& operator=(const MixtureFugacityTP &b); + + //! Destructor. + virtual ~MixtureFugacityTP(); + + + //! Duplication routine + /*! + * @return Returns a duplication + */ + virtual ThermoPhase *duplMyselfAsThermoPhase() const; + + //@} + + /** + * @name Utilities (MixtureFugacityTP) + */ + //@{ + /** + * Equation of state type flag. The base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Constants defined for this purpose are + * listed in mix_defs.h. + */ + virtual int eosType() const { return 0; } + + //! This method returns the convention used in specification + //! of the standard state, of which there are currently two, + //! temperature based, and variable pressure based. + /*! + * Currently, there are two standard state conventions: + * - Temperature-based activities + * cSS_CONVENTION_TEMPERATURE 0 + * - default + * + * - Variable Pressure and Temperature -based activities + * cSS_CONVENTION_VPSS 1 + */ + virtual int standardStateConvention() const; + + //! Set the solution branch to force the ThermoPhase to exist on one branch or another + /*! + * @param solnBranch Branch that the solution is restricted to. + * the value -1 means gas. The value -2 means unrestricted. + * Values of zero or greater refer to species dominated condensed phases. + */ + virtual void setForcedSolutionBranch(int solnBranch); + + //! Report the solution branch which the solution is restricted to + /*! + * @return Branch that the solution is restricted to. + * the value -1 means gas. The value -2 means unrestricted. + * Values of zero or greater refer to species dominated condensed phases. + */ + virtual int forcedSolutionBranch() const; + + //! Report the solution branch which the solution is actually on + /*! + * @return Branch that the solution is restricted to. + * the value -1 means gas. The value -2 means superfluid.. + * Values of zero or greater refer to species dominated condensed phases. + */ + virtual int reportSolnBranchActual() const; + + + + //! Get the array of log concentration-like derivatives of the + //! log activity coefficients + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. moles) + * that represents the standard state. + * This quantity is to be used in conjunction with derivatives of + * that concentration-like variable when the derivative of the chemical + * potential is taken. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of derivatives of the + * log Activity Coefficients. length = m_kk + */ + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + err("getdlnActCoeffdlnN_diag"); + } + + + //@} + /// @name Partial Molar Properties of the Solution (MixtureFugacityTP) + //@{ + + + //! Get the array of non-dimensional species chemical potentials + //! These are partial molar Gibbs free energies. + /*! + * \f$ \mu_k / \hat R T \f$. + * Units: unitless + * + * We close the loop on this function, here, calling + * getChemPotentials() and then dividing by RT. No need for child + * classes to handle. + * + * @param mu Output vector of non-dimensional species chemical potentials + * Length: m_kk. + */ + void getChemPotentials_RT(doublereal* mu) const; + + //@} + + /*! + * @name Properties of the Standard State of the Species in the Solution + * (MixtureFugacityTP) + * + * Within MixtureFugacityTP, these properties are calculated via a common routine, + * _updateStandardStateThermo(), + * which must be overloaded in inherited objects. + * The values are cached within this object, and are not recalculated unless + * the temperature or pressure changes. + */ + //@{ + + //! Get the array of chemical potentials at unit activity. + /*! + * These are the standard state chemical potentials \f$ \mu^0_k(T,P) + * \f$. The values are evaluated at the current temperature and pressure. + * + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. + * + * @param mu Output vector of standard state chemical potentials. + * length = m_kk. units are J / kmol. + */ + virtual void getStandardChemPotentials(doublereal* mu) const; + + //! Get the nondimensional Enthalpy functions for the species + //! at their standard states at the current T and P of the solution. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. + * + * @param hrt Output vector of standard state enthalpies. + * length = m_kk. units are unitless. + */ + virtual void getEnthalpy_RT(doublereal* hrt) const; + + + //! Get the array of nondimensional Enthalpy functions for the standard state species + /*! + * at the current T and P of the solution. + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. + * + * @param sr Output vector of nondimensional standard state + * entropies. length = m_kk. + */ + virtual void getEntropy_R(doublereal* sr) const; + + //! Get the nondimensional Gibbs functions for the species + //! at their standard states of solution at the current T and P of the solution. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. + * + * @param grt Output vector of nondimensional standard state + * Gibbs free energies. length = m_kk. + */ + virtual void getGibbs_RT(doublereal* grt) const; + + + //! Get the nondimensional Gibbs functions for the standard + //! state of the species at the current T and P. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. + * + * @param gpure Output vector of standard state + * Gibbs free energies. length = m_kk. + * units are J/kmol. + * + * @todo This could be eliminated. It doesn't fit into the current + * naming convention. + */ + void getPureGibbs(doublereal* gpure) const; + + //! Returns the vector of nondimensional internal Energies of the standard state at the current temperature + //! and pressure of the solution for each species. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. + * + * \f[ + * u^{ss}_k(T,P) = h^{ss}_k(T) - P * V^{ss}_k + * \f] + * + * @param urt Output vector of nondimensional standard state + * internal energies. length = m_kk. + */ + virtual void getIntEnergy_RT(doublereal *urt) const; + + + //! Get the nondimensional Heat Capacities at constant + //! pressure for the standard state of the species at the current T and P. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure of the solution. + * + * @param cpr Output vector containing the + * the nondimensional Heat Capacities at constant + * pressure for the standard state of the species. + * Length: m_kk. + */ + virtual void getCp_R(doublereal* cpr) const; + + + //! Get the molar volumes of each species in their standard + //! states at the current T and P of the solution. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure of the solution. + * + * units = m^3 / kmol + * + * @param vol Output vector of species volumes. length = m_kk. + * units = m^3 / kmol + */ + virtual void getStandardVolumes(doublereal *vol) const; + + + //! Set the temperature of the phase + /*! + * Currently this passes down to setState_TP(). It does not + * make sense to calculate the standard state without first + * setting T and P. + * + * @param temp Temperature (kelvin) + */ + virtual void setTemperature(const doublereal temp); + + + //! Set the internally storred pressure (Pa) at constant + //! temperature and composition + /*! + * Currently this passes down to setState_TP(). It does not + * make sense to calculate the standard state without first + * setting T and P. + * + * @param p input Pressure (Pa) + */ + virtual void setPressure(doublereal p); + + + +protected: + /** + * Calculate the density of the mixture using the partial + * molar volumes and mole fractions as input + * + * The formula for this is + * + * \f[ + * \rho = \frac{\sum_k{X_k W_k}}{\sum_k{X_k V_k}} + * \f] + * + * where \f$X_k\f$ are the mole fractions, \f$W_k\f$ are + * the molecular weights, and \f$V_k\f$ are the pure species + * molar volumes. + * + * Note, the basis behind this formula is that in an ideal + * solution the partial molar volumes are equal to the pure + * species molar volumes. We have additionally specified + * in this class that the pure species molar volumes are + * independent of temperature and pressure. + * + * NOTE: This is a non-virtual function, which is not a + * member of the ThermoPhase base class. + */ + virtual void calcDensity(); + + public: + //! Set the temperature and pressure at the same time + /*! + * Note this function triggers a reevalulation of the standard + * state quantities. + * + * @param T temperature (kelvin) + * @param pres pressure (pascal) + */ + virtual void setState_TP(doublereal T, doublereal pres); + + //! Set the internally storred temperature (K) and density (kg/m^3) + /*! + * @param t Temperature in kelvin + * @param rho Density (kg/m^3) + */ + virtual void setState_TR(doublereal T, doublereal rho); + + //! Set the temperature (K), pressure (Pa), and mole fractions. + /*! + * Note, the mole fractions are set first before the pressure is set. + * Setting the pressure may involve the solution of a nonlinear equation. + * + * @param t Temperature (K) + * @param p Pressure (Pa) + * @param x Vector of mole fractions. + * Length is equal to m_kk. + */ + virtual void setState_TPX(doublereal t, doublereal p, const doublereal* x); + + + //! Set the mass fractions to the specified values, and then + //! normalize them so that they sum to 1.0. + /*! + * @param y Array of unnormalized mass fraction values (input). + * Must have a length greater than or equal to the number of species. + */ + virtual void setMassFractions(const doublereal* const y); + + + //!Set the mass fractions to the specified values without normalizing. + /*! + * This is useful when the normalization + * condition is being handled by some other means, for example + * by a constraint equation as part of a larger set of + * equations. + * + * @param y Input vector of mass fractions. + * Length is m_kk. + */ + virtual void setMassFractions_NoNorm(const doublereal* const y); + + + + //! Set the mole fractions to the specified values, and then + //! normalize them so that they sum to 1.0. + /*! + * @param x Array of unnormalized mole fraction values (input). + * Must have a length greater than or equal to the number of species. + */ + virtual void setMoleFractions(const doublereal* const x); + + + //! Set the mole fractions to the specified values without normalizing. + /*! + * This is useful when the normalization + * condition is being handled by some other means, for example + * by a constraint equation as part of a larger set ofequations. + * + * @param x Input vector of mole fractions. + * Length is m_kk. + */ + virtual void setMoleFractions_NoNorm(const doublereal* const x); + + + //! Set the concentrations to the specified values within the phase. + /*! + * @param c The input vector to this routine is in dimensional + * units. For volumetric phases c[k] is the + * concentration of the kth species in kmol/m3. + * For surface phases, c[k] is the concentration + * in kmol/m2. The length of the vector is the number + * of species in the phase. + */ + virtual void setConcentrations(const doublereal* const c); + + protected: + void setMoleFractions_NoState(const doublereal* const x); + + + public: + //! Returns the current pressure of the phase + /*! + * The pressure is an independent variable in this phase. Its current value + * is storred in the object MixtureFugacityTP. + * + * @return return the pressure in pascals. + */ + doublereal pressure() const { + return m_Pcurrent; + } + + + + + + protected: + + //! Updates the reference state thermodynamic functions at the current T of the solution. + /*! + * + * If m_useTmpStandardStateStorage is true, + * this function must be called for every call to functions in this + * class. It checks to see whether the temperature or pressure has changed and + * thus the ss thermodynamics functions for all of the species + * must be recalculated. + * + * This function is responsible for updating the following internal members, + * when m_useTmpStandardStateStorage is true. + * + * - m_hss_RT; + * - m_cpss_R; + * - m_gss_RT; + * - m_sss_R; + * - m_Vss + * + * If m_useTmpStandardStateStorage is not true, this function may be + * required to be called by child classes to update internal member data. + * + */ + virtual void _updateReferenceStateThermo() const; + public: + + //@} + /// @name Thermodynamic Values for the Species Reference States (MixtureFugacityTP) + /*! + * There are also temporary + * variables for holding the species reference-state values of Cp, H, S, and V at the + * last temperature and reference pressure called. These functions are not recalculated + * if a new call is made using the previous temperature. + * All calculations are done within the routine _updateRefStateThermo(). + */ + //@{ + + + //! Returns the vector of nondimensional + //! enthalpies of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * @param hrt Output vector contains the nondimensional enthalpies + * of the reference state of the species + * length = m_kk, units = dimensionless. + */ + virtual void getEnthalpy_RT_ref(doublereal *hrt) const; + +#ifdef H298MODIFY_CAPABILITY + //! Modify the value of the 298 K Heat of Formation of the standard state of + //! one species in the phase (J kmol-1) + /*! + * The 298K heat of formation is defined as the enthalpy change to create the standard state + * of the species from its constituent elements in their standard states at 298 K and 1 bar. + * + * @param k Index of the species + * @param Hf298New Specify the new value of the Heat of Formation at 298K and 1 bar. + * units = J/kmol. + */ + void modifyOneHf298SS(const int k, const doublereal Hf298New); +#endif + + //! Returns the vector of nondimensional + //! Gibbs free energies of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * + * @param grt Output vector contains the nondimensional Gibbs free energies + * of the reference state of the species + * length = m_kk, units = dimensionless. + */ + virtual void getGibbs_RT_ref(doublereal *grt) const; + + protected: + //! Returns the vector of nondimensional + //! Gibbs free energies of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * @return Output vector contains the nondimensional Gibbs free energies + * of the reference state of the species + * length = m_kk, units = dimensionless. + */ + const vector_fp & gibbs_RT_ref() const; + + public: + /*! + * Returns the vector of the + * gibbs function of the reference state at the current temperature + * of the solution and the reference pressure for the species. + * units = J/kmol + * + * @param g Output vector contain the Gibbs free energies + * of the reference state of the species + * length = m_kk, units = J/kmol. + */ + virtual void getGibbs_ref(doublereal *g) const; + + /*! + * Returns the vector of nondimensional + * entropies of the reference state at the current temperature + * of the solution and the reference pressure for the species. + * + * @param er Output vector contain the nondimensional entropies + * of the species in their reference states + * length: m_kk, units: dimensionless. + */ + virtual void getEntropy_R_ref(doublereal *er) const; + + /*! + * Returns the vector of nondimensional + * constant pressure heat capacities of the reference state + * at the current temperature of the solution + * and reference pressure for the species. + * + * @param cprt Output vector contains the nondimensional heat capacities + * of the species in their reference states + * length: m_kk, units: dimensionless. + */ + virtual void getCp_R_ref(doublereal *cprt) const; + + //! Get the molar volumes of the species reference states at the current + //! T and reference pressure of the solution. + /*! + * units = m^3 / kmol + * + * @param vol Output vector containing the standard state volumes. + * Length: m_kk. + */ + virtual void getStandardVolumes_ref(doublereal *vol) const; + + protected: + + + + //@} + + + public: + + //! @name Initialization Methods - For Internal use (VPStandardState) + /*! + * The following methods are used in the process of constructing + * the phase and setting its parameters from a specification in an + * input file. They are not normally used in application programs. + * To see how they are used, see files importCTML.cpp and + * ThermoFactory.cpp. + */ + //@{ + + + //! Set the initial state of the phase to the conditions specified in the state XML element. + /*! + * + * This method sets the temperature, pressure, and mole fraction vector to a set default value. + * + * @param state AN XML_Node object corresponding to + * the "state" entry for this phase in the input file. + */ + virtual void setStateFromXML(const XML_Node& state); + + //! @internal Initialize the object + /*! + * This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called after calling installSpecies() + * for each species in the phase. It's called before calling + * initThermoXML() for the phase. Therefore, it's the correct + * place for initializing vectors which have lengths equal to the + * number of species. + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + //! Initialize a ThermoPhase object, potentially reading activity + //! coefficient information from an XML database. + /*! + * This routine initializes the lengths in the current object and + * then calls the parent routine. + * This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase(). + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + virtual void initThermoXML(XML_Node& phaseNode, std::string id); + + + private: + //! @internal Initialize the internal lengths in this object. + /*! + * Note this is not a virtual function. + */ + void initLengths(); + + protected: + // Special Functions for fugacity classes + + + //! Calculate the value of z + /*! + * \f[ + * z = \frac{P v}{ R T} + * \f] + * + * returns the value of z + */ + doublereal z() const; + + //! Calculate the deviation terms for the total entropy of the mixture from the + //! ideal gas mixture + /* + * Here we use the current state conditions + * + * @return Returns the change in entropy in units of J kmol-1 K-1. + */ + virtual doublereal sresid() const; + + //! Calculate the deviation terms for the total enthalpy of the mixture from the ideal gas mixture + /* + * Here we use the current state conditions + * + * @return Returns the change in entropy in units of J kmol-1. + */ + virtual doublereal hresid() const; + + + //! Estimate for the saturation pressure + /*! + * Note: this is only used as a starting guess for later routines that actually calculate an + * accurate value for the saturation pressure. + * + * @param TKelvin temperature in kelvin + * + * @return returns the estimated saturation pressure at the given temperature + */ + virtual doublereal psatEst(doublereal TKelvin) const; + public: + //! Estimate for the molar volume of the liquid + /*! + * Note: this is only used as a starting guess for later routines that actually calculate an + * accurate value for the liquid molar volume. + * This routine doesn't change the state of the system. + * + * @param TKelvin temperature in kelvin + * @param pres Pressure in Pa. This is used as an initial guess. If the routine + * needs to change the pressure to find a stable liquid state, the + * new pressure is returned in this variable. + * + * @return Returns the estimate of the liquid volume. If the liquid can't be found, this + * routine returns -1. + */ + virtual doublereal liquidVolEst(doublereal TKelvin, doublereal &pres) const; + + public: + //! Calculates the density given the temperature and the pressure and a guess at the density. + /*! + * Note, below T_c, this is a multivalued function. We do not cross the vapor dome in this. + * This is protected because it is called during setState_TP() routines. Infinite loops would result + * if it were not protected. + * + * -> why is this not const? + * + * parameters: + * @param TKelvin Temperature in Kelvin + * @param pressure Pressure in Pascals (Newton/m**2) + * @param phaseRequested int representing the phase whose density we are requesting. If we put + * a gas or liquid phase here, we will attempt to find a volume in that + * part of the volume space, only, in this routine. A value of FLUID_UNDEFINED + * means that we will accept anything. + * + * @param rhoguess Guessed density of the fluid. A value of -1.0 indicates that there + * is no guessed density + * + * + * @return We return the density of the fluid at the requested phase. If we have not found any + * acceptable density we return a -1. If we have found an accectable density at a + * different phase, we return a -2. + */ + virtual doublereal densityCalc(doublereal TKelvin, doublereal pressure, int phaseRequested, + doublereal rhoguess); + protected: + //! Utility routine in the calculation of the saturation pressure + /*! + * Private routine + * + * @param TKelvin temperature (kelvin) + * @param pres pressure (Pascal) + * @param densLiq Output density of liquid + * @param densGas output density of gas + * @param delGRT output delGRT + */ + int corr0(doublereal TKelvin, doublereal pre, doublereal &densLiq, + doublereal &densGas, doublereal &liqGRT, doublereal &gasGRT); + public: + //! Returns the Phase State flag for the current state of the object + /*! + * @param checkState If true, this function does a complete check to see where + * in paramters space we are + * + * There are three values: + * WATER_GAS below the critical temperature but below the critical density + * WATER_LIQUID below the critical temperature but above the critical density + * WATER_SUPERCRIT above the critical temperature + */ + int phaseState(bool checkState = false) const ; + + //! Return the value of the density at the liquid spinodal point (on the liquid side) + //! for the current temperature. + /*! + * @return returns the density with units of kg m-3 + */ + virtual doublereal densSpinodalLiquid() const; + + + //! Return the value of the density at the gas spinodal point (on the gas side) + //! for the current temperature. + /*! + * @return returns the density with units of kg m-3 + */ + virtual doublereal densSpinodalGas() const; + + + + + public: + //! Calculate the saturation pressure at the current mixture content for the given temperature + /*! + * @param TKelvin (input) Temperature (Kelvin) + * @param molarVolGas (return) Molar volume of the gas + * @param molarVolLiquid (return) Molar volume of the liquid + * + * @return Returns the saturation pressure at the given temperature + */ + doublereal calculatePsat(doublereal TKelvin, doublereal &molarVolGas, + doublereal &molarVolLiquid); + protected: + //! Calculate the pressure given the temperature and the molar volume + /*! + * Calculate the pressure given the temperature and the molar volume + * + * @param TKelvin temperature in kelvin + * @param molarVol molar volume ( m3/kmol) + * + * @return Returns the pressure. + */ + virtual doublereal pressureCalc(doublereal TKelvin, doublereal molarVol) const; + + + //! Calculate the pressure and the pressure derivative given the temperature and the molar volume + /*! + * Temperature and mole number are held constant + * + * @param TKelvin temperature in kelvin + * @param molarVol molar volume ( m3/kmol) + * + * @param presCalc Returns the pressure. + * + * @return Returns the derivative of the pressure wrt the molar volume + */ + virtual doublereal dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal &presCalc) const; + + + + virtual void updateMixingExpressions(); + + + //@} + + + class spinodalFunc : public Cantera::ResidEval + { + public: + + spinodalFunc(MixtureFugacityTP *tp); + + virtual int evalSS(const doublereal t, const doublereal * const y, doublereal * const r); + + MixtureFugacityTP *m_tp; + }; + + + protected: + + //! Current value of the pressurees + /*! + * Because the pressure is now a calculation, we store the result of the calculation whenever + * it is recalculated. + * + * units = Pascals + */ + doublereal m_Pcurrent; + + + //! Storage for the current values of the mole fractions of the species + /*! + * This vector is kept up-to-date when some the setState functions are called. + * + * The State object is allowed to com + * + * Therefore, it may be considered to be an independent variable. + * + + */ + std::vector moleFractions_; + + //! Current state of the fluid + /*! + * There are three possible states of the fluid + * FLUID_GAS + * FLUID_LIQUID + * FLUID_SUPERCRIT + */ + int iState_; + + + //! Force the system to be on a particular side of the spinodal curve + int forcedState_; + + //! The last temperature at which the reference state thermodynamic properties were calculated at. + mutable doublereal m_Tlast_ref; + + //! Temporary storage for log of p/rt + mutable doublereal m_logc0; + + //! Temporary storage for dimensionless reference state enthalpies + mutable array_fp m_h0_RT; + + //! Temporary storage for dimensionless reference state heat capacities + mutable array_fp m_cp0_R; + + //! Temporary storage for dimensionless reference state gibbs energies + mutable array_fp m_g0_RT; + + //! Temporary storage for dimensionless reference state entropies + mutable array_fp m_s0_R; + + spinodalFunc *fdpdv_; + private: + + //! MixtureFugacityTP has its own err routine + /*! + * @param msg Error message string + */ + doublereal err(std::string msg) const; + + }; +} + +#endif diff --git a/Cantera/src/thermo/MolalityVPSSTP.cpp b/Cantera/src/thermo/MolalityVPSSTP.cpp index da2a30e60..617f0224b 100644 --- a/Cantera/src/thermo/MolalityVPSSTP.cpp +++ b/Cantera/src/thermo/MolalityVPSSTP.cpp @@ -590,12 +590,12 @@ namespace Cantera { */ void MolalityVPSSTP::setStateFromXML(const XML_Node& state) { VPStandardStateTP::setStateFromXML(state); - string comp = getChildValue(state,"soluteMolalities"); + string comp = ctml::getChildValue(state,"soluteMolalities"); if (comp != "") { setMolalitiesByName(comp); } if (state.hasChild("pressure")) { - double p = getFloat(state, "pressure", "pressure"); + double p = ctml::getFloat(state, "pressure", "pressure"); setPressure(p); } } diff --git a/Cantera/src/thermo/MolalityVPSSTP.h b/Cantera/src/thermo/MolalityVPSSTP.h index 60ea18feb..5999b0add 100644 --- a/Cantera/src/thermo/MolalityVPSSTP.h +++ b/Cantera/src/thermo/MolalityVPSSTP.h @@ -793,6 +793,29 @@ namespace Cantera { */ void setState_TPM(doublereal t, doublereal p, const std::string& m); + //! Get the array of derivatives of the log activity coefficients with respect to the log of the species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * species log mole number (with all other species mole numbers held constant). The default treatment in the + * %ThermoPhase object is to set this vector to zero. + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) { + getdlnActCoeffdlnN_numderiv(ld, dlnActCoeffdlnN); + } + //! returns a summary of the state of the phase as a string /*! * @param show_thermo If true, extra information is printed out diff --git a/Cantera/src/thermo/MolarityIonicVPSSTP.cpp b/Cantera/src/thermo/MolarityIonicVPSSTP.cpp new file mode 100644 index 000000000..6f02b9ce1 --- /dev/null +++ b/Cantera/src/thermo/MolarityIonicVPSSTP.cpp @@ -0,0 +1,815 @@ +/** + * @file MolarityIonicVPSSTP.cpp + * Definitions for intermediate ThermoPhase object for phases which + * employ excess gibbs free energy formulations + * (see \ref thermoprops + * and class \link Cantera::MolarityIonicVPSSTP MolarityIonicVPSSTP\endlink). + * + * Header file for a derived class of ThermoPhase that handles + * variable pressure standard state methods for calculating + * thermodynamic properties that are further based upon expressions + * for the excess gibbs free energy expressed as a function of + * the mole fractions. + */ +/* + * Copywrite (2009) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ +/* + * $Date: 2009-11-09 16:36:49 -0700 (Mon, 09 Nov 2009) $ + * $Revision: 255 $ + */ + + +#include "MolarityIonicVPSSTP.h" +#include "ThermoFactory.h" +#include + +using namespace std; + +namespace Cantera { + static const double xxSmall = 1.0E-150; + //==================================================================================================================== + /* + * Default constructor. + * + */ + MolarityIonicVPSSTP::MolarityIonicVPSSTP() : + GibbsExcessVPSSTP(), + PBType_(PBTYPE_PASSTHROUGH), + numPBSpecies_(m_kk), + indexSpecialSpecies_(-1), + numCationSpecies_(0), + numAnionSpecies_(0), + numPassThroughSpecies_(0), + neutralPBindexStart(0) + { + } + //==================================================================================================================== + /* + * Working constructors + * + * The two constructors below are the normal way + * the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + */ + MolarityIonicVPSSTP::MolarityIonicVPSSTP(std::string inputFile, std::string id) : + GibbsExcessVPSSTP(), + PBType_(PBTYPE_PASSTHROUGH), + numPBSpecies_(m_kk), + indexSpecialSpecies_(-1), + numCationSpecies_(0), + numAnionSpecies_(0), + numPassThroughSpecies_(0), + neutralPBindexStart(0) + { + constructPhaseFile(inputFile, id); + } + //==================================================================================================================== + MolarityIonicVPSSTP::MolarityIonicVPSSTP(XML_Node& phaseRoot, std::string id) : + GibbsExcessVPSSTP(), + PBType_(PBTYPE_PASSTHROUGH), + numPBSpecies_(m_kk), + indexSpecialSpecies_(-1), + numCationSpecies_(0), + numAnionSpecies_(0), + numPassThroughSpecies_(0), + neutralPBindexStart(0) + { + constructPhaseXML(phaseRoot, id); + } + //==================================================================================================================== + /* + * Copy Constructor: + * + * Note this stuff will not work until the underlying phase + * has a working copy constructor + */ + MolarityIonicVPSSTP::MolarityIonicVPSSTP(const MolarityIonicVPSSTP &b) : + GibbsExcessVPSSTP(), + PBType_(PBTYPE_PASSTHROUGH), + numPBSpecies_(m_kk), + indexSpecialSpecies_(-1), + numCationSpecies_(0), + numAnionSpecies_(0), + numPassThroughSpecies_(0), + neutralPBindexStart(0) + { + *this = operator=(b); + } + //==================================================================================================================== + /* + * operator=() + * + * Note this stuff will not work until the underlying phase + * has a working assignment operator + */ + MolarityIonicVPSSTP& MolarityIonicVPSSTP:: + operator=(const MolarityIonicVPSSTP &b) { + if (&b != this) { + GibbsExcessVPSSTP::operator=(b); + } + + PBType_ = b.PBType_; + numPBSpecies_ = b.numPBSpecies_; + indexSpecialSpecies_ = b.indexSpecialSpecies_; + PBMoleFractions_ = b.PBMoleFractions_; + cationList_ = b.cationList_; + numCationSpecies_ = b.numCationSpecies_; + anionList_ = b.anionList_; + numAnionSpecies_ = b.numAnionSpecies_; + passThroughList_ = b.passThroughList_; + numPassThroughSpecies_ = b.numPassThroughSpecies_; + neutralPBindexStart = b.neutralPBindexStart; + moleFractionsTmp_ = b.moleFractionsTmp_; + + return *this; + } + //==================================================================================================================== + /** + * + * ~MolarityIonicVPSSTP(): (virtual) + * + * Destructor: does nothing: + * + */ + MolarityIonicVPSSTP::~MolarityIonicVPSSTP() { + } + + /* + * This routine duplicates the current object and returns + * a pointer to ThermoPhase. + */ + ThermoPhase* + MolarityIonicVPSSTP::duplMyselfAsThermoPhase() const { + MolarityIonicVPSSTP* mtp = new MolarityIonicVPSSTP(*this); + return (ThermoPhase *) mtp; + } + + /* + * -------------- Utilities ------------------------------- + */ + //==================================================================================================================== + + // Equation of state type flag. + /* + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The MolarityIonicVPSSTP class also returns + * zero, as it is a non-complete class. + */ + int MolarityIonicVPSSTP::eosType() const { + return 0; + } + + //==================================================================================================================== + /* + * Import, construct, and initialize a phase + * specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void MolarityIonicVPSSTP::constructPhaseFile(std::string inputFile, std::string id) { + + if ((int) inputFile.size() == 0) { + throw CanteraError("MolarityIonicVPSSTP:constructPhaseFile", + "input file is null"); + } + string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("MolarityIonicVPSSTP:constructPhaseFile","could not open " + +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("MolarityIonicVPSSTP:constructPhaseFile", + "ERROR: Can not find phase named " + + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; + } + //==================================================================================================================== + /* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * Most of the work is carried out by the cantera base + * routine, importPhase(). That routine imports all of the + * species and element data, including the standard states + * of the species. + * + * Then, In this routine, we read the information + * particular to the specification of the activity + * coefficient model for the Pitzer parameterization. + * + * We also read information about the molar volumes of the + * standard states if present in the XML file. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void MolarityIonicVPSSTP::constructPhaseXML(XML_Node& phaseNode, std::string id) { + string stemp; + if ((int) id.size() > 0) { + string idp = phaseNode.id(); + if (idp != id) { + throw CanteraError("MolarityIonicVPSSTP::constructPhaseXML", + "phasenode and Id are incompatible"); + } + } + + /* + * Find the Thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("MolarityIonicVPSSTP::constructPhaseXML", + "no thermo XML node"); + } + XML_Node& thermoNode = phaseNode.child("thermo"); + + /* + * Make sure that the thermo model is MolarityIonic + */ + stemp = thermoNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "molarityionicvpss" && formString != "molarityionicvpsstp") { + throw CanteraError("MolarityIonicVPSSTP::constructPhaseXML", + "model name isn't MolarityIonicVPSSTP: " + formString); + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the solvent and solute standard states + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("MolarityIonicVPSSTP::constructPhaseXML","importPhase failed "); + } + + } + //==================================================================================================================== + /* + * ------------ Molar Thermodynamic Properties ---------------------- + */ + //==================================================================================================================== + /* + * - Activities, Standard States, Activity Concentrations ----------- + */ + //==================================================================================================================== + // Get the array of non-dimensional molar-based activity coefficients at + // the current solution temperature, pressure, and solution concentration. + /* + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + void MolarityIonicVPSSTP::getLnActivityCoefficients(doublereal* lnac) const { + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + + /* + * take the exp of the internally storred coefficients. + */ + for (int k = 0; k < m_kk; k++) { + lnac[k] = lnActCoeff_Scaled_[k]; + } + } + //==================================================================================================================== + void MolarityIonicVPSSTP::getChemPotentials(doublereal* mu) const { + doublereal xx; + /* + * First get the standard chemical potentials in + * molar form. + * -> this requires updates of standard state as a function + * of T and P + */ + getStandardChemPotentials(mu); + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + /* + * + */ + doublereal RT = GasConstant * temperature(); + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + mu[k] += RT * (log(xx) + lnActCoeff_Scaled_[k]); + } + } + //==================================================================================================================== + + void MolarityIonicVPSSTP::getElectrochemPotentials(doublereal* mu) const { + getChemPotentials(mu); + double ve = Faraday * electricPotential(); + for (int k = 0; k < m_kk; k++) { + mu[k] += ve*charge(k); + } + } + + //==================================================================================================================== + // Returns an array of partial molar enthalpies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MolarityIonicVPSSTP::getPartialMolarEnthalpies(doublereal* hbar) const { + /* + * Get the nondimensional standard state enthalpies + */ + getEnthalpy_RT(hbar); + /* + * dimensionalize it. + */ + double T = temperature(); + double RT = GasConstant * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] *= RT; + } + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + double RTT = RT * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] -= RTT * dlnActCoeffdT_Scaled_[k]; + } + } + //==================================================================================================================== + // Returns an array of partial molar heat capacities for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????? \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MolarityIonicVPSSTP::getPartialMolarCp(doublereal* cpbar) const { + /* + * Get the nondimensional standard state entropies + */ + getCp_R(cpbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + cpbar[k] *= GasConstant; + } + } + //==================================================================================================================== + // Returns an array of partial molar entropies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void MolarityIonicVPSSTP::getPartialMolarEntropies(doublereal* sbar) const { + double xx; + /* + * Get the nondimensional standard state entropies + */ + getEntropy_R(sbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + sbar[k] *= GasConstant; + } + } + // Return an array of partial molar volumes for the + // species in the mixture. Units: m^3/kmol. + /* + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + void MolarityIonicVPSSTP::getPartialMolarVolumes(doublereal* vbar) const { + int iK; + /* + * Get the standard state values in m^3 kmol-1 + */ + getStandardVolumes(vbar); + for ( iK = 0; iK < m_kk; iK++ ){ + + vbar[iK] += 0.0; + } + } + //==================================================================================================================== + void MolarityIonicVPSSTP::calcPseudoBinaryMoleFractions() const { + int k; + int kCat; + int kMax; + doublereal sumCat; + doublereal sumAnion; + doublereal chP, chM; + doublereal sum = 0.0; + doublereal sumMax; + switch (PBType_) { + case PBTYPE_PASSTHROUGH: + for (k = 0; k < m_kk; k++) { + PBMoleFractions_[k] = moleFractions_[k]; + } + break; + case PBTYPE_SINGLEANION: + sumCat = 0.0; + sumAnion = 0.0; + for (k = 0; k < m_kk; k++) { + moleFractionsTmp_[k] = moleFractions_[k]; + } + kMax = -1; + sumMax = 0.0; + for (k = 0; k < (int) cationList_.size(); k++) { + kCat = cationList_[k]; + chP = m_speciesCharge[kCat]; + if (moleFractions_[kCat] > sumMax) { + kMax = k; + sumMax = moleFractions_[kCat]; + } + sumCat += chP * moleFractions_[kCat]; + } + k = anionList_[0]; + chM = m_speciesCharge[k]; + sumAnion = moleFractions_[k] * chM; + sum = sumCat - sumAnion; + if (fabs(sum) > 1.0E-16) { + moleFractionsTmp_[cationList_[kMax]] -= sum / m_speciesCharge[kMax]; + sum = 0.0; + for (k = 0; k < numCationSpecies_; k++) { + sum += moleFractionsTmp_[k]; + } + for (k = 0; k < numCationSpecies_; k++) { + moleFractionsTmp_[k]/= sum; + } + } + + for (k = 0; k < numCationSpecies_; k++) { + PBMoleFractions_[k] = moleFractionsTmp_[cationList_[k]]; + } + for (k = 0; k < numPassThroughSpecies_; k++) { + PBMoleFractions_[neutralPBindexStart + k] = moleFractions_[passThroughList_[k]]; + } + + sum = fmaxx(0.0, PBMoleFractions_[0]); + for (k = 1; k < numPBSpecies_; k++) { + sum += PBMoleFractions_[k]; + + } + for (k = 0; k < numPBSpecies_; k++) { + PBMoleFractions_[k] /= sum; + } + + break; + case PBTYPE_SINGLECATION: + throw CanteraError("eosType", "Unknown type"); + + break; + + case PBTYPE_MULTICATIONANION: + throw CanteraError("eosType", "Unknown type"); + + break; + default: + throw CanteraError("eosType", "Unknown type"); + break; + + } + } + //==================================================================================================================== + + // Update the activity coefficients + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + */ + void MolarityIonicVPSSTP::s_update_lnActCoeff() const { + int k; + for (k = 0; k < m_kk; k++) { + lnActCoeff_Scaled_[k] = 0.0; + } + } + //==================================================================================================================== + void MolarityIonicVPSSTP::s_update_dlnActCoeff_dT() const { + + + } + //==================================================================================================================== + // Internal routine that calculates the derivative of the activity coefficients wrt + // the mole fractions. + /* + * This routine calculates the the derivative of the activity coefficients wrt to mole fraction + * with all other mole fractions held constant. This is strictly not permitted. However, if the + * resulting matrix is multiplied by a permissible deltaX vector then everything is ok. + * + * This is the natural way to handle concentration derivatives in this routine. + */ + void MolarityIonicVPSSTP::s_update_dlnActCoeff_dX_() const { + + } + //==================================================================================================================== + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + //==================================================================================================================== + doublereal MolarityIonicVPSSTP::err(std::string msg) const { + throw CanteraError("MolarityIonicVPSSTP","Base class method " + +msg+" called. Equation of state type: "+int2str(eosType())); + return 0; + } + //==================================================================================================================== + /* + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + void MolarityIonicVPSSTP::initThermo() { + GibbsExcessVPSSTP::initThermo(); + initLengths(); + /* + * Go find the list of cations and anions + */ + double ch; + numCationSpecies_ = 0.0; + cationList_.clear(); + anionList_.clear(); + passThroughList_.clear(); + for (int k = 0; k < m_kk; k++) { + ch = m_speciesCharge[k]; + if (ch > 0.0) { + cationList_.push_back(k); + numCationSpecies_++; + } else if (ch < 0.0) { + anionList_.push_back(k); + numAnionSpecies_++; + } else { + passThroughList_.push_back(k); + numPassThroughSpecies_++; + } + } + numPBSpecies_ = numCationSpecies_ + numAnionSpecies_ - 1; + neutralPBindexStart = numPBSpecies_; + PBType_ = PBTYPE_MULTICATIONANION; + if (numAnionSpecies_ == 1) { + PBType_ = PBTYPE_SINGLEANION; + } else if (numCationSpecies_ == 1) { + PBType_ = PBTYPE_SINGLECATION; + } + if (numAnionSpecies_ == 0 && numCationSpecies_ == 0) { + PBType_ = PBTYPE_PASSTHROUGH; + } + } + //==================================================================================================================== + // Initialize lengths of local variables after all species have been identified. + void MolarityIonicVPSSTP::initLengths() { + m_kk = nSpecies(); + moleFractionsTmp_.resize(m_kk); + } + //==================================================================================================================== + /* + * initThermoXML() (virtual from ThermoPhase) + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void MolarityIonicVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) { + std::string subname = "MolarityIonicVPSSTP::initThermoXML"; + std::string stemp; + /* + * Check on the thermo field. Must have: + * + */ + + XML_Node& thermoNode = phaseNode.child("thermo"); + std::string mStringa = thermoNode.attrib("model"); + std::string mString = lowercase(mStringa); + if (mString != "molarityionicvpss" && mString != "molarityionicvpsstp") { + throw CanteraError(subname.c_str(), + "Unknown thermo model: " + mStringa + " - This object only knows \"MolarityIonicVPSSTP\" "); + } + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + XML_Node *acNodePtr = 0; + if (thermoNode.hasChild("activityCoefficients")) { + XML_Node& acNode = thermoNode.child("activityCoefficients"); + acNodePtr = &acNode; + std::string mStringa = acNode.attrib("model"); + std::string mString = lowercase(mStringa); + // if (mString != "redlich-kister") { + // throw CanteraError(subname.c_str(), + // "Unknown activity coefficient model: " + mStringa); + //} + int n = acNodePtr->nChildren(); + for (int i = 0; i < n; i++) { + XML_Node &xmlACChild = acNodePtr->child(i); + stemp = xmlACChild.name(); + std::string nodeName = lowercase(stemp); + /* + * Process a binary interaction + */ + if (nodeName == "binaryneutralspeciesparameters") { + readXMLBinarySpecies(xmlACChild); + } + } + } + + + /* + * Go down the chain + */ + GibbsExcessVPSSTP::initThermoXML(phaseNode, id); + } + //==================================================================================================================== + // Process an XML node called "binaryNeutralSpeciesParameters" + /* + * This node contains all of the parameters necessary to describe + * a single binary interaction. This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + */ + void MolarityIonicVPSSTP::readXMLBinarySpecies(XML_Node &xmLBinarySpecies) { + std::string xname = xmLBinarySpecies.name(); + + } + //==================================================================================================================== + /* + * Format a summary of the mixture state for output. + */ + std::string MolarityIonicVPSSTP::report(bool show_thermo) const { + char p[800]; + string s = ""; + try { + if (name() != "") { + sprintf(p, " \n %s:\n", name().c_str()); + s += p; + } + sprintf(p, " \n temperature %12.6g K\n", temperature()); + s += p; + sprintf(p, " pressure %12.6g Pa\n", pressure()); + s += p; + sprintf(p, " density %12.6g kg/m^3\n", density()); + s += p; + sprintf(p, " mean mol. weight %12.6g amu\n", meanMolecularWeight()); + s += p; + + doublereal phi = electricPotential(); + sprintf(p, " potential %12.6g V\n", phi); + s += p; + + int kk = nSpecies(); + array_fp x(kk); + array_fp molal(kk); + array_fp mu(kk); + array_fp muss(kk); + array_fp acMolal(kk); + array_fp actMolal(kk); + getMoleFractions(&x[0]); + + getChemPotentials(&mu[0]); + getStandardChemPotentials(&muss[0]); + getActivities(&actMolal[0]); + + + if (show_thermo) { + sprintf(p, " \n"); + s += p; + sprintf(p, " 1 kg 1 kmol\n"); + s += p; + sprintf(p, " ----------- ------------\n"); + s += p; + sprintf(p, " enthalpy %12.6g %12.4g J\n", + enthalpy_mass(), enthalpy_mole()); + s += p; + sprintf(p, " internal energy %12.6g %12.4g J\n", + intEnergy_mass(), intEnergy_mole()); + s += p; + sprintf(p, " entropy %12.6g %12.4g J/K\n", + entropy_mass(), entropy_mole()); + s += p; + sprintf(p, " Gibbs function %12.6g %12.4g J\n", + gibbs_mass(), gibbs_mole()); + s += p; + sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n", + cp_mass(), cp_mole()); + s += p; + try { + sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n", + cv_mass(), cv_mole()); + s += p; + } + catch(CanteraError) { + sprintf(p, " heat capacity c_v \n"); + s += p; + } + } + + } catch (CanteraError) { + ; + } + return s; + } + //==================================================================================================================== +} + diff --git a/Cantera/src/thermo/MolarityIonicVPSSTP.h b/Cantera/src/thermo/MolarityIonicVPSSTP.h new file mode 100644 index 000000000..1ab7cd25f --- /dev/null +++ b/Cantera/src/thermo/MolarityIonicVPSSTP.h @@ -0,0 +1,550 @@ +/** + * @file MolarityIonicVPSSTP.h + * Header for intermediate ThermoPhase object for phases which + * employ gibbs excess free energy based formulations + * (see \ref thermoprops + * and class \link Cantera::MolarityIonicVPSSTP MolarityIonicVPSSTP\endlink). + * + * Header file for a derived class of ThermoPhase that handles + * variable pressure standard state methods for calculating + * thermodynamic properties that are further based upon activities + * based on the molarity scale. In this class, we expect that there are + * ions, but they are treated on the molarity scale. + */ +/* + * 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. + */ +/* + * $Id: MolarityIonicVPSSTP.h 255 2009-11-09 23:36:49Z hkmoffa $ + */ + +#ifndef CT_MOLARITYIONICVPSSTP_H +#define CT_MOLARITYIONICVPSSTP_H + +#include "GibbsExcessVPSSTP.h" + +namespace Cantera { + + /** + * @ingroup thermoprops + */ + + /*! + * MolarityIonicVPSSTP is a derived class of ThermoPhase + * GibbsExcessVPSSTP that handles + * variable pressure standard state methods for calculating + * thermodynamic properties that are further based on + * expressing the Excess Gibbs free energy as a function of + * the mole fractions (or pseudo mole fractions) of the consitituents. + * This category is the workhorse for describing ionic systems which are not on the molality scale. + * + * This class adds additional functions onto the %ThermoPhase interface + * that handles the calculation of the excess Gibbs free energy. The %ThermoPhase + * class includes a member function, ThermoPhase::activityConvention() + * that indicates which convention the activities are based on. The + * default is to assume activities are based on the molar convention. + * That default is used here. + * + * All of the Excess Gibbs free energy formulations in this area employ + * symmetrical formulations. + * + * This layer will massage the mole fraction vector to implement + * cation and anion based mole numbers in an optional manner, such that + * it is expected that there exists a charge balance at all times. + * One of the ions must be a "special ion" in the sense that its' thermodynamic + * functions are set to zero, and the thermo functions of all other + * ions are based on a valuation relative to that special ion. + * + */ + class MolarityIonicVPSSTP : public GibbsExcessVPSSTP { + + public: + + /// Constructors + /*! + * This doesn't do much more than initialize constants with + * default values for water at 25C. Water molecular weight + * comes from the default elements.xml file. It actually + * differs slightly from the IAPWS95 value of 18.015268. However, + * density conservation and therefore element conservation + * is the more important principle to follow. + */ + MolarityIonicVPSSTP(); + + //! Construct and initialize a MolarityIonicVPSSTP ThermoPhase object + //! directly from an xml input file + /*! + * Working constructors + * + * The two constructors below are the normal way the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the XML database to get the info for the phase. + * + * @param inputFile Name of the input file containing the phase XML data + * to set up the object + * @param id ID of the phase in the input file. Defaults to the + * empty string. + */ + MolarityIonicVPSSTP(std::string inputFile, std::string id = ""); + + //! Construct and initialize a MolarityIonicVPSSTP ThermoPhase object + //! directly from an XML database + /*! + * @param phaseRef XML phase node containing the description of the phase + * @param id id attribute containing the name of the phase. + * (default is the empty string) + */ + MolarityIonicVPSSTP(XML_Node& phaseRef, std::string id = ""); + + + //! Copy constructor + /*! + * Note this stuff will not work until the underlying phase + * has a working copy constructor + * + * @param b class to be copied + */ + MolarityIonicVPSSTP(const MolarityIonicVPSSTP&b); + + /// Assignment operator + /*! + * + * @param b class to be copied. + */ + MolarityIonicVPSSTP& operator=(const MolarityIonicVPSSTP&b); + + /// Destructor. + virtual ~MolarityIonicVPSSTP(); + + //! Duplication routine for objects which inherit from ThermoPhase. + /*! + * This virtual routine can be used to duplicate thermophase objects + * inherited from ThermoPhase even if the application only has + * a pointer to ThermoPhase to work with. + */ + virtual ThermoPhase *duplMyselfAsThermoPhase() const; + + /** + * + * @name Utilities + * @{ + */ + + + //! Equation of state type flag. + /*! + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The MolalityVPSSTP class also returns + * zero, as it is a non-complete class. + */ + virtual int eosType() const; + + //! Initialization of a phase using an xml file + /*! + * This routine is a precursor to + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); + + //! Import and initialize a phase + //! specification in an XML tree into the current object. + /*! + * Here we read an XML description of the phase. + * We import descriptions of the elements that make up the + * species in a phase. + * We import information about the species, including their + * reference state thermodynamic polynomials. We then freeze + * the state of the species. + * + * Then, we read the species molar volumes from the xml + * tree to finish the initialization. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Molar Thermodynamic Properties + * @{ + */ + + + /** + * @} + * @name Utilities for Solvent ID and Molality + * @{ + */ + + + + + /** + * @} + * @name Mechanical Properties + * @{ + */ + + /** + * @} + * @name Potential Energy + * + * Species may have an additional potential energy due to the + * presence of external gravitation or electric fields. These + * methods allow specifying a potential energy for individual + * species. + * @{ + */ + + /** + * @} + * @name Activities, Standard States, and Activity Concentrations + * + * The activity \f$a_k\f$ of a species in solution is + * related to the chemical potential by \f[ \mu_k = \mu_k^0(T) + * + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is + * the chemical potential at unit activity, which depends only + * on temperature and pressure. + * @{ + */ + + //! Get the array of non-dimensional molar-based ln activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param lnac Output vector of ln activity coefficients. Length: m_kk. + */ + virtual void getLnActivityCoefficients(doublereal* ac) const; + + //@} + /// @name Partial Molar Properties of the Solution + //@{ + + //! Get the species chemical potentials. Units: J/kmol. + /*! + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ + virtual void getChemPotentials(doublereal* mu) const; + + /** + * Get the species electrochemical potentials. + * These are partial molar quantities. + * This method adds a term \f$ Fz_k \phi_k \f$ to the + * to each chemical potential. + * + * Units: J/kmol + * + * @param mu output vector containing the species electrochemical potentials. + * Length: m_kk. + */ + void getElectrochemPotentials(doublereal* mu) const; + + //! Returns an array of partial molar enthalpies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * @param hbar Vector of returned partial molar enthalpies + * (length m_kk, units = J/kmol) + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * @param sbar Vector of returned partial molar entropies + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????????? + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * ??????????????? + * \f] + * + * @param cpbar Vector of returned partial molar heat capacities + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + //! Return an array of partial molar volumes for the + //! species in the mixture. Units: m^3/kmol. + /*! + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + + //@} + /// @name Properties of the Standard State of the Species in the Solution + //@{ + + + + //@} + /// @name Thermodynamic Values for the Species Reference States + //@{ + + + /////////////////////////////////////////////////////// + // + // The methods below are not virtual, and should not + // be overloaded. + // + ////////////////////////////////////////////////////// + + /** + * @name Specific Properties + * @{ + */ + + + /** + * @name Setting the State + * + * These methods set all or part of the thermodynamic + * state. + * @{ + */ + + //! Calculate pseudo binary mole fractions + /*! + * + */ + virtual void calcPseudoBinaryMoleFractions() const; + + + //@} + + /** + * @name Chemical Equilibrium + * Routines that implement the Chemical equilibrium capability + * for a single phase, based on the element-potential method. + * @{ + */ + + + + //@} + + + + /// The following methods are used in the process of constructing + /// the phase and setting its parameters from a specification in an + /// input file. They are not normally used in application programs. + /// To see how they are used, see files importCTML.cpp and + /// ThermoFactory.cpp. + + + /*! + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + + /** + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void initThermoXML(XML_Node& phaseNode, std::string id); + + + //! returns a summary of the state of the phase as a string + /*! + * @param show_thermo If true, extra information is printed out + * about the thermodynamic state of the system. + */ + virtual std::string report(bool show_thermo = true) const; + + + private: + + + //! Initialize lengths of local variables after all species have been identified. + void initLengths(); + + //! Process an XML node called "binaryNeutralSpeciesParameters" + /*! + * This node contains all of the parameters necessary to describe + * the Redlich-Kister model for a particular binary interaction. + * This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + * + * @param xmlBinarySpecies Reference to the XML_Node named "binaryNeutralSpeciesParameters" + * containing the binary interaction + */ + void readXMLBinarySpecies(XML_Node &xmlBinarySpecies); + + + //! Update the activity coefficients + /*! + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + */ + void s_update_lnActCoeff() const; + + //! Update the derivative of the log of the activity coefficients wrt T + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt temperature. + */ + void s_update_dlnActCoeff_dT() const; + + //! Internal routine that calculates the derivative of the activity coefficients wrt + //! the mole fractions. + /*! + * This routine calculates the the derivative of the activity coefficients wrt to mole fraction + * with all other mole fractions held constant. This is strictly not permitted. However, if the + * resulting matrix is multiplied by a permissible deltaX vector then everything is ok. + * + * This is the natural way to handle concentration derivatives in this routine. + */ + void s_update_dlnActCoeff_dX_() const; + + + private: + //! Error function + /*! + * Print an error string and exit + * + * @param msg Message to be printed + */ + doublereal err(std::string msg) const; + + protected: + + // Pseudobinary type + /*! + * PBTYPE_PASSTHROUGH All species are passthrough species + * PBTYPE_SINGLEANION there is only one anion in the mixture + * PBTYPE_SINGLECATION there is only one cation in the mixture + * PBTYPE_MULTICATIONANION Complex mixture + */ + int PBType_; + + //! Number of pseudo binary species + int numPBSpecies_; + + //! index of special species + int indexSpecialSpecies_; + + mutable std::vector PBMoleFractions_; + + //! Vector of cation indecises in the mixture + std::vector cationList_; + + //! Number of cations in the mixture + int numCationSpecies_; + + std::vector anionList_; + int numAnionSpecies_; + + std::vector passThroughList_; + int numPassThroughSpecies_; + int neutralPBindexStart; + + + mutable std::vector moleFractionsTmp_; + + private: + + + }; + +#define PBTYPE_PASSTHROUGH 0 +#define PBTYPE_SINGLEANION 1 +#define PBTYPE_SINGLECATION 2 +#define PBTYPE_MULTICATIONANION 3 + + + +} + +#endif + + + + + diff --git a/Cantera/src/thermo/NasaThermo.h b/Cantera/src/thermo/NasaThermo.h index 46cf02a71..95bbe4777 100644 --- a/Cantera/src/thermo/NasaThermo.h +++ b/Cantera/src/thermo/NasaThermo.h @@ -155,7 +155,7 @@ namespace Cantera { * parameterization. * @see speciesThermoTypes.h */ - virtual void install(string name, int index, int type, + virtual void install(std::string name, int index, int type, const doublereal* c, doublereal minTemp, doublereal maxTemp, doublereal refPressure) { @@ -164,7 +164,7 @@ namespace Cantera { int imid = int(c[0]); // midpoint temp converted to integer int igrp = m_index[imid]; // has this value been seen before? if (igrp == 0) { // if not, prepare new group - vector v; + std::vector v; m_high.push_back(v); m_low.push_back(v); m_tmid.push_back(c[0]); @@ -209,11 +209,12 @@ namespace Cantera { if (m_p0 < 0.0) { m_p0 = refPressure; } else if (fabs(m_p0 - refPressure) > 0.1) { - string logmsg = " WARNING NasaThermo: New Species, " + name + ", has a different reference pressure, " + std::string logmsg = " ERROR NasaThermo: New Species, " + name + ", has a different reference pressure, " + fp2str(refPressure) + ", than existing reference pressure, " + fp2str(m_p0) + "\n"; writelog(logmsg); - logmsg = " This may become a fatal error in the future \n"; + logmsg = " This is now a fatal error\n"; writelog(logmsg); + throw CanteraError("install()", "species have different reference pressures"); } m_p0 = refPressure; } @@ -253,14 +254,14 @@ namespace Cantera { int grp = m_group_map[k]; int pos = m_posInGroup_map[k]; - const vector &mlg = m_low[grp-1]; + const std::vector &mlg = m_low[grp-1]; const NasaPoly1 *nlow = &(mlg[pos]); doublereal tmid = nlow->maxTemp(); if (t < tmid) { nlow->updateProperties(&m_t[0], cp_R, h_RT, s_R); } else { - const vector &mhg = m_high[grp-1]; + const std::vector &mhg = m_high[grp-1]; const NasaPoly1 *nhigh = &(mhg[pos]); nhigh->updateProperties(&m_t[0], cp_R, h_RT, s_R); } @@ -294,7 +295,7 @@ namespace Cantera { m_t[5] = log(t); // iterate over the groups - vector::const_iterator _begin, _end; + std::vector::const_iterator _begin, _end; for (i = 0; i != m_ngroups; i++) { if (t > m_tmid[i]) { _begin = m_high[i].begin(); @@ -391,8 +392,8 @@ namespace Cantera { if (type == NASA) { int grp = m_group_map[index]; int pos = m_posInGroup_map[index]; - const vector &mlg = m_low[grp-1]; - const vector &mhg = m_high[grp-1]; + const std::vector &mlg = m_low[grp-1]; + const std::vector &mhg = m_high[grp-1]; const NasaPoly1 *lowPoly = &(mlg[pos]); const NasaPoly1 *highPoly = &(mhg[pos]); int itype = NASA; @@ -439,8 +440,8 @@ namespace Cantera { if (type == NASA) { int grp = m_group_map[index]; int pos = m_posInGroup_map[index]; - vector &mlg = m_low[grp-1]; - vector &mhg = m_high[grp-1]; + std::vector &mlg = m_low[grp-1]; + std::vector &mhg = m_high[grp-1]; NasaPoly1 *lowPoly = &(mlg[pos]); NasaPoly1 *highPoly = &(mhg[pos]); doublereal tmid = lowPoly->maxTemp(); @@ -460,14 +461,14 @@ namespace Cantera { int grp = m_group_map[k]; int pos = m_posInGroup_map[k]; - const vector &mlg = m_low[grp-1]; + const std::vector &mlg = m_low[grp-1]; const NasaPoly1 *nlow = &(mlg[pos]); doublereal tmid = nlow->maxTemp(); double h; if (298.15 <= tmid) { h = nlow->reportHf298(0); } else { - const vector &mhg = m_high[grp-1]; + const std::vector &mhg = m_high[grp-1]; const NasaPoly1 *nhigh = &(mhg[pos]); h = nhigh->reportHf298(0); } @@ -477,9 +478,9 @@ namespace Cantera { virtual void modifyOneHf298(const int k, const doublereal Hf298New) { int grp = m_group_map[k]; int pos = m_posInGroup_map[k]; - vector &mlg = m_low[grp-1]; + std::vector &mlg = m_low[grp-1]; NasaPoly1 *nlow = &(mlg[pos]); - vector &mhg = m_high[grp-1]; + std::vector &mhg = m_high[grp-1]; NasaPoly1 *nhigh = &(mhg[pos]); doublereal tmid = nlow->maxTemp(); @@ -508,7 +509,7 @@ namespace Cantera { * The second vector is equal to the number of species * in that particular group. */ - vector > m_high; + std::vector > m_high; //! Vector of vector of NasaPoly1's for the low temp region. /*! @@ -517,13 +518,13 @@ namespace Cantera { * The second vector is equal to the number of species * in that particular group. */ - vector > m_low; + std::vector > m_low; //! Map between the midpoint temperature, as an int, to the group number /*! * Length is equal to the number of groups. Only used in the setup. */ - map m_index; + std::map m_index; //! Vector of log temperature limits /*! @@ -567,17 +568,17 @@ namespace Cantera { * for that species are stored. group indecises start at 1, * so a decrement is always performed to access vectors. */ - mutable map m_group_map; + mutable std::map m_group_map; /*! * This map takes as its index, the species index in the phase. * It returns the position index within the group, where the * temperature polynomials for that species are storred. */ - mutable map m_posInGroup_map; + mutable std::map m_posInGroup_map; //! Species name as a function of the species index - mutable map m_name; + mutable std::map m_name; private: diff --git a/Cantera/src/thermo/PDSS_ConstVol.cpp b/Cantera/src/thermo/PDSS_ConstVol.cpp index 6bd07eac0..c5e33b749 100644 --- a/Cantera/src/thermo/PDSS_ConstVol.cpp +++ b/Cantera/src/thermo/PDSS_ConstVol.cpp @@ -119,7 +119,7 @@ namespace Cantera { "standardState model for species isn't constant_incompressible: " + speciesNode.name()); } - m_constMolarVolume = getFloat(*ss, "molarVolume", "toSI"); + m_constMolarVolume = ctml::getFloat(*ss, "molarVolume", "toSI"); std::string id = ""; // initThermoXML(phaseNode, id); diff --git a/Cantera/src/thermo/PDSS_HKFT.cpp b/Cantera/src/thermo/PDSS_HKFT.cpp index 1ba20f27f..224c08d0a 100644 --- a/Cantera/src/thermo/PDSS_HKFT.cpp +++ b/Cantera/src/thermo/PDSS_HKFT.cpp @@ -24,6 +24,7 @@ #include using namespace std; +using namespace ctml; namespace Cantera { diff --git a/Cantera/src/thermo/PDSS_IonsFromNeutral.cpp b/Cantera/src/thermo/PDSS_IonsFromNeutral.cpp index 28fa361de..2bf67b6a3 100644 --- a/Cantera/src/thermo/PDSS_IonsFromNeutral.cpp +++ b/Cantera/src/thermo/PDSS_IonsFromNeutral.cpp @@ -24,10 +24,8 @@ using namespace std; namespace Cantera { - /** - * Basic list of constructors and duplicators - */ - + + //==================================================================================================================== PDSS_IonsFromNeutral::PDSS_IonsFromNeutral(VPStandardStateTP *tp, int spindex) : PDSS(tp, spindex), neutralMoleculePhase_(0), @@ -128,15 +126,27 @@ namespace Cantera { neutralMoleculePhase_ = ionPhase->neutralMoleculePhase_; } //==================================================================================================================== - /** - * constructPDSSXML: + // Initialization of a PDSS object using an xml tree + /* + * This routine is a driver for the initialization of the + * object. + * + * basic logic: + * initThermo() (cascade) + * getStuff from species Part of XML file + * initThermoXML(phaseNode) (cascade) + * + * @param vptp_ptr Pointer to the Variable pressure %ThermoPhase object + * This object must have already been malloced. * - * Initialization of a PDSS_IonsFromNeutral object using an - * xml file. - - * @param id Optional parameter identifying the name of the - * phase. If none is given, the first XML - * phase element will be used. + * @param spindex Species index within the phase + * + * @param phaseNode Reference to the phase Information for the phase + * that owns this species. + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. */ void PDSS_IonsFromNeutral::constructPDSSXML(VPStandardStateTP *tp, int spindex, const XML_Node& speciesNode, @@ -195,7 +205,25 @@ namespace Cantera { } //==================================================================================================================== - + // Initialization of a PDSS object using an + // input XML file. + /* + * + * This routine is a precursor to constructPDSSXML(XML_Node*) + * routine, which does most of the work. + * + * @param vptp_ptr Pointer to the Variable pressure %ThermoPhase object + * This object must have already been malloced. + * + * @param spindex Species index within the phase + * + * @param inputFile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ void PDSS_IonsFromNeutral::constructPDSSFile(VPStandardStateTP *tp, int spindex, std::string inputFile, std::string id) { @@ -233,11 +261,11 @@ namespace Cantera { constructPDSSXML(tp, spindex, *s, *fxml_phase, id); delete fxml; } - + //======================================================================================================= void PDSS_IonsFromNeutral::initThermoXML(const XML_Node& phaseNode, std::string &id) { PDSS::initThermoXML(phaseNode, id); } - + //======================================================================================================= void PDSS_IonsFromNeutral::initThermo() { PDSS::initThermo(); SpeciesThermo &sp = m_tp->speciesThermo(); @@ -245,8 +273,8 @@ namespace Cantera { m_minTemp = m_spthermo->minTemp(m_spindex); m_maxTemp = m_spthermo->maxTemp(m_spindex); } - - /** + //======================================================================================================= + /* * Return the molar enthalpy in units of J kmol-1 */ doublereal @@ -255,7 +283,7 @@ namespace Cantera { doublereal RT = GasConstant * m_temp; return (val * RT); } - + //======================================================================================================= doublereal PDSS_IonsFromNeutral::enthalpy_RT() const { neutralMoleculePhase_->getEnthalpy_RT(DATA_PTR(tmpNM)); @@ -266,9 +294,8 @@ namespace Cantera { } return val; } - - - /** + //======================================================================================================= + /* * Calculate the internal energy in mks units of * J kmol-1 */ @@ -278,8 +305,8 @@ namespace Cantera { doublereal RT = GasConstant * m_temp; return (val * RT); } - - /** + //======================================================================================================= + /* * Calculate the entropy in mks units of * J kmol-1 K-1 */ @@ -288,7 +315,7 @@ namespace Cantera { doublereal val = entropy_R(); return (val * GasConstant); } - + //======================================================================================================= doublereal PDSS_IonsFromNeutral::entropy_R() const { neutralMoleculePhase_->getEntropy_R(DATA_PTR(tmpNM)); @@ -302,8 +329,8 @@ namespace Cantera { } return val; } - - /** + //======================================================================================================= + /* * Calculate the Gibbs free energy in mks units of * J kmol-1 K-1. */ @@ -313,7 +340,7 @@ namespace Cantera { doublereal RT = GasConstant * m_temp; return (val * RT); } - + //======================================================================================================= doublereal PDSS_IonsFromNeutral::gibbs_RT() const { neutralMoleculePhase_->getGibbs_RT(DATA_PTR(tmpNM)); @@ -327,8 +354,8 @@ namespace Cantera { } return val; } - - /** + //======================================================================================================= + /* * Calculate the constant pressure heat capacity * in mks units of J kmol-1 K-1 */ @@ -337,7 +364,7 @@ namespace Cantera { doublereal val = cp_R(); return (val * GasConstant); } - + //======================================================================================================= doublereal PDSS_IonsFromNeutral::cp_R() const { neutralMoleculePhase_->getCp_R(DATA_PTR(tmpNM)); @@ -348,7 +375,7 @@ namespace Cantera { } return val; } - + //======================================================================================================= doublereal PDSS_IonsFromNeutral::molarVolume() const { neutralMoleculePhase_->getStandardVolumes(DATA_PTR(tmpNM)); @@ -359,8 +386,7 @@ namespace Cantera { } return val; } - - + //======================================================================================================= doublereal PDSS_IonsFromNeutral::density() const { return (m_pres * m_mw / (GasConstant * m_temp)); @@ -375,7 +401,7 @@ namespace Cantera { throw CanteraError("PDSS_IonsFromNeutral::cv_mole()", "unimplemented"); return 0.0; } - + //==================================================================================================================== doublereal PDSS_IonsFromNeutral::gibbs_RT_ref() const { @@ -390,7 +416,7 @@ namespace Cantera { } return val; } - + //==================================================================================================================== doublereal PDSS_IonsFromNeutral::enthalpy_RT_ref() const { neutralMoleculePhase_->getEnthalpy_RT_ref(DATA_PTR(tmpNM)); doublereal val = 0.0; @@ -400,7 +426,7 @@ namespace Cantera { } return val; } - + //==================================================================================================================== doublereal PDSS_IonsFromNeutral::entropy_R_ref() const { neutralMoleculePhase_->getEntropy_R_ref(DATA_PTR(tmpNM)); doublereal val = 0.0; @@ -413,7 +439,7 @@ namespace Cantera { } return val; } - + //==================================================================================================================== doublereal PDSS_IonsFromNeutral::cp_R_ref() const { neutralMoleculePhase_->getCp_R_ref(DATA_PTR(tmpNM)); doublereal val = 0.0; @@ -423,7 +449,7 @@ namespace Cantera { } return val; } - + //==================================================================================================================== doublereal PDSS_IonsFromNeutral::molarVolume_ref() const { neutralMoleculePhase_->getStandardVolumes_ref(DATA_PTR(tmpNM)); doublereal val = 0.0; @@ -433,7 +459,7 @@ namespace Cantera { } return val; } - + //==================================================================================================================== /* * Calculate the pressure (Pascals), given the temperature and density * Temperature: kelvin @@ -442,31 +468,31 @@ namespace Cantera { doublereal PDSS_IonsFromNeutral::pressure() const { return m_pres; } - + //==================================================================================================================== void PDSS_IonsFromNeutral::setPressure(doublereal p) { m_pres = p; neutralMoleculePhase_->setPressure(p); } - - /// critical temperature + //==================================================================================================================== + // critical temperature doublereal PDSS_IonsFromNeutral::critTemperature() const { throw CanteraError("PDSS_IonsFromNeutral::critTemperature()", "unimplemented"); return (0.0); } - - /// critical pressure + //==================================================================================================================== + // critical pressure doublereal PDSS_IonsFromNeutral::critPressure() const { throw CanteraError("PDSS_IonsFromNeutral::critPressure()", "unimplemented"); return (0.0); } - - /// critical density + //==================================================================================================================== + // critical density doublereal PDSS_IonsFromNeutral::critDensity() const { throw CanteraError("PDSS_IonsFromNeutral::critDensity()", "unimplemented"); return (0.0); } - + //==================================================================================================================== /* * Return the temperature @@ -478,29 +504,30 @@ namespace Cantera { m_temp = m_vpssmgr_ptr->temperature(); return m_temp; } - + //==================================================================================================================== void PDSS_IonsFromNeutral::setTemperature(doublereal temp) { m_temp = temp; neutralMoleculePhase_->setTemperature(temp); } - + //==================================================================================================================== void PDSS_IonsFromNeutral::setState_TP(doublereal temp, doublereal pres) { m_pres = pres; m_temp = temp; neutralMoleculePhase_->setState_TP(temp, pres); } - + //==================================================================================================================== void PDSS_IonsFromNeutral::setState_TR(doublereal temp, doublereal rho) { neutralMoleculePhase_->setState_TR(temp, rho); } - - /// saturation pressure + //==================================================================================================================== + // saturation pressure doublereal PDSS_IonsFromNeutral::satPressure(doublereal t){ throw CanteraError("PDSS_IonsFromNeutral::satPressure()", "unimplemented"); /*NOTREACHED*/ return (0.0); } - + //==================================================================================================================== } +//==================================================================================================================== diff --git a/Cantera/src/thermo/PDSS_IonsFromNeutral.h b/Cantera/src/thermo/PDSS_IonsFromNeutral.h index 4b95fd6c2..06782b254 100644 --- a/Cantera/src/thermo/PDSS_IonsFromNeutral.h +++ b/Cantera/src/thermo/PDSS_IonsFromNeutral.h @@ -183,12 +183,21 @@ namespace Cantera { */ virtual doublereal gibbs_mole() const; - //! Return the molar gibbs free energy divided by RT + //! Return the molar gibbs free energy divided by RT /*! - * Returns the species standard state gibbs free energy divided by RT at the + * Returns the species standard state gibbs free energy divided by RT at the * current temperature and pressure. * - * @return returns the species standard state gibbs free energy divided by RT + * \f[ + * \frac{\mu^o_k}{RT} = \sum_{m}{ \alpha_{m , k} \frac{\mu^o_{m}}{RT}} + ( 1 - \delta_{k,sp}) 2.0 \ln{2.0} + * \f] + * + * m is the neutral molecule species index. \f$ \alpha_{m , k} \f$ is the stoiciometric + * coefficient for the neutral molecule, m, that creates the thermodynamics for the ionic species k. + * A factor \f$ 2.0 \ln{2.0} \f$ is added to all ions except for the species ionic species, which in this + * case is the single anion species, with species index sp. + * + * @return Returns the species standard state gibbs free energy divided by RT */ virtual doublereal gibbs_RT() const; @@ -388,10 +397,9 @@ namespace Cantera { void constructPDSSFile(VPStandardStateTP *vptp_ptr, int spindex, std::string inputFile, std::string id); - //!Initialization of a PDSS object using an xml tree + //! Initialization of a PDSS object using an xml tree /*! - * This routine is a driver for the initialization of the - * object. + * This routine is a driver for the initialization of the object. * * basic logic: * initThermo() (cascade) @@ -403,6 +411,9 @@ namespace Cantera { * * @param spindex Species index within the phase * + * @param speciesNode Reference to the phase Information for the species + * that this standard state refers to + * * @param phaseNode Reference to the phase Information for the phase * that owns this species. * @@ -461,16 +472,28 @@ namespace Cantera { ThermoPhase *neutralMoleculePhase_; public: + + //! Number of neutral molecule species that make up the stoichiometric vector for + //! this species, in terms of calculating thermodynamic functions int numMult_; + //! Vector of species indecises in the neutral molecule ThermoPhase std::vector idNeutralMoleculeVec; + //! Stoichiometric coefficient for this species using the Neutral Molecule Species + //! in the vector idNeutralMoleculeVec std::vector factorVec; + //! Add 2RTln2 to the entropy and Gibbs free energies for this species + /*! + * This is true if this species is not the special species + */ bool add2RTln2_; + //! Vector of length equal to the number of species in the neutral molecule phase mutable std::vector tmpNM; + //! True if this species is the special species int specialSpecies_; }; } diff --git a/Cantera/src/thermo/PDSS_SSVol.cpp b/Cantera/src/thermo/PDSS_SSVol.cpp index 4ca9cd46f..78cd4f3e5 100644 --- a/Cantera/src/thermo/PDSS_SSVol.cpp +++ b/Cantera/src/thermo/PDSS_SSVol.cpp @@ -131,17 +131,17 @@ namespace Cantera { std::string model = (*ss)["model"]; if (model == "constant_incompressible" || model == "constant") { volumeModel_ = cSSVOLUME_CONSTANT; - m_constMolarVolume = getFloat(*ss, "molarVolume", "toSI"); + m_constMolarVolume = ctml::getFloat(*ss, "molarVolume", "toSI"); } else if (model == "temperature_polynomial") { volumeModel_ = cSSVOLUME_TPOLY; - int num = getFloatArray(*ss, TCoeff_, true, "toSI", "volumeTemperaturePolynomial"); + int num = ctml::getFloatArray(*ss, TCoeff_, true, "toSI", "volumeTemperaturePolynomial"); if (num != 4) { throw CanteraError("PDSS_SSVol::constructPDSSXML", " Didn't get 4 density polynomial numbers for species " + speciesNode.name()); } } else if (model == "density_temperature_polynomial") { volumeModel_ = cSSVOLUME_DENSITY_TPOLY; - int num = getFloatArray(*ss, TCoeff_, true, "toSI", "densityTemperaturePolynomial"); + int num = ctml::getFloatArray(*ss, TCoeff_, true, "toSI", "densityTemperaturePolynomial"); if (num != 4) { throw CanteraError("PDSS_SSVol::constructPDSSXML", " Didn't get 4 density polynomial numbers for species " + speciesNode.name()); diff --git a/Cantera/src/thermo/Phase.cpp b/Cantera/src/thermo/Phase.cpp index 423aa8c24..8367ceb9d 100644 --- a/Cantera/src/thermo/Phase.cpp +++ b/Cantera/src/thermo/Phase.cpp @@ -137,6 +137,41 @@ namespace Cantera { m_index = m; } + // Returns the index of a species named 'name' within the Phase object + /* + * The first species in the phase will have an index 0, and the last one in the + * phase will have an index of nSpecies() - 1. + * + * + * A species name may be referred to via three methods: + * + * - "speciesName" + * - "PhaseId:speciesName" + * - "phaseName:speciesName" + * . + * + * The first two methods of naming may not yield a unique species within + * complicated assemblies of Cantera Phases. + * + * @param nameStr String name of the species. It may also be the phase name + * species name combination, separated by a colon. + * @return Returns the index of the species. If the name is not found, + * the value of -1 is returned. + */ + int Phase::speciesIndex(std::string nameStr) const { + std::string pn; + std::string sn = parseSpeciesName(nameStr, pn); + if (pn == "" || pn == m_name || pn == m_id) { + return Constituents::speciesIndex(sn); + } + return -1; + } + + std::string Phase::speciesSPName(int k) const { + std::string sn = Constituents::speciesName(k); + return(m_name + ":" + sn); + } + void Phase::saveState(vector_fp& state) const { state.resize(nSpecies() + 2); saveState(state.size(),&(state[0])); @@ -315,8 +350,8 @@ namespace Cantera { return State::moleFraction(k); } - doublereal Phase::moleFraction(std::string name) const { - int iloc = speciesIndex(name); + doublereal Phase::moleFraction(std::string nameSpec) const { + int iloc = speciesIndex(nameSpec); if (iloc >= 0) return State::moleFraction(iloc); else return 0.0; } @@ -325,8 +360,8 @@ namespace Cantera { return State::massFraction(k); } - doublereal Phase::massFraction(std::string name) const { - int iloc = speciesIndex(name); + doublereal Phase::massFraction(std::string nameSpec) const { + int iloc = speciesIndex(nameSpec); if (iloc >= 0) return massFractions()[iloc]; else return 0.0; } diff --git a/Cantera/src/thermo/Phase.h b/Cantera/src/thermo/Phase.h index 60c5ec06a..5163d6d42 100644 --- a/Cantera/src/thermo/Phase.h +++ b/Cantera/src/thermo/Phase.h @@ -22,7 +22,6 @@ #include "vec_functions.h" #include "ctml.h" -using namespace ctml; namespace Cantera { @@ -138,6 +137,37 @@ namespace Cantera { * vector, which is in general of length (2 + nSpecies()). The first * two entries of the state vector is temperature and density. * + * The class Phase contains two strings that identify a phase. + * The string id() is the value of the ID attribute of the XML phase node + * that is used to initialize a phase when it is read it. + * The id() field will stay that way even if the name is changed. + * The name field is also set to the value of the ID attribute of + * the XML phase node. + * + * However, the name field may be changed to another value during the course of a calculation. + * For example, if a phase is located in two places, but has the same + * constituitive input, the id's of the two phases will be the same, + * but the names of the two phases may be different. + * + * The name of a phase can be the same as the id of that same phase. + * Actually, this is the default and normal condition to have the name and + * the id for each phase to be the same. However, it is expected that + * it's an error to have two phases in a single problem with the same name. + * or the same id (or the name from one phase being the same as the id + * of another phase). + * Thus, it is expected that there is a 1-1 correspondence between + * names and unique phases within a Cantera problem. + * + * A species name may be referred to via three methods: + * + * - "speciesName" + * - "PhaseId:speciesName" + * - "phaseName:speciesName" + * . + * + * The first two methods of naming may not yield a unique species within + * complicated assemblies of Cantera Phases. + * * * @todo * Make the concept of saving state vectors more general, so that @@ -237,6 +267,39 @@ namespace Cantera { */ void setIndex(int m); + //! Returns the index of a species named 'name' within the Phase object + /*! + * The first species in the phase will have an index 0, and the last one in the + * phase will have an index of nSpecies() - 1. + * + * A species name may be referred to via three methods: + * + * - "speciesName" + * - "PhaseId:speciesName" + * - "phaseName:speciesName" + * . + * + * The first two methods of naming may not yield a unique species within + * complicated assemblies of Cantera phases. The last method is guarranteed + * to be unique within a collection of Cantera phases. + * + * @param name String name of the species. It may also be the phase name + * species name combination, separated by a colon. + * @return Returns the index of the species. If the name is not found, + * the value of -1 is returned. + */ + int speciesIndex(std::string name) const; + + //! Returns the expanded species name of a species, including the phase name + /*! + * Returns the expanded phase name species name string. + * This is guarranteed to be unique within a Cantera problem. + * + * @param k Species index within the phase + * @return Returns the "phaseName:speciesName" string + */ + std::string speciesSPName(int k) const; + //! Save the current internal state of the phase /*! * Write to vector 'state' the current internal state. @@ -530,12 +593,22 @@ namespace Cantera { //! ID of the phase. /*! * This is the value of the ID attribute of the XML phase node. + * The field will stay that way even if the name is changed. */ std::string m_id; //! Name of the phase. /*! * Initially, this is the value of the ID attribute of the XML phase node. + * + * It may be changed to another value during the course of a calculation. + * for example, if a phase is located in two places, but has the same + * constituitive input, the id's of the two phases will be the same, + * but the names of the two phases may be different. + * + * The name can be the same as the id, within a phase. However, besides + * that case, it is expected that there is a 1-1 correspondence between + * names and unique phases within a Cantera problem. */ std::string m_name; }; diff --git a/Cantera/src/thermo/PhaseCombo_Interaction.cpp b/Cantera/src/thermo/PhaseCombo_Interaction.cpp new file mode 100644 index 000000000..ef01eb6d7 --- /dev/null +++ b/Cantera/src/thermo/PhaseCombo_Interaction.cpp @@ -0,0 +1,1237 @@ +/** + * @file + * + */ +/* + * Copywrite (2009) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ +/* + * $Date: 2010-11-12 14:37:41 -0700 (Fri, 12 Nov 2010) $ + * $Revision: 641 $ + */ + + +#include "PhaseCombo_Interaction.h" +#include "ThermoFactory.h" +#include + +using namespace std; + +namespace Cantera { + + static const double xxSmall = 1.0E-150; + //==================================================================================================================== + /* + * Default constructor. + * + * HKM - Checked for Transition + */ + PhaseCombo_Interaction::PhaseCombo_Interaction() : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + } + //==================================================================================================================== + /* + * Working constructors + * + * The two constructors below are the normal way + * the phase initializes itself. They are shells that call\ + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + * + * HKM - Checked for Transition + */ + PhaseCombo_Interaction::PhaseCombo_Interaction(std::string inputFile, std::string id) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + constructPhaseFile(inputFile, id); + } + //==================================================================================================================== + // + /* + * + * HKM - Checked for Transition + */ + PhaseCombo_Interaction::PhaseCombo_Interaction(XML_Node& phaseRoot, std::string id) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + constructPhaseXML(phaseRoot, id); + } + + //==================================================================================================================== + /* + * Copy Constructor: + * + * Note this stuff will not work until the underlying phase + * has a working copy constructor + * + * HKM - Checked for Transition + */ + PhaseCombo_Interaction::PhaseCombo_Interaction(const PhaseCombo_Interaction &b) : + GibbsExcessVPSSTP() + { + PhaseCombo_Interaction::operator=(b); + } + //==================================================================================================================== + /* + * operator=() + * + * Note this stuff will not work until the underlying phase + * has a working assignment operator + * + * HKM - Checked for Transition + */ + PhaseCombo_Interaction& PhaseCombo_Interaction:: + operator=(const PhaseCombo_Interaction &b) { + if (&b == this) { + return *this; + } + + GibbsExcessVPSSTP::operator=(b); + + numBinaryInteractions_ = b.numBinaryInteractions_ ; + m_HE_b_ij = b.m_HE_b_ij; + m_HE_c_ij = b.m_HE_c_ij; + m_HE_d_ij = b.m_HE_d_ij; + m_SE_b_ij = b.m_SE_b_ij; + m_SE_c_ij = b.m_SE_c_ij; + m_SE_d_ij = b.m_SE_d_ij; + m_VHE_b_ij = b.m_VHE_b_ij; + m_VHE_c_ij = b.m_VHE_c_ij; + m_VHE_d_ij = b.m_VHE_d_ij; + m_VSE_b_ij = b.m_VSE_b_ij; + m_VSE_c_ij = b.m_VSE_c_ij; + m_VSE_d_ij = b.m_VSE_d_ij; + m_pSpecies_A_ij = b.m_pSpecies_A_ij; + m_pSpecies_B_ij = b.m_pSpecies_B_ij; + formMargules_ = b.formMargules_; + formTempModel_ = b.formTempModel_; + + return *this; + } + //==================================================================================================================== + /** + * + * ~PhaseCombo_Interaction(): (virtual) + * + * Destructor: does nothing: + * + * HKM - Checked for Transition + */ + PhaseCombo_Interaction::~PhaseCombo_Interaction() { + } + //==================================================================================================================== + /* + * This routine duplicates the current object and returnsa pointer to ThermoPhase. + * + * HKM - Checked for Transition + */ + ThermoPhase* + PhaseCombo_Interaction::duplMyselfAsThermoPhase() const { + PhaseCombo_Interaction* mtp = new PhaseCombo_Interaction(*this); + return (ThermoPhase *) mtp; + } + //==================================================================================================================== + // Special constructor for a hard-coded problem + /* + * + * LiKCl treating the PseudoBinary layer as passthrough. + * -> test to predict the eutectic and liquidus correctly. + * + */ + PhaseCombo_Interaction::PhaseCombo_Interaction(int testProb) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + formMargules_(0), + formTempModel_(0) + { + + + constructPhaseFile("PhaseCombo_Interaction.xml", ""); + + + numBinaryInteractions_ = 1; + + m_HE_b_ij.resize(1); + m_HE_c_ij.resize(1); + m_HE_d_ij.resize(1); + + m_SE_b_ij.resize(1); + m_SE_c_ij.resize(1); + m_SE_d_ij.resize(1); + + m_VHE_b_ij.resize(1); + m_VHE_c_ij.resize(1); + m_VHE_d_ij.resize(1); + + m_VSE_b_ij.resize(1); + m_VSE_c_ij.resize(1); + m_VSE_d_ij.resize(1); + + m_pSpecies_A_ij.resize(1); + m_pSpecies_B_ij.resize(1); + + + + m_HE_b_ij[0] = -17570E3; + m_HE_c_ij[0] = -377.0E3; + m_HE_d_ij[0] = 0.0; + + m_SE_b_ij[0] = -7.627E3; + m_SE_c_ij[0] = 4.958E3; + m_SE_d_ij[0] = 0.0; + + + int iLiT = speciesIndex("LiTFe1S2(S)"); + if (iLiT < 0) { + throw CanteraError("PhaseCombo_Interaction test1 constructor", + "Unable to find LiTFe1S2(S)"); + } + m_pSpecies_A_ij[0] = iLiT; + + + int iLi2 = speciesIndex("Li2Fe1S2(S)"); + if (iLi2 < 0) { + throw CanteraError("PhaseCombo_Interaction test1 constructor", + "Unable to find Li2Fe1S2(S)"); + } + m_pSpecies_B_ij[0] = iLi2; + throw CanteraError("", "unimplemented"); + } + //==================================================================================================================== + + /* + * -------------- Utilities ------------------------------- + */ + + + // Equation of state type flag. + /* + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The PhaseCombo_Interaction class also returns + * zero, as it is a non-complete class. + */ + int PhaseCombo_Interaction::eosType() const { + return cPhaseCombo_Interaction; + } + //==================================================================================================================== + /* + * Import, construct, and initialize a phase + * specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::constructPhaseFile(std::string inputFile, std::string id) { + + if ((int) inputFile.size() == 0) { + throw CanteraError("PhaseCombo_Interaction:constructPhaseFile", + "input file is null"); + } + string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("PhaseCombo_Interaction:constructPhaseFile", + "Could not open " +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("PhaseCombo_Interaction:constructPhaseFile", + "ERROR: Can not find phase named " + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; + } + //==================================================================================================================== + /* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * Most of the work is carried out by the cantera base + * routine, importPhase(). That routine imports all of the + * species and element data, including the standard states + * of the species. + * + * Then, In this routine, we read the information + * particular to the specification of the activity + * coefficient model for the Pitzer parameterization. + * + * We also read information about the molar volumes of the + * standard states if present in the XML file. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::constructPhaseXML(XML_Node& phaseNode, std::string id) { + string stemp; + if ((int) id.size() > 0) { + string idp = phaseNode.id(); + if (idp != id) { + throw CanteraError("PhaseCombo_Interaction::constructPhaseXML", + "phasenode and Id are incompatible"); + } + } + + /* + * Find the Thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("PhaseCombo_Interaction::constructPhaseXML", + "no thermo XML node"); + } + XML_Node& thermoNode = phaseNode.child("thermo"); + + /* + * Make sure that the thermo model is PhaseCombo_Interaction + */ + stemp = thermoNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "phasecombo_interaction") { + throw CanteraError("PhaseCombo_Interaction::constructPhaseXML", + "model name isn't PhaseCombo_Interaction: " + formString); + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the species standard states + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("PhaseCombo_Interaction::constructPhaseXML","importPhase failed "); + } + } + //==================================================================================================================== + /* + * ------------ Molar Thermodynamic Properties ---------------------- + */ + //==================================================================================================================== + /* + * - Activities, Standard States, Activity Concentrations ----------- + */ + //==================================================================================================================== + // Get the array of non-dimensional molar-based activity coefficients at + // the current solution temperature, pressure, and solution concentration. + /* + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + void PhaseCombo_Interaction::getActivityCoefficients(doublereal* ac) const { + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + + /* + * take the exp of the internally storred coefficients. + */ + for (int k = 0; k < m_kk; k++) { + ac[k] = exp(lnActCoeff_Scaled_[k]); + } + } + + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + + //==================================================================================================================== + + void PhaseCombo_Interaction::getElectrochemPotentials(doublereal* mu) const { + getChemPotentials(mu); + double ve = Faraday * electricPotential(); + for (int k = 0; k < m_kk; k++) { + mu[k] += ve*charge(k); + } + } + + //==================================================================================================================== + void PhaseCombo_Interaction::getChemPotentials(doublereal* mu) const { + doublereal xx; + /* + * First get the standard chemical potentials in + * molar form. + * -> this requires updates of standard state as a function + * of T and P + */ + getStandardChemPotentials(mu); + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + /* + * + */ + doublereal RT = GasConstant * temperature(); + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + mu[k] += RT * (log(xx) + lnActCoeff_Scaled_[k]); + } + } + //==================================================================================================================== + // Molar enthalpy. Units: J/kmol. + doublereal PhaseCombo_Interaction::enthalpy_mole() const { + int kk = nSpecies(); + double hbar[kk], h = 0; + getPartialMolarEnthalpies(hbar); + for (int i = 0; i < kk; i++){ + h += moleFractions_[i]*hbar[i]; + } + return h; + } + //==================================================================================================================== + // Molar entropy. Units: J/kmol. + doublereal PhaseCombo_Interaction::entropy_mole() const { + int kk = nSpecies(); + double sbar[kk], s = 0; + getPartialMolarEntropies(sbar); + for (int i = 0; i < kk; i++){ + s += moleFractions_[i]*sbar[i]; + } + return s; + } + //==================================================================================================================== + // Molar heat capacity at constant pressure. Units: J/kmol/K. + doublereal PhaseCombo_Interaction::cp_mole() const { + int kk = nSpecies(); + double cpbar[kk], cp = 0; + getPartialMolarCp(cpbar); + for (int i = 0; i < kk; i++){ + cp += moleFractions_[i]*cpbar[i]; + } + return cp; + } + //==================================================================================================================== + // Molar heat capacity at constant volume. Units: J/kmol/K. + doublereal PhaseCombo_Interaction::cv_mole() const { + return cp_mole() - GasConstant; + } + //==================================================================================================================== + // Returns an array of partial molar enthalpies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void PhaseCombo_Interaction::getPartialMolarEnthalpies(doublereal* hbar) const { + /* + * Get the nondimensional standard state enthalpies + */ + getEnthalpy_RT(hbar); + /* + * dimensionalize it. + */ + double T = temperature(); + double RT = GasConstant * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] *= RT; + } + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + double RTT = RT * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] -= RTT * dlnActCoeffdT_Scaled_[k]; + } + } + //==================================================================================================================== + // Returns an array of partial molar heat capacities for the species in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????? \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void PhaseCombo_Interaction::getPartialMolarCp(doublereal* cpbar) const { + /* + * Get the nondimensional standard state entropies + */ + getCp_R(cpbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + cpbar[k] *= GasConstant; + } + } + //==================================================================================================================== + // Returns an array of partial molar entropies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void PhaseCombo_Interaction::getPartialMolarEntropies(doublereal* sbar) const { + double xx; + /* + * Get the nondimensional standard state entropies + */ + getEntropy_R(sbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + sbar[k] += - lnActCoeff_Scaled_[k] - log(xx) - T * dlnActCoeffdT_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + sbar[k] *= GasConstant; + } + } + //==================================================================================================================== + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + + // Return an array of partial molar volumes for the species in the mixture. Units: m^3/kmol. + /* + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + void PhaseCombo_Interaction::getPartialMolarVolumes(doublereal* vbar) const { + + int iA, iB, iK, delAK, delBK; + double XA, XB, XK, g0 , g1; + double T = temperature(); + + /* + * Get the standard state values in m^3 kmol-1 + */ + getStandardVolumes(vbar); + + for ( iK = 0; iK < m_kk; iK++ ){ + delAK = 0; + delBK = 0; + XK = moleFractions_[iK]; + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_VHE_b_ij[i] - T * m_VSE_b_ij[i]); + g1 = (m_VHE_c_ij[i] - T * m_VSE_c_ij[i]); + + vbar[iK] += XA*XB*(g0+g1*XB)+((delAK-XA)*XB+XA*(delBK-XB))*(g0+g1*XB)+XA*XB*(delBK-XB)*g1; + } + } + } + //==================================================================================================================== + doublereal PhaseCombo_Interaction::err(std::string msg) const { + throw CanteraError("PhaseCombo_Interaction","Base class method " + +msg+" called. Equation of state type: "+int2str(eosType())); + return 0; + } + + //==================================================================================================================== + /* + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + void PhaseCombo_Interaction::initThermo() { + initLengths(); + GibbsExcessVPSSTP::initThermo(); + } + + //==================================================================================================================== + // Initialize lengths of local variables after all species have + // been identified. + void PhaseCombo_Interaction::initLengths() { + m_kk = nSpecies(); + dlnActCoeffdlnN_.resize(m_kk, m_kk); + } + //==================================================================================================================== + /* + * initThermoXML() (virtual from ThermoPhase) + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void PhaseCombo_Interaction::initThermoXML(XML_Node& phaseNode, std::string id) { + string subname = "PhaseCombo_Interaction::initThermoXML"; + string stemp; + + /* + * Check on the thermo field. Must have: + * + */ + + XML_Node& thermoNode = phaseNode.child("thermo"); + string mStringa = thermoNode.attrib("model"); + string mString = lowercase(mStringa); + if (mString != "phasecombo_interaction") { + throw CanteraError(subname.c_str(), "Unknown thermo model: " + mStringa); + } + + + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + XML_Node *acNodePtr = 0; + if (thermoNode.hasChild("activityCoefficients")) { + XML_Node& acNode = thermoNode.child("activityCoefficients"); + acNodePtr = &acNode; + string mStringa = acNode.attrib("model"); + string mString = lowercase(mStringa); + if (mString != "margules") { + throw CanteraError(subname.c_str(), + "Unknown activity coefficient model: " + mStringa); + } + int n = acNodePtr->nChildren(); + for (int i = 0; i < n; i++) { + XML_Node &xmlACChild = acNodePtr->child(i); + stemp = xmlACChild.name(); + string nodeName = lowercase(stemp); + /* + * Process a binary salt field, or any of the other XML fields + * that make up the Pitzer Database. Entries will be ignored + * if any of the species in the entry isn't in the solution. + */ + if (nodeName == "binaryneutralspeciesparameters") { + readXMLBinarySpecies(xmlACChild); + + } + } + } + + /* + * Go down the chain + */ + GibbsExcessVPSSTP::initThermoXML(phaseNode, id); + + + } + //=================================================================================================================== + // Update the activity coefficients + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + * he = X_A X_B(B + C X_B) + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::s_update_lnActCoeff() const { + int iA, iB, iK, delAK, delBK; + doublereal XA, XB, g0 , g1; + doublereal xx; + doublereal T = temperature(); + doublereal RT = GasConstant*T; + fvo_zero_dbl_1(lnActCoeff_Scaled_, m_kk); + + for (iK = 0; iK < m_kk; iK++) { + /* + * We never sample the end of the mole fraction domains + */ + xx = fmaxx(moleFractions_[iK], xxSmall); + /* + * First wipe out the ideal solution mixing term + */ + lnActCoeff_Scaled_[iK] = - log(xx); + + /* + * Then add in the Margules interaction terms. that's it! + */ + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + delAK = 0; + delBK = 0; + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + lnActCoeff_Scaled_[iK] += (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1; + } + } + } + //=================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt T + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + * he = X_A X_B(B + C X_B) + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::s_update_dlnActCoeff_dT() const { + int iA, iB, iK, delAK, delBK; + doublereal XA, XB, g0, g1; + doublereal T = temperature(); + doublereal RTT = GasConstant*T*T; + fvo_zero_dbl_1(dlnActCoeffdT_Scaled_, m_kk); + fvo_zero_dbl_1(d2lnActCoeffdT2_Scaled_, m_kk); + for (iK = 0; iK < m_kk; iK++) { + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + delAK = 0; + delBK = 0; + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + g0 = -m_HE_b_ij[i] / RTT; + g1 = -m_HE_c_ij[i] / RTT; + double temp = (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1; + dlnActCoeffdT_Scaled_[iK] += temp; + d2lnActCoeffdT2_Scaled_[iK] -= 2.0 * temp / T; + } + } + } + //==================================================================================================================== + // + /* + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::getdlnActCoeffdT(doublereal *dlnActCoeffdT) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k]; + } + } + //==================================================================================================================== + // + /* + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k]; + } + } + //==================================================================================================================== + + // Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + // a line in parameter space or along a line in physical space + /* + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const { + + + int iA, iB, iK, delAK, delBK; + doublereal XA, XB, XK, g0 , g1, dXA, dXB; + doublereal T = temperature(); + doublereal RT = GasConstant*T; + doublereal xx; + + //fvo_zero_dbl_1(dlnActCoeff, m_kk); + s_update_dlnActCoeff_dT(); + + for (iK = 0; iK < m_kk; iK++) { + + XK = moleFractions_[iK]; + + /* + * We never sample the end of the mole fraction domains + */ + xx = fmaxx(moleFractions_[iK], xxSmall); + /* + * First wipe out the ideal solution mixing term + */ + if (xx > xxSmall) { + dlnActCoeffds[iK] += - 1.0 / xx; + } + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0; + delBK = 0; + + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + dXA = dXds[iA]; + dXB = dXds[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffds[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB + + dlnActCoeffdT_Scaled_[iK]*dTds; + } + } + } + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt the log of the corresponding species number density + /* + * This function will be called to update the internally stored gradients of the + * logarithm of the activity coefficients. These are used in the determination + * of the diffusion coefficients. + * + * he = X_A X_B(B + C X_B) + * + * This function only carries out the diagonal calculation + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::s_update_dlnActCoeff_dlnN_diag() const { + int iA, iB, iK, delAK, delBK; + doublereal XA, XB, XK, g0 , g1; + doublereal T = temperature(); + doublereal RT = GasConstant*T; + doublereal xx; + + fvo_zero_dbl_1(dlnActCoeffdlnN_diag_, m_kk); + + for (iK = 0; iK < m_kk; iK++) { + + XK = moleFractions_[iK]; + /* + * We never sample the end of the mole fraction domains + */ + xx = fmaxx(moleFractions_[iK], xxSmall); + /* + * First wipe out the ideal solution mixing term + */ + // lnActCoeff_Scaled_[iK] = - log(xx); + if (xx > xxSmall) { + dlnActCoeffdlnN_diag_[iK] = - 1.0 + xx; + } + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0; + delBK = 0; + + if (iA==iK) delAK = 1; + else if (iB==iK) delBK = 1; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnN_diag_[iK] += 2*(delBK-XB)*(g0*(delAK-XA)+g1*(2*(delAK-XA)*XB+XA*(delBK-XB))); + } + dlnActCoeffdlnN_diag_[iK] = XK*dlnActCoeffdlnN_diag_[iK]; + } + + } + //==================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt ln N_k + /* + * This function will be called to update the internally storred gradients of the + * logarithm of the activity coefficients. These are used in the determination + * of the diffusion coefficients. + * + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::s_update_dlnActCoeff_dlnN() const { + int iA, iB; + doublereal delAK, delBK; + double XA, XB, g0 , g1, XK, XM; + double xx , delKM; + double T = temperature(); + double RT = GasConstant*T; + + doublereal delAM, delBM; + + dlnActCoeffdlnN_.zero(); + + /* + * Loop over the activity coefficient gamma_k + */ + for (int iK = 0; iK < m_kk; iK++) { + XK = moleFractions_[iK]; + /* + * We never sample the end of the mole fraction domains + */ + xx = fmaxx(moleFractions_[iK], xxSmall); + + for (int iM = 0; iM < m_kk; iM++) { + XM = moleFractions_[iM]; + + if (xx > xxSmall) { + delKM = 0.0; + if (iK == iM) delKM = 1.0; + // this gets multiplied by XM at the bottom + dlnActCoeffdlnN_(iK,iM) += - delKM/XM + 1.0; + } + + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + delAK = 0.0; + delBK = 0.0; + delAM = 0.0; + delBM = 0.0; + if (iA==iK) delAK = 1.0; + else if (iB==iK) delBK = 1.0; + if (iA==iM) delAM = 1.0; + else if (iB==iM) delBM = 1.0; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnN_(iK,iM) += g0*((delAM-XA)*(delBK-XB)+(delAK-XA)*(delBM-XB)); + dlnActCoeffdlnN_(iK,iM) += 2*g1*((delAM-XA)*(delBK-XB)*XB+(delAK-XA)*(delBM-XB)*XB+(delBM-XB)*(delBK-XB)*XA); + + } + dlnActCoeffdlnN_(iK,iM) = XM * dlnActCoeffdlnN_(iK,iM); + } + } + } + //==================================================================================================================== + void PhaseCombo_Interaction::s_update_dlnActCoeff_dlnX_diag() const { + + int iA, iB; + doublereal XA, XB, g0 , g1; + doublereal T = temperature(); + + fvo_zero_dbl_1(dlnActCoeffdlnX_diag_, m_kk); + + doublereal RT = GasConstant * T; + + + for (int i = 0; i < numBinaryInteractions_; i++) { + + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + + g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT; + g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT; + + dlnActCoeffdlnX_diag_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB); + dlnActCoeffdlnX_diag_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB); + } + throw CanteraError("", "unimplemented"); + } + + //==================================================================================================================== + // + /* + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + s_update_dlnActCoeff_dlnN_diag(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k]; + } + } + //==================================================================================================================== + // + /* + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const { + s_update_dlnActCoeff_dlnX_diag(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k]; + } + } + //==================================================================================================================== + // + /* + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::getdlnActCoeffdlnN(const int ld, doublereal *dlnActCoeffdlnN) { + s_update_dlnActCoeff_dlnN(); + double *data = & dlnActCoeffdlnN_(0,0); + for (int k = 0; k < m_kk; k++) { + for (int m = 0; m < m_kk; m++) { + dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m]; + } + } + } + //==================================================================================================================== + // + /* + * HKM - Checked for Transition + */ + void PhaseCombo_Interaction::resizeNumInteractions(const int num) { + numBinaryInteractions_ = num; + m_HE_b_ij.resize(num, 0.0); + m_HE_c_ij.resize(num, 0.0); + m_HE_d_ij.resize(num, 0.0); + m_SE_b_ij.resize(num, 0.0); + m_SE_c_ij.resize(num, 0.0); + m_SE_d_ij.resize(num, 0.0); + m_VHE_b_ij.resize(num, 0.0); + m_VHE_c_ij.resize(num, 0.0); + m_VHE_d_ij.resize(num, 0.0); + m_VSE_b_ij.resize(num, 0.0); + m_VSE_c_ij.resize(num, 0.0); + m_VSE_d_ij.resize(num, 0.0); + + m_pSpecies_A_ij.resize(num, -1); + m_pSpecies_B_ij.resize(num, -1); + } + //==================================================================================================================== + + /* + * Process an XML node called "binaryNeutralSpeciesParameters" + * This node contains all of the parameters necessary to describe + * the Margules Interaction for a single binary interaction + * This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + */ + void PhaseCombo_Interaction::readXMLBinarySpecies(XML_Node &xmLBinarySpecies) { + string xname = xmLBinarySpecies.name(); + if (xname != "binaryNeutralSpeciesParameters") { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", + "Incorrect name for processing this routine: " + xname); + } + double *charge = DATA_PTR(m_speciesCharge); + string stemp; + int nParamsFound; + vector_fp vParams; + string iName = xmLBinarySpecies.attrib("speciesA"); + if (iName == "") { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "no speciesA attrib"); + } + string jName = xmLBinarySpecies.attrib("speciesB"); + if (jName == "") { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "no speciesB attrib"); + } + /* + * Find the index of the species in the current phase. It's not + * an error to not find the species + */ + int iSpecies = speciesIndex(iName); + if (iSpecies < 0) { + return; + } + string ispName = speciesName(iSpecies); + if (charge[iSpecies] != 0) { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "speciesA charge problem"); + } + int jSpecies = speciesIndex(jName); + if (jSpecies < 0) { + return; + } + string jspName = speciesName(jSpecies); + if (charge[jSpecies] != 0) { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "speciesB charge problem"); + } + + resizeNumInteractions(numBinaryInteractions_ + 1); + int iSpot = numBinaryInteractions_ - 1; + m_pSpecies_A_ij[iSpot] = iSpecies; + m_pSpecies_B_ij[iSpot] = jSpecies; + + int num = xmLBinarySpecies.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = xmLBinarySpecies.child(iChild); + stemp = xmlChild.name(); + string nodeName = lowercase(stemp); + /* + * Process the binary species interaction child elements + */ + if (nodeName == "excessenthalpy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessEnthalpy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_HE_b_ij[iSpot] = vParams[0]; + m_HE_c_ij[iSpot] = vParams[1]; + } + + if (nodeName == "excessentropy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessEntropy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_SE_b_ij[iSpot] = vParams[0]; + m_SE_c_ij[iSpot] = vParams[1]; + } + + if (nodeName == "excessvolume_enthalpy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_VHE_b_ij[iSpot] = vParams[0]; + m_VHE_c_ij[iSpot] = vParams[1]; + } + + if (nodeName == "excessvolume_entropy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy"); + nParamsFound = vParams.size(); + + if (nParamsFound != 2) { + throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessVolume_Entropy for " + ispName + + "::" + jspName, + "wrong number of params found"); + } + m_VSE_b_ij[iSpot] = vParams[0]; + m_VSE_c_ij[iSpot] = vParams[1]; + } + + + } + } + //==================================================================================================================== +} +//====================================================================================================================== diff --git a/Cantera/src/thermo/PhaseCombo_Interaction.h b/Cantera/src/thermo/PhaseCombo_Interaction.h new file mode 100644 index 000000000..8e42709f5 --- /dev/null +++ b/Cantera/src/thermo/PhaseCombo_Interaction.h @@ -0,0 +1,978 @@ +/** + * @file PhaseCombo_Interaction.h + * Header for intermediate ThermoPhase object for phases which + * employ the Margules gibbs free energy formulation and eliminates the ideal mixing term. + * (see \ref thermoprops + * and class \link Cantera::PhaseCombo_Interaction PhaseCombo_Interaction\endlink). + */ +/* + * Copywrite (2011) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ + +/* + * $Author: hkmoffa $ + * $Date: 2009-11-09 16:36:49 -0700 (Mon, 09 Nov 2009) $ + * $Revision: 255 $ + */ + +#ifndef CT_PHASECOMBO_INTERACTION_H +#define CT_PHASECOMBO_INTERACTION_H + + +#include "GibbsExcessVPSSTP.h" + +namespace Cantera { + + /** + * @ingroup thermoprops + */ + + + + //! PhaseCombo_Interaction is a derived class of GibbsExcessVPSSTP that employs + //! the Margules approximation for the excess gibbs free energy while eliminating + //! the entropy of mixing term. + /*! + * + * %PhaseCombo_Interaction derives from class GibbsExcessVPSSTP which is derived from VPStandardStateTP, + * and overloads the virtual methods defined there with ones that + * use expressions appropriate for the Margules Excess gibbs free energy approximation. + * The reader should refer to the MargulesVPSSTP class for information on that class. + * This class in addition adds a term to the activity coefficient that eliminates the + * ideal solution mixing term within the chemical potential. This is a very radical thing + * to do, but it is supported by experimental evidence under some conditions. + * + * The independent unknowns are pressure, temperature, and mass fraction. + * + * Several concepts are introduced. The first concept is that there are temporary + * variables for holding the species standard state values of Cp, H, S, G, and V at the + * last temperature and pressure called. These functions are not recalculated + * if a new call is made using the previous temperature and pressure. Currently, + * these variables and the calculation method are handled by the VPSSMgr class, + * for which VPStandardStateTP owns a pointer to. + * + * To support the above functionality, pressure and temperature variables, + * m_plast_ss and m_tlast_ss, are kept which store the last pressure and temperature + * used in the evaluation of standard state properties. + * + * This class is introduced to represent specific conditions observed in thermal batteries. + * HOwever, it may be physically motivated to represent conditions where there may + * be a mixture of componds that are not "mixed" at the molecular level. Therefore, there + * is no mixing term. + * + * The lack of a mixing term has profound effects. First, the mole fraction of a species + * can now be identically zero due to thermodynamic considerations. The phase behaves more + * like a series of phases. That's why we named it PhaseCombo. + * + * + * + *
+ *

Specification of Species Standard %State Properties

+ *
+ * + * All species are defined to have standard states that depend upon both + * the temperature and the pressure. The Margules approximation assumes + * symmetric standard states, where all of the standard state assume + * that the species are in pure component states at the temperatue + * and pressure of the solution. I don't think it prevents, however, + * some species from being dilute in the solution. + * + * + *
+ *

Specification of Solution Thermodynamic Properties

+ *
+ * + * The molar excess Gibbs free energy is given by the following formula which is a sum over interactions i. + * Each of the interactions are binary interactions involving two of the species in the phase, denoted, Ai + * and Bi. + * This is the generalization of the Margules formulation for a phase + * that has more than 2 species. The second term in the excess gibbs free energy is a negation of the + * ideal solution's mixing term. + * + * \f[ + * G^E = \sum_i \left( H_{Ei} - T S_{Ei} \right) - \sum_i \left( n_i R T \ln{X_i} \right) + * \f] + * \f[ + * H^E_i = n X_{Ai} X_{Bi} \left( h_{o,i} + h_{1,i} X_{Bi} \right) + * \f] + * \f[ + * S^E_i = n X_{Ai} X_{Bi} \left( s_{o,i} + s_{1,i} X_{Bi} \right) + * \f] + * + * where n is the total moles in the solution. + * + * The activity of a species defined in the phase is given by an excess Gibbs free energy formulation. + * + * \f[ + * a_k = \gamma_k X_k + * \f] + * + * where + * + * \f[ + * R T \ln( \gamma_k )= \frac{d(n G^E)}{d(n_k)}\Bigg|_{n_i} + * \f] + * + * Taking the derivatives results in the following expression + * + * \f[ + * R T \ln( \gamma_k )= \sum_i \left( \left( \delta_{Ai,k} X_{Bi} + \delta_{Bi,k} X_{Ai} - X_{Ai} X_{Bi} \right) + * \left( g^E_{o,i} + g^E_{1,i} X_{Bi} \right) + + * \left( \delta_{Bi,k} - X_{Bi} \right) X_{Ai} X_{Bi} g^E_{1,i} \right) - RT \ln{X_k} + * \f] + * + * where + * \f$ g^E_{o,i} = h_{o,i} - T s_{o,i} \f$ and \f$ g^E_{1,i} = h_{1,i} - T s_{1,i} \f$ + * and where \f$ X_k \f$ is the mole fraction of species k. + * + * This object inherits from the class VPStandardStateTP. Therefore, the specification and + * calculation of all standard state and reference state values are handled at that level. Various functional + * forms for the standard state are permissible. + * The chemical potential for species k is equal to + * + * \f[ + * \mu_k(T,P) = \mu^o_k(T, P) + R T \ln(\gamma_k X_k) + * \f] + * + * The partial molar entropy for species k is given by the following relation, + * + * \f[ + * \tilde{s}_k(T,P) = s^o_k(T,P) - R \ln( \gamma_k X_k ) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * The partial molar enthalpy for species k is given by + * + * \f[ + * \tilde{h}_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * The partial molar volume for species k is + * + * \f[ + * \tilde V_k(T,P) = V^o_k(T,P) + R T \frac{d \ln(\gamma_k) }{dP} + * \f] + * + * The partial molar Heat Capacity for species k is + * + * \f[ + * \tilde{C}_{p,k}(T,P) = C^o_{p,k}(T,P) - 2 R T \frac{d \ln( \gamma_k )}{dT} + * - R T^2 \frac{d^2 \ln(\gamma_k) }{{dT}^2} + * \f] + * + * + *
+ *

%Application within %Kinetics Managers

+ *
+ * + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^s_k, \f$ where \f$ C^s_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) concentrations are used + * by kinetics manager classes to compute the forward and reverse rates of elementary reactions. + * The activity concentration,\f$ C^a_k \f$,is given by the following expression. + * + * \f[ + * C^a_k = C^s_k X_k = \frac{P}{R T} X_k + * \f] + * + * The standard concentration for species k is independent of k and equal to + * + * \f[ + * C^s_k = C^s = \frac{P}{R T} + * \f] + * + * For example, a bulk-phase binary gas reaction between species j and k, producing + * a new gas species l would have the + * following equation for its rate of progress variable, \f$ R^1 \f$, which has + * units of kmol m-3 s-1. + * + * \f[ + * R^1 = k^1 C_j^a C_k^a = k^1 (C^s a_j) (C^s a_k) + * \f] + * + * where + * + * \f[ + * C_j^a = C^s a_j \mbox{\quad and \quad} C_k^a = C^s a_k + * \f] + * + * \f$ C_j^a \f$ is the activity concentration of species j, and + * \f$ C_k^a \f$ is the activity concentration of species k. \f$ C^s \f$ + * is the standard concentration. \f$ a_j \f$ is + * the activity of species j which is equal to the mole fraction of j. + * + * The reverse rate constant can then be obtained from the law of microscopic reversibility + * and the equilibrium expression for the system. + * + * \f[ + * \frac{a_j a_k}{ a_l} = K_a^{o,1} = \exp(\frac{\mu^o_l - \mu^o_j - \mu^o_k}{R T} ) + * \f] + * + * \f$ K_a^{o,1} \f$ is the dimensionless form of the equilibrium constant, associated with + * the pressure dependent standard states \f$ \mu^o_l(T,P) \f$ and their associated activities, + * \f$ a_l \f$, repeated here: + * + * \f[ + * \mu_l(T,P) = \mu^o_l(T, P) + R T \log(a_l) + * \f] + * + * We can switch over to expressing the equilibrium constant in terms of the reference + * state chemical potentials + * + * \f[ + * K_a^{o,1} = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{P} + * \f] + * + * The concentration equilibrium constant, \f$ K_c \f$, may be obtained by changing over + * to activity concentrations. When this is done: + * + * \f[ + * \frac{C^a_j C^a_k}{ C^a_l} = C^o K_a^{o,1} = K_c^1 = + * \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{RT} + * \f] + * + * %Kinetics managers will calculate the concentration equilibrium constant, \f$ K_c \f$, + * using the second and third part of the above expression as a definition for the concentration + * equilibrium constant. + * + * For completeness, the pressure equilibrium constant may be obtained as well + * + * \f[ + * \frac{P_j P_k}{ P_l P_{ref}} = K_p^1 = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) + * \f] + * + * \f$ K_p \f$ is the simplest form of the equilibrium constant for ideal gases. However, it isn't + * necessarily the simplest form of the equilibrium constant for other types of phases; \f$ K_c \f$ is + * used instead because it is completely general. + * + * The reverse rate of progress may be written down as + * \f[ + * R^{-1} = k^{-1} C_l^a = k^{-1} (C^o a_l) + * \f] + * + * where we can use the concept of microscopic reversibility to + * write the reverse rate constant in terms of the + * forward reate constant and the concentration equilibrium + * constant, \f$ K_c \f$. + * + * \f[ + * k^{-1} = k^1 K^1_c + * \f] + * + * \f$k^{-1} \f$ has units of s-1. + * + * + *
+ *

Instantiation of the Class

+ *
+ * + * + * The constructor for this phase is located in the default ThermoFactory + * for %Cantera. A new %PhaseCombo_Interaction object may be created by the following code + * snippet: + * + * @code + * XML_Node *xc = get_XML_File("LiFeS_X_combo.xml"); + * XML_Node * const xs = xc->findNameID("phase", "LiFeS_X"); + * ThermoPhase *l_tp = newPhase(*xs); + * PhaseCombo_Interaction *LiFeS_X_solid = dynamic_cast (l_tp); + * @endcode + * + * or by the following code + * + * @code + * std::string id = "LiFeS_X"; + * Cantera::ThermoPhase *LiFeS_X_Phase = Cantera::newPhase("LiFeS_X_combo.xml", id); + * PhaseCombo_Interaction *LiFeS_X_solid = dynamic_cast (l_tp); + * @endcode + * + * + * or by the following constructor: + * + * @code + * XML_Node *xc = get_XML_File("LiFeS_X_combo.xml"); + * XML_Node * const xs = xc->findNameID("phase", "LiFeS_X"); + * PhaseCombo_Interaction *LiFeS_X_solid = new PhaseCombo_Interaction(*xs); + * @endcode + * + * + *
+ *

XML Example

+ *
+ * An example of an XML Element named phase setting up a PhaseCombo_Interaction + * object named LiFeS_X is given below. + * + * + * @verbatim + + + + Li Fe S + + + LiTFe1S2(S) Li2Fe1S2(S) + + + + + + 84.67069219, -269.1959421 + + + 100.7511565, -361.4222659 + + + 0, 0 + + + 0, 0 + + + + + + + + + @endverbatim + * + * The model attribute "PhaseCombo_Interaction" of the thermo XML element identifies the phase as + * being of the type handled by the PhaseCombo_Interaction object. + * + * @ingroup thermoprops + * + */ + class PhaseCombo_Interaction : public GibbsExcessVPSSTP { + + public: + + //! Constructor + /*! + * This doesn't do much more than initialize constants with + * default values for water at 25C. Water molecular weight + * comes from the default elements.xml file. It actually + * differs slightly from the IAPWS95 value of 18.015268. However, + * density conservation and therefore element conservation + * is the more important principle to follow. + */ + PhaseCombo_Interaction(); + + //! Construct and initialize a PhaseCombo_Interaction ThermoPhase object + //! directly from an xml input file + /*! + * Working constructors + * + * The two constructors below are the normal way + * the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + * + * @param inputFile Name of the input file containing the phase XML data + * to set up the object + * @param id ID of the phase in the input file. Defaults to the + * empty string. + */ + PhaseCombo_Interaction(std::string inputFile, std::string id = ""); + + //! Construct and initialize a PhaseCombo_Interaction ThermoPhase object + //! directly from an XML database + /*! + * @param phaseRef XML phase node containing the description of the phase + * @param id id attribute containing the name of the phase. + * (default is the empty string) + */ + PhaseCombo_Interaction(XML_Node& phaseRef, std::string id = ""); + + + //! Special constructor for a hard-coded problem + /*! + * + * @param testProb Hard-coded value. Only the value of 1 is + * used. It's for + * a LiKCl system + * -> test to predict the eutectic and liquidus correctly. + */ + PhaseCombo_Interaction(int testProb); + + //! Copy constructor + /*! + * Note this stuff will not work until the underlying phase + * has a working copy constructor + * + * @param b class to be copied + */ + PhaseCombo_Interaction(const PhaseCombo_Interaction& b); + + //! Assignment operator + /*! + * + * @param b class to be copied. + */ + PhaseCombo_Interaction& operator=(const PhaseCombo_Interaction &b); + + //! Destructor + virtual ~PhaseCombo_Interaction(); + + //! Duplication routine for objects which inherit from ThermoPhase. + /*! + * This virtual routine can be used to duplicate thermophase objects + * inherited from ThermoPhase even if the application only has + * a pointer to ThermoPhase to work with. + */ + virtual ThermoPhase *duplMyselfAsThermoPhase() const; + + /** + * + * @name Utilities + * @{ + */ + + + //! Equation of state type flag. + /*! + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The MolalityVPSSTP class also returns + * zero, as it is a non-complete class. + */ + virtual int eosType() const; + + //! Initialization of a phase using an xml file + /*! + * This routine is a precursor to + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); + + //! Import and initialize a phase + //! specification in an XML tree into the current object. + /*! + * Here we read an XML description of the phase. + * We import descriptions of the elements that make up the + * species in a phase. + * We import information about the species, including their + * reference state thermodynamic polynomials. We then freeze + * the state of the species. + * + * Then, we read the species molar volumes from the xml + * tree to finish the initialization. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Molar Thermodynamic Properties + * @{ + */ + + + /** + * @} + * @name Utilities for Solvent ID and Molality + * @{ + */ + + + + + /** + * @} + * @name Mechanical Properties + * @{ + */ + + /** + * @} + * @name Potential Energy + * + * Species may have an additional potential energy due to the + * presence of external gravitation or electric fields. These + * methods allow specifying a potential energy for individual + * species. + * @{ + */ + + /** + * @} + * @name Activities, Standard States, and Activity Concentrations + * + * The activity \f$a_k\f$ of a species in solution is + * related to the chemical potential by \f[ \mu_k = \mu_k^0(T) + * + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is + * the chemical potential at unit activity, which depends only + * on temperature and pressure. + * @{ + */ + + //! Get the array of non-dimensional molar-based activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + virtual void getActivityCoefficients(doublereal* ac) const; + + //@} + /// @name Partial Molar Properties of the Solution + //@{ + + //! Get the species chemical potentials. Units: J/kmol. + /*! + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ + virtual void getChemPotentials(doublereal* mu) const; + + /// Molar enthalpy. Units: J/kmol. + virtual doublereal enthalpy_mole() const; + + /// Molar entropy. Units: J/kmol. + virtual doublereal entropy_mole() const; + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + virtual doublereal cp_mole() const; + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + virtual doublereal cv_mole() const; + + //! Returns an array of partial molar enthalpies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * @param hbar Vector of returned partial molar enthalpies + * (length m_kk, units = J/kmol) + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * @param sbar Vector of returned partial molar entropies + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????????? + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * ??????????????? + * \f] + * + * @param cpbar Vector of returned partial molar heat capacities + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + + //! Return an array of partial molar volumes for the + //! species in the mixture. Units: m^3/kmol. + /*! + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //! Get the species electrochemical potentials. + /*! + * These are partial molar quantities. + * This method adds a term \f$ Fz_k \phi_k \f$ to the + * to each chemical potential. + * + * Units: J/kmol + * + * @param mu output vector containing the species electrochemical potentials. + * Length: m_kk., units = J/kmol + */ + void getElectrochemPotentials(doublereal* mu) const; + + //! Get the array of temperature second derivatives of the log activity coefficients + /*! + * This function is a virtual class, but it first appears in GibbsExcessVPSSTP + * class and derived classes from GibbsExcessVPSSTP. + * + * units = 1/Kelvin + * + * @param d2lnActCoeffdT2 Output vector of temperature 2nd derivatives of the + * log Activity Coefficients. length = m_kk + * + */ + virtual void getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const; + + //! Get the array of temperature derivatives of the log activity coefficients + /*! + * This function is a virtual class, but it first appears in GibbsExcessVPSSTP + * class and derived classes from GibbsExcessVPSSTP. + * + * units = 1/Kelvin + * + * @param dlnActCoeffdT Output vector of temperature derivatives of the + * log Activity Coefficients. length = m_kk + * + */ + virtual void getdlnActCoeffdT(doublereal *dlnActCoeffdT) const; + + + + //@} + /// @name Properties of the Standard State of the Species in the Solution + //@{ + + + + //@} + /// @name Thermodynamic Values for the Species Reference States + //@{ + + + + + + /// The following methods are used in the process of constructing + /// the phase and setting its parameters from a specification in an + /// input file. They are not normally used in application programs. + /// To see how they are used, see files importCTML.cpp and + /// ThermoFactory.cpp. + + + /*! + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + + /** + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void initThermoXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Derivatives of Thermodynamic Variables needed for Applications + * @{ + */ + + //! Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + //! a line in parameter space or along a line in physical space + /*! + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + virtual void getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, doublereal *dlnActCoeffds) const; + + //! Get the array of log concentration-like derivatives of the + //! log activity coefficients - diagonal component + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the mole fraction. + * + * units = dimensionless + * + * @param dlnActCoeffdlnX_diag Output vector of the diagonal component of the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const; + + //! Get the array of derivatives of the log activity coefficients wrt mole numbers - diagonal only + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. mole fraction, + * molality, etc.) that represents the standard state. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of the diagonal entries for the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const; + + + //! Get the array of derivatives of the log activity coefficients with respect to the ln species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * log of a species mole number (with all other species mole numbers held constant) + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN); + + //@} + + private: + + //! Process an XML node called "binaryNeutralSpeciesParameters" + /*! + * This node contains all of the parameters necessary to describe + * the Margules model for a particular binary interaction. + * This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + * + * @param xmlBinarySpecies Reference to the XML_Node named "binaryNeutralSpeciesParameters" + * containing the binary interaction + */ + void readXMLBinarySpecies(XML_Node &xmlBinarySpecies); + + //! Resize internal arrays within the object that depend upon the number + //! of binary Margules interaction terms + /*! + * @param num Number of binary Margules interaction terms + */ + void resizeNumInteractions(const int num); + + + //! Initialize lengths of local variables after all species have + //! been identified. + void initLengths(); + + //! Update the activity coefficients + /*! + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + */ + void s_update_lnActCoeff() const; + + //! Update the derivative of the log of the activity coefficients wrt T + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt temperature. + */ + void s_update_dlnActCoeff_dT() const; + + //! Update the derivative of the log of the activity coefficients + //! wrt log(mole fraction) + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the mole fractions. + */ + void s_update_dlnActCoeff_dlnX_diag() const; + + //! Update the derivative of the log of the activity coefficients + //! wrt log(moles) - diagonal only + /*! + * This function will be called to update the internally storred diagonal entries for the + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the moles. + */ + void s_update_dlnActCoeff_dlnN_diag() const; + + //! Update the derivative of the log of the activity coefficients wrt log(moles_m) + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt logarithm of the mole number of species + */ + void s_update_dlnActCoeff_dlnN() const; + + + private: + //! Error function + /*! + * Print an error string and exit + * + * @param msg Message to be printed + */ + doublereal err(std::string msg) const; + + protected: + + + //! number of binary interaction expressions + int numBinaryInteractions_; + + //! Enthalpy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_HE_b_ij; + + //! Enthalpy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_HE_c_ij; + + //! Enthalpy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_HE_d_ij; + + //! Entropy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_SE_b_ij; + + //! Entropy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_SE_c_ij; + + //! Entropy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_SE_d_ij; + + //! Enthalpy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VHE_b_ij; + + //! Enthalpy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VHE_c_ij; + + //! Enthalpy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VHE_d_ij; + + //! Entropy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VSE_b_ij; + + //! Entropy term for the ternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VSE_c_ij; + + //! Entropy term for the quaternary mole fraction interaction of the + //! excess gibbs free energy expression + mutable vector_fp m_VSE_d_ij; + + + + //! vector of species indices representing species A in the interaction + /*! + * Each Margules excess Gibbs free energy term involves two species, A and B. + * This vector identifies species A. + */ + vector_int m_pSpecies_A_ij; + + //! vector of species indices representing species B in the interaction + /*! + * Each Margules excess Gibbs free energy term involves two species, A and B. + * This vector identifies species B. + */ + vector_int m_pSpecies_B_ij; + + //! form of the Margules interaction expression + /*! + * Currently there is only one form. + */ + int formMargules_; + + //! form of the temperatuer dependence of the Margules interaction expression + /*! + * Currently there is only one form -> constant wrt temperature. + */ + int formTempModel_; + + + }; + + + +} + +#endif + + + + + diff --git a/Cantera/src/thermo/PseudoBinaryVPSSTP.cpp b/Cantera/src/thermo/PseudoBinaryVPSSTP.cpp deleted file mode 100644 index f909098a6..000000000 --- a/Cantera/src/thermo/PseudoBinaryVPSSTP.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/** - * @file PseudoBinaryVPSSTP.cpp - * Definitions for intermediate ThermoPhase object for phases which - * employ excess gibbs free energy formulations - * (see \ref thermoprops - * and class \link Cantera::PseudoBinaryVPSSTP PseudoBinaryVPSSTP\endlink). - * - * Header file for a derived class of ThermoPhase that handles - * variable pressure standard state methods for calculating - * thermodynamic properties that are further based upon expressions - * for the excess gibbs free energy expressed as a function of - * the mole fractions. - */ -/* - * Copywrite (2009) Sandia Corporation. Under the terms of - * Contract DE-AC04-94AL85000 with Sandia Corporation, the - * U.S. Government retains certain rights in this software. - */ -/* - * $Date$ - * $Revision$ - */ - - -#include "PseudoBinaryVPSSTP.h" - -#include - -using namespace std; - -namespace Cantera { - - /* - * Default constructor. - * - */ - PseudoBinaryVPSSTP::PseudoBinaryVPSSTP() : - GibbsExcessVPSSTP(), - PBType_(PBTYPE_PASSTHROUGH), - numPBSpecies_(m_kk), - indexSpecialSpecies_(-1), - numCationSpecies_(0), - numAnionSpecies_(0), - numPassThroughSpecies_(0), - neutralPBindexStart(0), - cationPhase_(0), - anionPhase_(0) - { - } - - /* - * Copy Constructor: - * - * Note this stuff will not work until the underlying phase - * has a working copy constructor - */ - PseudoBinaryVPSSTP::PseudoBinaryVPSSTP(const PseudoBinaryVPSSTP &b) : - GibbsExcessVPSSTP(), - PBType_(PBTYPE_PASSTHROUGH), - numPBSpecies_(m_kk), - indexSpecialSpecies_(-1), - numCationSpecies_(0), - numAnionSpecies_(0), - numPassThroughSpecies_(0), - neutralPBindexStart(0), - cationPhase_(0), - anionPhase_(0) - { - *this = operator=(b); - } - - /* - * operator=() - * - * Note this stuff will not work until the underlying phase - * has a working assignment operator - */ - PseudoBinaryVPSSTP& PseudoBinaryVPSSTP:: - operator=(const PseudoBinaryVPSSTP &b) { - if (&b != this) { - GibbsExcessVPSSTP::operator=(b); - } - - PBType_ = b.PBType_; - numPBSpecies_ = b.numPBSpecies_; - indexSpecialSpecies_ = b.indexSpecialSpecies_; - PBMoleFractions_ = b.PBMoleFractions_; - cationList_ = b.cationList_; - numCationSpecies_ = b.numCationSpecies_; - anionList_ = b.anionList_; - numAnionSpecies_ = b.numAnionSpecies_; - passThroughList_ = b.passThroughList_; - numPassThroughSpecies_ = b.numPassThroughSpecies_; - neutralPBindexStart = b.neutralPBindexStart; - cationPhase_ = b.cationPhase_; - anionPhase_ = b.anionPhase_; - moleFractionsTmp_ = b.moleFractionsTmp_; - - return *this; - } - - /** - * - * ~PseudoBinaryVPSSTP(): (virtual) - * - * Destructor: does nothing: - * - */ - PseudoBinaryVPSSTP::~PseudoBinaryVPSSTP() { - } - - /* - * This routine duplicates the current object and returns - * a pointer to ThermoPhase. - */ - ThermoPhase* - PseudoBinaryVPSSTP::duplMyselfAsThermoPhase() const { - PseudoBinaryVPSSTP* mtp = new PseudoBinaryVPSSTP(*this); - return (ThermoPhase *) mtp; - } - - /* - * -------------- Utilities ------------------------------- - */ - - - // Equation of state type flag. - /* - * The ThermoPhase base class returns - * zero. Subclasses should define this to return a unique - * non-zero value. Known constants defined for this purpose are - * listed in mix_defs.h. The PseudoBinaryVPSSTP class also returns - * zero, as it is a non-complete class. - */ - int PseudoBinaryVPSSTP::eosType() const { - return 0; - } - - - - /* - * ------------ Molar Thermodynamic Properties ---------------------- - */ - - - /* - * - Activities, Standard States, Activity Concentrations ----------- - */ - - - doublereal PseudoBinaryVPSSTP::standardConcentration(int k) const { - err("standardConcentration"); - return -1.0; - } - - doublereal PseudoBinaryVPSSTP::logStandardConc(int k) const { - err("logStandardConc"); - return -1.0; - } - - - - void PseudoBinaryVPSSTP::getElectrochemPotentials(doublereal* mu) const { - getChemPotentials(mu); - double ve = Faraday * electricPotential(); - for (int k = 0; k < m_kk; k++) { - mu[k] += ve*charge(k); - } - } - - void PseudoBinaryVPSSTP::calcPseudoBinaryMoleFractions() const { - int k; - doublereal sumCat; - doublereal sumAnion; - doublereal sum = 0.0; - switch (PBType_) { - case PBTYPE_PASSTHROUGH: - for (k = 0; k < m_kk; k++) { - PBMoleFractions_[k] = moleFractions_[k]; - } - break; - case PBTYPE_SINGLEANION: - sumCat = 0.0; - sumAnion = 0.0; - for (k = 0; k < m_kk; k++) { - moleFractionsTmp_[k] = moleFractions_[k]; - } - for (k = 0; k < (int) cationList_.size(); k++) { - sumCat += moleFractions_[cationList_[k]]; - } - sumAnion = moleFractions_[anionList_[k]]; - PBMoleFractions_[0] = sumCat -sumAnion; - moleFractionsTmp_[indexSpecialSpecies_] -= PBMoleFractions_[0]; - - - for (k = 0; k < numCationSpecies_; k++) { - PBMoleFractions_[1+k] = moleFractionsTmp_[cationList_[k]]; - } - - for (k = 0; k < numPassThroughSpecies_; k++) { - PBMoleFractions_[neutralPBindexStart + k] = - moleFractions_[cationList_[k]]; - } - - sum = fmaxx(0.0, PBMoleFractions_[0]); - for (k = 1; k < numPBSpecies_; k++) { - sum += PBMoleFractions_[k]; - } - for (k = 0; k < numPBSpecies_; k++) { - PBMoleFractions_[k] /= sum; - } - - break; - case PBTYPE_SINGLECATION: - throw CanteraError("eosType", "Unknown type"); - - break; - - case PBTYPE_MULTICATIONANION: - throw CanteraError("eosType", "Unknown type"); - - break; - default: - throw CanteraError("eosType", "Unknown type"); - break; - - } - } - - /* - * ------------ Partial Molar Properties of the Solution ------------ - */ - - - doublereal PseudoBinaryVPSSTP::err(std::string msg) const { - throw CanteraError("PseudoBinaryVPSSTP","Base class method " - +msg+" called. Equation of state type: "+int2str(eosType())); - return 0; - } - - - /* - * @internal Initialize. This method is provided to allow - * subclasses to perform any initialization required after all - * species have been added. For example, it might be used to - * resize internal work arrays that must have an entry for - * each species. The base class implementation does nothing, - * and subclasses that do not require initialization do not - * need to overload this method. When importing a CTML phase - * description, this method is called just prior to returning - * from function importPhase. - * - * @see importCTML.cpp - */ - void PseudoBinaryVPSSTP::initThermo() { - initLengths(); - GibbsExcessVPSSTP::initThermo(); - } - - - // Initialize lengths of local variables after all species have - // been identified. - void PseudoBinaryVPSSTP::initLengths() { - m_kk = nSpecies(); - moleFractions_.resize(m_kk); - } - - /* - * initThermoXML() (virtual from ThermoPhase) - * Import and initialize a ThermoPhase object - * - * @param phaseNode This object must be the phase node of a - * complete XML tree - * description of the phase, including all of the - * species data. In other words while "phase" must - * point to an XML phase object, it must have - * sibling nodes "speciesData" that describe - * the species in the phase. - * @param id ID of the phase. If nonnull, a check is done - * to see if phaseNode is pointing to the phase - * with the correct id. - */ - void PseudoBinaryVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) { - - - GibbsExcessVPSSTP::initThermoXML(phaseNode, id); - } - - /** - * Format a summary of the mixture state for output. - */ - std::string PseudoBinaryVPSSTP::report(bool show_thermo) const { - - - char p[800]; - string s = ""; - try { - if (name() != "") { - sprintf(p, " \n %s:\n", name().c_str()); - s += p; - } - sprintf(p, " \n temperature %12.6g K\n", temperature()); - s += p; - sprintf(p, " pressure %12.6g Pa\n", pressure()); - s += p; - sprintf(p, " density %12.6g kg/m^3\n", density()); - s += p; - sprintf(p, " mean mol. weight %12.6g amu\n", meanMolecularWeight()); - s += p; - - doublereal phi = electricPotential(); - sprintf(p, " potential %12.6g V\n", phi); - s += p; - - int kk = nSpecies(); - array_fp x(kk); - array_fp molal(kk); - array_fp mu(kk); - array_fp muss(kk); - array_fp acMolal(kk); - array_fp actMolal(kk); - getMoleFractions(&x[0]); - - getChemPotentials(&mu[0]); - getStandardChemPotentials(&muss[0]); - getActivities(&actMolal[0]); - - - if (show_thermo) { - sprintf(p, " \n"); - s += p; - sprintf(p, " 1 kg 1 kmol\n"); - s += p; - sprintf(p, " ----------- ------------\n"); - s += p; - sprintf(p, " enthalpy %12.6g %12.4g J\n", - enthalpy_mass(), enthalpy_mole()); - s += p; - sprintf(p, " internal energy %12.6g %12.4g J\n", - intEnergy_mass(), intEnergy_mole()); - s += p; - sprintf(p, " entropy %12.6g %12.4g J/K\n", - entropy_mass(), entropy_mole()); - s += p; - sprintf(p, " Gibbs function %12.6g %12.4g J\n", - gibbs_mass(), gibbs_mole()); - s += p; - sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n", - cp_mass(), cp_mole()); - s += p; - try { - sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n", - cv_mass(), cv_mole()); - s += p; - } - catch(CanteraError) { - sprintf(p, " heat capacity c_v \n"); - s += p; - } - } - - } catch (CanteraError) { - ; - } - return s; - } - - -} - diff --git a/Cantera/src/thermo/PseudoBinaryVPSSTP.h b/Cantera/src/thermo/PseudoBinaryVPSSTP.h deleted file mode 100644 index 3cc9a9d5b..000000000 --- a/Cantera/src/thermo/PseudoBinaryVPSSTP.h +++ /dev/null @@ -1,392 +0,0 @@ -/** - * @file PseudoBinaryVPSSTP.h - * Header for intermediate ThermoPhase object for phases which - * employ gibbs excess free energy based formulations - * (see \ref thermoprops - * and class \link Cantera::gibbsExcessVPSSTP gibbsExcessVPSSTP\endlink). - * - * Header file for a derived class of ThermoPhase that handles - * variable pressure standard state methods for calculating - * thermodynamic properties that are further based upon activities - * based on the molality scale. These include most of the methods for - * calculating liquid electrolyte thermodynamics. - */ -/* - * 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. - */ -/* - * $Id$ - */ - -#ifndef CT_PSEUDOBINARYVPSSTP_H -#define CT_PSEUDOBINARYVPSSTP_H - -#include "GibbsExcessVPSSTP.h" - -namespace Cantera { - - /** - * @ingroup thermoprops - */ - - /*! - * PseudoBinaryVPSSTP is a derived class of ThermoPhase - * GibbsExcessVPSSTP that handles - * variable pressure standard state methods for calculating - * thermodynamic properties that are further based on - * expressing the Excess Gibbs free energy as a function of - * the mole fractions (or pseudo mole fractions) of consitituents. - * This category is the workhorse for describing molten salts, - * solid-phase mixtures of semiconductors, and mixtures of miscible - * and semi-miscible compounds. - * - * It includes - * . regular solutions - * . Margueles expansions - * . NTRL equation - * . Wilson's equation - * . UNIQUAC equation of state. - * - * This class adds additional functions onto the %ThermoPhase interface - * that handles the calculation of the excess Gibbs free energy. The %ThermoPhase - * class includes a member function, ThermoPhase::activityConvention() - * that indicates which convention the activities are based on. The - * default is to assume activities are based on the molar convention. - * That default is used here. - * - * All of the Excess Gibbs free energy formulations in this area employ - * symmetrical formulations. - * - * This layer will massage the mole fraction vector to implement - * cation and anion based mole numbers in an optional manner - * - * The way that it collects the cation and anion based mole numbers - * is via holding two extra ThermoPhase objects. These - * can include standard states for salts. - * - * - */ - class PseudoBinaryVPSSTP : public GibbsExcessVPSSTP { - - public: - - /// Constructors - /*! - * This doesn't do much more than initialize constants with - * default values for water at 25C. Water molecular weight - * comes from the default elements.xml file. It actually - * differs slightly from the IAPWS95 value of 18.015268. However, - * density conservation and therefore element conservation - * is the more important principle to follow. - */ - PseudoBinaryVPSSTP(); - - //! Copy constructor - /*! - * Note this stuff will not work until the underlying phase - * has a working copy constructor - * - * @param b class to be copied - */ - PseudoBinaryVPSSTP(const PseudoBinaryVPSSTP&b); - - /// Assignment operator - /*! - * - * @param b class to be copied. - */ - PseudoBinaryVPSSTP& operator=(const PseudoBinaryVPSSTP&b); - - /// Destructor. - virtual ~PseudoBinaryVPSSTP(); - - //! Duplication routine for objects which inherit from ThermoPhase. - /*! - * This virtual routine can be used to duplicate thermophase objects - * inherited from ThermoPhase even if the application only has - * a pointer to ThermoPhase to work with. - */ - virtual ThermoPhase *duplMyselfAsThermoPhase() const; - - /** - * - * @name Utilities - * @{ - */ - - - //! Equation of state type flag. - /*! - * The ThermoPhase base class returns - * zero. Subclasses should define this to return a unique - * non-zero value. Known constants defined for this purpose are - * listed in mix_defs.h. The MolalityVPSSTP class also returns - * zero, as it is a non-complete class. - */ - virtual int eosType() const; - - - - /** - * @} - * @name Molar Thermodynamic Properties - * @{ - */ - - - /** - * @} - * @name Utilities for Solvent ID and Molality - * @{ - */ - - - - - /** - * @} - * @name Mechanical Properties - * @{ - */ - - /** - * @} - * @name Potential Energy - * - * Species may have an additional potential energy due to the - * presence of external gravitation or electric fields. These - * methods allow specifying a potential energy for individual - * species. - * @{ - */ - - /** - * @} - * @name Activities, Standard States, and Activity Concentrations - * - * The activity \f$a_k\f$ of a species in solution is - * related to the chemical potential by \f[ \mu_k = \mu_k^0(T) - * + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is - * the chemical potential at unit activity, which depends only - * on temperature and pressure. - * @{ - */ - - - - - /** - * The standard concentration \f$ C^0_k \f$ used to normalize - * the generalized concentration. In many cases, this quantity - * will be the same for all species in a phase - for example, - * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this - * reason, this method returns a single value, instead of an - * array. However, for phases in which the standard - * concentration is species-specific (e.g. surface species of - * different sizes), this method may be called with an - * optional parameter indicating the species. - * - * @param k species index. Defaults to zero. - */ - virtual doublereal standardConcentration(int k=0) const; - - /** - * Returns the natural logarithm of the standard - * concentration of the kth species - * - * @param k species index - */ - virtual doublereal logStandardConc(int k=0) const; - - - - - //@} - /// @name Partial Molar Properties of the Solution - //@{ - - - /** - * Get the species electrochemical potentials. - * These are partial molar quantities. - * This method adds a term \f$ Fz_k \phi_k \f$ to the - * to each chemical potential. - * - * Units: J/kmol - * - * @param mu output vector containing the species electrochemical potentials. - * Length: m_kk. - */ - void getElectrochemPotentials(doublereal* mu) const; - - - //@} - /// @name Properties of the Standard State of the Species in the Solution - //@{ - - - - //@} - /// @name Thermodynamic Values for the Species Reference States - //@{ - - - /////////////////////////////////////////////////////// - // - // The methods below are not virtual, and should not - // be overloaded. - // - ////////////////////////////////////////////////////// - - /** - * @name Specific Properties - * @{ - */ - - - /** - * @name Setting the State - * - * These methods set all or part of the thermodynamic - * state. - * @{ - */ - - //! Calculate pseudo binary mole fractions - /*! - * - */ - virtual void calcPseudoBinaryMoleFractions() const; - - - //@} - - /** - * @name Chemical Equilibrium - * Routines that implement the Chemical equilibrium capability - * for a single phase, based on the element-potential method. - * @{ - */ - - - - //@} - - - - /// The following methods are used in the process of constructing - /// the phase and setting its parameters from a specification in an - /// input file. They are not normally used in application programs. - /// To see how they are used, see files importCTML.cpp and - /// ThermoFactory.cpp. - - - /*! - * @internal Initialize. This method is provided to allow - * subclasses to perform any initialization required after all - * species have been added. For example, it might be used to - * resize internal work arrays that must have an entry for - * each species. The base class implementation does nothing, - * and subclasses that do not require initialization do not - * need to overload this method. When importing a CTML phase - * description, this method is called just prior to returning - * from function importPhase. - * - * @see importCTML.cpp - */ - virtual void initThermo(); - - - /** - * Import and initialize a ThermoPhase object - * - * @param phaseNode This object must be the phase node of a - * complete XML tree - * description of the phase, including all of the - * species data. In other words while "phase" must - * point to an XML phase object, it must have - * sibling nodes "speciesData" that describe - * the species in the phase. - * @param id ID of the phase. If nonnull, a check is done - * to see if phaseNode is pointing to the phase - * with the correct id. - */ - void initThermoXML(XML_Node& phaseNode, std::string id); - - - //! returns a summary of the state of the phase as a string - /*! - * @param show_thermo If true, extra information is printed out - * about the thermodynamic state of the system. - */ - virtual std::string report(bool show_thermo = true) const; - - - private: - - - //! Initialize lengths of local variables after all species have - //! been identified. - void initLengths(); - - - - private: - //! Error function - /*! - * Print an error string and exit - * - * @param msg Message to be printed - */ - doublereal err(std::string msg) const; - - protected: - - int PBType_; - - //! Number of pseudo binary species - int numPBSpecies_; - - //! index of special species - int indexSpecialSpecies_; - - mutable std::vector PBMoleFractions_; - - std::vector cationList_; - int numCationSpecies_; - - std::vectoranionList_; - int numAnionSpecies_; - - std::vector passThroughList_; - int numPassThroughSpecies_; - int neutralPBindexStart; - - ThermoPhase *cationPhase_; - - ThermoPhase *anionPhase_; - - mutable std::vector moleFractionsTmp_; - - private: - - - }; - -#define PBTYPE_PASSTHROUGH 0 -#define PBTYPE_SINGLEANION 1 -#define PBTYPE_SINGLECATION 2 -#define PBTYPE_MULTICATIONANION 3 - - - -} - -#endif - - - - - diff --git a/Cantera/src/thermo/PureFluidPhase.cpp b/Cantera/src/thermo/PureFluidPhase.cpp index b5e8b96ff..0c30fe03e 100644 --- a/Cantera/src/thermo/PureFluidPhase.cpp +++ b/Cantera/src/thermo/PureFluidPhase.cpp @@ -19,6 +19,8 @@ #include #include +using namespace std; + namespace Cantera { // Base Constructor @@ -76,241 +78,425 @@ namespace Cantera { - PureFluidPhase::~PureFluidPhase() { - delete m_sub; - } + PureFluidPhase::~PureFluidPhase() { + delete m_sub; + } - void PureFluidPhase:: - initThermo() { - if (m_sub) delete m_sub; - m_sub = tpx::GetSub(m_subflag); - if (m_sub == 0) { - throw CanteraError("PureFluidPhase::initThermo", - "could not create new substance object."); - } - m_mw = m_sub->MolWt(); - m_weight[0] = m_mw; - setMolecularWeight(0,m_mw); - double one = 1.0; - setMoleFractions(&one); - double cp0_R, h0_RT, s0_R, T0, p; - T0 = 298.15; - if (T0 < m_sub->Tcrit()) { - m_sub->Set(tpx::TX, T0, 1.0); - p = 0.01*m_sub->P(); - } - else { - p = 0.001*m_sub->Pcrit(); - } - m_sub->Set(tpx::TP, T0, p); + void PureFluidPhase:: + initThermo() { + if (m_sub) delete m_sub; + m_sub = tpx::GetSub(m_subflag); + if (m_sub == 0) { + throw CanteraError("PureFluidPhase::initThermo", + "could not create new substance object."); + } + m_mw = m_sub->MolWt(); + m_weight[0] = m_mw; + setMolecularWeight(0,m_mw); + double one = 1.0; + setMoleFractions(&one); + double cp0_R, h0_RT, s0_R, T0, p; + T0 = 298.15; + if (T0 < m_sub->Tcrit()) { + m_sub->Set(tpx::TX, T0, 1.0); + p = 0.01*m_sub->P(); + } + else { + p = 0.001*m_sub->Pcrit(); + } + p = 0.001 * p; + m_sub->Set(tpx::TP, T0, p); - m_spthermo->update_one(0, T0, &cp0_R, &h0_RT, &s0_R); - double s_R = s0_R - log(p/refPressure()); - m_sub->setStdState(h0_RT*GasConstant*298.15/m_mw, - s_R*GasConstant/m_mw, T0, p); - if (m_verbose) { - writelog("PureFluidPhase::initThermo: initialized phase " - +id()+"\n"); - } + m_spthermo->update_one(0, T0, &cp0_R, &h0_RT, &s0_R); + double s_R = s0_R - log(p/refPressure()); + m_sub->setStdState(h0_RT*GasConstant*298.15/m_mw, + s_R*GasConstant/m_mw, T0, p); + if (m_verbose) { + writelog("PureFluidPhase::initThermo: initialized phase " + +id()+"\n"); } + } - void PureFluidPhase:: - setParametersFromXML(const XML_Node& eosdata) { - eosdata._require("model","PureFluid"); - m_subflag = atoi(eosdata["fluid_type"].c_str()); - if (m_subflag < 0) - throw CanteraError("PureFluidPhase::setParametersFromXML", - "missing or negative substance flag"); - } + void PureFluidPhase:: + setParametersFromXML(const XML_Node& eosdata) { + eosdata._require("model","PureFluid"); + m_subflag = atoi(eosdata["fluid_type"].c_str()); + if (m_subflag < 0) + throw CanteraError("PureFluidPhase::setParametersFromXML", + "missing or negative substance flag"); + } - doublereal PureFluidPhase:: - enthalpy_mole() const { - setTPXState(); - doublereal h = m_sub->h() * m_mw; - check(h); - return h; - } + doublereal PureFluidPhase:: + enthalpy_mole() const { + setTPXState(); + doublereal h = m_sub->h() * m_mw; + check(h); + return h; + } - doublereal PureFluidPhase:: - intEnergy_mole() const { - setTPXState(); - doublereal u = m_sub->u() * m_mw; - check(u); - return u; - } + doublereal PureFluidPhase:: + intEnergy_mole() const { + setTPXState(); + doublereal u = m_sub->u() * m_mw; + check(u); + return u; + } - doublereal PureFluidPhase:: - entropy_mole() const { - setTPXState(); - doublereal s = m_sub->s() * m_mw; - check(s); - return s; - } + doublereal PureFluidPhase:: + entropy_mole() const { + setTPXState(); + doublereal s = m_sub->s() * m_mw; + check(s); + return s; + } - doublereal PureFluidPhase:: - gibbs_mole() const { - setTPXState(); - doublereal g = m_sub->g() * m_mw; - check(g); - return g; - } + doublereal PureFluidPhase:: + gibbs_mole() const { + setTPXState(); + doublereal g = m_sub->g() * m_mw; + check(g); + return g; + } - doublereal PureFluidPhase:: - cp_mole() const { - setTPXState(); - doublereal cp = m_sub->cp() * m_mw; - check(cp); - return cp; - } + doublereal PureFluidPhase:: + cp_mole() const { + setTPXState(); + doublereal cp = m_sub->cp() * m_mw; + check(cp); + return cp; + } - doublereal PureFluidPhase:: - cv_mole() const { - setTPXState(); - doublereal cv = m_sub->cv() * m_mw; - check(cv); - return cv; - } + doublereal PureFluidPhase:: + cv_mole() const { + setTPXState(); + doublereal cv = m_sub->cv() * m_mw; + check(cv); + return cv; + } - doublereal PureFluidPhase:: - pressure() const { - setTPXState(); - doublereal p = m_sub->P(); - check(p); - return p; + doublereal PureFluidPhase:: + pressure() const { + setTPXState(); + doublereal p = m_sub->P(); + check(p); + return p; + } + //==================================================================================================================== + void PureFluidPhase:: + setPressure(doublereal p) { + Set(tpx::TP, temperature(), p); + setDensity(1.0/m_sub->v()); + check(); + } + //==================================================================================================================== + void PureFluidPhase::Set(int n, double x, double y) const { + try { + m_sub->Set(n, x, y); } + catch(tpx::TPX_Error) { + reportTPXError(); + } + } + //==================================================================================================================== + void PureFluidPhase::setTPXState() const { + Set(tpx::TV, temperature(), 1.0/density()); + } + //==================================================================================================================== + void PureFluidPhase::check(doublereal v) const { + if (m_sub->Error() || v == tpx::Undef) { + throw CanteraError("PureFluidPhase",string(tpx::errorMsg( + m_sub->Error()))); + } + } + //==================================================================================================================== + void PureFluidPhase::reportTPXError() const { + string msg = tpx::TPX_Error::ErrorMessage; + string proc = "tpx::"+tpx::TPX_Error::ErrorProcedure; + throw CanteraError(proc,msg); + } + //==================================================================================================================== + + doublereal PureFluidPhase::isothermalCompressibility() const { + return m_sub->isothermalCompressibility(); + } + //==================================================================================================================== + doublereal PureFluidPhase::thermalExpansionCoeff() const { + return m_sub->thermalExpansionCoeff(); + } + //==================================================================================================================== + tpx::Substance& PureFluidPhase::TPX_Substance() { return *m_sub; } + //==================================================================================================================== + // Returns an array of partial molar enthalpies for the species + // in the mixture. Units (J/kmol) + /* + * @param hbar Output vector of species partial molar enthalpies. + * Length: m_kk. units are J/kmol. + */ + void PureFluidPhase::getPartialMolarEnthalpies(doublereal* hbar) const { + hbar[0] = enthalpy_mole(); + } + //==================================================================================================================== + // Returns an array of partial molar entropies of the species in the + // solution. Units: J/kmol/K. + /* + * @param sbar Output vector of species partial molar entropies. + * Length = m_kk. units are J/kmol/K. + */ + void PureFluidPhase::getPartialMolarEntropies(doublereal* sbar) const { + sbar[0] = entropy_mole(); + } + //==================================================================================================================== + // Return an array of partial molar internal energies for the + // species in the mixture. Units: J/kmol. + /* + * @param ubar Output vector of speciar partial molar internal energies. + * Length = m_kk. units are J/kmol. + */ + void PureFluidPhase::getPartialMolarIntEnergies(doublereal* ubar) const { + ubar[0] = intEnergy_mole(); + } + //==================================================================================================================== + // Return an array of partial molar heat capacities for the + // species in the mixture. Units: J/kmol/K + /* + * @param cpbar Output vector of species partial molar heat + * capacities at constant pressure. + * Length = m_kk. units are J/kmol/K. + */ + void PureFluidPhase::getPartialMolarCp(doublereal* cpbar) const { + cpbar[0] = cp_mole(); + } + //==================================================================================================================== + // Return an array of partial molar volumes for the + // species in the mixture. Units: m^3/kmol. + /* + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + void PureFluidPhase::getPartialMolarVolumes(doublereal* vbar) const { + vbar[0] = 1.0 / molarDensity(); + } + //==================================================================================================================== + int PureFluidPhase::standardStateConvention() const { + return cSS_CONVENTION_TEMPERATURE; + } + //==================================================================================================================== + void PureFluidPhase::getActivityConcentrations(doublereal* c) const { + c[0] = 1.0; + } + //==================================================================================================================== + doublereal PureFluidPhase::standardConcentration(int k) const { + return 1.0; + } + //==================================================================================================================== + void PureFluidPhase::getActivities(doublereal *a) const { + a[0] = 1.0; + } + //==================================================================================================================== + // Get the array of chemical potentials at unit activity for the species + // at their standard states at the current T and P of the solution. + /* + * These are the standard state chemical potentials \f$ \mu^0_k(T,P) + * \f$. The values are evaluated at the current + * temperature and pressure of the solution + * + * @param mu Output vector of chemical potentials. + * Length: m_kk. + */ + void PureFluidPhase::getStandardChemPotentials(doublereal* mu) const { + mu[0] = gibbs_mole(); + } + //==================================================================================================================== + // Get the nondimensional Enthalpy functions for the species + // at their standard states at the current T and P of the solution. + /* + * @param hrt Output vector of nondimensional standard state enthalpies. + * Length: m_kk. + */ + void PureFluidPhase::getEnthalpy_RT(doublereal* hrt) const { + doublereal rt = _RT(); + doublereal h = enthalpy_mole(); + hrt[0] = h / rt; + } + //==================================================================================================================== + // Get the array of nondimensional Entropy functions for the + // standard state species at the current T and P of the solution. + /* + * @param sr Output vector of nondimensional standard state entropies. + * Length: m_kk. + */ + void PureFluidPhase::getEntropy_R(doublereal* sr) const { + doublereal s = entropy_mole(); + sr[0] = s / GasConstant; + } + //==================================================================================================================== + // Get the nondimensional Gibbs functions for the species + // in their standard states at the current T and P of the solution. + /* + * @param grt Output vector of nondimensional standard state gibbs free energies + * Length: m_kk. + */ + void PureFluidPhase::getGibbs_RT(doublereal* grt) const { + doublereal rt = _RT(); + doublereal g = gibbs_mole(); + grt[0] = g / rt; + } + //==================================================================================================================== + // Returns the vector of nondimensional enthalpies of the reference state at the current temperature + // of the solution and the reference pressure for the species. + /* + * This base function will throw a CanteraException unless + * it is overwritten in a derived class. + * + * @param hrt Output vector containing the nondimensional reference state enthalpies + * Length: m_kk. + */ + void PureFluidPhase::getEnthalpy_RT_ref(doublereal *hrt) const { + double psave = pressure(); + double t = temperature(); + //double pref = m_spthermo->refPressure(); + double plow = 1.0E-8; + Set(tpx::TP, t, plow); + getEnthalpy_RT(hrt); + Set(tpx::TP, t, psave); + + } + //==================================================================================================================== + // Returns the vector of nondimensional Gibbs Free Energies of the reference state at the current temperature + // of the solution and the reference pressure for the species. + /* + * @param grt Output vector containing the nondimensional reference state + * Gibbs Free energies. Length: m_kk. + */ + void PureFluidPhase::getGibbs_RT_ref(doublereal *grt) const { + double psave = pressure(); + double t = temperature(); + double pref = m_spthermo->refPressure(); + double plow = 1.0E-8; + Set(tpx::TP, t, plow); + getGibbs_RT(grt); + grt[0] += log(pref/plow); + Set(tpx::TP, t, psave); + } + //==================================================================================================================== + // Returns the vector of the gibbs function of the reference state at the current temperature + // of the solution and the reference pressure for the species. + /* + * units = J/kmol + * + * @param g Output vector containing the reference state + * Gibbs Free energies. Length: m_kk. Units: J/kmol. + */ + void PureFluidPhase::getGibbs_ref(doublereal *g) const { + getGibbs_RT_ref(g); + g[0] *= (GasConstant * temperature()); + } + //==================================================================================================================== + // Returns the vector of nondimensional entropies of the reference state at the current temperature + // of the solution and the reference pressure for each species. + /* + * @param er Output vector containing the nondimensional reference state + * entropies. Length: m_kk. + */ + void PureFluidPhase::getEntropy_R_ref(doublereal *er) const { + double psave = pressure(); + double t = temperature(); + double pref = m_spthermo->refPressure(); + double plow = 1.0E-8; + Set(tpx::TP, t, plow); + getEntropy_R(er); + er[0] -= log(pref/plow); + Set(tpx::TP, t, psave); + } + //==================================================================================================================== + // critical temperature + doublereal PureFluidPhase::critTemperature() const { return m_sub->Tcrit(); } + //==================================================================================================================== + /// critical pressure + doublereal PureFluidPhase::critPressure() const { return m_sub->Pcrit(); } + //==================================================================================================================== + /// critical density + doublereal PureFluidPhase::critDensity() const { return 1.0/m_sub->Vcrit(); } + //==================================================================================================================== - void PureFluidPhase:: - setPressure(doublereal p) { - Set(tpx::TP, temperature(), p); - setDensity(1.0/m_sub->v()); - check(); + /// saturation temperature + doublereal PureFluidPhase::satTemperature(doublereal p) const { + try { + doublereal ts = m_sub->Tsat(p); + return ts; } + catch(tpx::TPX_Error) { + reportTPXError(); + return -1.0; + } + } + //==================================================================================================================== + void PureFluidPhase::setState_HP(doublereal h, doublereal p, + doublereal tol) { + Set(tpx::HP, h, p); + setState_TR(m_sub->Temp(), 1.0/m_sub->v()); + check(); + } + //==================================================================================================================== + void PureFluidPhase::setState_UV(doublereal u, doublereal v, + doublereal tol) { + Set(tpx::UV, u, v); + setState_TR(m_sub->Temp(), 1.0/m_sub->v()); + check(); + } + //==================================================================================================================== + void PureFluidPhase::setState_SV(doublereal s, doublereal v, + doublereal tol) { + Set(tpx::SV, s, v); + setState_TR(m_sub->Temp(), 1.0/m_sub->v()); + check(); + } + //==================================================================================================================== + void PureFluidPhase::setState_SP(doublereal s, doublereal p, + doublereal tol) { + Set(tpx::SP, s, p); + setState_TR(m_sub->Temp(), 1.0/m_sub->v()); + check(); + } + //==================================================================================================================== + // saturation pressure + doublereal PureFluidPhase::satPressure(doublereal t) const { + doublereal vsv = m_sub->v(); + try { + Set(tpx::TV,t,vsv); + doublereal ps = m_sub->Ps(); + return ps; + } + catch(tpx::TPX_Error) { + reportTPXError(); + return -1.0; + } + } + //==================================================================================================================== + doublereal PureFluidPhase::vaporFraction() const { + setTPXState(); + doublereal x = m_sub->x(); + check(x); + return x; + } + //==================================================================================================================== + void PureFluidPhase::setState_Tsat(doublereal t, doublereal x) { + setTemperature(t); + setTPXState(); + Set(tpx::TX, t, x); + setDensity(1.0/m_sub->v()); + check(); + } + //==================================================================================================================== + void PureFluidPhase::setState_Psat(doublereal p, doublereal x) { + setTPXState(); + Set(tpx::PX, p, x); + setTemperature(m_sub->Temp()); + setDensity(1.0/m_sub->v()); + check(); + } - void PureFluidPhase::Set(int n, double x, double y) const { - try { - m_sub->Set(n, x, y); - } - catch(tpx::TPX_Error) { - reportTPXError(); - } - } - - void PureFluidPhase::setTPXState() const { - Set(tpx::TV, temperature(), 1.0/density()); - } - - void PureFluidPhase::check(doublereal v) const { - if (m_sub->Error() || v == tpx::Undef) { - throw CanteraError("PureFluidPhase",string(tpx::errorMsg( - m_sub->Error()))); - } - } - - void PureFluidPhase::reportTPXError() const { - string msg = tpx::TPX_Error::ErrorMessage; - string proc = "tpx::"+tpx::TPX_Error::ErrorProcedure; - throw CanteraError(proc,msg); - } - - - doublereal PureFluidPhase::isothermalCompressibility() const { - return m_sub->isothermalCompressibility(); - } - - doublereal PureFluidPhase::thermalExpansionCoeff() const { - return m_sub->thermalExpansionCoeff(); - } - - tpx::Substance& PureFluidPhase::TPX_Substance() { return *m_sub; } - - /// critical temperature - doublereal PureFluidPhase::critTemperature() const { return m_sub->Tcrit(); } - - /// critical pressure - doublereal PureFluidPhase::critPressure() const { return m_sub->Pcrit(); } - - /// critical density - doublereal PureFluidPhase::critDensity() const { return 1.0/m_sub->Vcrit(); } - - - /// saturation temperature - doublereal PureFluidPhase::satTemperature(doublereal p) const { - try { - doublereal ts = m_sub->Tsat(p); - return ts; - } - catch(tpx::TPX_Error) { - reportTPXError(); - return -1.0; - } - } - - void PureFluidPhase::setState_HP(doublereal h, doublereal p, - doublereal tol) { - Set(tpx::HP, h, p); - setState_TR(m_sub->Temp(), 1.0/m_sub->v()); - check(); - } - - void PureFluidPhase::setState_UV(doublereal u, doublereal v, - doublereal tol) { - Set(tpx::UV, u, v); - setState_TR(m_sub->Temp(), 1.0/m_sub->v()); - check(); - } - - void PureFluidPhase::setState_SV(doublereal s, doublereal v, - doublereal tol) { - Set(tpx::SV, s, v); - setState_TR(m_sub->Temp(), 1.0/m_sub->v()); - check(); - } - - void PureFluidPhase::setState_SP(doublereal s, doublereal p, - doublereal tol) { - Set(tpx::SP, s, p); - setState_TR(m_sub->Temp(), 1.0/m_sub->v()); - check(); - } - - /// saturation pressure - doublereal PureFluidPhase::satPressure(doublereal t) const { - doublereal vsv = m_sub->v(); - try { - Set(tpx::TV,t,vsv); - doublereal ps = m_sub->Ps(); - return ps; - } - catch(tpx::TPX_Error) { - reportTPXError(); - return -1.0; - } - } - - doublereal PureFluidPhase::vaporFraction() const { - setTPXState(); - doublereal x = m_sub->x(); - check(x); - return x; - } - - void PureFluidPhase::setState_Tsat(doublereal t, doublereal x) { - setTemperature(t); - setTPXState(); - Set(tpx::TX, t, x); - setDensity(1.0/m_sub->v()); - check(); - } - - void PureFluidPhase::setState_Psat(doublereal p, doublereal x) { - setTPXState(); - Set(tpx::PX, p, x); - setTemperature(m_sub->Temp()); - setDensity(1.0/m_sub->v()); - check(); - } - - + //==================================================================================================================== /** * Format a summary of the mixture state for output. */ @@ -428,14 +614,14 @@ namespace Cantera { } return s; } - + //==================================================================================================================== /* * Format a summary of the mixture state for output. */ void PureFluidPhase::reportCSV(std::ofstream& csvFile) const { - csvFile.precision(3); + csvFile.precision(3); int tabS = 15; int tabM = 30; int tabL = 40; @@ -464,74 +650,74 @@ namespace Cantera { csvFile.precision(8); int kk = nSpecies(); - std::vector x(kk, 0.0); - std::vector y(kk, 0.0); - std::vector mu(kk, 0.0); - std::vector a(kk, 0.0); - std::vector ac(kk, 0.0); - std::vector hbar(kk, 0.0); - std::vector sbar(kk, 0.0); - std::vector ubar(kk, 0.0); - std::vector cpbar(kk, 0.0); - std::vector vbar(kk, 0.0); + double x[kk]; + double y[kk]; + double mu[kk]; + double a[kk]; + double ac[kk]; + double hbar[kk]; + double sbar[kk]; + double ubar[kk]; + double cpbar[kk]; + double vbar[kk]; vector pNames; vector data; - getMoleFractions(DATA_PTR(x)); + getMoleFractions(x); pNames.push_back("X"); - data.push_back(DATA_PTR(x)); + data.push_back(x); try{ - getMassFractions(DATA_PTR(y)); + getMassFractions(y); pNames.push_back("Y"); - data.push_back(DATA_PTR(y)); + data.push_back(y); } catch (CanteraError) {;} try{ - getChemPotentials(DATA_PTR(mu)); + getChemPotentials(mu); pNames.push_back("Chem. Pot (J/kmol)"); - data.push_back(DATA_PTR(mu)); + data.push_back(mu); } catch (CanteraError) {;} try{ - getActivities(DATA_PTR(a)); + getActivities(a); pNames.push_back("Activity"); - data.push_back(DATA_PTR(a)); + data.push_back(a); } catch (CanteraError) {;} try{ - getActivityCoefficients(DATA_PTR(ac)); + getActivityCoefficients(ac); pNames.push_back("Act. Coeff."); - data.push_back(DATA_PTR(ac)); + data.push_back(ac); } catch (CanteraError) {;} try{ - getPartialMolarEnthalpies(DATA_PTR(hbar)); + getPartialMolarEnthalpies(hbar); pNames.push_back("Part. Mol Enthalpy (J/kmol)"); - data.push_back(DATA_PTR(hbar)); + data.push_back(hbar); } catch (CanteraError) {;} try{ - getPartialMolarEntropies(DATA_PTR(sbar)); + getPartialMolarEntropies(sbar); pNames.push_back("Part. Mol. Entropy (J/K/kmol)"); - data.push_back(DATA_PTR(sbar)); + data.push_back(sbar); } catch (CanteraError) {;} try{ - getPartialMolarIntEnergies(DATA_PTR(ubar)); + getPartialMolarIntEnergies(ubar); pNames.push_back("Part. Mol. Energy (J/kmol)"); - data.push_back(DATA_PTR(ubar)); + data.push_back(ubar); } catch (CanteraError) {;} try{ - getPartialMolarCp(DATA_PTR(cpbar)); + getPartialMolarCp(cpbar); pNames.push_back("Part. Mol. Cp (J/K/kmol"); - data.push_back(DATA_PTR(cpbar)); + data.push_back(cpbar); } catch (CanteraError) {;} try{ - getPartialMolarVolumes(DATA_PTR(vbar)); + getPartialMolarVolumes(vbar); pNames.push_back("Part. Mol. Cv (J/K/kmol)"); - data.push_back(DATA_PTR(vbar)); + data.push_back(vbar); } catch (CanteraError) {;} @@ -541,9 +727,9 @@ namespace Cantera { } csvFile << endl; /* - csvFile.fill('-'); - csvFile << setw(tabS+(tabM+1)*pNames.size()) << "-\n"; - csvFile.fill(' '); + csvFile.fill('-'); + csvFile << setw(tabS+(tabM+1)*pNames.size()) << "-\n"; + csvFile.fill(' '); */ for (int k = 0; k < kk; k++) { csvFile << setw(tabS) << speciesName(k) + ","; @@ -564,8 +750,7 @@ namespace Cantera { catch (CanteraError) { ; } - } - + } } #endif // WITH_PURE_FLUIDS diff --git a/Cantera/src/thermo/PureFluidPhase.h b/Cantera/src/thermo/PureFluidPhase.h index 74626fe22..d548fc6f4 100644 --- a/Cantera/src/thermo/PureFluidPhase.h +++ b/Cantera/src/thermo/PureFluidPhase.h @@ -34,7 +34,7 @@ #include "mix_defs.h" namespace tpx { - class Substance; + class Substance; } namespace Cantera { @@ -107,7 +107,7 @@ namespace Cantera { /// Molar Gibbs function. Units: J/kmol. virtual doublereal gibbs_mole() const; - /// Molar heat capacity at constant pressure. Units: J/kmol/K. + /// Molar heat capacity at constant pressure. Units: J/kmol/K. virtual doublereal cp_mole() const; /// Molar heat capacity at constant volume. Units: J/kmol/K. @@ -142,6 +142,145 @@ namespace Cantera { mu[0] = gibbs_mole(); } + + + //! Get the species electrochemical potentials. + /*! + * These are partial molar quantities. This method adds a term \f$ F z_k + * \phi_p \f$ to each chemical potential. + * The electrochemical potential of species k in a phase p, \f$ \zeta_k \f$, + * is related to the chemical potential via + * the following equation, + * + * \f[ + * \zeta_{k}(T,P) = \mu_{k}(T,P) + F z_k \phi_p + * \f] + * + * @param mu Output vector of species electrochemical + * potentials. Length: m_kk. Units: J/kmol + */ + void getElectrochemPotentials(doublereal* mu) const { + getChemPotentials(mu); + double ve = Faraday * electricPotential(); + for (int k = 0; k < m_kk; k++) { + mu[k] += ve*charge(k); + } + } + + //! Returns an array of partial molar enthalpies for the species + //! in the mixture. Units (J/kmol) + /*! + * @param hbar Output vector of species partial molar enthalpies. + * Length: m_kk. units are J/kmol. + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + + //! Returns an array of partial molar entropies of the species in the + //! solution. Units: J/kmol/K. + /*! + * @param sbar Output vector of species partial molar entropies. + * Length = m_kk. units are J/kmol/K. + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + //! Return an array of partial molar internal energies for the + //! species in the mixture. Units: J/kmol. + /*! + * @param ubar Output vector of speciar partial molar internal energies. + * Length = m_kk. units are J/kmol. + */ + virtual void getPartialMolarIntEnergies(doublereal* ubar) const; + + //! Return an array of partial molar heat capacities for the + //! species in the mixture. Units: J/kmol/K + /*! + * @param cpbar Output vector of species partial molar heat + * capacities at constant pressure. + * Length = m_kk. units are J/kmol/K. + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + //! Return an array of partial molar volumes for the + //! species in the mixture. Units: m^3/kmol. + /*! + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //! This method returns the convention used in specification + //! of the standard state, of which there are currently two, + //! temperature based, and variable pressure based. + /*! + * Currently, there are two standard state conventions: + * - Temperature-based activities + * cSS_CONVENTION_TEMPERATURE 0 + * - default + * + * - Variable Pressure and Temperature -based activities + * cSS_CONVENTION_VPSS 1 + * + * - Thermodynamics is set via slave ThermoPhase objects with + * nothing being carried out at this %ThermoPhase object level + * cSS_CONVENTION_SLAVE 2 + */ + virtual int standardStateConvention() const; + + //! This method returns an array of generalized concentrations + /*! + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used + * by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. Note that they may + * or may not have units of concentration --- they might be + * partial pressures, mole fractions, or surface coverages, + * for example. + * + * @param c Output array of generalized concentrations. The + * units depend upon the implementation of the + * reaction rate expressions within the phase. + */ + virtual void getActivityConcentrations(doublereal* c) const; + + //! Return the standard concentration for the kth species + /*! + * The standard concentration \f$ C^0_k \f$ used to normalize + * the activity (i.e., generalized) concentration. In many cases, this quantity + * will be the same for all species in a phase - for example, + * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this + * reason, this method returns a single value, instead of an + * array. However, for phases in which the standard + * concentration is species-specific (e.g. surface species of + * different sizes), this method may be called with an + * optional parameter indicating the species. + * + * @param k Optional parameter indicating the species. The default + * is to assume this refers to species 0. + * @return + * Returns the standard concentration. The units are by definition + * dependent on the ThermoPhase and kinetics manager representation. + */ + virtual doublereal standardConcentration(int k=0) const; + + //! Get the array of non-dimensional activities at + //! the current solution temperature, pressure, and solution concentration. + /*! + * Note, for molality based formulations, this returns the + * molality based activities. + * + * We resolve this function at this level by calling + * on the activityConcentration function. However, + * derived classes may want to override this default + * implementation. + * + * @param a Output vector of activities. Length: m_kk. + */ + virtual void getActivities(doublereal* a) const; + //! Returns the isothermal compressibility. Units: 1/Pa. /*! * The isothermal compressibility is defined as @@ -163,20 +302,106 @@ namespace Cantera { //! Returns a reference to the substance object tpx::Substance& TPX_Substance(); - /// critical temperature - virtual doublereal critTemperature() const; - - /// critical pressure - virtual doublereal critPressure() const; - - /// critical density - virtual doublereal critDensity() const; - - /// saturation temperature + //@} + /// @name Properties of the Standard State of the Species in the Solution /*! - * @param p Pressure (Pa) + * The standard state of the pure fluid is defined as the real properties + * of the pure fluid at the most stable state of the fluid at the current + * temperature and pressure of the solution. With this definition, the + * activity of the fluid is always then defined to be equal to one. + */ + //@{ + + //! Get the array of chemical potentials at unit activity for the species + //! at their standard states at the current T and P of the solution. + /*! + * These are the standard state chemical potentials \f$ \mu^0_k(T,P) + * \f$. The values are evaluated at the current + * temperature and pressure of the solution + * + * @param mu Output vector of chemical potentials. + * Length: m_kk. + */ + virtual void getStandardChemPotentials(doublereal* mu) const; + + //! Get the nondimensional Enthalpy functions for the species + //! at their standard states at the current T and P of the solution. + /*! + * @param hrt Output vector of nondimensional standard state enthalpies. + * Length: m_kk. + */ + virtual void getEnthalpy_RT(doublereal* hrt) const; + + //! Get the array of nondimensional Entropy functions for the + //! standard state species at the current T and P of the solution. + /*! + * @param sr Output vector of nondimensional standard state entropies. + * Length: m_kk. + */ + virtual void getEntropy_R(doublereal* sr) const; + + //! Get the nondimensional Gibbs functions for the species + //! in their standard states at the current T and P of the solution. + /*! + * @param grt Output vector of nondimensional standard state gibbs free energies + * Length: m_kk. + */ + virtual void getGibbs_RT(doublereal* grt) const; + + //@} + + /// @name Thermodynamic Values for the Species Reference States + /*! + * The species reference state for pure fluids is defined as an ideal gas at the + * reference pressure and current temperature of the fluid. + */ + //@{ + + //! Returns the vector of nondimensional enthalpies of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * This base function will throw a Cantera exception unless + * it is overwritten in a derived class. + * + * @param hrt Output vector containing the nondimensional reference state enthalpies + * Length: m_kk. + */ + virtual void getEnthalpy_RT_ref(doublereal *hrt) const; + + //! Returns the vector of nondimensional Gibbs Free Energies of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * @param grt Output vector containing the nondimensional reference state + * Gibbs Free energies. Length: m_kk. + */ + virtual void getGibbs_RT_ref(doublereal *grt) const; + + //! Returns the vector of the gibbs function of the reference state at the current temperature + //! of the solution and the reference pressure for the species. + /*! + * units = J/kmol + * + * @param g Output vector containing the reference state + * Gibbs Free energies. Length: m_kk. Units: J/kmol. + */ + virtual void getGibbs_ref(doublereal *g) const; + + + + //! Returns the vector of nondimensional entropies of the reference state at the current temperature + //! of the solution and the reference pressure for each species. + /*! + * @param er Output vector containing the nondimensional reference state + * entropies. Length: m_kk. + */ + virtual void getEntropy_R_ref(doublereal *er) const; + + /** + * @name Setting the State + * + * These methods set all or part of the thermodynamic state. + * @{ */ - virtual doublereal satTemperature(doublereal p) const; //! Set the internally storred specific enthalpy (J/kg) and pressure (Pa) of the phase. /*! @@ -227,8 +452,25 @@ namespace Cantera { virtual void setState_SP(doublereal s, doublereal p, doublereal tol = 1.e-8); + //@} + //! @name Critical State Properties + /*! + * Critical properties for the pure fluid + */ + //@{ + + //! critical temperature + virtual doublereal critTemperature() const; + + //! critical pressure + virtual doublereal critPressure() const; + + //! critical density + virtual doublereal critDensity() const; + //@} + //! @name Saturation properties. /*! * These methods are only implemented by subclasses that @@ -237,6 +479,13 @@ namespace Cantera { */ //@{ + + //! saturation temperature + /*! + * @param p Pressure (Pa) + */ + virtual doublereal satTemperature(doublereal p) const; + //! Return the saturation pressure given the temperatur /*! * @param t Temperature (Kelvin) diff --git a/Cantera/src/thermo/RedlichKisterVPSSTP.cpp b/Cantera/src/thermo/RedlichKisterVPSSTP.cpp new file mode 100644 index 000000000..1f3944cd3 --- /dev/null +++ b/Cantera/src/thermo/RedlichKisterVPSSTP.cpp @@ -0,0 +1,1100 @@ +/** + * @file RedlichKisterVPSSTP.cpp + * Definitions for ThermoPhase object for phases which + * employ excess gibbs free energy formulations related to RedlichKister + * expansions (see \ref thermoprops + * and class \link Cantera::RedlichKisterVPSSTP RedlichKisterVPSSTP\endlink). + * + */ +/* + * Copywrite (2009) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ +/* + * $Date: 2011-04-14 12:24:13 -0600 (Thu, 14 Apr 2011) $ + * $Revision: 713 $ + */ + + +#include "RedlichKisterVPSSTP.h" +#include "ThermoFactory.h" +#include + +using namespace std; + +namespace Cantera { + + static const double xxSmall = 1.0E-150; + //==================================================================================================================== + /* + * Default constructor. + * + */ + RedlichKisterVPSSTP::RedlichKisterVPSSTP() : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + m_pSpecies_A_ij(0), + m_pSpecies_B_ij(0), + m_N_ij(0), + m_HE_m_ij(0), + m_SE_m_ij(0), + formRedlichKister_(0), + formTempModel_(0), + dlnActCoeff_dX_() + { + } + //==================================================================================================================== + /* + * Working constructors + * + * The two constructors below are the normal way + * the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + + */ + RedlichKisterVPSSTP::RedlichKisterVPSSTP(std::string inputFile, std::string id) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + m_pSpecies_A_ij(0), + m_pSpecies_B_ij(0), + m_N_ij(0), + m_HE_m_ij(0), + m_SE_m_ij(0), + formRedlichKister_(0), + formTempModel_(0), + dlnActCoeff_dX_() + { + constructPhaseFile(inputFile, id); + } + //==================================================================================================================== + RedlichKisterVPSSTP::RedlichKisterVPSSTP(XML_Node& phaseRoot, std::string id) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + m_pSpecies_A_ij(0), + m_pSpecies_B_ij(0), + m_N_ij(0), + m_HE_m_ij(0), + m_SE_m_ij(0), + formRedlichKister_(0), + formTempModel_(0), + dlnActCoeff_dX_() + { + constructPhaseXML(phaseRoot, id); + } + //==================================================================================================================== + // Special constructor for a hard-coded problem + /* + * + * LiKCl treating the PseudoBinary layer as passthrough. + * -> test to predict the eutectic and liquidus correctly. + * + */ + RedlichKisterVPSSTP::RedlichKisterVPSSTP(int testProb) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + m_pSpecies_A_ij(0), + m_pSpecies_B_ij(0), + m_N_ij(0), + m_HE_m_ij(0), + m_SE_m_ij(0), + formRedlichKister_(0), + formTempModel_(0), + dlnActCoeff_dX_() + { + constructPhaseFile("LiKCl_liquid.xml", ""); + numBinaryInteractions_ = 1; + + m_HE_m_ij.resize(0); + m_SE_m_ij.resize(0); + + vector_fp he(2); + he[0] = 0.0; + he[1] = 0.0; + vector_fp se(2); + se[0] = 0.0; + se[1] = 0.0; + + m_HE_m_ij.push_back(he); + m_SE_m_ij.push_back(se); + m_N_ij.push_back(1); + m_pSpecies_A_ij.resize(1); + m_pSpecies_B_ij.resize(1); + + int iLiLi = speciesIndex("LiLi"); + if (iLiLi < 0) { + throw CanteraError("RedlichKisterVPSSTP test1 constructor", + "Unable to find LiLi"); + } + m_pSpecies_A_ij[0] = iLiLi; + + + int iVLi = speciesIndex("VLi"); + if (iVLi < 0) { + throw CanteraError("RedlichKisterVPSSTP test1 constructor", + "Unable to find VLi"); + } + m_pSpecies_B_ij[0] = iVLi; + + + } + //==================================================================================================================== + /* + * Copy Constructor: + * + * Note this stuff will not work until the underlying phase + * has a working copy constructor + */ + RedlichKisterVPSSTP::RedlichKisterVPSSTP(const RedlichKisterVPSSTP &b) : + GibbsExcessVPSSTP(), + numBinaryInteractions_(0), + m_pSpecies_A_ij(0), + m_pSpecies_B_ij(0), + m_N_ij(0), + m_HE_m_ij(0), + m_SE_m_ij(0), + formRedlichKister_(0), + formTempModel_(0), + dlnActCoeff_dX_() + { + RedlichKisterVPSSTP::operator=(b); + } + //==================================================================================================================== + /* + * operator=() + * + * Note this stuff will not work until the underlying phase + * has a working assignment operator + */ + RedlichKisterVPSSTP& RedlichKisterVPSSTP:: + operator=(const RedlichKisterVPSSTP &b) { + if (&b == this) { + return *this; + } + + GibbsExcessVPSSTP::operator=(b); + + numBinaryInteractions_ = b.numBinaryInteractions_ ; + m_pSpecies_A_ij = b.m_pSpecies_A_ij; + m_pSpecies_B_ij = b.m_pSpecies_B_ij; + m_N_ij = b.m_N_ij; + m_HE_m_ij = b.m_HE_m_ij; + m_SE_m_ij = b.m_SE_m_ij; + formRedlichKister_ = b.formRedlichKister_; + formTempModel_ = b.formTempModel_; + dlnActCoeff_dX_ = b.dlnActCoeff_dX_; + + return *this; + } + //==================================================================================================================== + /* + * + * ~RedlichKisterVPSSTP(): (virtual) + * + * Destructor: does nothing: + * + */ + RedlichKisterVPSSTP::~RedlichKisterVPSSTP() { + } + //==================================================================================================================== + /* + * This routine duplicates the current object and returns + * a pointer to ThermoPhase. + */ + ThermoPhase* + RedlichKisterVPSSTP::duplMyselfAsThermoPhase() const { + RedlichKisterVPSSTP* mtp = new RedlichKisterVPSSTP(*this); + return (ThermoPhase *) mtp; + } + + //==================================================================================================================== + // Equation of state type flag. + /* + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The RedlichKisterVPSSTP class also returns + * zero, as it is a non-complete class. + */ + int RedlichKisterVPSSTP::eosType() const { + return 0; + } + //==================================================================================================================== + /* + * Import, construct, and initialize a phase + * specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void RedlichKisterVPSSTP::constructPhaseFile(std::string inputFile, std::string id) { + + if ((int) inputFile.size() == 0) { + throw CanteraError("RedlichKisterVPSSTP:constructPhaseFile", + "input file is null"); + } + string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("RedlichKisterVPSSTP:constructPhaseFile","could not open " + +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("RedlichKisterVPSSTP:constructPhaseFile", + "ERROR: Can not find phase named " + + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; + } + //==================================================================================================================== + /* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * Most of the work is carried out by the cantera base + * routine, importPhase(). That routine imports all of the + * species and element data, including the standard states + * of the species. + * + * Then, In this routine, we read the information + * particular to the specification of the activity + * coefficient model for the Pitzer parameterization. + * + * We also read information about the molar volumes of the + * standard states if present in the XML file. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void RedlichKisterVPSSTP::constructPhaseXML(XML_Node& phaseNode, std::string id) { + string stemp; + if ((int) id.size() > 0) { + string idp = phaseNode.id(); + if (idp != id) { + throw CanteraError("RedlichKisterVPSSTP::constructPhaseXML", + "phasenode and Id are incompatible"); + } + } + + /* + * Find the Thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("RedlichKisterVPSSTP::constructPhaseXML", + "no thermo XML node"); + } + XML_Node& thermoNode = phaseNode.child("thermo"); + + /* + * Make sure that the thermo model is RedlichKister + */ + stemp = thermoNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "redlich-kister") { + throw CanteraError("RedlichKisterVPSSTP::constructPhaseXML", + "model name isn't Redlich-Kister: " + formString); + + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the solvent and solute standard states + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("RedlichKisterVPSSTP::constructPhaseXML","importPhase failed "); + } + + } + //==================================================================================================================== + /* + * ------------ Molar Thermodynamic Properties ---------------------- + */ + //==================================================================================================================== + /* + * - Activities, Standard States, Activity Concentrations ----------- + */ + //==================================================================================================================== + // Get the array of non-dimensional molar-based activity coefficients at + // the current solution temperature, pressure, and solution concentration. + /* + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + void RedlichKisterVPSSTP::getLnActivityCoefficients(doublereal* lnac) const { + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + + /* + * take the exp of the internally storred coefficients. + */ + for (int k = 0; k < m_kk; k++) { + lnac[k] = lnActCoeff_Scaled_[k]; + } + } + //==================================================================================================================== + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + //==================================================================================================================== + void RedlichKisterVPSSTP::getElectrochemPotentials(doublereal* mu) const { + getChemPotentials(mu); + double ve = Faraday * electricPotential(); + for (int k = 0; k < m_kk; k++) { + mu[k] += ve*charge(k); + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::getChemPotentials(doublereal* mu) const { + doublereal xx; + /* + * First get the standard chemical potentials in + * molar form. + * -> this requires updates of standard state as a function + * of T and P + */ + getStandardChemPotentials(mu); + /* + * Update the activity coefficients + */ + s_update_lnActCoeff(); + /* + * + */ + doublereal RT = GasConstant * temperature(); + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + mu[k] += RT * (log(xx) + lnActCoeff_Scaled_[k]); + } + } + //==================================================================================================================== + //Molar enthalpy. Units: J/kmol. + doublereal RedlichKisterVPSSTP::enthalpy_mole() const { + int kk = nSpecies(); + double hbar[kk], h = 0; + getPartialMolarEnthalpies(hbar); + for (int i = 0; i < kk; i++){ + h += moleFractions_[i]*hbar[i]; + } + return h; + } + //==================================================================================================================== + /// Molar entropy. Units: J/kmol. + doublereal RedlichKisterVPSSTP::entropy_mole() const { + int kk = nSpecies(); + double sbar[kk], s = 0; + getPartialMolarEntropies(sbar); + for (int i = 0; i < kk; i++){ + s += moleFractions_[i]*sbar[i]; + } + return s; + } + //==================================================================================================================== + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + doublereal RedlichKisterVPSSTP::cp_mole() const { + int kk = nSpecies(); + double cpbar[kk], cp = 0; + getPartialMolarCp(cpbar); + for (int i = 0; i < kk; i++){ + cp += moleFractions_[i]*cpbar[i]; + } + return cp; + } + //==================================================================================================================== + /// Molar heat capacity at constant volume. Units: J/kmol/K. + doublereal RedlichKisterVPSSTP::cv_mole() const { + return cp_mole() - GasConstant; + } + //==================================================================================================================== + // Returns an array of partial molar enthalpies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void RedlichKisterVPSSTP::getPartialMolarEnthalpies(doublereal* hbar) const { + /* + * Get the nondimensional standard state enthalpies + */ + getEnthalpy_RT(hbar); + /* + * dimensionalize it. + */ + double T = temperature(); + double RT = GasConstant * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] *= RT; + } + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + double RTT = RT * T; + for (int k = 0; k < m_kk; k++) { + hbar[k] -= RTT * dlnActCoeffdT_Scaled_[k]; + } + } + //==================================================================================================================== + // Returns an array of partial molar heat capacities for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????? \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void RedlichKisterVPSSTP::getPartialMolarCp(doublereal* cpbar) const { + /* + * Get the nondimensional standard state entropies + */ + getCp_R(cpbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + cpbar[k] *= GasConstant; + } + } + //==================================================================================================================== + // Returns an array of partial molar entropies for the species + // in the mixture. + /* + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + */ + void RedlichKisterVPSSTP::getPartialMolarEntropies(doublereal* sbar) const { + double xx; + /* + * Get the nondimensional standard state entropies + */ + getEntropy_R(sbar); + double T = temperature(); + /* + * Update the activity coefficients, This also update the + * internally storred molalities. + */ + s_update_lnActCoeff(); + s_update_dlnActCoeff_dT(); + + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(moleFractions_[k], xxSmall); + sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k]; + } + /* + * dimensionalize it. + */ + for (int k = 0; k < m_kk; k++) { + sbar[k] *= GasConstant; + } + } + + /* + * ------------ Partial Molar Properties of the Solution ------------ + */ + //==================================================================================================================== + // Return an array of partial molar volumes for the + // species in the mixture. Units: m^3/kmol. + /* + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + void RedlichKisterVPSSTP::getPartialMolarVolumes(doublereal* vbar) const { + int iK; + /* + * Get the standard state values in m^3 kmol-1 + */ + getStandardVolumes(vbar); + for ( iK = 0; iK < m_kk; iK++ ){ + + vbar[iK] += 0.0; + } + } + //==================================================================================================================== + doublereal RedlichKisterVPSSTP::err(std::string msg) const { + throw CanteraError("RedlichKisterVPSSTP","Base class method " + +msg+" called. Equation of state type: "+int2str(eosType())); + return 0; + } + //==================================================================================================================== + /* + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + void RedlichKisterVPSSTP::initThermo() { + initLengths(); + GibbsExcessVPSSTP::initThermo(); + } + //==================================================================================================================== + // Initialize lengths of local variables after all species have + // been identified. + void RedlichKisterVPSSTP::initLengths() { + m_kk = nSpecies(); + dlnActCoeffdlnN_.resize(m_kk, m_kk); + } + //==================================================================================================================== + /* + * initThermoXML() (virtual from ThermoPhase) + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a complete XML tree + * description of the phase, including all of the species data. In other words while "phase" must + * point to an XML phase object, it must have sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done to see if phaseNode is pointing to the phase + * with the correct id. + */ + void RedlichKisterVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) { + std::string subname = "RedlichKisterVPSSTP::initThermoXML"; + std::string stemp; + + /* + * Check on the thermo field. Must have: + * + */ + + XML_Node& thermoNode = phaseNode.child("thermo"); + std::string mStringa = thermoNode.attrib("model"); + std::string mString = lowercase(mStringa); + if (mString != "redlich-kister") { + throw CanteraError(subname.c_str(), + "Unknown thermo model: " + mStringa + " - This object only knows \"Redlich-Kister\" "); + } + + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + XML_Node *acNodePtr = 0; + if (thermoNode.hasChild("activityCoefficients")) { + XML_Node& acNode = thermoNode.child("activityCoefficients"); + acNodePtr = &acNode; + std::string mStringa = acNode.attrib("model"); + std::string mString = lowercase(mStringa); + if (mString != "redlich-kister") { + throw CanteraError(subname.c_str(), + "Unknown activity coefficient model: " + mStringa); + } + int n = acNodePtr->nChildren(); + for (int i = 0; i < n; i++) { + XML_Node &xmlACChild = acNodePtr->child(i); + stemp = xmlACChild.name(); + std::string nodeName = lowercase(stemp); + /* + * Process a binary salt field, or any of the other XML fields + * that make up the Pitzer Database. Entries will be ignored + * if any of the species in the entry isn't in the solution. + */ + if (nodeName == "binaryneutralspeciesparameters") { + readXMLBinarySpecies(xmlACChild); + } + } + } + /* + * Go down the chain + */ + GibbsExcessVPSSTP::initThermoXML(phaseNode, id); + } + //=================================================================================================================== + // Update the activity coefficients + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + */ + void RedlichKisterVPSSTP::s_update_lnActCoeff() const { + int iA, iB, m, k; + doublereal XA, XB; + doublereal T = temperature(); + doublereal RT = GasConstant * T; + + fvo_zero_dbl_1(lnActCoeff_Scaled_, m_kk); + + /* + * Scaling: I moved the division of RT higher so that we are always dealing with G/RT dimensionless terms + * within the routine. There is a severe problem with roundoff error in these calculations. The + * dimensionless terms help. + */ + + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + doublereal deltaX = XA - XB; + int N = m_N_ij[i]; + vector_fp &he_vec = m_HE_m_ij[i]; + vector_fp &se_vec = m_SE_m_ij[i]; + doublereal poly = 1.0; + doublereal polyMm1 = 1.0; + doublereal sum = 0.0; + doublereal sumMm1 = 0.0; + doublereal sum2 = 0.0; + for (m = 0; m < N; m++) { + doublereal A_ge = (he_vec[m] - T * se_vec[m]) / RT; + sum += A_ge * poly; + sum2 += A_ge * (m + 1) * poly; + poly *= deltaX; + if (m >= 1) { + sumMm1 += (A_ge * polyMm1 * m); + polyMm1 *= deltaX; + } + } + doublereal oneMXA = 1.0 - XA; + doublereal oneMXB = 1.0 - XB; + for (k = 0; k < m_kk; k++) { + if (iA == k) { + lnActCoeff_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB)); + } else if (iB == k) { + lnActCoeff_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA)); + } else { + lnActCoeff_Scaled_[k] += -(XA * XB * sum2); + } + } + // Debug against formula in literature +#ifdef DEBUG_MODE_NOT + double lnA = 0.0; + double lnB = 0.0; + double polyk = 1.0; + double fac = 2.0 * XA - 1.0; + for (m = 0; m < N; m++) { + doublereal A_ge = (he_vec[m] - T * se_vec[m]) / RT; + lnA += A_ge * oneMXA * oneMXA * polyk * (1.0 + 2.0 * XA * m / fac); + lnB += A_ge * XA * XA * polyk * (1.0 - 2.0 * oneMXA * m / fac); + polyk *= fac; + } + // This gives the same result as above + // printf("RT lnActCoeff_Scaled_[iA] = %15.8E , lnA = %15.8E\n", lnActCoeff_Scaled_[iA], lnA); + // printf("RT lnActCoeff_Scaled_[iB] = %15.8E , lnB = %15.8E\n", lnActCoeff_Scaled_[iB], lnB); + +#endif + + } + + } + //=================================================================================================================== + // Update the derivative of the log of the activity coefficients wrt T + /* + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + * + + */ + void RedlichKisterVPSSTP::s_update_dlnActCoeff_dT() const { + int iA, iB, m, k; + doublereal XA, XB; + // doublereal T = temperature(); + + fvo_zero_dbl_1(dlnActCoeffdT_Scaled_, m_kk); + fvo_zero_dbl_1(d2lnActCoeffdT2_Scaled_, m_kk); + + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + doublereal deltaX = XA - XB; + int N = m_N_ij[i]; + doublereal poly = 1.0; + doublereal sum = 0.0; + + vector_fp &se_vec = m_SE_m_ij[i]; + doublereal sumMm1 = 0.0; + doublereal polyMm1 = 1.0; + doublereal sum2 = 0.0; + for (m = 0; m < N; m++) { + doublereal A_ge = - se_vec[m]; + sum += A_ge * poly; + sum2 += A_ge * (m + 1) * poly; + poly *= deltaX; + if (m >= 1) { + sumMm1 += (A_ge * polyMm1 * m); + polyMm1 *= deltaX; + } + } + doublereal oneMXA = 1.0 - XA; + doublereal oneMXB = 1.0 - XB; + for (k = 0; k < m_kk; k++) { + if (iA == k) { + dlnActCoeffdT_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB)); + } else if (iB == k) { + dlnActCoeffdT_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA)); + } else { + dlnActCoeffdT_Scaled_[k] += -(XA * XB * sum2); + } + } + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::getdlnActCoeffdT(doublereal *dlnActCoeffdT) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k]; + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const { + s_update_dlnActCoeff_dT(); + for (int k = 0; k < m_kk; k++) { + d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k]; + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::s_update_dlnActCoeff_dX_() const { + + + int iA, iB, m, k; + doublereal XA, XB; + doublereal T = temperature(); + + dlnActCoeff_dX_.zero(); + + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + doublereal deltaX = XA - XB; + int N = m_N_ij[i]; + doublereal poly = 1.0; + doublereal sum = 0.0; + vector_fp &he_vec = m_HE_m_ij[i]; + vector_fp &se_vec = m_SE_m_ij[i]; + doublereal sumMm1 = 0.0; + doublereal polyMm1 = 1.0; + doublereal polyMm2 = 1.0; + doublereal sum2 = 0.0; + doublereal sum2Mm1 = 0.0; + doublereal sumMm2 = 0.0; + for (m = 0; m < N; m++) { + doublereal A_ge = he_vec[m] - T * se_vec[m]; + sum += A_ge * poly; + sum2 += A_ge * (m + 1) * poly; + poly *= deltaX; + if (m >= 1) { + sumMm1 += (A_ge * polyMm1 * m); + sum2Mm1 += (A_ge * polyMm1 * m * (1.0 + m)); + polyMm1 *= deltaX; + } + if (m >= 2) { + sumMm2 += (A_ge * polyMm2 * m * (m - 1.0)); + polyMm2 *= deltaX; + } + } + + for (k = 0; k < m_kk; k++) { + if (iA == k) { + + dlnActCoeff_dX_(k, iA) += (- XB * sum + (1.0 - XA) * XB * sumMm1 + + XB * sumMm1 * (1.0 - 2.0 * XA + XB) + + XA * XB * sumMm2 * (1.0 - XA + XB)); + + dlnActCoeff_dX_(k, iB) += ((1.0 - XA) * sum - (1.0 - XA) * XB * sumMm1 + + XA * sumMm1 * (1.0 + 2.0 * XB - XA) + - XA * XB * sumMm2 * (1.0 - XA + XB)); + + } else if (iB == k) { + + dlnActCoeff_dX_(k, iA) += ((1.0 - XB) * sum + (1.0 - XA) * XB * sumMm1 + + XB * sumMm1 * (1.0 - 2.0 * XA + XB) + + XA * XB * sumMm2 * (1.0 - XA + XB)); + + dlnActCoeff_dX_(k, iB) += (- XA * sum - (1.0 - XB) * XA * sumMm1 + + XA * sumMm1 * (XB - XA - (1.0 - XB)) + - XA * XB * sumMm2 * (-XA - (1.0 - XB))); + } else { + + dlnActCoeff_dX_(k, iA) += ( - XB * sum2 - XA * XB * sum2Mm1); + + dlnActCoeff_dX_(k, iB) += ( - XA * sum2 + XA * XB * sum2Mm1); + + } + } + } + } + //==================================================================================================================== + // Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + // a line in parameter space or along a line in physical space + /* + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + void RedlichKisterVPSSTP::getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const { + s_update_dlnActCoeff_dT(); + s_update_dlnActCoeff_dX_(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffds[k] = dlnActCoeffdT_Scaled_[k] * dTds; + for (int l = 0; l < m_kk; l++) { + dlnActCoeffds[k] += dlnActCoeff_dX_(k, l) * dXds[l]; + } + } + } + + //==================================================================================================================== + void RedlichKisterVPSSTP::getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + s_update_dlnActCoeff_dX_(); + for (int l = 0; l < m_kk; l++) { + dlnActCoeffdlnN_diag[l] = dlnActCoeff_dX_(l, l); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnN_diag[k] -= dlnActCoeff_dX_(l, k) * moleFractions_[k]; + } + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const { + s_update_dlnActCoeff_dX_(); + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k]; + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::getdlnActCoeffdlnN(const int ld, doublereal *dlnActCoeffdlnN) { + s_update_dlnActCoeff_dX_(); + double *data = & dlnActCoeffdlnN_(0,0); + for (int k = 0; k < m_kk; k++) { + for (int m = 0; m < m_kk; m++) { + dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m]; + } + } + } + //==================================================================================================================== + void RedlichKisterVPSSTP::resizeNumInteractions(const int num) { + numBinaryInteractions_ = num; + m_pSpecies_A_ij.resize(num, -1); + m_pSpecies_B_ij.resize(num, -1); + m_N_ij.resize(num, -1); + m_HE_m_ij.resize(num); + m_SE_m_ij.resize(num); + dlnActCoeff_dX_.resize(num, num, 0.0); + } + //==================================================================================================================== + // Process an XML node called "binaryNeutralSpeciesParameters" + /* + * This node contains all of the parameters necessary to describe the RedlichKister Interaction for + * a single binary interaction. This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + */ + void RedlichKisterVPSSTP::readXMLBinarySpecies(XML_Node &xmLBinarySpecies) { + std::string xname = xmLBinarySpecies.name(); + if (xname != "binaryNeutralSpeciesParameters") { + throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", + "Incorrect name for processing this routine: " + xname); + } + double *charge = DATA_PTR(m_speciesCharge); + std::string stemp; + int nParamsFound = 0; + int Npoly = 0; + vector_fp hParams, sParams, vParams; + std::string iName = xmLBinarySpecies.attrib("speciesA"); + if (iName == "") { + throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "no speciesA attrib"); + } + std::string jName = xmLBinarySpecies.attrib("speciesB"); + if (jName == "") { + throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "no speciesB attrib"); + } + /* + * Find the index of the species in the current phase. It's not + * an error to not find the species. This means that the interaction doesn't occur for the current + * implementation of the phase. + */ + int iSpecies = speciesIndex(iName); + if (iSpecies < 0) { + return; + } + string ispName = speciesName(iSpecies); + if (charge[iSpecies] != 0) { + throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "speciesA charge problem"); + } + int jSpecies = speciesIndex(jName); + if (jSpecies < 0) { + return; + } + std::string jspName = speciesName(jSpecies); + if (charge[jSpecies] != 0) { + throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "speciesB charge problem"); + } + /* + * Ok we have found a valid interaction + */ + numBinaryInteractions_++; + int iSpot = numBinaryInteractions_ - 1; + m_pSpecies_A_ij.resize(numBinaryInteractions_); + m_pSpecies_B_ij.resize(numBinaryInteractions_); + m_pSpecies_A_ij[iSpot] = iSpecies; + m_pSpecies_B_ij[iSpot] = jSpecies; + + int num = xmLBinarySpecies.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = xmLBinarySpecies.child(iChild); + stemp = xmlChild.name(); + string nodeName = lowercase(stemp); + /* + * Process the binary species interaction child elements + */ + if (nodeName == "excessenthalpy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, hParams, true, "toSI", "excessEnthalpy"); + nParamsFound = hParams.size(); + if (nParamsFound > Npoly) { + Npoly = nParamsFound; + } + + } + + if (nodeName == "excessentropy") { + /* + * Get the string containing all of the values + */ + ctml::getFloatArray(xmlChild, sParams, true, "toSI", "excessEntropy"); + nParamsFound = sParams.size(); + if (nParamsFound > Npoly) { + Npoly = nParamsFound; + } + } + } + hParams.resize(Npoly, 0.0); + sParams.resize(Npoly, 0.0); + m_HE_m_ij.push_back(hParams); + m_SE_m_ij.push_back(sParams); + m_N_ij.push_back(Npoly); + resizeNumInteractions(numBinaryInteractions_); + } + //==================================================================================================================== +#ifdef DEBUG_MODE + void RedlichKisterVPSSTP::Vint(double &VintOut, double &voltsOut) { + int iA, iB, m; + doublereal XA, XB; + doublereal T = temperature(); + doublereal RT = GasConstant * T; + double Volts = 0.0; + + fvo_zero_dbl_1(lnActCoeff_Scaled_, m_kk); + + for (int i = 0; i < numBinaryInteractions_; i++) { + iA = m_pSpecies_A_ij[i]; + iB = m_pSpecies_B_ij[i]; + XA = moleFractions_[iA]; + XB = moleFractions_[iB]; + if (XA <= 1.0E-14) { + XA = 1.0E-14; + } + if (XA >= (1.0 - 1.0E-14)) { + XA = 1.0 - 1.0E-14; + } + + int N = m_N_ij[i]; + vector_fp &he_vec = m_HE_m_ij[i]; + vector_fp &se_vec = m_SE_m_ij[i]; + double fac = 2.0 * XA - 1.0; + if (fabs(fac) < 1.0E-13) { + fac = 1.0E-13; + } + double polykp1 = fac; + double poly1mk = fac; + + for (m = 0; m < N; m++) { + doublereal A_ge = he_vec[m] - T * se_vec[m]; + Volts += A_ge * ( polykp1 - (2.0 * XA * m * (1.0-XA) ) / poly1mk ); + polykp1 *= fac; + poly1mk /= fac; + } + } + Volts /= Faraday; + + double termp = RT * log((1.0 - XA)/XA) / Faraday; + + VintOut = Volts; + voltsOut = Volts + termp; + } + #endif + //==================================================================================================================== +} + diff --git a/Cantera/src/thermo/RedlichKisterVPSSTP.h b/Cantera/src/thermo/RedlichKisterVPSSTP.h new file mode 100644 index 000000000..87d11f306 --- /dev/null +++ b/Cantera/src/thermo/RedlichKisterVPSSTP.h @@ -0,0 +1,937 @@ +/** + * @file RedlichKisterVPSSTP.h + * Header for intermediate ThermoPhase object for phases which + * employ gibbs excess free energy based formulations + * (see \ref thermoprops + * and class \link Cantera::RedlichKisterVPSSTP RedlichKisterVPSSTP\endlink). + * + * Header file for a derived class of ThermoPhase that handles + * variable pressure standard state methods for calculating + * thermodynamic properties that are further based upon activities + * based on the molality scale. These include most of the methods for + * calculating liquid electrolyte thermodynamics. + */ +/* + * 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. + */ +/* + * $Id: MargulesVPSSTP.h 782 2011-10-19 20:45:06Z hkmoffa $ + */ + +#ifndef CT_REDLICHKISTERVPSSTP_H +#define CT_REDLICHKISTERVPSSTP_H + +#include "GibbsExcessVPSSTP.h" +#include "Array.h" + +namespace Cantera { + + /** + * @ingroup thermoprops + */ + + + //! RedlichKisterVPSSTP is a derived class of GibbsExcessVPSSTP that employs + //! the Redlich-Kister approximation for the excess gibbs free energy + /*! + * + * %RedlichKisterVPSSTP derives from class GibbsExcessVPSSTP which is derived + * from VPStandardStateTP, and overloads the virtual methods defined there with ones that + * use expressions appropriate for the Redlich Kister Excess gibbs free energy approximation. + * + * The independent unknowns are pressure, temperature, and mass fraction. + * + * Several concepts are introduced. The first concept is there are temporary + * variables for holding the species standard state values of Cp, H, S, G, and V at the + * last temperature and pressure called. These functions are not recalculated + * if a new call is made using the previous temperature and pressure. Currently, + * these variables and the calculation method are handled by the VPSSMgr class, + * for which VPStandardStateTP owns a pointer to. + * + * To support the above functionality, pressure and temperature variables, + * m_plast_ss and m_tlast_ss, are kept which store the last pressure and temperature + * used in the evaluation of standard state properties. + * + * This class is usually used for nearly incompressible phases. For those phases, it + * makes sense to change the equation of state independent variable from + * density to pressure. The variable m_Pcurrent contains the current value of the + * pressure within the phase. + * + * + *
+ *

Specification of Species Standard %State Properties

+ *
+ * + * All species are defined to have standard states that depend upon both + * the temperature and the pressure. The Redlich-Kister approximation assumes + * symmetric standard states, where all of the standard state assume + * that the species are in pure component states at the temperatue + * and pressure of the solution. I don't think it prevents, however, + * some species from being dilute in the solution. + * + * + *
+ *

Specification of Solution Thermodynamic Properties

+ *
+ * + * The molar excess Gibbs free energy is given by the following formula which is a sum over interactions i. + * Each of the interactions are binary interactions involving two of the species in the phase, denoted, Ai + * and Bi. + * This is the generalization of the Redlich-Kister formulation for a phase that has more than 2 species. + * + * \f[ + * G^E = \sum_{i} G^E_{i} + * \f] + * + * where + * + * \f[ + * G^E_{i} = n X_{Ai} X_{Bi} \sum_m \left( A^{i}_m {\left( X_{Ai} - X_{Bi} \right)}^m \right) + * \f] + * + * and where we can break down the gibbs free energy contributions into enthalpy and entropy contributions + * + * \f[ + * H^E_i = n X_{Ai} X_{Bi} \sum_m \left( H^{i}_m {\left( X_{Ai} - X_{Bi} \right)}^m \right) + * \f] + * + * \f[ + * S^E_i = n X_{Ai} X_{Bi} \sum_m \left( S^{i}_m {\left( X_{Ai} - X_{Bi} \right)}^m \right) + * \f] + * + * where n is the total moles in the solution. + * + * The activity of a species defined in the phase is given by an excess Gibbs free energy formulation. + * + * \f[ + * a_k = \gamma_k X_k + * \f] + * + * where + * + * \f[ + * R T \ln( \gamma_k )= \frac{d(n G^E)}{d(n_k)}\Bigg|_{n_i} + * \f] + * + * Taking the derivatives results in the following expression + * \f[ + * R T \ln( \gamma_k )= \sum_i \delta_{Ai,k} (1 - X_{Ai}) X_{Bi} \sum_m \left( A^{i}_m {\left( X_{Ai} - X_{Bi} \right)}^m \right) + * + \sum_i \delta_{Ai,k} X_{Ai} X_{Bi} \sum_m \left( A^{i}_0 + A^{i}_m {\left( X_{Ai} - X_{Bi} \right)}^{m-1} (1 - X_{Ai} + X_{Bi}) \right) + * \f] + * where + * + * + * This object inherits from the class VPStandardStateTP. Therefore, the specification and + * calculation of all standard state and reference state values are handled at that level. Various functional + * forms for the standard state are permissible. + * The chemical potential for species k is equal to + * + * \f[ + * \mu_k(T,P) = \mu^o_k(T, P) + R T \ln(\gamma_k X_k) + * \f] + * + * The partial molar entropy for species k is given by the following relation, + * + * \f[ + * \tilde{s}_k(T,P) = s^o_k(T,P) - R \ln( \gamma_k X_k ) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * The partial molar enthalpy for species k is given by + * + * \f[ + * \tilde{h}_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * The partial molar volume for species k is + * + * \f[ + * \tilde V_k(T,P) = V^o_k(T,P) + R T \frac{d \ln(\gamma_k) }{dP} + * \f] + * + * The partial molar Heat Capacity for species k is + * + * \f[ + * \tilde{C}_{p,k}(T,P) = C^o_{p,k}(T,P) - 2 R T \frac{d \ln( \gamma_k )}{dT} + * - R T^2 \frac{d^2 \ln(\gamma_k) }{{dT}^2} + * \f] + * + *
+ *

%Application within %Kinetics Managers

+ *
+ * + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^s_k, \f$ where \f$ C^s_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used + * by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. + * The activity concentration,\f$ C^a_k \f$,is given by the following expression. + * + * \f[ + * C^a_k = C^s_k X_k = \frac{P}{R T} X_k + * \f] + * + * The standard concentration for species k is independent of k and equal to + * + * \f[ + * C^s_k = C^s = \frac{P}{R T} + * \f] + * + * For example, a bulk-phase binary gas reaction between species j and k, producing + * a new gas species l would have the + * following equation for its rate of progress variable, \f$ R^1 \f$, which has + * units of kmol m-3 s-1. + * + * \f[ + * R^1 = k^1 C_j^a C_k^a = k^1 (C^s a_j) (C^s a_k) + * \f] + * where + * \f[ + * C_j^a = C^s a_j \mbox{\quad and \quad} C_k^a = C^s a_k + * \f] + * + * + * \f$ C_j^a \f$ is the activity concentration of species j, and + * \f$ C_k^a \f$ is the activity concentration of species k. \f$ C^s \f$ + * is the standard concentration. \f$ a_j \f$ is + * the activity of species j which is equal to the mole fraction of j. + * + * The reverse rate constant can then be obtained from the law of microscopic reversibility + * and the equilibrium expression for the system. + * + * \f[ + * \frac{a_j a_k}{ a_l} = K_a^{o,1} = \exp(\frac{\mu^o_l - \mu^o_j - \mu^o_k}{R T} ) + * \f] + * + * \f$ K_a^{o,1} \f$ is the dimensionless form of the equilibrium constant, associated with + * the pressure dependent standard states \f$ \mu^o_l(T,P) \f$ and their associated activities, + * \f$ a_l \f$, repeated here: + * + * \f[ + * \mu_l(T,P) = \mu^o_l(T, P) + R T \log(a_l) + * \f] + * + * We can switch over to expressing the equilibrium constant in terms of the reference + * state chemical potentials + * + * \f[ + * K_a^{o,1} = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{P} + * \f] + * + * The concentration equilibrium constant, \f$ K_c \f$, may be obtained by changing over + * to activity concentrations. When this is done: + * + * \f[ + * \frac{C^a_j C^a_k}{ C^a_l} = C^o K_a^{o,1} = K_c^1 = + * \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{RT} + * \f] + * + * %Kinetics managers will calculate the concentration equilibrium constant, \f$ K_c \f$, + * using the second and third part of the above expression as a definition for the concentration + * equilibrium constant. + * + * For completeness, the pressure equilibrium constant may be obtained as well + * + * \f[ + * \frac{P_j P_k}{ P_l P_{ref}} = K_p^1 = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) + * \f] + * + * \f$ K_p \f$ is the simplest form of the equilibrium constant for ideal gases. However, it isn't + * necessarily the simplest form of the equilibrium constant for other types of phases; \f$ K_c \f$ is + * used instead because it is completely general. + * + * The reverse rate of progress may be written down as + * \f[ + * R^{-1} = k^{-1} C_l^a = k^{-1} (C^o a_l) + * \f] + * + * where we can use the concept of microscopic reversibility to + * write the reverse rate constant in terms of the + * forward reate constant and the concentration equilibrium + * constant, \f$ K_c \f$. + * + * \f[ + * k^{-1} = k^1 K^1_c + * \f] + * + * \f$k^{-1} \f$ has units of s-1. + * + * + *
+ *

Instantiation of the Class

+ *
+ * + * + * The constructor for this phase is located in the default ThermoFactory + * for %Cantera. A new %IdealGasPhase may be created by the following code + * snippet: + * + * @code + * XML_Node *xc = get_XML_File("silane.xml"); + * XML_Node * const xs = xc->findNameID("phase", "silane"); + * ThermoPhase *silane_tp = newPhase(*xs); + * IdealGasPhase *silaneGas = dynamic_cast (silane_tp); + * @endcode + * + * or by the following constructor: + * + * @code + * XML_Node *xc = get_XML_File("silane.xml"); + * XML_Node * const xs = xc->findNameID("phase", "silane"); + * IdealGasPhase *silaneGas = new IdealGasPhase(*xs); + * @endcode + * + *
+ *

XML Example

+ *
+ * An example of an XML Element named phase setting up a IdealGasPhase + * object named silane is given below. + * + * + * @verbatim + + + Si H He + + H2 H HE SIH4 SI SIH SIH2 SIH3 H3SISIH SI2H6 + H2SISIH2 SI3H8 SI2 SI3 + + + + + + + @endverbatim + * + * The model attribute "IdealGas" of the thermo XML element identifies the phase as + * being of the type handled by the IdealGasPhase object. + * + * @ingroup thermoprops + * + + */ + class RedlichKisterVPSSTP : public GibbsExcessVPSSTP { + + public: + + //! Constructor + /*! + * This doesn't do much more than initialize constants with + * default values. + */ + RedlichKisterVPSSTP(); + + //! Construct and initialize a RedlichKisterVPSSTP ThermoPhase object + //! directly from an xml input file + /*! + * Working constructors + * + * The two constructors below are the normal way the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the XML database to get the info for the phase. + * + * @param inputFile Name of the input file containing the phase XML data + * to set up the object + * @param id ID of the phase in the input file. Defaults to the + * empty string. + */ + RedlichKisterVPSSTP(std::string inputFile, std::string id = ""); + + //! Construct and initialize a RedlichKisterVPSSTP ThermoPhase object + //! directly from an XML database + /*! + * @param phaseRef XML phase node containing the description of the phase + * @param id id attribute containing the name of the phase. + * (default is the empty string) + */ + RedlichKisterVPSSTP(XML_Node& phaseRef, std::string id = ""); + + + //! Special constructor for a hard-coded problem + /*! + * + * @param testProb Hard-coded value. Only the value of 1 is + * used. It's for + * a LiKCl system + * -> test to predict the eutectic and liquidus correctly. + */ + RedlichKisterVPSSTP(int testProb); + + //! Copy constructor + /*! + * Note this stuff will not work until the underlying phase + * has a working copy constructor + * + * @param b class to be copied + */ + RedlichKisterVPSSTP(const RedlichKisterVPSSTP& b); + + //! Assignment operator + /*! + * + * @param b class to be copied. + */ + RedlichKisterVPSSTP& operator=(const RedlichKisterVPSSTP &b); + + //! Destructor + virtual ~RedlichKisterVPSSTP(); + + //! Duplication routine for objects which inherit from ThermoPhase. + /*! + * This virtual routine can be used to duplicate thermophase objects + * inherited from ThermoPhase even if the application only has + * a pointer to ThermoPhase to work with. + */ + virtual ThermoPhase *duplMyselfAsThermoPhase() const; + + /** + * + * @name Utilities + * @{ + */ + + + //! Equation of state type flag. + /*! + * The ThermoPhase base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Known constants defined for this purpose are + * listed in mix_defs.h. The MolalityVPSSTP class also returns + * zero, as it is a non-complete class. + */ + virtual int eosType() const; + + //! Initialization of a phase using an xml file + /*! + * This routine is a precursor to + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); + + //! Import and initialize a phase + //! specification in an XML tree into the current object. + /*! + * Here we read an XML description of the phase. + * We import descriptions of the elements that make up the + * species in a phase. + * We import information about the species, including their + * reference state thermodynamic polynomials. We then freeze + * the state of the species. + * + * Then, we read the species molar volumes from the xml + * tree to finish the initialization. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Molar Thermodynamic Properties + * @{ + */ + + + /** + * @} + * @name Utilities for Solvent ID and Molality + * @{ + */ + + + + + /** + * @} + * @name Mechanical Properties + * @{ + */ + + /** + * @} + * @name Potential Energy + * + * Species may have an additional potential energy due to the + * presence of external gravitation or electric fields. These + * methods allow specifying a potential energy for individual + * species. + * @{ + */ + + /** + * @} + * @name Activities, Standard States, and Activity Concentrations + * + * The activity \f$a_k\f$ of a species in solution is + * related to the chemical potential by \f[ \mu_k = \mu_k^0(T) + * + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is + * the chemical potential at unit activity, which depends only + * on temperature and pressure. + * @{ + */ + + //! Get the array of non-dimensional molar-based ln activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param lnac Output vector of ln activity coefficients. Length: m_kk. + */ + virtual void getLnActivityCoefficients(doublereal* ac) const; + + //@} + /// @name Partial Molar Properties of the Solution + //@{ + + //! Get the species chemical potentials. Units: J/kmol. + /*! + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ + virtual void getChemPotentials(doublereal* mu) const; + + /// Molar enthalpy. Units: J/kmol. + virtual doublereal enthalpy_mole() const; + + /// Molar entropy. Units: J/kmol. + virtual doublereal entropy_mole() const; + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + virtual doublereal cp_mole() const; + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + virtual doublereal cv_mole() const; + + //! Returns an array of partial molar enthalpies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * molality-based activity coefficent wrt temperature + * + * \f[ + * \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * \f] + * + * @param hbar Vector of returned partial molar enthalpies + * (length m_kk, units = J/kmol) + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * \f] + * + * @param sbar Vector of returned partial molar entropies + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + //! Returns an array of partial molar entropies for the species + //! in the mixture. + /*! + * Units (J/kmol) + * + * For this phase, the partial molar enthalpies are equal to the + * standard state enthalpies modified by the derivative of the + * activity coefficent wrt temperature + * + * \f[ + * ??????????????? + * \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT} + * - R \ln( \gamma_k X_k) + * - R T \frac{d \ln(\gamma_k) }{dT} + * ??????????????? + * \f] + * + * @param cpbar Vector of returned partial molar heat capacities + * (length m_kk, units = J/kmol/K) + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + + //! Return an array of partial molar volumes for the + //! species in the mixture. Units: m^3/kmol. + /*! + * Frequently, for this class of thermodynamics representations, + * the excess Volume due to mixing is zero. Here, we set it as + * a default. It may be overriden in derived classes. + * + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //! Get the species electrochemical potentials. + /*! + * These are partial molar quantities. + * This method adds a term \f$ Fz_k \phi_k \f$ to the + * to each chemical potential. + * + * Units: J/kmol + * + * @param mu output vector containing the species electrochemical potentials. + * Length: m_kk., units = J/kmol + */ + void getElectrochemPotentials(doublereal* mu) const; + + //! Get the array of temperature second derivatives of the log activity coefficients + /*! + * This function is a virtual class, but it first appears in GibbsExcessVPSSTP + * class and derived classes from GibbsExcessVPSSTP. + * + * units = 1/Kelvin + * + * @param d2lnActCoeffdT2 Output vector of temperature 2nd derivatives of the + * log Activity Coefficients. length = m_kk + * + */ + virtual void getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const; + + //! Get the array of temperature derivatives of the log activity coefficients + /*! + * This function is a virtual class, but it first appears in GibbsExcessVPSSTP + * class and derived classes from GibbsExcessVPSSTP. + * + * units = 1/Kelvin + * + * @param dlnActCoeffdT Output vector of temperature derivatives of the + * log Activity Coefficients. length = m_kk + * + */ + virtual void getdlnActCoeffdT(doublereal *dlnActCoeffdT) const; + + + + //@} + /// @name Properties of the Standard State of the Species in the Solution + //@{ + + + + //@} + /// @name Thermodynamic Values for the Species Reference States + //@{ + + + /////////////////////////////////////////////////////// + // + // The methods below are not virtual, and should not + // be overloaded. + // + ////////////////////////////////////////////////////// + + /** + * @name Specific Properties + * @{ + */ + + + /** + * @name Setting the State + * + * These methods set all or part of the thermodynamic + * state. + * @{ + */ + + + + //@} + + /** + * @name Chemical Equilibrium + * Routines that implement the Chemical equilibrium capability + * for a single phase, based on the element-potential method. + * @{ + */ + + + + //@} + + + + /// The following methods are used in the process of constructing + /// the phase and setting its parameters from a specification in an + /// input file. They are not normally used in application programs. + /// To see how they are used, see files importCTML.cpp and + /// ThermoFactory.cpp. + + + /*! + * @internal Initialize. This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase. + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + + /** + * Import and initialize a ThermoPhase object + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void initThermoXML(XML_Node& phaseNode, std::string id); + + /** + * @} + * @name Derivatives of Thermodynamic Variables needed for Applications + * @{ + */ + + //! Get the change in activity coefficients w.r.t. change in state (temp, mole fraction, etc.) along + //! a line in parameter space or along a line in physical space + /*! + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + virtual void getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, doublereal *dlnActCoeffds) const; + + //! Get the array of log concentration-like derivatives of the + //! log activity coefficients - diagonal component + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the mole fraction. + * + * units = dimensionless + * + * @param dlnActCoeffdlnX_diag Output vector of the diagonal component of the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const; + + //! Get the array of derivatives of the log activity coefficients wrt mole numbers - diagonal only + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. mole fraction, + * molality, etc.) that represents the standard state. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of the diagonal entries for the log(mole fraction) + * derivatives of the log Activity Coefficients. + * length = m_kk + */ + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const; + + + //! Get the array of derivatives of the ln activity coefficients with respect to the ln species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * log of a species mole number (with all other species mole numbers held constant) + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) ; + + //@} + + private: + + //! Process an XML node called "binaryNeutralSpeciesParameters" + /*! + * This node contains all of the parameters necessary to describe + * the Redlich-Kister model for a particular binary interaction. + * This function reads the XML file and writes the coefficients + * it finds to an internal data structures. + * + * @param xmlBinarySpecies Reference to the XML_Node named "binaryNeutralSpeciesParameters" + * containing the binary interaction + */ + void readXMLBinarySpecies(XML_Node &xmlBinarySpecies); + + //! Resize internal arrays within the object that depend upon the number + //! of binary Redlich-Kister interaction terms + /*! + * @param num Number of binary Redlich-Kister interaction terms + */ + void resizeNumInteractions(const int num); + + + //! Initialize lengths of local variables after all species have + //! been identified. + void initLengths(); + + //! Update the activity coefficients + /*! + * This function will be called to update the internally storred + * natural logarithm of the activity coefficients + */ + void s_update_lnActCoeff() const; + + //! Update the derivative of the log of the activity coefficients wrt T + /*! + * This function will be called to update the internally storred + * derivative of the natural logarithm of the activity coefficients + * wrt temperature. + */ + void s_update_dlnActCoeff_dT() const; + + //! Internal routine that calculates the derivative of the activity coefficients wrt + //! the mole fractions. + /*! + * This routine calculates the the derivative of the activity coefficients wrt to mole fraction + * with all other mole fractions held constant. This is strictly not permitted. However, if the + * resulting matrix is multiplied by a permissible deltaX vector then everything is ok. + * + * This is the natural way to handle concentration derivatives in this routine. + */ + void s_update_dlnActCoeff_dX_() const; + +#ifdef DEBUG_MODE + public: + //! Utility routine that calculates a literature expression + /*! + * @param VintOut Output contribution to the voltage corresponding to nonideal term + * @param voltsOut Output contribution to the voltage corresponding to nonideal term and mf term + */ + void Vint(double &VintOut, double &voltsOut) ; +#endif + + private: + //! Error function + /*! + * Print an error string and exit + * + * @param msg Message to be printed + */ + doublereal err(std::string msg) const; + + protected: + + //! number of binary interaction expressions + int numBinaryInteractions_; + + //! vector of species indices representing species A in the interaction + /*! + * Each Redlich-Kister excess Gibbs free energy term involves two species, A and B. + * This vector identifies species A. + */ + vector_int m_pSpecies_A_ij; + + //! vector of species indices representing species B in the interaction + /*! + * Each Redlich-Kisterexcess Gibbs free energy term involves two species, A and B. + * This vector identifies species B. + */ + vector_int m_pSpecies_B_ij; + + + //! Vector of the length of the polynomial for the interaction. + vector_int m_N_ij; + + + //! Enthalpy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable std::vector< vector_fp> m_HE_m_ij; + + + //! Entropy term for the binary mole fraction interaction of the + //! excess gibbs free energy expression + mutable std::vector< vector_fp> m_SE_m_ij; + + //! form of the RedlichKister interaction expression + /*! + * Currently there is only one form. + */ + int formRedlichKister_; + + //! form of the temperatuer dependence of the Redlich-Kister interaction expression + /*! + * Currently there is only one form -> constant wrt temperature. + */ + int formTempModel_; + + + //! Two dimensional array of derivatives of activity coefficients wrt mole fractions + mutable Array2D dlnActCoeff_dX_; + + + }; + + + +} + +#endif + + + + + diff --git a/Cantera/src/thermo/RedlichKwongMFTP.cpp b/Cantera/src/thermo/RedlichKwongMFTP.cpp new file mode 100644 index 000000000..4b225585a --- /dev/null +++ b/Cantera/src/thermo/RedlichKwongMFTP.cpp @@ -0,0 +1,1898 @@ +/** + * @file RedlichKwongMFTP.cpp + * Definition file for a derived class of ThermoPhase that assumes either + * an ideal gas or ideal solution approximation and handles + * variable pressure standard state methods for calculating + * thermodynamic properties (see \ref thermoprops and + * class \link Cantera::RedlichKwongMFTP RedlichKwongMFTP\endlink). + */ +/* + * 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. + */ +/* + * $Author: hkmoffa $ + * $Date: 2009-11-09 16:36:49 -0700 (Mon, 09 Nov 2009) $ + * $Revision: 255 $ + */ + +// turn off warnings under Windows +#ifdef WIN32 +#pragma warning(disable:4786) +#pragma warning(disable:4503) +#endif + +#include "RedlichKwongMFTP.h" + + +#include "mix_defs.h" +#include "ThermoFactory.h" +#include "RootFind.h" + +using namespace std; + +namespace Cantera { +#ifdef WITH_REAL_GASSES + //==================================================================================================================== + /* + * Default constructor + */ + RedlichKwongMFTP::RedlichKwongMFTP() : + MixtureFugacityTP(), + m_standardMixingRules(0), + m_formTempParam(0), + m_b_current(0.0), + m_a_current(0.0), + a_vec_Curr_(0), + b_vec_Curr_(0), + a_coeff_vec(0,0), + m_pc_Species(0), + m_tc_Species(0), + m_vc_Species(0), + NSolns_(0), + m_pp(0), + m_tmpV(0), + m_partialMolarVolumes(0), + dpdV_(0.0), + dpdT_(0.0), + dpdni_(0) + { + Vroot_[0] = 0.0; + Vroot_[1] = 0.0; + Vroot_[2] = 0.0; + } + //==================================================================================================================== + RedlichKwongMFTP::RedlichKwongMFTP(std::string infile, std::string id) : + MixtureFugacityTP(), + m_standardMixingRules(0), + m_formTempParam(0), + m_b_current(0.0), + m_a_current(0.0), + a_vec_Curr_(0), + b_vec_Curr_(0), + a_coeff_vec(0,0), + m_pc_Species(0), + m_tc_Species(0), + m_vc_Species(0), + NSolns_(0), + m_pp(0), + m_tmpV(0), + m_partialMolarVolumes(0), + dpdV_(0.0), + dpdT_(0.0), + dpdni_(0) + { + Vroot_[0] = 0.0; + Vroot_[1] = 0.0; + Vroot_[2] = 0.0; + XML_Node* root = get_XML_File(infile); + if (id == "-") id = ""; + XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, root); + if (!xphase) { + throw CanteraError("newPhase", + "Couldn't find phase named \"" + id + "\" in file, " + infile); + } + importPhase(*xphase, this); + } + //==================================================================================================================== + RedlichKwongMFTP::RedlichKwongMFTP(XML_Node& phaseRefRoot, std::string id) : + MixtureFugacityTP(), + m_standardMixingRules(0), + m_formTempParam(0), + m_b_current(0.0), + m_a_current(0.0), + a_vec_Curr_(0), + b_vec_Curr_(0), + a_coeff_vec(0,0), + m_pc_Species(0), + m_tc_Species(0), + m_vc_Species(0), + NSolns_(0), + m_pp(0), + m_tmpV(0), + m_partialMolarVolumes(0), + dpdV_(0.0), + dpdT_(0.0), + dpdni_(0) + { + Vroot_[0] = 0.0; + Vroot_[1] = 0.0; + Vroot_[2] = 0.0; + XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, &phaseRefRoot); + if (!xphase) { + throw CanteraError("RedlichKwongMFTP::RedlichKwongMFTP()","Couldn't find phase named \"" + id + "\" in XML node"); + } + importPhase(*xphase, this); + } + + //==================================================================================================================== + RedlichKwongMFTP::RedlichKwongMFTP(int testProb) : + MixtureFugacityTP(), + m_standardMixingRules(0), + m_formTempParam(0), + m_b_current(0.0), + m_a_current(0.0), + a_vec_Curr_(0), + b_vec_Curr_(0), + a_coeff_vec(0,0), + m_pc_Species(0), + m_tc_Species(0), + m_vc_Species(0), + NSolns_(0), + m_pp(0), + m_tmpV(0), + m_partialMolarVolumes(0), + dpdV_(0.0), + dpdT_(0.0), + dpdni_(0) + { + std::string infile = "co2_redlichkwong.xml"; + std::string id; + if (testProb == 1) { + infile = "co2_redlichkwong.xml"; + id = "carbondioxide"; + } else { + throw CanteraError("", "test prob = 1 only"); + } + XML_Node* root = get_XML_File(infile); + if (id == "-") id = ""; + XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, root); + if (!xphase) { + throw CanteraError("newPhase", "Couldn't find phase named \"" + id + "\" in file, " + infile); + } + importPhase(*xphase, this); + } + //==================================================================================================================== + /* + * Copy Constructor: + * + * Note this stuff will not work until the underlying phase + * has a working copy constructor. + * + * The copy constructor just calls the assignment operator + * to do the heavy lifting. + */ + RedlichKwongMFTP::RedlichKwongMFTP(const RedlichKwongMFTP &b) : + MixtureFugacityTP(), + m_standardMixingRules(0), + m_formTempParam(0), + m_b_current(0.0), + m_a_current(0.0), + a_vec_Curr_(0), + b_vec_Curr_(0), + a_coeff_vec(0,0), + m_pc_Species(0), + m_tc_Species(0), + m_vc_Species(0), + NSolns_(0), + m_pp(0), + m_tmpV(0), + m_partialMolarVolumes(0), + dpdV_(0.0), + dpdT_(0.0), + dpdni_(0) + { + *this = b; + } + + //==================================================================================================================== + /* + * operator=() + * + * Note this stuff will not work until the underlying phase + * has a working assignment operator + */ + RedlichKwongMFTP& RedlichKwongMFTP:: + operator=(const RedlichKwongMFTP &b) { + if (&b != this) { + /* + * Mostly, this is a passthrough to the underlying + * assignment operator for the ThermoPhae parent object. + */ + MixtureFugacityTP::operator=(b); + /* + * However, we have to handle data that we own. + */ + m_standardMixingRules = b.m_standardMixingRules; + m_formTempParam = b.m_formTempParam; + m_b_current = b.m_b_current; + m_a_current = b.m_a_current; + a_vec_Curr_ = b.a_vec_Curr_; + b_vec_Curr_ = b.b_vec_Curr_; + a_coeff_vec = b.a_coeff_vec; + + m_pc_Species = b.m_pc_Species; + m_tc_Species = b.m_tc_Species; + m_vc_Species = b.m_vc_Species; + NSolns_ = b.NSolns_; + Vroot_[0] = b.Vroot_[0]; + Vroot_[1] = b.Vroot_[1]; + Vroot_[2] = b.Vroot_[2]; + m_pp = b.m_pp; + m_tmpV = b.m_tmpV; + m_partialMolarVolumes = b.m_partialMolarVolumes; + dpdV_ = b.dpdV_; + dpdT_ = b.dpdT_; + dpdni_ = b.dpdni_; + } + return *this; + } + //==================================================================================================================== + /* + * ~RedlichKwongMFTP(): (virtual) + * + */ + RedlichKwongMFTP::~RedlichKwongMFTP() { + } + //==================================================================================================================== + /* + * Duplication function. + * This calls the copy constructor for this object. + */ + ThermoPhase* RedlichKwongMFTP::duplMyselfAsThermoPhase() const { + RedlichKwongMFTP* vptp = new RedlichKwongMFTP(*this); + return (ThermoPhase *) vptp; + } + //==================================================================================================================== + int RedlichKwongMFTP::eosType() const { + return cRedlichKwongMFTP; + } + + //==================================================================================================================== + /* + * ------------Molar Thermodynamic Properties ------------------------- + */ + //==================================================================================================================== + // Molar enthalpy. Units: J/kmol. + doublereal RedlichKwongMFTP::enthalpy_mole() const { + _updateReferenceStateThermo(); + doublereal rt = _RT(); + doublereal h_ideal = rt * mean_X(DATA_PTR(m_h0_RT)); + doublereal h_nonideal = hresid(); + return (h_ideal + h_nonideal); + } + //==================================================================================================================== + // Molar internal energy. Units: J/kmol. + doublereal RedlichKwongMFTP::intEnergy_mole() const { + doublereal p0 = pressure(); + doublereal md = molarDensity(); + return (enthalpy_mole() - p0 / md); + } + //==================================================================================================================== + // Molar entropy. Units: J/kmol/K. + doublereal RedlichKwongMFTP::entropy_mole() const { + _updateReferenceStateThermo(); + doublereal sr_ideal = GasConstant * (mean_X(DATA_PTR(m_s0_R)) + - sum_xlogx() - std::log(pressure()/m_spthermo->refPressure())); + doublereal sr_nonideal = sresid(); + return (sr_ideal + sr_nonideal); + } + //==================================================================================================================== + // Molar Gibbs function. Units: J/kmol. + doublereal RedlichKwongMFTP::gibbs_mole() const { + return enthalpy_mole() - temperature() * entropy_mole(); + } + //==================================================================================================================== + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + doublereal RedlichKwongMFTP::cp_mole() const { + _updateReferenceStateThermo(); + doublereal TKelvin = temperature(); + doublereal sqt = sqrt(TKelvin); + doublereal mv = molarVolume(); + doublereal vpb = mv + m_b_current; + pressureDerivatives(); + doublereal cpref = GasConstant * mean_X(DATA_PTR(m_cp0_R)); + doublereal dadt = da_dt(); + doublereal fac = TKelvin * dadt - 3.0 * m_a_current / 2.0; + doublereal dHdT_V = (cpref + mv * dpdT_ - GasConstant - 1.0 / (2.0 * m_b_current * TKelvin * sqt) * log(vpb/mv) * fac + +1.0/(m_b_current * sqt) * log(vpb/mv) * (-0.5 * dadt)); + double cp = dHdT_V - (mv + TKelvin * dpdT_ / dpdV_) * dpdT_; + return cp; + } + //==================================================================================================================== + /// Molar heat capacity at constant volume. Units: J/kmol/K. + doublereal RedlichKwongMFTP::cv_mole() const { + throw CanteraError("", "unimplemented"); + return cp_mole() - GasConstant; + } + //==================================================================================================================== + // Return the thermodynamic pressure (Pa). + /* + * Since the mass density, temperature, and mass fractions are stored, + * this method uses these values to implement the + * mechanical equation of state \f$ P(T, \rho, Y_1, \dots, Y_K) \f$. + * + * \f[ + * P = \frac{RT}{v-b_{mix}} - \frac{a_{mix}}{T^{0.5} v \left( v + b_{mix} \right) } + * \f] + * + */ + doublereal RedlichKwongMFTP::pressure() const { + + +#ifdef DEBUG_MODE + _updateReferenceStateThermo(); + + // Get a copy of the private variables stored in the State object + double rho = density(); + doublereal T = temperature(); + doublereal mmw = meanMolecularWeight(); + double molarV = mmw / rho; + + double pp = GasConstant * T/(molarV - m_b_current) - m_a_current/(sqrt(T) * molarV * (molarV + m_b_current)); + + if (fabs(pp -m_Pcurrent) > 1.0E-5 * fabs(m_Pcurrent)) { + throw CanteraError(" RedlichKwongMFTP::pressure()", "setState broken down, maybe"); + } +#endif + + return m_Pcurrent; + } + //==================================================================================================================== + void RedlichKwongMFTP::calcDensity() { + /* + * Calculate the molarVolume of the solution (m**3 kmol-1) + */ + + const doublereal * const dtmp = moleFractdivMMW(); + getPartialMolarVolumes(DATA_PTR(m_tmpV)); + double invDens = dot(m_tmpV.begin(), m_tmpV.end(), dtmp); + /* + * Set the density in the parent State object directly, + * by calling the State::setDensity() function. + */ + double dens = 1.0/invDens; + State::setDensity(dens); + + } + + //==================================================================================================================== + void RedlichKwongMFTP::setTemperature(const doublereal temp) { + State::setTemperature(temp); + _updateReferenceStateThermo(); + updateAB(); + } + //==================================================================================================================== + void RedlichKwongMFTP::setMassFractions(const doublereal * const x) { + MixtureFugacityTP::setMassFractions(x); + updateAB(); + } + //==================================================================================================================== + void RedlichKwongMFTP::setMassFractions_NoNorm(const doublereal * const x) { + MixtureFugacityTP::setMassFractions_NoNorm(x); + updateAB(); + } + //==================================================================================================================== + void RedlichKwongMFTP::setMoleFractions(const doublereal * const x) { + MixtureFugacityTP::setMoleFractions(x); + updateAB(); + } + //==================================================================================================================== + void RedlichKwongMFTP::setMoleFractions_NoNorm(const doublereal * const x) { + MixtureFugacityTP::setMoleFractions(x); + updateAB(); + } + //==================================================================================================================== + void RedlichKwongMFTP::setConcentrations(const doublereal * const c) { + MixtureFugacityTP::setConcentrations(c); + updateAB(); + } + + //==================================================================================================================== + doublereal RedlichKwongMFTP::isothermalCompressibility() const { + + + throw CanteraError("RedlichKwongMFTP::isothermalCompressibility() ", + "not implemented"); + + return 0.0; + } + //==================================================================================================================== + void RedlichKwongMFTP::getActivityConcentrations(doublereal* c) const { + + int k; + getPartialMolarVolumes(DATA_PTR(m_partialMolarVolumes)); + + for (k = 0; k < m_kk; k++) { + c[k] = moleFraction(k) / m_partialMolarVolumes[k]; + } + } + //==================================================================================================================== + /* + * Returns the standard concentration \f$ C^0_k \f$, which is used to normalize + * the generalized concentration. + */ + doublereal RedlichKwongMFTP::standardConcentration(int k) const { + + getStandardVolumes(DATA_PTR(m_tmpV)); + + return 1.0 / m_tmpV[k]; + + + + } + //==================================================================================================================== + /* + * Returns the natural logarithm of the standard + * concentration of the kth species + */ + doublereal RedlichKwongMFTP::logStandardConc(int k) const { + double c = standardConcentration(k); + double lc = std::log(c); + return lc; + } + //==================================================================================================================== + /* + * + * getUnitsStandardConcentration() + * + * Returns the units of the standard and general concentrations + * Note they have the same units, as their divisor is + * defined to be equal to the activity of the kth species + * in the solution, which is unitless. + * + * This routine is used in print out applications where the + * units are needed. Usually, MKS units are assumed throughout + * the program and in the XML input files. + * + * uA[0] = kmol units - default = 1 + * uA[1] = m units - default = -nDim(), the number of spatial + * dimensions in the Phase class. + * uA[2] = kg units - default = 0; + * uA[3] = Pa(pressure) units - default = 0; + * uA[4] = Temperature units - default = 0; + * uA[5] = time units - default = 0 + * + * For EOS types other than cIdealSolidSolnPhase1, the default + * kmol/m3 holds for standard concentration units. For + * cIdealSolidSolnPhase0 type, the standard concentrtion is + * unitless. + */ + void RedlichKwongMFTP::getUnitsStandardConc(double *uA, int, int sizeUA) const { + //int eos = eosType(); + + for (int i = 0; i < sizeUA; i++) { + if (i == 0) uA[0] = 1.0; + if (i == 1) uA[1] = -nDim(); + if (i == 2) uA[2] = 0.0; + if (i == 3) uA[3] = 0.0; + if (i == 4) uA[4] = 0.0; + if (i == 5) uA[5] = 0.0; + } + + } + + //==================================================================================================================== + //! Get the array of non-dimensional activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * For ideal gases, the activity coefficients are all equal to one. + * + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + void RedlichKwongMFTP::getActivityCoefficients(doublereal *ac) const { + doublereal TKelvin = temperature(); + doublereal rt = TKelvin * GasConstant; + doublereal mv = molarVolume(); + doublereal sqt = sqrt(TKelvin); + doublereal vpb = mv + m_b_current; + doublereal vmb = mv - m_b_current; + + for (int k = 0; k < m_kk; k++) { + m_pp[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_pp[k] += moleFractions_[i] * a_vec_Curr_[counter]; + } + } + doublereal pres = pressure(); + + for (int k = 0; k < m_kk; k++) { + ac[k] = ( - rt * log(pres * mv / rt) + + rt * log(mv / vmb) + + rt * b_vec_Curr_[k] / vmb + - 2.0 * m_pp[k] / (m_b_current * sqt) * log(vpb/mv) + + m_a_current * b_vec_Curr_[k] / (m_b_current * m_b_current * sqt) * log(vpb/mv) + - m_a_current / (m_b_current * sqt) * ( b_vec_Curr_[k]/vpb) + ); + } + for (int k = 0; k < m_kk; k++) { + ac[k] = exp(ac[k]/rt); + } + } + //==================================================================================================================== + /* + * ---- Partial Molar Properties of the Solution ----------------- + */ + //==================================================================================================================== + /* + * Get the array of non-dimensional species chemical potentials + * These are partial molar Gibbs free energies. + * \f$ \mu_k / \hat R T \f$. + * Units: unitless + * + * We close the loop on this function, here, calling + * getChemPotentials() and then dividing by RT. + */ + void RedlichKwongMFTP::getChemPotentials_RT(doublereal* muRT) const{ + getChemPotentials(muRT); + doublereal invRT = 1.0 / _RT(); + for (int k = 0; k < m_kk; k++) { + muRT[k] *= invRT; + } + } + //==================================================================================================================== + void RedlichKwongMFTP::getChemPotentials(doublereal* mu) const { + getGibbs_ref(mu); + doublereal xx; + doublereal rt = temperature() * GasConstant; + for (int k = 0; k < m_kk; k++) { + xx = fmaxx(SmallNumber, moleFraction(k)); + mu[k] += rt*(log(xx)); + } + + doublereal TKelvin = temperature(); + doublereal mv = molarVolume(); + doublereal sqt = sqrt(TKelvin); + doublereal vpb = mv + m_b_current; + doublereal vmb = mv - m_b_current; + + for (int k = 0; k < m_kk; k++) { + m_pp[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_pp[k] += moleFractions_[i] * a_vec_Curr_[counter]; + } + } + doublereal pres = pressure(); + doublereal refP = refPressure(); + + for (int k = 0; k < m_kk; k++) { + mu[k] += (rt * log(pres/refP) - rt * log(pres * mv / rt) + + rt * log(mv / vmb) + + rt * b_vec_Curr_[k] / vmb + - 2.0 * m_pp[k] / (m_b_current * sqt) * log(vpb/mv) + + m_a_current * b_vec_Curr_[k] / (m_b_current * m_b_current * sqt) * log(vpb/mv) + - m_a_current / (m_b_current * sqt) * ( b_vec_Curr_[k]/vpb) + ); + } + } + //==================================================================================================================== + void RedlichKwongMFTP::getPartialMolarEnthalpies(doublereal* hbar) const { + /* + * First we get the reference state contributions + */ + getEnthalpy_RT_ref(hbar); + doublereal rt = GasConstant * temperature(); + scale(hbar, hbar+m_kk, hbar, rt); + + /* + * We calculate dpdni_ + */ + doublereal TKelvin = temperature(); + doublereal mv = molarVolume(); + doublereal sqt = sqrt(TKelvin); + + doublereal vpb = mv + m_b_current; + doublereal vmb = mv - m_b_current; + + for (int k = 0; k < m_kk; k++) { + m_pp[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_pp[k] += moleFractions_[i] * a_vec_Curr_[counter]; + } + } + + + + for (int k = 0; k < m_kk; k++) { + dpdni_[k] = rt/vmb + rt * b_vec_Curr_[k] / (vmb * vmb) - 2.0 * m_pp[k] / (sqt * mv * vpb) + + m_a_current * b_vec_Curr_[k]/(sqt * mv * vpb * vpb); + } + doublereal dadt = da_dt(); + doublereal fac = TKelvin * dadt - 3.0 * m_a_current / 2.0; + + for (int k = 0; k < m_kk; k++) { + m_tmpV[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_tmpV[k] += 2.0 * moleFractions_[i] * TKelvin * a_coeff_vec(1,counter) - 3.0 * moleFractions_[i] * a_vec_Curr_[counter]; + } + } + + pressureDerivatives(); + doublereal fac2 = mv + TKelvin * dpdT_ / dpdV_; + + for (int k = 0; k < m_kk; k++) { + double hE_v = (mv * dpdni_[k] - rt - b_vec_Curr_[k]/ (m_b_current * m_b_current * sqt) * log(vpb/mv)*fac + + 1.0 / (m_b_current * sqt) * log(vpb/mv) * m_tmpV[k] + + b_vec_Curr_[k] / vpb / (m_b_current * sqt) * fac); + hbar[k] = hbar[k] + hE_v; + + + hbar[k] -= fac2 * dpdni_[k]; + } + + } + //==================================================================================================================== + void RedlichKwongMFTP::getPartialMolarEntropies(doublereal* sbar) const { + getEntropy_R_ref(sbar); + doublereal r = GasConstant; + scale(sbar, sbar+m_kk, sbar, r); + doublereal TKelvin = temperature(); + doublereal sqt = sqrt(TKelvin); + doublereal mv = molarVolume(); + doublereal refP = refPressure(); + + for (int k = 0; k < m_kk; k++) { + doublereal xx = fmaxx(SmallNumber, moleFraction(k)); + sbar[k] += r * ( - log(xx)); + } + + for (int k = 0; k < m_kk; k++) { + m_pp[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_pp[k] += moleFractions_[i] * a_vec_Curr_[counter]; + } + } + + for (int k = 0; k < m_kk; k++) { + m_tmpV[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_tmpV[k] += moleFractions_[i] * a_coeff_vec(1,counter); + } + } + + + doublereal dadt = da_dt(); + doublereal fac = dadt - m_a_current / (2.0 * TKelvin); + doublereal vmb = mv - m_b_current; + doublereal vpb = mv + m_b_current; + + + for (int k = 0; k < m_kk; k++) { + sbar[k] -=( GasConstant * log(GasConstant * TKelvin / (refP * mv)) + + GasConstant + + GasConstant * log(mv/vmb) + + GasConstant * b_vec_Curr_[k]/vmb + + m_pp[k]/(m_b_current * TKelvin * sqt) * log(vpb/mv) + - 2.0 * m_tmpV[k]/(m_b_current * sqt) * log(vpb/mv) + + b_vec_Curr_[k] / (m_b_current * m_b_current * sqt) * log(vpb/mv) * fac + - 1.0 / (m_b_current * sqt) * b_vec_Curr_[k] / vpb * fac + ) ; + } + + pressureDerivatives(); + getPartialMolarVolumes(DATA_PTR(m_partialMolarVolumes)); + for (int k = 0; k < m_kk; k++) { + sbar[k] -= -m_partialMolarVolumes[k] * dpdT_; + } + } + //==================================================================================================================== + void RedlichKwongMFTP::getPartialMolarIntEnergies(doublereal* ubar) const { + getIntEnergy_RT(ubar); + doublereal rt = GasConstant * temperature(); + scale(ubar, ubar+m_kk, ubar, rt); + } + //==================================================================================================================== + void RedlichKwongMFTP::getPartialMolarCp(doublereal* cpbar) const { + getCp_R(cpbar); + doublereal r = GasConstant; + scale(cpbar, cpbar+m_kk, cpbar, r); + } + //==================================================================================================================== + void RedlichKwongMFTP::getPartialMolarVolumes(doublereal* vbar) const { + // getStandardVolumes(vbar); + + + for (int k = 0; k < m_kk; k++) { + m_pp[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_pp[k] += moleFractions_[i] * a_vec_Curr_[counter]; + } + } + + for (int k = 0; k < m_kk; k++) { + m_tmpV[k] = 0.0; + for (int i = 0; i < m_kk; i++) { + int counter = k + m_kk*i; + m_tmpV[k] += moleFractions_[i] * a_coeff_vec(1,counter); + } + } + + doublereal TKelvin = temperature(); + doublereal sqt = sqrt(TKelvin); + doublereal mv = molarVolume(); + + doublereal rt = GasConstant * TKelvin; + + doublereal vmb = mv - m_b_current; + doublereal vpb = mv + m_b_current; + + for (int k = 0; k < m_kk; k++) { + + doublereal num = (rt + rt * m_b_current/ vmb + rt * b_vec_Curr_[k] / vmb + + rt * m_b_current * b_vec_Curr_[k] /(vmb * vmb) + - 2.0 * m_pp[k] / (sqt * vpb) + + m_a_current * b_vec_Curr_[k] / (sqt * vpb * vpb) + ); + + doublereal denom = (m_Pcurrent + rt * m_b_current/(vmb * vmb) - m_a_current / (sqt * vpb * vpb) + ); + + vbar[k] = num / denom; + } + + } + //==================================================================================================================== + doublereal RedlichKwongMFTP::critTemperature() const { + double pc, tc, vc; + double a0 = 0.0; + double aT = 0.0; + for (int i = 0; i < m_kk; i++) { + for (int j = 0; j 500.0) { + tmp2 = tmp / 500.; + tmp2 *= tmp2; + m_pp[k] = m_p0 * exp(500.) * tmp2; + } else { + m_pp[k] = m_p0 * exp(tmp); + } + pres += m_pp[k]; + } + // set state + setState_PX(pres, &m_pp[0]); + } + //==================================================================================================================== + /* + * Initialize the internal lengths. + * (this is not a virtual function) + */ + void RedlichKwongMFTP::initLengths() { + + + a_vec_Curr_.resize(m_kk * m_kk, 0.0); + b_vec_Curr_.resize(m_kk, 0.0); + + a_coeff_vec.resize(2, m_kk * m_kk, 0.0); + + + m_pc_Species.resize(m_kk, 0.0); + m_tc_Species.resize(m_kk, 0.0); + m_vc_Species.resize(m_kk, 0.0); + + + m_pp.resize(m_kk, 0.0); + m_tmpV.resize(m_kk, 0.0); + m_partialMolarVolumes.resize(m_kk, 0.0); + dpdni_.resize(m_kk, 0.0); + } + //==================================================================================================================== + /* + * Import and initialize a ThermoPhase object + * + * param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + * + * This routine initializes the lengths in the current object and + * then calls the parent routine. + */ + void RedlichKwongMFTP::initThermoXML(XML_Node& phaseNode, std::string id) { + RedlichKwongMFTP::initLengths(); + + /* + * Check the model parameter for the Redlich-Kwong equation of state + * two are allowed + * RedlichKwong mixture of species, each of which are RK fluids + * RedlichKwongMFTP mixture of species with cross term coefficients + */ + if (phaseNode.hasChild("thermo")) { + XML_Node& thermoNode = phaseNode.child("thermo"); + std::string model = thermoNode["model"]; + if (model == "RedlichKwong" ) { + m_standardMixingRules = 1; + } else if (model == "RedlichKwongMFTP") { + m_standardMixingRules = 0; + } else { + throw CanteraError("RedlichKwongMFTP::initThermoXML", + "Unknown thermo model : " + model); + } + + + /* + * Go get all of the coefficients and factors in the + * activityCoefficients XML block + */ + XML_Node *acNodePtr = 0; + if (thermoNode.hasChild("activityCoefficients")) { + XML_Node& acNode = thermoNode.child("activityCoefficients"); + acNodePtr = &acNode; + int nC = acNode.nChildren(); + + /* + * Loop through the children getting multiple instances of + * parameters + */ + for (int i = 0; i < nC; i++) { + XML_Node &xmlACChild = acNodePtr->child(i); + string stemp = xmlACChild.name(); + string nodeName = lowercase(stemp); + /* + * Process a binary salt field, or any of the other XML fields + * that make up the Pitzer Database. Entries will be ignored + * if any of the species in the entry isn't in the solution. + */ + if (nodeName == "purefluidparameters") { + readXMLPureFluid(xmlACChild); + } + } + if (m_standardMixingRules == 1) { + applyStandardMixingRules(); + } + /* + * Loop through the children getting multiple instances of + * parameters + */ + for (int i = 0; i < nC; i++) { + XML_Node &xmlACChild = acNodePtr->child(i); + string stemp = xmlACChild.name(); + string nodeName = lowercase(stemp); + /* + * Process a binary salt field, or any of the other XML fields + * that make up the Pitzer Database. Entries will be ignored + * if any of the species in the entry isn't in the solution. + */ + if (nodeName == "crossfluidparameters") { + readXMLCrossFluid(xmlACChild); + } + } + + } + } + + for (int i = 0; i < m_kk; i++) { + double a0coeff = a_coeff_vec(0, i*m_kk + i); + double aTcoeff = a_coeff_vec(1, i*m_kk + i); + double ai = a0coeff + aTcoeff * 500.; + double bi = b_vec_Curr_[i]; + calcCriticalConditions(ai, bi, a0coeff, aTcoeff, m_pc_Species[i], m_tc_Species[i], m_vc_Species[i]); + } + + MixtureFugacityTP::initThermoXML(phaseNode, id); + } + //==================================================================================================================== + + void RedlichKwongMFTP::readXMLPureFluid(XML_Node &PureFluidParam) { + vector_fp vParams; + string xname = PureFluidParam.name(); + if (xname != "pureFluidParameters") { + throw CanteraError("RedlichKwongMFTP::readXMLPureFluid", + "Incorrect name for processing this routine: " + xname); + } + + /* + * Read the species + * Find the index of the species in the current phase. It's not an error to not find the species + */ + string iName = PureFluidParam.attrib("species"); + if (iName == "") { + throw CanteraError("RedlichKwongMFTP::readXMLPureFluid", "no species attribute"); + } + int iSpecies = speciesIndex(iName); + if (iSpecies < 0) { + return; + } + int counter = iSpecies + m_kk * iSpecies; + int nParamsExpected, nParamsFound; + int num = PureFluidParam.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = PureFluidParam.child(iChild); + string stemp = xmlChild.name(); + string nodeName = lowercase(stemp); + + if (nodeName == "a_coeff") { + string iModel = lowercase(xmlChild.attrib("model")); + if (iModel == "constant") { + nParamsExpected = 1; + } else if (iModel == "linear_a") { + nParamsExpected = 2; + if (m_formTempParam == 0) { + m_formTempParam = 1; + } + } else { + throw CanteraError("", "unknown model"); + } + + ctml::getFloatArray(xmlChild, vParams, true, "Pascal-m6/kmol2", "a_coeff"); + nParamsFound = vParams.size(); + if (nParamsFound != nParamsExpected) { + throw CanteraError("RedlichKwongMFTP::readXMLPureFluid(for a_coeff" + iName + ")", + "wrong number of params found"); + } + + for (int i = 0; i < nParamsFound; i++) { + a_coeff_vec(i, counter) = vParams[i]; + } + } else if (nodeName == "b_coeff") { + ctml::getFloatArray(xmlChild, vParams, true, "m3/kmol", "b_coeff"); + nParamsFound = vParams.size(); + if (nParamsFound != 1) { + throw CanteraError("RedlichKwongMFTP::readXMLPureFluid(for b_coeff" + iName + ")", + "wrong number of params found"); + } + b_vec_Curr_[iSpecies] = vParams[0]; + } + } + } + //==================================================================================================================== + void RedlichKwongMFTP::applyStandardMixingRules() { + int nParam = 2; + for (int i = 0; i < m_kk; i++) { + int icounter = i + m_kk * i; + for (int j = 0; j < m_kk; j++) { + if (i != j) { + int counter = i + m_kk * j; + int jcounter = j + m_kk * j; + for (int n = 0; n < nParam; n++) { + a_coeff_vec(n, counter) = sqrt(a_coeff_vec(n, icounter) * a_coeff_vec(n, jcounter)); + } + } + } + } + } + //==================================================================================================================== + + void RedlichKwongMFTP::readXMLCrossFluid(XML_Node &CrossFluidParam) { + vector_fp vParams; + string xname = CrossFluidParam.name(); + if (xname != "crossFluidParameters") { + throw CanteraError("RedlichKwongMFTP::readXMLCrossFluid", + "Incorrect name for processing this routine: " + xname); + } + + /* + * Read the species + * Find the index of the species in the current phase. It's not an error to not find the species + */ + string iName = CrossFluidParam.attrib("species1"); + if (iName == "") { + throw CanteraError("RedlichKwongMFTP::readXMLCrossFluid", "no species1 attribute"); + } + int iSpecies = speciesIndex(iName); + if (iSpecies < 0) { + return; + } + string jName = CrossFluidParam.attrib("species2"); + if (iName == "") { + throw CanteraError("RedlichKwongMFTP::readXMLCrossFluid", "no species2 attribute"); + } + int jSpecies = speciesIndex(jName); + if (jSpecies < 0) { + return; + } + + int counter = iSpecies + m_kk * jSpecies; + int counter0 = jSpecies + m_kk * iSpecies; + int nParamsExpected, nParamsFound; + int num = CrossFluidParam.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = CrossFluidParam.child(iChild); + string stemp = xmlChild.name(); + string nodeName = lowercase(stemp); + + if (nodeName == "a_coeff") { + string iModel = lowercase(xmlChild.attrib("model")); + if (iModel == "constant") { + nParamsExpected = 1; + } else if (iModel == "linear_a") { + nParamsExpected = 2; + if (m_formTempParam == 0) { + m_formTempParam = 1; + } + } else { + throw CanteraError("", "unknown model"); + } + + ctml::getFloatArray(xmlChild, vParams, true, "Pascal-m6/kmol2", "a_coeff"); + nParamsFound = vParams.size(); + if (nParamsFound != nParamsExpected) { + throw CanteraError("RedlichKwongMFTP::readXMLCrossFluid(for a_coeff" + iName + ")", + "wrong number of params found"); + } + + for (int i = 0; i < nParamsFound; i++) { + a_coeff_vec(i, counter) = vParams[i]; + a_coeff_vec(i, counter0) = vParams[i]; + } + } + } + } + //==================================================================================================================== + void RedlichKwongMFTP::setParametersFromXML(const XML_Node& thermoNode) { + MixtureFugacityTP::setParametersFromXML(thermoNode); + std::string model = thermoNode["model"]; + + + } + //==================================================================================================================== + // Calculate the deviation terms for the total entropy of the mixture from the + // ideal gas mixture + /* + * Here we use the current state conditions + * + * @return Returns the change in entropy in units of J kmol-1 K-1. + */ + doublereal RedlichKwongMFTP::sresid() const{ + // note this agrees with tpx + doublereal rho = density(); + doublereal mmw = meanMolecularWeight(); + doublereal molarV = mmw / rho; + double hh = m_b_current / molarV; + doublereal zz = z(); + doublereal dadt = da_dt(); + doublereal T = temperature(); + doublereal sqT = sqrt(T); + doublereal fac = dadt - m_a_current / (2.0 * T); + double sresid_mol_R = log(zz*(1.0 - hh)) + log(1.0 + hh) * fac / (sqT * GasConstant * m_b_current); + double sp = GasConstant * sresid_mol_R; + return sp; + } + //==================================================================================================================== + // Calculate the deviation terms for the total enthalpy of the mixture from the + // ideal gas mixture + /* + * Here we use the current state conditions + * + * @return Returns the change in entropy in units of J kmol-1. + */ + doublereal RedlichKwongMFTP::hresid() const{ + // note this agrees with tpx + doublereal rho = density(); + doublereal mmw = meanMolecularWeight(); + doublereal molarV = mmw / rho; + double hh = m_b_current / molarV; + doublereal zz = z(); + doublereal dadt = da_dt(); + doublereal T = temperature(); + doublereal sqT = sqrt(T); + doublereal fac = T * dadt - 3.0 *m_a_current / (2.0); + double hresid_mol = GasConstant * T * (zz - 1.0) + fac * log(1.0 + hh) / (sqT * m_b_current); + return hresid_mol; + } + //==================================================================================================================== + // Estimate for the molar volume of the liquid + /* + * Note: this is only used as a starting guess for later routines that actually calculate an + * accurate value for the liquid molar volume. + * This routine doesn't change the state of the system. + * + * @param TKelvin temperature in kelvin + * @param pres Pressure in Pa. This is used as an initial guess. If the routine + * needs to change the pressure to find a stable liquid state, the + * new pressure is returned in this variable. + * + * @return Returns the estimate of the liquid volume. If the liquid can't be found, this + * routine returns -1. + */ + doublereal RedlichKwongMFTP::liquidVolEst(doublereal TKelvin, doublereal &presGuess) const + { + + double v = m_b_current * 1.1; + double atmp; + double btmp; + calculateAB(TKelvin, atmp, btmp); + + doublereal pres = presGuess; + double pp = psatEst(TKelvin); + if (pres < pp) { + pres = pp; + } + double Vroot[3]; + +#ifdef NNN + if (TKelvin == 308.) { + double pVec[100]; + int n = 0; + for (int i = 0; i < 100; i++) { + pVec[n++] = 6.8E6 + 2.0E5 * i; + } + + for (int i = 0; i < 100; i++) { + int nsol = NicholsSolve(TKelvin, pVec[i], atmp, btmp, Vroot); + printf ("nsol = %d, p = %g, T = %g, v[0] = %g, v[1] %g, v[2] = %g\n", nsol, pVec[i], TKelvin, Vroot[0], Vroot[1], Vroot[2]); + } + } +#endif + + bool foundLiq = false; + int m = 0; + do { + + int nsol = NicholsSolve(TKelvin, pres, atmp, btmp, Vroot); + + // printf("nsol = %d\n", nsol); + // printf("liquidVolEst start: T = %g , p = %g, a = %g, b = %g\n", TKelvin, pres, m_a_current, m_b_current); + + if (nsol == 1 || nsol == 2) { + double pc = critPressure(); + if (pres > pc) { + foundLiq = true; + } + pres *= 1.04; + + } else { + foundLiq = true; + } + } while ((m < 100) && (!foundLiq)); + +#ifdef DONTUSE + int i; + double c; + double vnew; + double deltav; + double sqt = sqrt(TKelvin); + for (i = 0; i < 200; i++) { + c = bCalc * bCalc + bCalc * GasConstant * TKelvin / pres - atmp / (pres * sqt); + vnew = (1.0/c)*(v*v*v - GasConstant * TKelvin *v*v/pp - atmp * bCalc / (pres * sqt)); + deltav = vnew - v; + if (deltav > v*0.2) { + deltav = v * 0.2; + } else if (deltav < - (v * 0.2)) { + deltav = - v * 0.2; + } + v += deltav; + if (fabs(deltav) < 1.0E-6 * v) { + break; + } + } + if (i > 30) { + printf("liquidVolEst problem solve: T = %g , p = %g, a = %g, b = %g\n", TKelvin, pres, atmp, bCalc); + printf(" v final = %g\n", v); + } + if (fabs(deltav) > 1.0E-5 * v) { + throw CanteraError("RedlichKwongMFTP::liquidVolEst(T = " + fp2str(TKelvin) + ", " + fp2str(pres) + ")", + "failed to converge"); + } +#else + if (foundLiq) { + v = Vroot[0]; + presGuess = pres; + } else { + v = -1.0; + } +#endif + //printf (" RedlichKwongMFTP::liquidVolEst %g %g converged in %d its\n", TKelvin, pres, i); + return v; + } + //==================================================================================================================== + // Calculates the density given the temperature and the pressure and a guess at the density. + /* + * Note, below T_c, this is a multivalued function. We do not cross the vapor dome in this. + * This is protected because it is called during setState_TP() routines. Infinite loops would result + * if it were not protected. + * + * -> why is this not const? + * + * parameters: + * @param TKelvin Temperature in Kelvin + * @param pressure Pressure in Pascals (Newton/m**2) + * @param phaseReqested int representing the phase whose density we are requesting. If we put + * a gas or liquid phase here, we will attempt to find a volume in that + * part of the volume space, only, in this routine. A value of FLUID_UNDEFINED + * means that we will accept anything. + * + * @param rhoguess Guessed density of the fluid. A value of -1.0 indicates that there + * is no guessed density + * + * + * @return We return the density of the fluid at the requested phase. If we have not found any + * acceptable density we return a -1. If we have found an accectable density at a + * different phase, we return a -2. + */ + doublereal RedlichKwongMFTP::densityCalc(doublereal TKelvin, doublereal presPa, int phaseRequested, doublereal rhoguess) { + + /* + * It's necessary to set the temperature so that m_a_current is set correctly. + */ + setTemperature(TKelvin); + double tcrit = critTemperature(); + doublereal mmw = meanMolecularWeight(); + double densBase = 0.0; + if (rhoguess == -1.0) { + if (phaseRequested != FLUID_GAS) { + if (TKelvin > tcrit) { + rhoguess = presPa * mmw / (GasConstant * TKelvin); + } else { + if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT) { + rhoguess = presPa * mmw / (GasConstant * TKelvin); + } else if (phaseRequested >= FLUID_LIQUID_0) { + double lqvol = liquidVolEst(TKelvin, presPa); + rhoguess = mmw / lqvol; + } + } + } else { + /* + * Assume the Gas phase initial guess, if nothing is + * specified to the routine + */ + rhoguess = presPa * mmw / (GasConstant * TKelvin); + } + + } + + + doublereal volguess = mmw / rhoguess; + NSolns_ = NicholsSolve(TKelvin, presPa, m_a_current, m_b_current, Vroot_); + + doublereal molarVolLast = Vroot_[0]; + if (NSolns_ >= 2) { + if (phaseRequested >= FLUID_LIQUID_0) { + molarVolLast = Vroot_[0]; + } else if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT) { + molarVolLast = Vroot_[2]; + } else { + if (volguess > Vroot_[1]) { + molarVolLast = Vroot_[2]; + } else { + molarVolLast = Vroot_[0]; + } + } + } else if (NSolns_ == 1) { + if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT || phaseRequested == FLUID_UNDEFINED) { + molarVolLast = Vroot_[0]; + } else { + //molarVolLast = Vroot_[0]; + //printf("DensityCalc(): Possible problem encountered\n"); + return -2.0; + } + } else if (NSolns_ == -1) { + if (phaseRequested >= FLUID_LIQUID_0 || phaseRequested == FLUID_UNDEFINED || phaseRequested == FLUID_SUPERCRIT) { + molarVolLast = Vroot_[0]; + } else if (TKelvin > tcrit) { + molarVolLast = Vroot_[0]; + } else { + // molarVolLast = Vroot_[0]; + //printf("DensityCalc(): Possible problem encountered\n"); + return -2.0; + } + } else { + molarVolLast = Vroot_[0]; + //printf("DensityCalc(): Possible problem encountered\n"); + return -1.0; + } + densBase = mmw / molarVolLast; + return densBase; + } + //==================================================================================================================== + // Return the value of the density at the liquid spinodal point (on the liquid side) + // for the current temperature. + /* + * @return returns the density with units of kg m-3 + */ + doublereal RedlichKwongMFTP::densSpinodalLiquid() const { + if (NSolns_ != 3) { + double dens = critDensity(); + return dens; + } + double vmax = Vroot_[1]; + double vmin = Vroot_[0]; + RootFind rf(fdpdv_); + rf.setPrintLvl(10); + rf.setTol(1.0E-5, 1.0E-10); + rf.setFuncIsGenerallyDecreasing(true); + + double vbest = 0.5 * (Vroot_[0]+Vroot_[1]); + double funcNeeded = 0.0; + + int status = rf.solve(vmin, vmax, 100, funcNeeded, &vbest); + if (status != ROOTFIND_SUCCESS) { + throw CanteraError(" RedlichKwongMFTP::densSpinodalLiquid() ", "didn't converge"); + } + doublereal mmw = meanMolecularWeight(); + doublereal rho = mmw / vbest; + return rho; + } + //==================================================================================================================== + // Return the value of the density at the gas spinodal point (on the gas side) + // for the current temperature. + /* + * @return returns the density with units of kg m-3 + */ + doublereal RedlichKwongMFTP::densSpinodalGas() const { + if (NSolns_ != 3) { + double dens = critDensity(); + return dens; + } + double vmax = Vroot_[2]; + double vmin = Vroot_[1]; + RootFind rf(fdpdv_); + rf.setPrintLvl(10); + rf.setTol(1.0E-5, 1.0E-10); + rf.setFuncIsGenerallyIncreasing(true); + + double vbest = 0.5 * (Vroot_[1]+Vroot_[2]); + double funcNeeded = 0.0; + + int status = rf.solve(vmin, vmax, 100, funcNeeded, &vbest); + if (status != ROOTFIND_SUCCESS) { + throw CanteraError(" RedlichKwongMFTP::densSpinodalGas() ", "didn't converge"); + } + doublereal mmw = meanMolecularWeight(); + doublereal rho = mmw / vbest; + return rho; + } + //==================================================================================================================== + // Calculate the pressure given the temperature and the molar volume + /* + * Calculate the pressure given the temperature and the molar volume + * + * @param TKelvin temperature in kelvin + * @param molarVol molar volume ( m3/kmol) + * + * @return Returns the pressure. + */ + doublereal RedlichKwongMFTP::pressureCalc(doublereal TKelvin, doublereal molarVol) const { + doublereal sqt = sqrt(TKelvin); + double pres = GasConstant * TKelvin / (molarVol - m_b_current) + - m_a_current / (sqt * molarVol * (molarVol + m_b_current)); + return pres; + } + //==================================================================================================================== + // Calculate the pressure and the pressure derivative given the temperature and the molar volume + /* + * Temperature and mole number are held constant + * + * @param TKelvin temperature in kelvin + * @param molarVol molar volume ( m3/kmol) + * + * @param presCalc Returns the pressure. + * + * @return Returns the derivative of the pressure wrt the molar volume + */ + doublereal RedlichKwongMFTP::dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal &presCalc) const { + doublereal sqt = sqrt(TKelvin); + presCalc = GasConstant * TKelvin / (molarVol - m_b_current) + - m_a_current / (sqt * molarVol * (molarVol + m_b_current)); + + doublereal vpb = molarVol + m_b_current; + doublereal vmb = molarVol - m_b_current; + doublereal dpdv = (- GasConstant * TKelvin / (vmb * vmb) + + m_a_current * (2 * molarVol + m_b_current) / (sqt * molarVol * molarVol * vpb * vpb)); + return dpdv; + } + //==================================================================================================================== + + void RedlichKwongMFTP::pressureDerivatives() const { + doublereal TKelvin = temperature(); + doublereal mv = molarVolume(); + doublereal pres; + + dpdV_ = dpdVCalc(TKelvin, mv, pres); + + doublereal sqt = sqrt(TKelvin); + doublereal vpb = mv + m_b_current; + doublereal vmb = mv - m_b_current; + doublereal dadt = da_dt(); + doublereal fac = dadt - m_a_current/(2.0 * TKelvin); + + dpdT_ = (GasConstant / (vmb) - fac / (sqt * mv * vpb)); + } + //==================================================================================================================== + void RedlichKwongMFTP::updateMixingExpressions() { + updateAB(); + } + //==================================================================================================================== + void RedlichKwongMFTP::updateAB() { + double temp = temperature(); + int counter; + if (m_formTempParam == 1) { + for (int i = 0; i < m_kk; i++) { + for (int j = 0; j < m_kk; j++) { + counter = i * m_kk + j; + a_vec_Curr_[counter] = a_coeff_vec(0,counter) + a_coeff_vec(1,counter) * temp; + } + } + } + + m_b_current = 0.0; + m_a_current = 0.0; + for (int i = 0; i < m_kk; i++) { + m_b_current += moleFractions_[i] * b_vec_Curr_[i]; + for (int j = 0; j < m_kk; j++) { + m_a_current += a_vec_Curr_[i * m_kk + j] * moleFractions_[i] * moleFractions_[j]; + } + } + } + //==================================================================================================================== + void RedlichKwongMFTP::calculateAB(doublereal temp, doublereal &aCalc, doublereal &bCalc) const { + int counter; + bCalc = 0.0; + aCalc = 0.0; + if (m_formTempParam == 1) { + for (int i = 0; i < m_kk; i++) { + bCalc += moleFractions_[i] * b_vec_Curr_[i]; + for (int j = 0; j < m_kk; j++) { + counter = i * m_kk + j; + doublereal a_vec_Curr = a_coeff_vec(0,counter) + a_coeff_vec(1,counter) * temp; + aCalc += a_vec_Curr * moleFractions_[i] * moleFractions_[j]; + } + } + } else { + for (int i = 0; i < m_kk; i++) { + bCalc += moleFractions_[i] * b_vec_Curr_[i]; + for (int j = 0; j < m_kk; j++) { + counter = i * m_kk + j; + doublereal a_vec_Curr = a_coeff_vec(0,counter); + aCalc += a_vec_Curr * moleFractions_[i] * moleFractions_[j]; + } + } + } + } + //==================================================================================================================== + doublereal RedlichKwongMFTP::da_dt() const { + + doublereal dadT = 0.0; + if (m_formTempParam == 1) { + for (int i = 0; i < m_kk; i++) { + for (int j = 0; j < m_kk; j++) { + int counter = i * m_kk + j; + dadT+= a_coeff_vec(1,counter) * moleFractions_[i] * moleFractions_[j]; + } + } + } + return dadT; + } + //==================================================================================================================== + void RedlichKwongMFTP::calcCriticalConditions(doublereal a, doublereal b, doublereal a0_coeff, doublereal aT_coeff, + doublereal &pc, doublereal &tc, doublereal &vc) const { + if (m_formTempParam != 0) { + a = a0_coeff; + } + if (b <= 0.0) { + tc = 1000000.; + pc = 1.0E13; + vc = omega_vc * GasConstant * tc / pc; + return; + } + if (a <= 0.0) { + tc = 0.0; + pc = 0.0; + vc = 2.0 * b; + return; + } + double tmp = a * omega_b / (b * omega_a * GasConstant); + double pp = 2./3.; + doublereal sqrttc, f, dfdt, deltatc; + + if (m_formTempParam == 0) { + + tc = pow(tmp, pp); + } else { + tc = pow(tmp, pp); + for (int j = 0; j < 10; j++) { + sqrttc = sqrt(tc); + f = omega_a * b * GasConstant * tc * sqrttc / omega_b - aT_coeff * tc - a0_coeff; + dfdt = 1.5 * omega_a * b * GasConstant * sqrttc / omega_b - aT_coeff; + deltatc = - f / dfdt; + tc += deltatc; + } + if (deltatc > 0.1) { + throw CanteraError("RedlichKwongMFTP::calcCriticalConditions", "didn't converge"); + } + } + + pc = omega_b * GasConstant * tc / b; + vc = omega_vc * GasConstant * tc / pc; + } + + //==================================================================================================================== + // Solve the cubic equation of state + /* + * The R-K equation of state may be solved via the following formula + * + * V**3 - V**2(RT/P) - V(RTb/P - a/(P T**.5) + b*b) - (a b / (P T**.5)) = 0 + * + + * Returns the number of solutions found. If it only finds the liquid branch solution, it will return a -1 or a -2 + * instead of 1 or 2. If it returns 0, then there is an error. + * + */ + int RedlichKwongMFTP::NicholsSolve(double TKelvin, double pres, doublereal a, doublereal b, + doublereal Vroot[3]) const { + Vroot[0] = 0.0; + Vroot[1] = 0.0; + Vroot[2] = 0.0; + int nTurningPoints; + bool lotsOfNumError = false; + doublereal Vturn[2]; + if (TKelvin <= 0.0) { + throw CanteraError("RedlichKwongMFTP::NicholsSolve()", "neg temperature"); + } + /* + * Derive the coefficients of the cubic polynomial to solve. + */ + doublereal an = 1.0; + doublereal bn = - GasConstant * TKelvin / pres; + doublereal sqt = sqrt(TKelvin); + doublereal cn = - (GasConstant * TKelvin * b / pres - a/(pres * sqt) + b * b); + doublereal dn = - (a * b / (pres * sqt)); + + double tmp = a * omega_b / (b * omega_a * GasConstant); + double pp = 2./3.; + double tc = pow(tmp, pp); + double pc = omega_b * GasConstant * tc / b; + double vc = omega_vc * GasConstant * tc / pc; + // Derive the center of the cubic, x_N + doublereal xN = - bn /(3 * an); + + + // Derive the value of delta**2. This is a key quantity that determines the number of turning points + doublereal delta2 = (bn * bn - 3 * an * cn) / (9 * an * an); + doublereal delta = 0.0; + + // Calculate a couple of ratios + doublereal ratio1 = 3.0 * an * cn / (bn * bn); + doublereal ratio2 = pres * b / (GasConstant * TKelvin); + if (fabs(ratio1) < 1.0E-7) { + //printf("NicholsSolve(): Alternative solution (p = %g T = %g)\n", pres, TKelvin); + doublereal ratio3 = a / (GasConstant * sqt) * pres / (GasConstant * TKelvin); + if (fabs(ratio2) < 1.0E-5 && fabs(ratio3) < 1.0E-5) { + doublereal z = 1.0; + for (int i = 0; i < 10; i++) { + doublereal znew = z / (z - ratio2) - ratio3 / (z + ratio1); + doublereal deltaz = znew - z; + z = znew; + if (fabs(deltaz) < 1.0E-14) { + break; + } + } + doublereal v = z * GasConstant * TKelvin / pres; + Vroot[0] = v; + return 1; + } + } + + + int nSolnValues; + nTurningPoints = 2; + +#ifdef PRINTPV + double V[100]; + int n = 0; + for (int i = 0; i < 90; i++) { + V[n++] = 0.030 + 0.005 * i; + } + double p1, presCalc; + for (int i = 0; i < n; i++) { + p1 = dpdVCalc(TKelvin, V[i], presCalc); + printf(" %13.5g %13.5g %13.5g \n", V[i], presCalc , p1); + } +#endif + + double h2 = 4. * an * an * delta2 * delta2 * delta2; + if (delta2 == 0.0) { + nTurningPoints = 1; + Vturn[0] = xN; + Vturn[1] = xN; + } else if (delta2 < 0.0) { + nTurningPoints = 0; + Vturn[0] = xN; + Vturn[1] = xN; + } else { + delta = sqrt(delta2); + Vturn[0] = xN - delta; + Vturn[1] = xN + delta; +#ifdef PRINTPV + double presCalc; + double p1 = dpdVCalc(TKelvin, Vturn[0], presCalc); + + double p2 = dpdVCalc(TKelvin, Vturn[1], presCalc); + + printf("p1 = %g p2 = %g \n", p1, p2); + p1 = dpdVCalc(TKelvin, 0.9*Vturn[0], presCalc); + printf("0.9 p1 = %g \n", p1); +#endif + } + + doublereal h = 2.0 * an * delta * delta2; + + doublereal yN = 2.0 * bn * bn * bn / (27.0 * an * an) - bn * cn / (3.0 * an) + dn; + + doublereal desc = yN * yN - h2; + + if (fabs(fabs(h) - fabs(yN)) < 1.0E-10) { + if (desc != 0.0) { + // this is for getting to other cases + printf("NicholsSolve(): numerical issues\n"); + throw CanteraError("NicholsSolve()", "numerical issues"); + } + desc = 0.0; + } + + if (desc < 0.0) { + nSolnValues = 3; + } else if (desc == 0.0) { + nSolnValues = 2; + // We are here as p goes to zero. + // double hleft = 3.0 * an * cn / (bn * bn); + //double ynleft = 9.0 * an * cn / (2.0 * bn * bn) - 27.0 * an * an * dn / (2.0 * bn * bn * bn); + //printf("hleft = %g , ynleft = %g\n", -3. / 2. * hleft, -ynleft); + //double h2left = - 3 * hleft + 3 * hleft * hleft - hleft * hleft * hleft; + //double y2left = - 2.0 * ynleft + ynleft * ynleft; + //printf("h2left = %g , yn2left = %g\n", h2left, y2left); + + } else if (desc > 0.0) { + nSolnValues = 1; + } + + /* + * One real root -> have to determine whether gas or liquid is the root + */ + if (desc > 0.0) { + doublereal tmpD = sqrt(desc); + doublereal tmp1 = (- yN + tmpD) / (2.0 * an); + doublereal sgn1 = 1.0; + if (tmp1 < 0.0) { + sgn1 = -1.0; + tmp1 = -tmp1; + } + doublereal tmp2 = (- yN - tmpD) / (2.0 * an); + doublereal sgn2 = 1.0; + if (tmp2 < 0.0) { + sgn2 = -1.0; + tmp2 = -tmp2; + } + doublereal p1 = pow(tmp1, 1./3.); + doublereal p2 = pow(tmp2, 1./3.); + + doublereal alpha = xN + sgn1 * p1 + sgn2 * p2; + Vroot[0] = alpha; + Vroot[1] = 0.0; + Vroot[2] = 0.0; + + double tmp = an * Vroot[0] * Vroot[0] * Vroot[0] + bn * Vroot[0] * Vroot[0] + cn * Vroot[0] + dn; + if (fabs (tmp) > 1.0E-4) { + lotsOfNumError = true; + } + + } else if (desc < 0.0) { + doublereal tmp = - yN/h; + + doublereal val = acos(tmp); + doublereal theta = val / 3.0; + + doublereal oo = 2. * Cantera::Pi / 3.; + doublereal alpha = xN + 2. * delta * cos(theta); + + doublereal beta = xN + 2. * delta * cos(theta + oo); + + doublereal gamma = xN + 2. * delta * cos(theta + 2.0 * oo); + + + Vroot[0] = beta; + Vroot[1] = gamma; + Vroot[2] = alpha; + + for (int i = 0; i < 3; i++) { + double tmp = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn; + if (fabs (tmp) > 1.0E-4) { + lotsOfNumError = true; + for (int j = 0; j < 3; j++) { + if (j != i) { + if (fabs(Vroot[i] - Vroot[j]) < 1.0E-4 * (fabs(Vroot[i]) + fabs(Vroot[j]))) { + writelog("RedlichKwongMFTP::NicholsSolve(T = " + fp2str(TKelvin) + ", p = " + + fp2str(pres) + "): WARNING roots have merged: " + + fp2str(Vroot[i]) + ", " + fp2str(Vroot[j])); + writelogendl(); + } + } + } + } + } + } else if (desc == 0.0) { + if (yN == 0.0 && h == 0.0) { + Vroot[0] = xN; + Vroot[1] = xN; + Vroot[2] = xN; + } else { + // need to figure out whether delta is pos or neg + if (yN > 0.0) { + double tmp = pow(yN/(2*an), 1./3.); + if (fabs(tmp - delta) > 1.0E-9) { + throw CanteraError("RedlichKwongMFTP::NicholsSolve()", "unexpected"); + } + Vroot[1] = xN + delta; + Vroot[0] = xN - 2.0*delta; // liquid phase root + } else { + double tmp = pow(yN/(2*an), 1./3.); + if (fabs(tmp - delta) > 1.0E-9) { + throw CanteraError("RedlichKwongMFTP::NicholsSolve()", "unexpected"); + } + delta = -delta; + Vroot[0] = xN + delta; + Vroot[1] = xN - 2.0*delta; // gas phase root + } + } + for (int i = 0; i < 2; i++) { + double tmp = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn; + if (fabs (tmp) > 1.0E-4) { + lotsOfNumError = true; + } + } + } + + /* + * Unfortunately, there is a heavy amount of roundoff error due to bad conditioning in this + */ + double res, dresdV;; + for (int i = 0; i < nSolnValues; i++) { + for (int n = 0; n < 20; n++) { + res = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn; + if (fabs(res) < 1.0E-14) { + break; + } + dresdV = 3.0 * an * Vroot[i] * Vroot[i] + 2.0 * bn * Vroot[i] + cn; + double del = - res / dresdV; + + Vroot[i] += del; + if (fabs(del) / (fabs(Vroot[i]) + fabs(del)) < 1.0E-14) { + break; + } + double res2 = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn; + if (fabs(res2) < fabs(res)) { + continue; + } else { + Vroot[i] -= del; + Vroot[i] += 0.1 * del; + } + } + if ((fabs(res) > 1.0E-14) && (fabs(res) > 1.0E-14 * fabs(dresdV) * fabs(Vroot[i])) ) { + writelog("RedlichKwongMFTP::NicholsSolve(T = " + fp2str(TKelvin) + ", p = " + + fp2str(pres) + "): WARNING root didn't converge V = " + fp2str(Vroot[i]) ); + writelogendl(); + } + } + + if (nSolnValues == 1) { + if (TKelvin > tc) { + if (Vroot[0] < vc) { + nSolnValues = -1; + } + } else { + if (Vroot[0] < xN) { + nSolnValues = -1; + } + } + + } else { + if (nSolnValues == 2) { + if (delta > 0.0) { + nSolnValues = -2; + } + } + } + // writelog("RedlichKwongMFTP::NicholsSolve(T = " + fp2str(TKelvin) + ", p = " + fp2str(pres) + "): finished"); + // writelogendl(); + return nSolnValues; + } + + +#endif +} + + diff --git a/Cantera/src/thermo/RedlichKwongMFTP.h b/Cantera/src/thermo/RedlichKwongMFTP.h new file mode 100644 index 000000000..979957d96 --- /dev/null +++ b/Cantera/src/thermo/RedlichKwongMFTP.h @@ -0,0 +1,844 @@ +/** + * @file RedlichKwongMFTP.h + * Definition file for a derived class of ThermoPhase that assumes either + * an ideal gas or ideal solution approximation and handles + * variable pressure standard state methods for calculating + * thermodynamic properties (see \ref thermoprops and + * class \link Cantera::RedlichKwongMFTP RedlichKwongMFTP\endlink). + */ +/* + * 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. + */ +/* + * $Author: hkmoffa $ + * $Date: 2009-11-09 16:36:49 -0700 (Mon, 09 Nov 2009) $ + * $Revision: 255 $ + */ + +#ifndef CT_REDLICHKWONGMFTP_H +#define CT_REDLICHKWONGMFTP_H + +#include "MixtureFugacityTP.h" + +namespace Cantera { + + class XML_Node; + class PDSS; + + /*! + * @name CONSTANTS - Models for the Standard State of IdealSolnPhase's + */ + //@{ + +#ifdef WITH_REAL_GASSES + + /** + * @ingroup thermoprops + * + * This class can handle either an ideal solution or an ideal gas approximation + * of a phase. + * + * + * @nosubgrouping + */ + class RedlichKwongMFTP : public MixtureFugacityTP { + + public: + + /*! + * + * @name Constructors and Duplicators for %RedlichKwongMFTP + * + */ + //! Base constructor. + RedlichKwongMFTP(); + + //! Construct and initialize a RedlichKwongMFTP ThermoPhase object + //! directly from an asci input file + /*! + * Working constructors + * + * The two constructors below are the normal way the phase initializes itself. They are shells that call + * the routine initThermo(), with a reference to the + * XML database to get the info for the phase. + * + * @param inputFile Name of the input file containing the phase XML data + * to set up the object + * @param id ID of the phase in the input file. Defaults to the empty string. + */ + RedlichKwongMFTP(std::string infile, std::string id=""); + + //! Construct and initialize a RedlichKwongMFTP ThermoPhase object + //! directly from an XML database + /*! + * @param phaseRef XML phase node containing the description of the phase + * @param id id attribute containing the name of the phase. (default is the empty string) + */ + RedlichKwongMFTP(XML_Node& phaseRef, std::string id = ""); + + //! This is a special constructor, used to replicate test problems + //! during the initial verification of the object + /*! + * + * test problems: + * 1: Pure CO2 problem + * input file = CO2_RedlickKwongMFTP.xml + * + * @param testProb Hard -coded test problem to instantiate. + * Current valid values are 1. + */ + RedlichKwongMFTP(int testProb); + + //! Copy Constructor + /*! + * Copy constructor for the object. Constructed object will be a clone of this object, but will + * also own all of its data. This is a wrapper around the assignment operator + * + * @param right Object to be copied. + */ + RedlichKwongMFTP(const RedlichKwongMFTP &right); + + //! Asignment operator + /*! + * Assignment operator for the object. Constructed object will be a clone of this object, but will + * also own all of its data. + * + * @param right Object to be copied. + */ + RedlichKwongMFTP& operator=(const RedlichKwongMFTP &right); + + //! Destructor. + virtual ~RedlichKwongMFTP(); + + + //! Duplicator from the ThermoPhase parent class + /*! + * Given a pointer to a ThermoPhase object, this function will + * duplicate the ThermoPhase object and all underlying structures. + * This is basically a wrapper around the copy constructor. + * + * @return returns a pointer to a ThermoPhase + */ + virtual ThermoPhase *duplMyselfAsThermoPhase() const; + + //@} + + /** + * @name Utilities (RedlichKwongMFTP) + */ + //@{ + /** + * Equation of state type flag. The base class returns + * zero. Subclasses should define this to return a unique + * non-zero value. Constants defined for this purpose are + * listed in mix_defs.h. + */ + virtual int eosType() const; + + //@} + + /// Molar enthalpy. Units: J/kmol. + virtual doublereal enthalpy_mole() const; + + /// Molar internal energy. Units: J/kmol. + virtual doublereal intEnergy_mole() const; + + /// Molar entropy. Units: J/kmol/K. + virtual doublereal entropy_mole() const; + + /// Molar Gibbs function. Units: J/kmol. + virtual doublereal gibbs_mole() const; + + /// Molar heat capacity at constant pressure. Units: J/kmol/K. + virtual doublereal cp_mole() const; + + /// Molar heat capacity at constant volume. Units: J/kmol/K. + virtual doublereal cv_mole() const; + + /** + * @} + * @name Mechanical Properties + * @{ + */ + + //! Return the thermodynamic pressure (Pa). + /*! + * Since the mass density, temperature, and mass fractions are stored, + * this method uses these values to implement the + * mechanical equation of state \f$ P(T, \rho, Y_1, \dots, Y_K) \f$. + * + * \f[ + * P = \frac{RT}{v-b_{mix}} - \frac{a_{mix}}{T^{0.5} v \left( v + b_{mix} \right) } + * \f] + * + */ + virtual doublereal pressure() const; + + //! Returns the isothermal compressibility. Units: 1/Pa. + /*! + * The isothermal compressibility is defined as + * \f[ + * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T + * \f] + */ + virtual doublereal isothermalCompressibility() const; + + protected: + /** + * Calculate the density of the mixture using the partial + * molar volumes and mole fractions as input + * + * The formula for this is + * + * \f[ + * \rho = \frac{\sum_k{X_k W_k}}{\sum_k{X_k V_k}} + * \f] + * + * where \f$X_k\f$ are the mole fractions, \f$W_k\f$ are + * the molecular weights, and \f$V_k\f$ are the pure species + * molar volumes. + * + * Note, the basis behind this formula is that in an ideal + * solution the partial molar volumes are equal to the + * species standard state molar volumes. + * The species molar volumes may be functions + * of temperature and pressure. + * + * NOTE: This is a non-virtual function, which is not a + * member of the ThermoPhase base class. + */ + virtual void calcDensity(); + + protected: + //! Set the temperature (K) + /*! + * Overwritten setTemperature(double) from State.h. This + * function sets the temperature, and makes sure that + * the value propagates to underlying objects + * + * @todo Make State::setTemperature a virtual function + * + * @param temp Temperature in kelvin + */ + virtual void setTemperature(const doublereal temp); + + //! Set the mass fractions to the specified values, and then + //! normalize them so that they sum to 1.0. + /*! + * @param y Array of unnormalized mass fraction values (input). + * Must have a length greater than or equal to the number of species. + */ + virtual void setMassFractions(const doublereal* const y); + + //!Set the mass fractions to the specified values without normalizing. + /*! + * This is useful when the normalization + * condition is being handled by some other means, for example + * by a constraint equation as part of a larger set of + * equations. + * + * @param y Input vector of mass fractions. + * Length is m_kk. + */ + virtual void setMassFractions_NoNorm(const doublereal* const y); + + //! Set the mole fractions to the specified values, and then + //! normalize them so that they sum to 1.0. + /*! + * @param x Array of unnormalized mole fraction values (input). + * Must have a length greater than or equal to the number of species. + */ + virtual void setMoleFractions(const doublereal* const x); + + //! Set the mole fractions to the specified values without normalizing. + /*! + * This is useful when the normalization + * condition is being handled by some other means, for example + * by a constraint equation as part of a larger set ofequations. + * + * @param x Input vector of mole fractions. + * Length is m_kk. + */ + virtual void setMoleFractions_NoNorm(const doublereal* const x); + + + //! Set the concentrations to the specified values within the phase. + /*! + * @param c The input vector to this routine is in dimensional + * units. For volumetric phases c[k] is the + * concentration of the kth species in kmol/m3. + * For surface phases, c[k] is the concentration + * in kmol/m2. The length of the vector is the number + * of species in the phase. + */ + virtual void setConcentrations(const doublereal* const c); + + + public: + + //! This method returns an array of generalized concentrations + /*! + * \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k / + * C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration + * defined below and \f$ a_k \f$ are activities used in the + * thermodynamic functions. These activity (or generalized) + * concentrations are used + * by kinetics manager classes to compute the forward and + * reverse rates of elementary reactions. Note that they may + * or may not have units of concentration --- they might be + * partial pressures, mole fractions, or surface coverages, + * for example. + * + * @param c Output array of generalized concentrations. The + * units depend upon the implementation of the + * reaction rate expressions within the phase. + */ + virtual void getActivityConcentrations(doublereal* c) const; + + //! Returns the standard concentration \f$ C^0_k \f$, which is used to normalize + //! the generalized concentration. + /*! + * This is defined as the concentration by which the generalized + * concentration is normalized to produce the activity. + * In many cases, this quantity will be the same for all species in a phase. + * Since the activity for an ideal gas mixture is + * simply the mole fraction, for an ideal gas \f$ C^0_k = P/\hat R T \f$. + * + * @param k Optional parameter indicating the species. The default + * is to assume this refers to species 0. + * @return + * Returns the standard Concentration in units of m3 kmol-1. + */ + virtual doublereal standardConcentration(int k=0) const; + + //! Returns the natural logarithm of the standard + //! concentration of the kth species + /*! + * @param k index of the species. (defaults to zero) + */ + virtual doublereal logStandardConc(int k=0) const; + + //! Returns the units of the standard and generalized concentrations. + /*! + * Note they have the same units, as their + * ratio is defined to be equal to the activity of the kth + * species in the solution, which is unitless. + * + * This routine is used in print out applications where the + * units are needed. Usually, MKS units are assumed throughout + * the program and in the XML input files. + * + * The base %ThermoPhase class assigns the default quantities + * of (kmol/m3) for all species. + * Inherited classes are responsible for overriding the default + * values if necessary. + * + * @param uA Output vector containing the units + * uA[0] = kmol units - default = 1 + * uA[1] = m units - default = -nDim(), the number of spatial + * dimensions in the Phase class. + * uA[2] = kg units - default = 0; + * uA[3] = Pa(pressure) units - default = 0; + * uA[4] = Temperature units - default = 0; + * uA[5] = time units - default = 0 + * @param k species index. Defaults to 0. + * @param sizeUA output int containing the size of the vector. + * Currently, this is equal to 6. + */ + virtual void getUnitsStandardConc(double *uA, int k = 0, int sizeUA = 6) const; + + //! Get the array of non-dimensional activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * For all objects with the Mixture Fugacity approximation, we define the + * standard state as an ideal gas at the current temperature and pressure + * of the solution. The activities are based on this standard state. + * + * @param ac Output vector of activity coefficients. Length: m_kk. + */ + virtual void getActivityCoefficients(doublereal* ac) const; + + + /// @name Partial Molar Properties of the Solution (RedlichKwongMFTP) + //@{ + + //! Get the array of non-dimensional species chemical potentials. + //! These are partial molar Gibbs free energies. + /*! + * \f$ \mu_k / \hat R T \f$. + * Units: unitless + * + * We close the loop on this function, here, calling + * getChemPotentials() and then dividing by RT. No need for child + * classes to handle. + * + * @param mu Output vector of non-dimensional species chemical potentials + * Length: m_kk. + */ + void getChemPotentials_RT(doublereal* mu) const; + + //! Get the species chemical potentials. Units: J/kmol. + /*! + * This function returns a vector of chemical potentials of the + * species in solution at the current temperature, pressure + * and mole fraction of the solution. + * + * @param mu Output vector of species chemical + * potentials. Length: m_kk. Units: J/kmol + */ + virtual void getChemPotentials(doublereal* mu) const; + + //! Get the species partial molar enthalpies. Units: J/kmol. + /*! + * @param hbar Output vector of species partial molar enthalpies. + * Length: m_kk. units are J/kmol. + */ + virtual void getPartialMolarEnthalpies(doublereal* hbar) const; + + //! Get the species partial molar entropies. Units: J/kmol/K. + /*! + * @param sbar Output vector of species partial molar entropies. + * Length = m_kk. units are J/kmol/K. + */ + virtual void getPartialMolarEntropies(doublereal* sbar) const; + + //! Get the species partial molar enthalpies. Units: J/kmol. + /*! + * @param ubar Output vector of speciar partial molar internal energies. + * Length = m_kk. units are J/kmol. + */ + virtual void getPartialMolarIntEnergies(doublereal* ubar) const; + + //! Get the partial molar heat capacities Units: J/kmol/K + /*! + * @param cpbar Output vector of species partial molar heat capacities + * at constant pressure. + * Length = m_kk. units are J/kmol/K. + */ + virtual void getPartialMolarCp(doublereal* cpbar) const; + + //! Get the species partial molar volumes. Units: m^3/kmol. + /*! + * @param vbar Output vector of speciar partial molar volumes. + * Length = m_kk. units are m^3/kmol. + */ + virtual void getPartialMolarVolumes(doublereal* vbar) const; + + //@} + + /*! + * @name Properties of the Standard State of the Species in the Solution + * + * Properties of the standard states are delegated to the VPSSMgr object. + * The values are cached within this object, and are not recalculated unless + * the temperature or pressure changes. + */ + //@{ + + //@} + + /// @name Thermodynamic Values for the Species Reference States (RedlichKwongMFTP) + /*! + * Properties of the reference states are delegated to the VPSSMgr object. + * The values are cached within this object, and are not recalculated unless + * the temperature or pressure changes. + */ + //@{ + + //@} + + + + //--------------------------------------------------------- + /// @name Critical State Properties. + /// These methods are only implemented by some subclasses, and may + /// be moved out of ThermoPhase at a later date. + + //@{ + + /// Critical temperature (K). + virtual doublereal critTemperature() const; + + /// Critical pressure (Pa). + virtual doublereal critPressure() const; + + /// Critical density (kg/m3). + virtual doublereal critDensity() const; + //@} + + + + + public: + + //! @name Initialization Methods - For Internal use (VPStandardState) + /*! + * The following methods are used in the process of constructing + * the phase and setting its parameters from a specification in an + * input file. They are not normally used in application programs. + * To see how they are used, see files importCTML.cpp and + * ThermoFactory.cpp. + */ + //@{ + + + //! Set equation of state parameter values from XML + //! entries. + /*! + * This method is called by function importPhase in + * file importCTML.cpp when processing a phase definition in + * an input file. It should be overloaded in subclasses to set + * any parameters that are specific to that particular phase + * model. + * + * @param thermoNode An XML_Node object corresponding to + * the "thermo" entry for this phase in the input file. + */ + virtual void setParametersFromXML(const XML_Node& thermoNode); + + //! @internal Initialize the object + /*! + * This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase(). + * + * @see importCTML.cpp + */ + virtual void initThermo(); + + + //!This method is used by the ChemEquil equilibrium solver. + /*! + * It sets the state such that the chemical potentials satisfy + * \f[ \frac{\mu_k}{\hat R T} = \sum_m A_{k,m} + * \left(\frac{\lambda_m} {\hat R T}\right) \f] where + * \f$ \lambda_m \f$ is the element potential of element m. The + * temperature is unchanged. Any phase (ideal or not) that + * implements this method can be equilibrated by ChemEquil. + * + * @param lambda_RT Input vector of dimensionless element potentials + * The length is equal to nElements(). + */ + void setToEquilState(const doublereal* lambda_RT); + + //! Initialize a ThermoPhase object, potentially reading activity + //! coefficient information from an XML database. + /*! + * + * This routine initializes the lengths in the current object and + * then calls the parent routine. + * This method is provided to allow + * subclasses to perform any initialization required after all + * species have been added. For example, it might be used to + * resize internal work arrays that must have an entry for + * each species. The base class implementation does nothing, + * and subclasses that do not require initialization do not + * need to overload this method. When importing a CTML phase + * description, this method is called just prior to returning + * from function importPhase(). + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + virtual void initThermoXML(XML_Node& phaseNode, std::string id); + + private: + //! Read the pure species RedlichKwong input parameters + /*! + * @param pureFluidParam XML_Node for the pure fluid parameters + */ + void readXMLPureFluid(XML_Node &PureFluidParam); + + + //! Apply mixing rules for a coefficients + void applyStandardMixingRules(); + + + //! Read the cross species RedlichKwong input parameters + /*! + * @param pureFluidParam XML_Node for the cross fluid parameters + */ + void readXMLCrossFluid(XML_Node &PureFluidParam); + + + + //============================================================================== + private: + //! @internal Initialize the internal lengths in this object. + /*! + * Note this is not a virtual function and only handles + * this object + */ + void initLengths(); + + //============================================================================== + // Special functions inherited from MixtureFugacityTP + + protected: + + //! Calculate the deviation terms for the total entropy of the mixture from the + //! ideal gas mixture + /*! + * Here we use the current state conditions + * + * @return Returns the change in entropy in units of J kmol-1 K-1. + */ + virtual doublereal sresid() const; + + // Calculate the deviation terms for the total enthalpy of the mixture from the + // ideal gas mixture + /* + * Here we use the current state conditions + * + * @return Returns the change in enthalpy in units of J kmol-1. + */ + virtual doublereal hresid() const; + public: + //! Estimate for the molar volume of the liquid + /*! + * Note: this is only used as a starting guess for later routines that actually calculate an + * accurate value for the liquid molar volume. + * This routine doesn't change the state of the system. + * + * @param TKelvin temperature in kelvin + * @param pres Pressure in Pa. This is used as an initial guess. If the routine + * needs to change the pressure to find a stable liquid state, the + * new pressure is returned in this variable. + * + * @return Returns the estimate of the liquid volume. + */ + virtual doublereal liquidVolEst(doublereal TKelvin, doublereal &pres) const; + + public: + //! Calculates the density given the temperature and the pressure and a guess at the density. + /*! + * Note, below T_c, this is a multivalued function. We do not cross the vapor dome in this. + * This is protected because it is called during setState_TP() routines. Infinite loops would result + * if it were not protected. + * + * -> why is this not const? + * + * parameters: + * @param TKelvin Temperature in Kelvin + * @param pressure Pressure in Pascals (Newton/m**2) + * @param phase int representing the phase whose density we are requesting. If we put + * a gas or liquid phase here, we will attempt to find a volume in that + * part of the volume space, only, in this routine. A value of FLUID_UNDEFINED + * means that we will accept anything. + * + * @param rhoguess Guessed density of the fluid. A value of -1.0 indicates that there + * is no guessed density + * + * + * @return We return the density of the fluid at the requested phase. If we have not found any + * acceptable density we return a -1. If we have found an accectable density at a + * different phase, we return a -2. + */ + virtual doublereal densityCalc(doublereal TKelvin, doublereal pressure, int phase, doublereal rhoguess); + + public: + //! Return the value of the density at the liquid spinodal point (on the liquid side) + //! for the current temperature. + /*! + * @return returns the density with units of kg m-3 + */ + virtual doublereal densSpinodalLiquid() const; + + + //! Return the value of the density at the gas spinodal point (on the gas side) + //! for the current temperature. + /*! + * @return returns the density with units of kg m-3 + */ + virtual doublereal densSpinodalGas() const; + + + + //! Calculate the pressure given the temperature and the molar volume + /*! + * Calculate the pressure given the temperature and the molar volume + * + * @param TKelvin temperature in kelvin + * @param molarVol molar volume ( m3/kmol) + * + * @return Returns the pressure. + */ + virtual doublereal pressureCalc(doublereal TKelvin, doublereal molarVol) const; + + + //! Calculate the pressure and the pressure derivative given the temperature and the molar volume + /*! + * Temperature and mole number are held constant + * + * @param TKelvin temperature in kelvin + * @param molarVol molar volume ( m3/kmol) + * + * @param presCalc Returns the pressure. + * + * @return Returns the derivative of the pressure wrt the molar volume + */ + virtual doublereal dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal &presCalc) const; + + + //! Calculate dpdV and dpdT at the current conditions + /*! + * These are storred internally. + */ + void pressureDerivatives() const; + + + virtual void updateMixingExpressions(); + + + //! Update the a and b parameters + /*! + * The a and the b parameters depend on the mole fraction and the temperature. + * This function updates the internal numbers based on the state of the object. + */ + void updateAB(); + + + //! Calculate the a and the b parameters given the temperature + /*! + * + * This function doesn't change the internal state of the object, so it is a const + * function. It does use the storred mole fractions in the object. + * + * @param temp Temperature (TKelvin) + * + * @param aCalc (output) Returns the a value + * @param bCalc (output) Returns the b value. + */ + void calculateAB(doublereal temp, doublereal &aCalc, doublereal &bCalc) const; + + + //========================================================================================= + // Special functions not inherited from MixtureFugacityTP + + doublereal da_dt() const; + + void calcCriticalConditions(doublereal a, doublereal b, doublereal a0_coeff, doublereal aT_coeff, + doublereal &pc, doublereal &tc, doublereal &vc) const; + + + + int NicholsSolve(double TKelvin, double pres, doublereal a, doublereal b, + doublereal Vroot[3]) const; + + //@} + //============================================================================== + protected: + + //! boolean indicating whether standard mixing rules are applied + /*! + * - 1 = Yes, there are standard cross terms in the a coefficient matrices. + * - 0 = No, there are nonstaandard cross terms in the a coefficient matrices. + */ + int m_standardMixingRules; + + //! Form of the temperature parameterization + /*! + * - 0 = There is no temperature parameterization of a or b + * - 1 = The a_ij parameter is a linear function of the temperature + */ + int m_formTempParam; + + + //! Value of b in the equation of state + /*! + * m_b is a function of the temperature and the mole fraction. + */ + doublereal m_b_current; + + //! Value of a in the equation of state + /*! + * a_b is a function of the temperature and the mole fraction. + */ + doublereal m_a_current; + + + vector_fp a_vec_Curr_; + vector_fp b_vec_Curr_; + + Array2D a_coeff_vec; + + + vector_fp m_pc_Species; + vector_fp m_tc_Species; + vector_fp m_vc_Species; + + int NSolns_; + + doublereal Vroot_[3]; + + + + //! Temporary storage - length = m_kk. + mutable vector_fp m_pp; + + //! Temporary storage - length = m_kk. + mutable vector_fp m_tmpV; + + // mutable vector_fp m_tmpV2; + + // Partial molar volumes of the species + mutable vector_fp m_partialMolarVolumes; + + + + //! The derivative of the pressure wrt the volume + /*! + * Calcualted at the current conditions + * temperature and mole number kept constant + */ + mutable doublereal dpdV_; + + //! The derivative of the pressure wrt the temperature + /*! + * Calcualted at the current conditions + * Total volume and mole number kept constant + */ + mutable doublereal dpdT_; + + //! Vector of derivatives of pressure wrt mole number + /*! + * Calcualted at the current conditions + * Total volume, temperature and other mole number kept constant + */ + mutable vector_fp dpdni_; + + public: + //! Omega constant for a -> value of a in terms of critical properties + /*! + * this was calculated from a small nonlinear solve + */ + static const doublereal omega_a = 4.27480233540E-01; + + //! Omega constant for b + static const doublereal omega_b = 8.66403499650E-02; + + //! Omega constant for the critical molar volume + static const doublereal omega_vc = 3.33333333333333E-01; + + + }; +#endif +} + +#endif diff --git a/Cantera/src/thermo/SemiconductorPhase.h b/Cantera/src/thermo/SemiconductorPhase.h index 561d7df0b..a6e121f02 100644 --- a/Cantera/src/thermo/SemiconductorPhase.h +++ b/Cantera/src/thermo/SemiconductorPhase.h @@ -70,15 +70,15 @@ namespace Cantera { virtual void setParametersFromXML(const XML_Node& eosdata) { eosdata._require("model","Semiconductor"); - doublereal rho = getFloat(eosdata, "density", "-"); + doublereal rho = ctml::getFloat(eosdata, "density", "-"); setDensity(rho); - doublereal bandgap = getFloat(eosdata, "bandgap", "-"); - doublereal e_mass = getFloat(eosdata, "electron_mass", "-"); - doublereal h_mass = getFloat(eosdata, "hole_mass", "-"); - doublereal e_donor = getFloat(eosdata, "donor_energy", "-"); - doublereal n_donor = getFloat(eosdata, "donor_concentration", "-"); - doublereal e_acceptor = getFloat(eosdata, "acceptor_energy", "-"); - doublereal n_acceptor = getFloat(eosdata, "acceptor_concentration", "-"); + doublereal bandgap = ctml::getFloat(eosdata, "bandgap", "-"); + doublereal e_mass = ctml::getFloat(eosdata, "electron_mass", "-"); + doublereal h_mass = ctml::getFloat(eosdata, "hole_mass", "-"); + doublereal e_donor = ctml::getFloat(eosdata, "donor_energy", "-"); + doublereal n_donor = ctml::getFloat(eosdata, "donor_concentration", "-"); + doublereal e_acceptor = ctml::getFloat(eosdata, "acceptor_energy", "-"); + doublereal n_acceptor = ctml::getFloat(eosdata, "acceptor_concentration", "-"); setEffectiveMasses(e_mass, h_mass); setDonorDoping(n_donor, e_donor); setAcceptorDoping(n_acceptor, e_acceptor); diff --git a/Cantera/src/thermo/ShomateThermo.h b/Cantera/src/thermo/ShomateThermo.h index c37822801..e82bbf8a4 100644 --- a/Cantera/src/thermo/ShomateThermo.h +++ b/Cantera/src/thermo/ShomateThermo.h @@ -162,14 +162,14 @@ namespace Cantera { * @see ShomatePoly * @see ShomatePoly2 */ - virtual void install(string name, int index, int type, + virtual void install(std::string name, int index, int type, const doublereal* c, doublereal minTemp, doublereal maxTemp, doublereal refPressure) { int imid = int(c[0]); // midpoint temp converted to integer int igrp = m_index[imid]; // has this value been seen before? if (igrp == 0) { // if not, prepare new group - vector v; + std::vector v; m_high.push_back(v); m_low.push_back(v); m_tmid.push_back(c[0]); @@ -201,12 +201,13 @@ namespace Cantera { if (m_p0 < 0.0) { m_p0 = refPressure; } else if (fabs(m_p0 - refPressure) > 0.1) { - string logmsg = " WARNING ShomateThermo: New Species, " + name + std::string logmsg = " ERROR ShomateThermo: New Species, " + name + ", has a different reference pressure, " + fp2str(refPressure) + ", than existing reference pressure, " + fp2str(m_p0) + "\n"; writelog(logmsg); - logmsg = " This may become a fatal error in the future \n"; + logmsg = " This is now a fatal error\n"; writelog(logmsg); + throw CanteraError("install()", "Species have different reference pressures"); } m_p0 = refPressure; @@ -247,14 +248,14 @@ namespace Cantera { int grp = m_group_map[k]; int pos = m_posInGroup_map[k]; - const vector &mlg = m_low[grp-1]; + const std::vector &mlg = m_low[grp-1]; const ShomatePoly *nlow = &(mlg[pos]); doublereal tmid = nlow->maxTemp(); if (t < tmid) { nlow->updateProperties(&m_t[0], cp_R, h_RT, s_R); } else { - const vector &mhg = m_high[grp-1]; + const std::vector &mhg = m_high[grp-1]; const ShomatePoly *nhigh = &(mhg[pos]); nhigh->updateProperties(&m_t[0], cp_R, h_RT, s_R); } @@ -288,7 +289,7 @@ namespace Cantera { m_t[5] = 1.0/GasConstant; m_t[6] = 1.0/(GasConstant * t); - vector::const_iterator _begin, _end; + std::vector::const_iterator _begin, _end; for (i = 0; i != m_ngroups; i++) { if (t > m_tmid[i]) { _begin = m_high[i].begin(); @@ -387,8 +388,8 @@ namespace Cantera { int grp = m_group_map[index]; int pos = m_posInGroup_map[index]; int itype = SHOMATE; - const vector &mlg = m_low[grp-1]; - const vector &mhg = m_high[grp-1]; + const std::vector &mlg = m_low[grp-1]; + const std::vector &mhg = m_high[grp-1]; const ShomatePoly *lowPoly = &(mlg[pos]); const ShomatePoly *highPoly = &(mhg[pos]); doublereal tmid = lowPoly->maxTemp(); @@ -427,8 +428,8 @@ namespace Cantera { if (type == SHOMATE) { int grp = m_group_map[index]; int pos = m_posInGroup_map[index]; - vector &mlg = m_low[grp-1]; - vector &mhg = m_high[grp-1]; + std::vector &mlg = m_low[grp-1]; + std::vector &mhg = m_high[grp-1]; ShomatePoly *lowPoly = &(mlg[pos]); ShomatePoly *highPoly = &(mhg[pos]); doublereal tmid = lowPoly->maxTemp(); @@ -453,14 +454,14 @@ namespace Cantera { int grp = m_group_map[k]; int pos = m_posInGroup_map[k]; - const vector &mlg = m_low[grp-1]; + const std::vector &mlg = m_low[grp-1]; const ShomatePoly *nlow = &(mlg[pos]); doublereal tmid = nlow->maxTemp(); if (t <= tmid) { h = nlow->reportHf298(); } else { - const vector &mhg = m_high[grp-1]; + const std::vector &mhg = m_high[grp-1]; const ShomatePoly *nhigh = &(mhg[pos]); h = nhigh->reportHf298(); } @@ -471,9 +472,9 @@ namespace Cantera { int grp = m_group_map[k]; int pos = m_posInGroup_map[k]; - vector &mlg = m_low[grp-1]; + std::vector &mlg = m_low[grp-1]; ShomatePoly *nlow = &(mlg[pos]); - vector &mhg = m_high[grp-1]; + std::vector &mhg = m_high[grp-1]; ShomatePoly *nhigh = &(mhg[pos]); doublereal tmid = nlow->maxTemp(); @@ -504,7 +505,7 @@ namespace Cantera { * The second vector is equal to the number of species * in that particular group. */ - vector > m_high; + std::vector > m_high; //! Vector of vector of NasaPoly1's for the low temp region. /*! @@ -513,13 +514,13 @@ namespace Cantera { * The second vector is equal to the number of species * in that particular group. */ - vector > m_low; + std::vector > m_low; //! Map between the midpoint temperature, as an int, to the group number /*! * Length is equal to the number of groups. Only used in the setup. */ - map m_index; + std::map m_index; //! Vector of log temperature limits /*! @@ -563,14 +564,14 @@ namespace Cantera { * for that species are stored. group indecises start at 1, * so a decrement is always performed to access vectors. */ - mutable map m_group_map; + mutable std::map m_group_map; /*! * This map takes as its index, the species index in the phase. * It returns the position index within the group, where the * temperature polynomials for that species are storred. */ - mutable map m_posInGroup_map; + mutable std::map m_posInGroup_map; }; } diff --git a/Cantera/src/thermo/SimpleThermo.h b/Cantera/src/thermo/SimpleThermo.h index e0536259f..83bcb99e1 100644 --- a/Cantera/src/thermo/SimpleThermo.h +++ b/Cantera/src/thermo/SimpleThermo.h @@ -13,6 +13,7 @@ #define CT_SIMPLETHERMO_H #include "SpeciesThermoMgr.h" +#include "speciesThermoTypes.h" namespace Cantera { @@ -150,10 +151,9 @@ namespace Cantera { * * @see ConstCpPoly */ - virtual void install(string name, int index, int type, - const doublereal* c, + virtual void install(std::string name, int index, int type, const doublereal* c, doublereal minTemp, doublereal maxTemp, doublereal refPressure) { - //writelog("installing const_cp for species "+name+"\n"); + m_logt0.push_back(log(c[0])); m_t0.push_back(c[0]); m_h0_R.push_back(c[1]/GasConstant); @@ -178,12 +178,13 @@ namespace Cantera { if (m_p0 < 0.0) { m_p0 = refPressure; } else if (fabs(m_p0 - refPressure) > 0.1) { - string logmsg = " WARNING SimpleThermo: New Species, " + name + + std::string logmsg = " WARNING SimpleThermo: New Species, " + name + ", has a different reference pressure, " + fp2str(refPressure) + ", than existing reference pressure, " + fp2str(m_p0) + "\n"; writelog(logmsg); - logmsg = " This may become a fatal error in the future \n"; + logmsg = " This is now a fatal error\n"; writelog(logmsg); + throw CanteraError("install()", "Species have different reference pressures"); } m_p0 = refPressure; } @@ -382,7 +383,7 @@ namespace Cantera { * This index keeps track of it. * indexData = m_loc[kspec] */ - mutable map m_loc; + mutable std::map m_loc; //! Map between the vector index where the coefficients are kept and the species index /*! diff --git a/Cantera/src/thermo/SingleSpeciesTP.cpp b/Cantera/src/thermo/SingleSpeciesTP.cpp index 8e8372c47..7860bb859 100644 --- a/Cantera/src/thermo/SingleSpeciesTP.cpp +++ b/Cantera/src/thermo/SingleSpeciesTP.cpp @@ -346,7 +346,7 @@ namespace Cantera { * This member function is resolved here. A single species phase obtains its * thermo from the standard state function. * - * @param cpbar On return, Contains the molar volume of the single species + * @param vbar On return, Contains the molar volume of the single species * and the phase. Units are m^3 / kmol. Length = 1 */ void SingleSpeciesTP::getPartialMolarVolumes(doublereal* vbar) const { @@ -514,7 +514,11 @@ namespace Cantera { void SingleSpeciesTP::setState_UV(doublereal u, doublereal v, doublereal tol) { doublereal dt; - setDensity(1.0/v); + if (v == 0.0) { + setDensity(1.0E100); + } else { + setDensity(1.0/v); + } for (int n = 0; n < 50; n++) { dt = (u - intEnergy_mass())/cv_mass(); if (dt > 100.0) dt = 100.0; @@ -548,7 +552,11 @@ namespace Cantera { void SingleSpeciesTP::setState_SV(doublereal s, doublereal v, doublereal tol) { doublereal dt; - setDensity(1.0/v); + if (v == 0.0) { + setDensity(1.0E100); + } else { + setDensity(1.0/v); + } for (int n = 0; n < 50; n++) { dt = (s - entropy_mass())*temperature()/cv_mass(); if (dt > 100.0) dt = 100.0; diff --git a/Cantera/src/thermo/SpeciesThermoFactory.cpp b/Cantera/src/thermo/SpeciesThermoFactory.cpp index 816e26f07..a26a53c8e 100644 --- a/Cantera/src/thermo/SpeciesThermoFactory.cpp +++ b/Cantera/src/thermo/SpeciesThermoFactory.cpp @@ -53,15 +53,18 @@ namespace Cantera { boost::mutex SpeciesThermoFactory::species_thermo_mutex ; #endif - //! Examine the types of species thermo parameterizations, //! and return a flag indicating the type of reference state thermo manager //! that will be needed in order to evaluate them all. /*! * - * @param spDataNodeList, This vector contains a list - * of species XML nodes that will be in the phase + * @param spDataNodeList This vector contains a list + * of species XML nodes that will be in the phase + * @param has_nasa Return int that indicates whether the phase has a NASA polynomial form for one of its species + * @param has_shomate Return int that indicates whether the phase has a SHOMATE polynomial form for one of its species + * @param has_simple Return int that indicates whether the phase has a SIMPLE polynomial form for one of its species + * @param has_other Return int that indicates whether the phase has a form for one of its species that is not one of the ones listed above. * * @todo Make sure that spDadta_node is species Data XML node by checking its name is speciesData */ @@ -294,11 +297,15 @@ namespace Cantera { } - /** - * Install a NASA polynomial thermodynamic property - * parameterization for species k into a SpeciesThermo instance. - * This is called by method installThermoForSpecies if a NASA - * block is found in the XML input. + //! Install a NASA polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a NASA block is found in the XML input. + * + * @param speciesName String name of the species + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial + * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial */ static void installNasaThermoFromXML(std::string speciesName, SpeciesThermo& sp, int k, @@ -377,12 +384,17 @@ namespace Cantera { #ifdef INCL_NASA96 - /** - * Install a NASA96 polynomial thermodynamic property - * parameterization for species k into a SpeciesThermo instance. + //! Install a NASA96 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a NASA block is found in the XML input. + * + * @param speciesName String name of the species + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial + * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial */ - static void installNasa96ThermoFromXML(std::string speciesName, - SpeciesThermo& sp, int k, + static void installNasa96ThermoFromXML(std::string speciesName, SpeciesThermo& sp, int k, const XML_Node* f0ptr, const XML_Node* f1ptr) { doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax; @@ -444,6 +456,11 @@ namespace Cantera { #endif + //! Look up the elemental reference state entropies + /*! + * @param elemName String name of the element + * @param th_ptr Pointer to the thermophase. + */ static doublereal LookupGe(const std::string& elemName, ThermoPhase *th_ptr) { #ifdef OLDWAY int num = sizeof(geDataTable) / sizeof(struct GeData); @@ -471,6 +488,13 @@ namespace Cantera { #endif } + //! Convert delta G formulation + /*! + * Calculates the sum of the elemental reference state entropies + * + * @param k species index + * @param th_ptr Pointer to the ThermoPhase + */ static doublereal convertDGFormation(int k, ThermoPhase *th_ptr) { /* * Ok let's get the element compositions and conversion factors. @@ -493,7 +517,16 @@ namespace Cantera { } - + //! Install a NASA96 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a MinEQ3node block is found in the XML input. + * + * @param speciesName String name of the species + * @param th_ptr Pointer to the %ThermoPhase object + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param MinEQ3node Ptr to the first XML_Node for the first MinEQ3 parameterization + */ static void installMinEQ3asShomateThermoFromXML(std::string speciesName, ThermoPhase *th_ptr, SpeciesThermo& sp, int k, @@ -570,21 +603,34 @@ namespace Cantera { sp.install(speciesName, k, SHOMATE, &coef[0], tmin0, tmax0, p0); } - - /** - * Install a Shomate polynomial thermodynamic property - * parameterization for species k. + //! Install a Shomate polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a Shomate block is found in the XML input. + * + * @param speciesName String name of the species + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial + * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial */ - static void installShomateThermoFromXML(std::string speciesName, - SpeciesThermo& sp, int k, + static void installShomateThermoFromXML(std::string speciesName, SpeciesThermo& sp, int k, const XML_Node* f0ptr, const XML_Node* f1ptr) { doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax; - const XML_Node& f0 = *f0ptr; bool dualRange = false; if (f1ptr) {dualRange = true;} tmin0 = fpValue(f0["Tmin"]); tmax0 = fpValue(f0["Tmax"]); + + doublereal p0 = OneAtm; + if (f0.hasAttrib("P0")) { + p0 = fpValue(f0["P0"]); + } + if (f0.hasAttrib("Pref")) { + p0 = fpValue(f0["Pref"]); + } + p0 = OneAtm; + tmin1 = tmax0; tmax1 = tmin1 + 0.0001; if (dualRange) { @@ -618,17 +664,19 @@ namespace Cantera { } array_fp c(15); c[0] = tmid; - doublereal p0 = OneAtm; copy(c0.begin(), c0.begin()+7, c.begin() + 1); copy(c1.begin(), c1.begin()+7, c.begin() + 8); sp.install(speciesName, k, SHOMATE, &c[0], tmin, tmax, p0); } - - - /** - * Install a constant-cp thermodynamic property - * parameterization for species k. + //! Install a Simple thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a SimpleThermo block is found + * + * @param speciesName String name of the species + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param f XML_Node for the SimpleThermo block */ static void installSimpleThermoFromXML(std::string speciesName, SpeciesThermo& sp, int k, @@ -647,11 +695,15 @@ namespace Cantera { sp.install(speciesName, k, SIMPLE, &c[0], tmin, tmax, p0); } - /** - * Install a NASA9 polynomial thermodynamic property - * parameterization for species k into a SpeciesThermo instance. - * This is called by method installThermoForSpecies if a NASA9 - * block is found in the XML input. + + //! Install a NASA9 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a NASA9 block is found in the XML input. + * + * @param speciesName String name of the species + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param tp Vector of XML Nodes that make up the parameterization */ static void installNasa9ThermoFromXML(std::string speciesName, SpeciesThermo& sp, int k, @@ -705,13 +757,16 @@ namespace Cantera { } - /** - * Install an Adsorbate thermodynamic property - * parameterization for species k into a SpeciesThermo instance. - * This is called by method installThermoForSpecies if a NASA9 - * block is found in the XML input. - */ #ifdef WITH_ADSORBATE + //! Install a Adsorbate polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. + /*! + * This is called by method installThermoForSpecies if a Adsorbate block is found in the XML input. + * + * @param speciesName String name of the species + * @param sp SpeciesThermo object that will receive the nasa polynomial object + * @param k Species index within the phase + * @param tp Vector of XML Nodes that make up the parameterization + */ static void installAdsorbateThermoFromXML(std::string speciesName, SpeciesThermo& sp, int k, const XML_Node& f) { @@ -739,8 +794,6 @@ namespace Cantera { coeffs[0] = nfreq; coeffs[1] = getFloat(f, "binding_energy", "toSI"); copy(freqs.begin(), freqs.end(), coeffs.begin() + 2); - //posc = new Adsorbate(k, tmin, tmax, pref, - // DATA_PTR(coeffs)); (&sp)->install(speciesName, k, ADSORBATE, &coeffs[0], tmin, tmax, pref); } #endif @@ -771,7 +824,17 @@ namespace Cantera { speciesNode["name"], ""); } const XML_Node& thermo = speciesNode.child("thermo"); - const std::vector& tp = thermo.children(); + + // Get the children of the thermo XML node. In the next bit of code we take out the comments that + // may have been childrent of the thermo XML node by doing a selective copy. + // These shouldn't interfere with the algorithm at any point. + const std::vector& tpWC = thermo.children(); + std::vector tp; + for (int i = 0; i < static_cast(tpWC.size()); i++) { + if (! (tpWC[i])->isComment()) { + tp.push_back(tpWC[i]); + } + } int nc = static_cast(tp.size()); string mname = thermo["model"]; @@ -800,9 +863,6 @@ namespace Cantera { else if (f->name() == "NASA9") { installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp); } - // else if (f->name() == "HKFT") { - // installHKFTThermoFromXML(s["name"], spthermo, k, tp); - //} #ifdef WITH_ADSORBATE else if (f->name() == "adsorbate") { installAdsorbateThermoFromXML(speciesNode["name"], spthermo, k, *f); @@ -829,7 +889,7 @@ namespace Cantera { f0->name() + " and " + f1->name()); } } - else if (nc >= 2) { + else if (nc > 2) { const XML_Node* f0 = tp[0]; if (f0->name() == "NASA9") { installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp); diff --git a/Cantera/src/thermo/State.h b/Cantera/src/thermo/State.h index ca2826df9..d9725b33e 100644 --- a/Cantera/src/thermo/State.h +++ b/Cantera/src/thermo/State.h @@ -122,20 +122,16 @@ namespace Cantera { * @param k species index */ doublereal moleFraction(const int k) const; - //! Set the mole fractions to the specified values, and then //! normalize them so that they sum to 1.0. /*! * @param x Array of unnormalized mole fraction values (input). * Must have a length greater than or equal to the number of - * species. - * - * @param x Input vector of mole fractions. There is no restriction - * on the sum of the mole fraction vector. Internally, - * the State object will normalize this vector before - * storring its contents. - * Length is m_kk. + * species, m_kk. There is no restriction + * on the sum of the mole fraction vector. Internally, + * the State object will normalize this vector before + * storring its contents. */ virtual void setMoleFractions(const doublereal* const x); @@ -151,36 +147,28 @@ namespace Cantera { */ virtual void setMoleFractions_NoNorm(const doublereal* const x); - /** - * Get the species mass fractions. - * @param y On return, y - * contains the mass fractions. Array \a y must have a length - * greater than or equal to the number of species. - * - * @param y Output vector of mass fractions. - * Length is m_kk. + //! Get the species mass fractions. + /*! + * @param y On return, y contains the mass fractions. Array \a y must have a length + * greater than or equal to the number of species. */ void getMassFractions(doublereal* const y) const; //! Mass fraction of species k. /*! - * If k is outside the valid - * range, an exception will be thrown. Note that it is - * somewhat more efficent to call getMassFractions if the - * mass fractions of all species are desired. + * If k is outside the valid range, an exception will be thrown. Note that it is + * somewhat more efficent to call getMassFractions if the mass fractions of all species are desired. * * @param k species index */ doublereal massFraction(const int k) const; - /** - * Set the mass fractions to the specified values, and then - * normalize them so that they sum to 1.0. - * @param y Array of unnormalized mass fraction values (input). - * Must have a length greater than or equal to the number of - * species. - * - * @param y Input vector of mass fractions. There is no restriction + //! Set the mass fractions to the specified values, and then + //! normalize them so that they sum to 1.0. + /*! + * @param y Array of unnormalized mass fraction values (input). + * Must have a length greater than or equal to the number of species. + * Input vector of mass fractions. There is no restriction * on the sum of the mass fraction vector. Internally, * the State object will normalize this vector before * storring its contents. @@ -188,12 +176,11 @@ namespace Cantera { */ virtual void setMassFractions(const doublereal* const y); - /** - * Set the mass fractions to the specified values without - * normalizing. This is useful when the normalization + //! Set the mass fractions to the specified values without normalizing. + /*! + * This is useful when the normalization * condition is being handled by some other means, for example - * by a constraint equation as part of a larger set of - * equations. + * by a constraint equation as part of a larger set of equations. * * @param y Input vector of mass fractions. * Length is m_kk. @@ -305,20 +292,32 @@ namespace Cantera { /// mass density. //@{ - /// Temperature (K). + //! Temperature (K). + /*! + * @return Returns the temperature of the phase + */ doublereal temperature() const { return m_temp; } - /// Density (kg/m^3). + //! Density (kg/m^3). + /*! + * @return Returns the density of the phase + */ virtual doublereal density() const { return m_dens; } - /// Molar density (kmol/m^3). + //! Molar density (kmol/m^3). + /*! + * @return Returns the molar density of the phase + */ doublereal molarDensity() const; - /// Molar density (kmol/m^3). + //! Molar volume (m^3/kmol). + /*! + * @return Returns the molar volume of the phase + */ doublereal molarVolume() const; //! Set the internally storred density (kg/m^3) of the phase diff --git a/Cantera/src/thermo/StoichSubstance.cpp b/Cantera/src/thermo/StoichSubstance.cpp index 7770c149a..995333aa9 100644 --- a/Cantera/src/thermo/StoichSubstance.cpp +++ b/Cantera/src/thermo/StoichSubstance.cpp @@ -293,7 +293,7 @@ namespace Cantera { void StoichSubstance::setParametersFromXML(const XML_Node& eosdata) { eosdata._require("model","StoichSubstance"); - doublereal rho = getFloat(eosdata, "density", "toSI"); + doublereal rho = ctml::getFloat(eosdata, "density", "toSI"); setDensity(rho); } diff --git a/Cantera/src/thermo/StoichSubstance.h b/Cantera/src/thermo/StoichSubstance.h index 991ef4962..a154f8096 100644 --- a/Cantera/src/thermo/StoichSubstance.h +++ b/Cantera/src/thermo/StoichSubstance.h @@ -394,7 +394,10 @@ namespace Cantera { protected: int m_kk; - doublereal m_tmin, m_tmax, m_press, m_p0; + doublereal m_tmin; + doublereal m_tmax; + doublereal m_press; + doublereal m_p0; mutable doublereal m_tlast; mutable array_fp m_h0_RT; diff --git a/Cantera/src/thermo/StoichSubstanceSSTP.cpp b/Cantera/src/thermo/StoichSubstanceSSTP.cpp index 565e7cfc5..84345f861 100644 --- a/Cantera/src/thermo/StoichSubstanceSSTP.cpp +++ b/Cantera/src/thermo/StoichSubstanceSSTP.cpp @@ -434,7 +434,7 @@ namespace Cantera { "no thermo XML node"); } XML_Node &tnode = phaseNode.child("thermo"); - double dens = getFloatDefaultUnits(tnode, "density", "kg/m3"); + double dens = ctml::getFloatDefaultUnits(tnode, "density", "kg/m3"); setDensity(dens); SingleSpeciesTP::initThermoXML(phaseNode, id); } @@ -482,7 +482,7 @@ namespace Cantera { throw CanteraError("StoichSubstanceSSTP::setParametersFromXML", "thermo model attribute must be StoichSubstance"); } - doublereal rho = getFloat(eosdata, "density", "toSI"); + doublereal rho = ctml::getFloat(eosdata, "density", "toSI"); setDensity(rho); } diff --git a/Cantera/src/thermo/SurfPhase.cpp b/Cantera/src/thermo/SurfPhase.cpp index 44fea43fd..ab0ecc4c7 100644 --- a/Cantera/src/thermo/SurfPhase.cpp +++ b/Cantera/src/thermo/SurfPhase.cpp @@ -23,6 +23,8 @@ #include "EdgePhase.h" #include "ThermoFactory.h" +using namespace ctml; + using namespace std; /////////////////////////////////////////////////////////// @@ -209,6 +211,8 @@ namespace Cantera { } } + // HKM 9/1/11 The partial molar volumes returned here are really partial molar areas. + // Partial molar volumes for this phase should actually be equal to zero. void SurfPhase::getPartialMolarVolumes(doublereal* vbar) const { getStandardVolumes(vbar); } diff --git a/Cantera/src/thermo/ThermoFactory.cpp b/Cantera/src/thermo/ThermoFactory.cpp index 7913d50d4..ea51c3f6d 100644 --- a/Cantera/src/thermo/ThermoFactory.cpp +++ b/Cantera/src/thermo/ThermoFactory.cpp @@ -28,13 +28,19 @@ #ifdef WITH_IDEAL_SOLUTIONS #include "IdealSolidSolnPhase.h" #include "MargulesVPSSTP.h" +#include "RedlichKisterVPSSTP.h" #include "IonsFromNeutralVPSSTP.h" +#include "PhaseCombo_Interaction.h" #endif #ifdef WITH_PURE_FLUIDS #include "PureFluidPhase.h" #endif +#ifdef WITH_REAL_GASSES +#include "RedlichKwongMFTP.h" +#endif + #include "ConstDensityThermo.h" #include "SurfPhase.h" #include "EdgePhase.h" @@ -51,7 +57,6 @@ #ifdef WITH_STOICH_SUBSTANCE #ifdef USE_SSTP #include "StoichSubstanceSSTP.h" - #else #include "StoichSubstance.h" #endif @@ -60,6 +65,7 @@ #ifdef WITH_STOICH_SUBSTANCE #include "MineralEQ3.h" #include "MetalSHEelectrons.h" +#include "FixedChemPotSSTP.h" #endif //#include "importCTML.h" @@ -73,6 +79,8 @@ #include "HMWSoln.h" #include "DebyeHuckel.h" #include "IdealMolalSoln.h" +#include "MolarityIonicVPSSTP.h" +#include "MixedSolventElectrolyte.h" #endif #include "IdealSolnGasVPSS.h" @@ -80,6 +88,7 @@ #include using namespace std; +using namespace ctml; namespace Cantera { @@ -87,24 +96,32 @@ namespace Cantera { #if defined(THREAD_SAFE_CANTERA) boost::mutex ThermoFactory::thermo_mutex; #endif + //! Define the number of %ThermoPhase types for use in this factory routine + /*! + * @deprecated This entire structure could be replaced with a std::map + */ + static int ntypes = 23; - static int ntypes = 18; + //! Define the string name of the %ThermoPhase types that are handled by this factory routine static string _types[] = {"IdealGas", "Incompressible", "Surface", "Edge", "Metal", "StoichSubstance", "PureFluid", "LatticeSolid", "Lattice", "HMW", "IdealSolidSolution", "DebyeHuckel", "IdealMolalSolution", "IdealGasVPSS", - "MineralEQ3", "MetalSHEelectrons", "Margules", - "IonsFromNeutralMolecule" + "MineralEQ3", "MetalSHEelectrons", "Margules", "PhaseCombo_Interaction", + "IonsFromNeutralMolecule", "FixedChemPot", "MolarityIonicVPSSTP", + "MixedSolventElectrolyte", "Redlich-Kister" }; + //! Define the integer id of the %ThermoPhase types that are handled by this factory routine static int _itypes[] = {cIdealGas, cIncompressible, cSurf, cEdge, cMetal, cStoichSubstance, cPureFluid, cLatticeSolid, cLattice, cHMW, cIdealSolidSolnPhase, cDebyeHuckel, cIdealMolalSoln, cVPSS_IdealGas, cMineralEQ3, cMetalSHEelectrons, - cMargulesVPSSTP, cIonsFromNeutral + cMargulesVPSSTP, cPhaseCombo_Interaction, cIonsFromNeutral, cFixedChemPot, + cMolarityIonicVPSSTP, cMixedSolventElectrolyte, cRedlichKisterVPSSTP }; /* @@ -146,6 +163,18 @@ namespace Cantera { th = new MargulesVPSSTP(); break; + case cRedlichKisterVPSSTP: + th = new RedlichKisterVPSSTP(); + break; + + case cMolarityIonicVPSSTP: + th = new MolarityIonicVPSSTP(); + break; + + case cPhaseCombo_Interaction: + th = new PhaseCombo_Interaction(); + break; + case cIonsFromNeutral: th = new IonsFromNeutralVPSSTP(); break; @@ -167,6 +196,12 @@ namespace Cantera { break; #endif +#ifdef WITH_STOICH_SUBSTANCE + case cFixedChemPot: + th = new FixedChemPotSSTP; + break; +#endif + #ifdef WITH_STOICH_SUBSTANCE case cMineralEQ3: th = new MineralEQ3(); @@ -194,6 +229,13 @@ namespace Cantera { th = new PureFluidPhase; break; #endif + +#ifdef WITH_REAL_GASSES + case cRedlichKwongMFTP: + th = new RedlichKwongMFTP; + break; +#endif + #ifdef WITH_ELECTROLYTES case cHMW: th = new HMWSoln; @@ -291,7 +333,21 @@ namespace Cantera { return (ThermoPhase *) 0; } - + //==================================================================================================================== + //! Gather a vector of pointers to XML_Nodes for a phase + /*! + * + * @param spDataNodeList Output vector of pointer to XML_Nodes which contain the species XML_Nodes for the + * species in the current phase. + * @param spNamesList Output Vector of strings, which contain the names of the species in the phase + * @param spRuleList Output Vector of ints, which contain the value of sprule for each species in the phase + * @param spArray_names Vector of pointers to the XML_Nodes which contains the names of the + * species in the phase + * + * @param spArray_dbases Input vector of pointers to species data bases. + * We search each data base for the required species names + * @param sprule Input vector of sprule values + */ static void formSpeciesXMLNodeList(std::vector &spDataNodeList, std::vector &spNamesList, std::vector &spRuleList, @@ -312,7 +368,7 @@ namespace Cantera { // Get the top XML for the database const XML_Node *db = spArray_dbases[jsp]; - // Get the array of species name strings and the count them + // Get the array of species name strings and then count them std::vector spnames; getStringArray(speciesArray, spnames); int nsp = static_cast(spnames.size()); @@ -402,7 +458,7 @@ namespace Cantera { } } } - + //==================================================================================================================== /* * Import a phase specification. * Here we read an XML description of the phase. @@ -499,7 +555,9 @@ namespace Cantera { /*************************************************************** * Add the elements. ***************************************************************/ - th->addElementsFromXML(phase); + if (ssConvention != cSS_CONVENTION_SLAVE) { + th->addElementsFromXML(phase); + } /*************************************************************** * Add the species. @@ -512,11 +570,13 @@ namespace Cantera { vector sparrays; phase.getChildren("speciesArray", sparrays); int jsp, nspa = static_cast(sparrays.size()); - if (nspa == 0) { - throw CanteraError("importPhase", - "phase, " + th->id() + ", has zero \"speciesArray\" XML nodes.\n" + if (ssConvention != cSS_CONVENTION_SLAVE) { + if (nspa == 0) { + throw CanteraError("importPhase", + "phase, " + th->id() + ", has zero \"speciesArray\" XML nodes.\n" + " There must be at least one speciesArray nodes " "with one or more species"); + } } vector dbases; vector_int sprule(nspa,0); @@ -561,7 +621,7 @@ namespace Cantera { // file. db = get_XML_Node(speciesArray["datasrc"], &phase.root()); if (db == 0) { - throw CanteraError("importPhase", + throw CanteraError("importPhase()", " Can not find XML node for species database: " + speciesArray["datasrc"]); } @@ -582,7 +642,7 @@ namespace Cantera { // If the phase has a species thermo manager already installed, // delete it since we are adding new species. - delete &th->speciesThermo(); + //delete &th->speciesThermo(); // Decide whether the the phase has a variable pressure ss or not SpeciesThermo* spth = 0; @@ -597,17 +657,29 @@ namespace Cantera { // install it in the phase object th->setSpeciesThermo(spth); - } else { + } else if (ssConvention == cSS_CONVENTION_SLAVE) { + /* + * No species thermo manager for this type + */ + } else if (ssConvention == cSS_CONVENTION_VPSS) { vp_spth = newVPSSMgr(vpss_ptr, &phase, spDataNodeList); vpss_ptr->setVPSSMgr(vp_spth); spth = vp_spth->SpeciesThermoMgr(); th->setSpeciesThermo(spth); + } else { + throw CanteraError("importPhase()", "unknown convention"); } int k = 0; int nsp = spDataNodeList.size(); + if (ssConvention == cSS_CONVENTION_SLAVE) { + if (nsp > 0) { + throw CanteraError("importPhase()", "For Slave standard states, number of species must be zero: " + + int2str(nsp)); + } + } for (int i = 0; i < nsp; i++) { XML_Node *s = spDataNodeList[i]; AssertTrace(s != 0); @@ -619,6 +691,10 @@ namespace Cantera { } } + if (ssConvention == cSS_CONVENTION_SLAVE) { + th->installSlavePhases(&phase); + } + // done adding species. th->freezeSpecies(); @@ -627,7 +703,7 @@ namespace Cantera { // Perform any required subclass-specific initialization // that requires the XML phase object - string id = ""; + std::string id = ""; th->initThermoXML(phase, id); return true; @@ -744,7 +820,6 @@ namespace Cantera { factory->installThermoForSpecies(k, s, &th, *spthermo_ptr, phaseNode_ptr); } - return true; } diff --git a/Cantera/src/thermo/ThermoFactory.h b/Cantera/src/thermo/ThermoFactory.h index 01ec78d12..b4af0abef 100644 --- a/Cantera/src/thermo/ThermoFactory.h +++ b/Cantera/src/thermo/ThermoFactory.h @@ -255,8 +255,7 @@ namespace Cantera { * * @ingroup thermoprops */ - bool importPhase(XML_Node& phase, ThermoPhase* th, - SpeciesThermoFactory* spfactory = 0); + bool importPhase(XML_Node& phase, ThermoPhase* th, SpeciesThermoFactory* spfactory = 0); //! Install a species into a ThermoPhase object, which defines //! the phase thermodynamics and speciation. @@ -305,7 +304,7 @@ namespace Cantera { VPSSMgr *vpss_ptr = 0, SpeciesThermoFactory* factory = 0); - //!Search an XML tree for species data. + //! Search an XML tree for species data. /*! * This utility routine will search the XML tree for the species * named by the string, kname. It will return the XML_Node diff --git a/Cantera/src/thermo/ThermoPhase.cpp b/Cantera/src/thermo/ThermoPhase.cpp index afc819617..746203f18 100644 --- a/Cantera/src/thermo/ThermoPhase.cpp +++ b/Cantera/src/thermo/ThermoPhase.cpp @@ -21,6 +21,7 @@ #endif #include "ThermoPhase.h" +#include "mdp_allo.h" #include //@{ @@ -30,6 +31,7 @@ //@} using namespace std; +using namespace ctml; namespace Cantera { @@ -59,7 +61,8 @@ namespace Cantera { m_spthermo = 0; } - /** + //==================================================================================================================== + /* * Copy Constructor for the ThermoPhase object. * * Currently, this is implemented, but not tested. If called it will @@ -80,7 +83,7 @@ namespace Cantera { */ *this = operator=(right); } - + //==================================================================================================================== /* * operator=() * @@ -134,7 +137,7 @@ namespace Cantera { m_ssConvention = right.m_ssConvention; return *this; } - + //==================================================================================================================== /* * Duplication routine for objects which inherit from * ThermoPhase. @@ -150,45 +153,42 @@ namespace Cantera { ThermoPhase* tp = new ThermoPhase(*this); return tp; } - + //==================================================================================================================== int ThermoPhase::activityConvention() const { return cAC_CONVENTION_MOLAR; } - + //================================================================================================================= int ThermoPhase::standardStateConvention() const { return m_ssConvention; } - + //================================================================================================================= doublereal ThermoPhase::logStandardConc(int k) const { return log(standardConcentration(k)); } - + //================================================================================================================= void ThermoPhase::getActivities(doublereal* a) const { getActivityConcentrations(a); int nsp = nSpecies(); int k; for (k = 0; k < nsp; k++) a[k] /= standardConcentration(k); } - - void ThermoPhase::getLNActivityCoefficients(doublereal *const lnac) const { + //================================================================================================================= + void ThermoPhase::getLnActivityCoefficients(doublereal *const lnac) const { getActivityCoefficients(lnac); for (int k = 0; k < m_kk; k++) { lnac[k] = std::log(lnac[k]); } } - - void ThermoPhase::setState_TPX(doublereal t, doublereal p, - const doublereal* x) { + //================================================================================================================= + void ThermoPhase::setState_TPX(doublereal t, doublereal p, const doublereal* x) { setMoleFractions(x); setTemperature(t); setPressure(p); } - - void ThermoPhase::setState_TPX(doublereal t, doublereal p, - compositionMap& x) { + //================================================================================================================= + void ThermoPhase::setState_TPX(doublereal t, doublereal p, compositionMap& x) { setMoleFractionsByName(x); setTemperature(t); setPressure(p); } - - void ThermoPhase::setState_TPX(doublereal t, doublereal p, - const std::string& x) { + //================================================================================================================= + void ThermoPhase::setState_TPX(doublereal t, doublereal p, const std::string& x) { compositionMap xx; int kk = nSpecies(); for (int k = 0; k < kk; k++) xx[speciesName(k)] = -1.0; @@ -201,17 +201,17 @@ namespace Cantera { } setMoleFractionsByName(xx); setTemperature(t); setPressure(p); } - + //================================================================================================================= void ThermoPhase::setState_TPY(doublereal t, doublereal p, const doublereal* y) { setMassFractions(y); setTemperature(t); setPressure(p); } - + //================================================================================================================= void ThermoPhase::setState_TPY(doublereal t, doublereal p, compositionMap& y) { setMassFractionsByName(y); setTemperature(t); setPressure(p); } - + //================================================================================================================= void ThermoPhase::setState_TPY(doublereal t, doublereal p, const std::string& y) { compositionMap yy; @@ -226,28 +226,34 @@ namespace Cantera { } setMassFractionsByName(yy); setTemperature(t); setPressure(p); } + //================================================================================================================= void ThermoPhase::setState_TP(doublereal t, doublereal p) { setTemperature(t); setPressure(p); } + //================================================================================================================= void ThermoPhase::setState_PX(doublereal p, doublereal* x) { setMoleFractions(x); setPressure(p); } + //================================================================================================================= void ThermoPhase::setState_PY(doublereal p, doublereal* y) { setMassFractions(y); setPressure(p); } + //================================================================================================================= void ThermoPhase::setState_HP(doublereal Htarget, doublereal p, doublereal dTtol) { setState_HPorUV(Htarget, p, dTtol, false); } + //================================================================================================================= void ThermoPhase::setState_UV(doublereal u, doublereal v, doublereal dTtol) { setState_HPorUV(u, v, dTtol, true); } + //================================================================================================================= // Do the convergence work /* @@ -512,16 +518,19 @@ namespace Cantera { throw CanteraError("setState_HPorUV (HP)", ErrString); } } + //================================================================================================================= void ThermoPhase::setState_SP(doublereal Starget, doublereal p, doublereal dTtol) { setState_SPorSV(Starget, p, dTtol, false); } + //================================================================================================================= void ThermoPhase::setState_SV(doublereal Starget, doublereal v, doublereal dTtol) { setState_SPorSV(Starget, v, dTtol, true); } + //================================================================================================================= // Do the convergence work for fixed entropy situations /* @@ -771,6 +780,7 @@ namespace Cantera { throw CanteraError("setState_SPorSV (SP)", ErrString); } } + //================================================================================================================= doublereal ThermoPhase::err(std::string msg) const { throw CanteraError("ThermoPhase","Base class method " @@ -814,8 +824,47 @@ namespace Cantera { if (i == 4) uA[4] = 0.0; if (i == 5) uA[5] = 0.0; } + } + //================================================================================================================= + // Install a species thermodynamic property manager. + /* + * The species thermodynamic property manager + * computes properties of the pure species for use in + * constructing solution properties. It is meant for internal + * use, and some classes derived from ThermoPhase may not use + * any species thermodynamic property manager. This method is + * called by function importPhase() in importCTML.cpp. + * + * @param spthermo input pointer to the species thermodynamic property + * manager. + * + * @internal + */ + void ThermoPhase::setSpeciesThermo(SpeciesThermo* spthermo) { + if (m_spthermo) { + if (m_spthermo != spthermo) { + delete m_spthermo; + } + } + m_spthermo = spthermo; } - + //================================================================================================================= + // Return a changeable reference to the calculation manager + // for species reference-state thermodynamic properties + /* + * + * @param k Speices id. The default is -1, meaning return the default + * + * @internal + */ + SpeciesThermo& ThermoPhase::speciesThermo(int k) { + if (!m_spthermo) { + throw CanteraError("ThermoPhase::speciesThermo()", + "species reference state thermo manager was not set"); + } + return *m_spthermo; + } + //================================================================================================================= /* * initThermoFile(): * @@ -860,6 +909,7 @@ namespace Cantera { initThermoXML(*fxml_phase, id); delete fxml; } + //================================================================================================================= /* * Import and initialize a ThermoPhase object @@ -941,16 +991,20 @@ namespace Cantera { } xMol_Ref.resize(m_kk, 0.0); } + //==================================================================================================================== + void ThermoPhase::installSlavePhases(Cantera::XML_Node* phaseNode) { + } + //==================================================================================================================== void ThermoPhase::saveSpeciesData(const int k, const XML_Node* const data) { if ((int) m_speciesData.size() < (k + 1)) { m_speciesData.resize(k+1, 0); } m_speciesData[k] = new XML_Node(*data); } - - //! Return a pointer to the XML tree containing the species - /// data for this phase. + //==================================================================================================================== + // Return a pointer to the XML tree containing the species + // data for this phase. const std::vector & ThermoPhase::speciesData() const { if ((int) m_speciesData.size() != m_kk) { throw CanteraError("ThermoPhase::speciesData", @@ -958,7 +1012,7 @@ namespace Cantera { } return m_speciesData; } - + //==================================================================================================================== /* * Set the thermodynamic state. */ @@ -984,7 +1038,7 @@ namespace Cantera { setDensity(rho); } } - + //==================================================================================================================== /* * Called by function 'equilibrate' in ChemEquil.h to transfer * the element potentials to this object after every successful @@ -1026,7 +1080,109 @@ namespace Cantera { } return (m_hasElementPotentials); } + //==================================================================================================================== + // Get the array of derivatives of the log activity coefficients with respect to the species mole numbers + /* + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * species mole number (with all other species mole numbers held constant) + * + * units = 1 / kmol + * + * dlnActCoeffdN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d n_k }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + void ThermoPhase::getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN) { + + + for (int m = 0; m < m_kk; m++) { + for (int k = 0; k < m_kk; k++) { + dlnActCoeffdlnN[ld * k + m] = 0.0; + } + } + return; + } + //==================================================================================================================== + void ThermoPhase::getdlnActCoeffdlnN_numderiv(const int ld, doublereal * const dlnActCoeffdlnN) { + + int k, j; + double deltaMoles_j = 0.0; + double pres = pressure(); + + /* + * Evaluate the current base activity coefficients if necessary + */ + std::vector ActCoeff_Base(m_kk); + getActivityCoefficients(DATA_PTR(ActCoeff_Base)); + std::vector Xmol_Base(m_kk); + getMoleFractions(DATA_PTR(Xmol_Base)); + // Make copies of ActCoeff and Xmol_ for use in taking differences + std::vector ActCoeff(m_kk); + std::vector Xmol(m_kk); + double v_totalMoles = 1.0; + double TMoles_base = v_totalMoles; + + /* + * Loop over the columns species to be deltad + */ + for (j = 0; j < m_kk; j++) { + /* + * Calculate a value for the delta moles of species j + * -> NOte Xmol_[] and Tmoles are always positive or zero + * quantities. + * -> experience has shown that you always need to make the deltas greater than needed to + * change the other mole fractions in order to capture some effects. + */ + double moles_j_base = v_totalMoles * Xmol_Base[j]; + deltaMoles_j = 1.0E-7 * moles_j_base + v_totalMoles * 1.0E-13 + 1.0E-150; + /* + * Now, update the total moles in the phase and all of the + * mole fractions based on this. + */ + v_totalMoles = TMoles_base + deltaMoles_j; + for (k = 0; k < m_kk; k++) { + Xmol[k] = Xmol_Base[k] * TMoles_base / v_totalMoles; + } + Xmol[j] = (moles_j_base + deltaMoles_j) / v_totalMoles; + + /* + * Go get new values for the activity coefficients. + * -> Note this calls setState_PX(); + */ + setState_PX(pres, DATA_PTR(Xmol)); + getActivityCoefficients(DATA_PTR(ActCoeff)); + + /* + * Calculate the column of the matrix + */ + double * const lnActCoeffCol = dlnActCoeffdlnN + ld * j; + for (k = 0; k < m_kk; k++) { + lnActCoeffCol[k] = (2*moles_j_base + deltaMoles_j) *(ActCoeff[k] - ActCoeff_Base[k]) / + ((ActCoeff[k] + ActCoeff_Base[k]) * deltaMoles_j); + } + /* + * Revert to the base case Xmol_, v_totalMoles + */ + v_totalMoles = TMoles_base; + mdp::mdp_copy_dbl_1(DATA_PTR(Xmol), DATA_PTR(Xmol_Base), m_kk); + } + /* + * 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. + */ + setState_PX(pres, DATA_PTR(Xmol_Base)); + } + //==================================================================================================================== /* * Format a summary of the mixture state for output. */ @@ -1135,7 +1291,7 @@ namespace Cantera { } return s; } - +//==================================================================================================================== /* * Format a summary of the mixture state for output. */ diff --git a/Cantera/src/thermo/ThermoPhase.h b/Cantera/src/thermo/ThermoPhase.h index c52e74e75..322a749f1 100644 --- a/Cantera/src/thermo/ThermoPhase.h +++ b/Cantera/src/thermo/ThermoPhase.h @@ -37,9 +37,11 @@ namespace Cantera { */ //@{ //! Standard state uses the molar convention - const int cSS_CONVENTION_TEMPERATURE = 0; + const int cSS_CONVENTION_TEMPERATURE = 0; //! Standard state uses the molality convention - const int cSS_CONVENTION_VPSS = 1; + const int cSS_CONVENTION_VPSS = 1; + //! Standard state thermodynamics is obtained from slave %ThermoPhase objects + const int cSS_CONVENTION_SLAVE = 2; //@} @@ -756,7 +758,7 @@ namespace Cantera { * Returns the reference pressure in Pa. This function is a wrapper * that calls the species thermo refPressure function. */ - doublereal refPressure() const { + virtual doublereal refPressure() const { return m_spthermo->refPressure(); } @@ -773,7 +775,7 @@ namespace Cantera { * @param k index of the species. Default is -1, which will return the max of the min value * over all species. */ - doublereal minTemp(int k = -1) const { + virtual doublereal minTemp(int k = -1) const { return m_spthermo->minTemp(k); } @@ -842,9 +844,20 @@ namespace Cantera { * @param k index of the species. Default is -1, which will return the min of the max value * over all species. */ - doublereal maxTemp(int k = -1) const { + virtual doublereal maxTemp(int k = -1) const { return m_spthermo->maxTemp(k); } + + //! Returns the chargeNeutralityNecessity boolean + /*! + * Some phases must have zero net charge in order for their thermodynamics functions to be valid. + * If this is so, then the value returned from this function is true. + * If this is not the case, then this is false. Now, ideal gases have this parameter set to false, + * while solution with molality-based activity coefficients have this parameter set to true. + */ + bool chargeNeutralityNecessary() const { + return m_chargeNeutralityNecessary; + } /** * @} @@ -859,7 +872,7 @@ namespace Cantera { /// Molar internal energy. Units: J/kmol. virtual doublereal intEnergy_mole() const { - return err("intEnergy_mole"); + return enthalpy_mole() - pressure()* molarVolume(); } /// Molar entropy. Units: J/kmol/K. @@ -869,7 +882,7 @@ namespace Cantera { /// Molar Gibbs function. Units: J/kmol. virtual doublereal gibbs_mole() const { - return err("gibbs_mole"); + return enthalpy_mole() - temperature()*entropy_mole(); } /// Molar heat capacity at constant pressure. Units: J/kmol/K. @@ -883,66 +896,6 @@ namespace Cantera { } - //! Get the change in activity coefficients w.r.t. change in state - //! (temp, mole fraction, etc.) - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can gradX/X. - * - * @param dT Input of temperature change - * @param dX Input vector of changes in mole fraction. length = m_kk - * @param dlnActCoeff Output vector of derivatives of the - * log Activity Coefficients. length = m_kk - */ - virtual void getdlnActCoeff(const doublereal dT, const doublereal * const dX, doublereal *dlnActCoeff) const { - err("getdlnActCoeff"); - } - - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can return zero. - * Implementations should take the derivative of the - * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. mole fraction) - * that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. - * - * units = dimensionless - * - * @param dlnActCoeffdlnX Output vector of derivatives of the - * log Activity Coefficients. length = m_kk - */ - virtual void getdlnActCoeffdlnX(doublereal *dlnActCoeffdlnX) const { - err("getdlnActCoeffdlnX"); - } - - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can return zero. - * Implementations should take the derivative of the - * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. moles) - * that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. - * - * units = dimensionless - * - * @param dlnActCoeffdlnN Output vector of derivatives of the - * log Activity Coefficients. length = m_kk - */ - virtual void getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const { - err("getdlnActCoeffdlnN"); - } - - /** * @} * @name Mechanical Properties @@ -1085,6 +1038,10 @@ namespace Cantera { * * - Variable Pressure and Temperature -based activities * cSS_CONVENTION_VPSS 1 + * + * - Thermodynamics is set via slave ThermoPhase objects with + * nothing being carried out at this %ThermoPhase object level + * cSS_CONVENTION_SLAVE 2 */ virtual int standardStateConvention() const; @@ -1196,7 +1153,12 @@ namespace Cantera { } } - virtual void getLNActivityCoefficients(doublereal * const lnac) const; + //! Get the array of non-dimensional molar-based ln activity coefficients at + //! the current solution temperature, pressure, and solution concentration. + /*! + * @param lnac Output vector of ln activity coefficients. Length: m_kk. + */ + virtual void getLnActivityCoefficients(doublereal * const lnac) const; //@} /// @name Partial Molar Properties of the Solution @@ -1302,7 +1264,31 @@ namespace Cantera { virtual void getPartialMolarVolumes(doublereal* vbar) const { err("getPartialMolarVolumes"); } - + + //! Return an array of derivatives of partial molar volumes wrt temperature for the + //! species in the mixture. Units: m^3/kmol. + /*! + * The derivative is at constant pressure + * + * @param d_vbar_dT Output vector of derivatives of species partial molar volumes wrt T. + * Length = m_kk. units are m^3/kmol/K. + */ + virtual void getdPartialMolarVolumes_dT(doublereal* d_vbar_dT) const { + err("getdPartialMolarVolumes_dT"); + } + + //! Return an array of derivatives of partial molar volumes wrt pressure for the + //! species in the mixture. Units: m^3/kmol. + /*! + * The derivative is at constant temperature + * + * @param d_vbar_dP Output vector of derivatives of species partial molar volumes wrt P. + * Length = m_kk. units are m^3/kmol/Pa. + */ + virtual void getdPartialMolarVolumes_dP(doublereal* d_vbar_dP) const { + err("getdPartialMolarVolumes_dP"); + } + //@} /// @name Properties of the Standard State of the Species in the Solution //@{ @@ -1395,11 +1381,36 @@ namespace Cantera { err("getStandardVolumes"); } + //! Get the derivative of the molar volumes of the species standard states wrt temperature at the current + //! T and P of the solution. + /*! + * The derivative is at constant pressure + * units = m^3 / kmol / K + * + * @param d_vol_dT Output vector containing derivatives of standard state volumes wrt T + * Length: m_kk. + */ + virtual void getdStandardVolumes_dT(doublereal *d_vol_dT) const { + err("getdStandardVolumes_dT"); + } + + //! Get the derivative molar volumes of the species standard states wrt pressure at the current + //! T and P of the solution. + /*! + * The derivative is at constant temperature. + * units = m^3 / kmol / Pa + * + * @param d_vol_dP Output vector containing the derivative of standard state volumes wrt P. + * Length: m_kk. + */ + virtual void getdStandardVolumes_dP(doublereal *d_vol_dP) const { + err("getdStandardVolumes_dP"); + } + //@} /// @name Thermodynamic Values for the Species Reference States //@{ - //! Returns the vector of nondimensional //! enthalpies of the reference state at the current temperature //! of the solution and the reference pressure for the species. @@ -1582,7 +1593,7 @@ namespace Cantera { * @param x Vector of mole fractions. * Length is equal to m_kk. */ - void setState_TPX(doublereal t, doublereal p, const doublereal* x); + virtual void setState_TPX(doublereal t, doublereal p, const doublereal* x); //! Set the temperature (K), pressure (Pa), and mole fractions. /*! @@ -1921,19 +1932,17 @@ namespace Cantera { * * @internal */ - void setSpeciesThermo(SpeciesThermo* spthermo) - { m_spthermo = spthermo; } + void setSpeciesThermo(SpeciesThermo* spthermo); //! Return a changeable reference to the calculation manager //! for species reference-state thermodynamic properties /*! * - * @todo This method will fail if no species thermo - * manager has been installed. + * @param k Speices id. The default is -1, meaning return the default * * @internal */ - SpeciesThermo& speciesThermo() { return *m_spthermo; } + virtual SpeciesThermo& speciesThermo(int k = -1); /** * @internal @@ -2010,6 +2019,14 @@ namespace Cantera { */ virtual void initThermo(); + //! Add in species from Slave phases + /*! + * This hook is used for cSS_CONVENTION_SLAVE phases + * + * @param phaseNode XML Element for the phase + */ + virtual void installSlavePhases(Cantera::XML_Node* phaseNode); + // The following methods are used by the clib interface // library, and should not be used by application programs. @@ -2086,24 +2103,98 @@ namespace Cantera { */ virtual void setStateFromXML(const XML_Node& state); - - //@} - - //! Returns the chargeNeutralityNecessity boolean - /*! - * Some phases must have zero net charge in order for - * their thermodynamics functions to be valid. - * If this is so, then the value returned from this - * function is true. - * If this is not the case, then this is false. - * Now, ideal gases have this parameter set to false, - * while solution with molality-based activity - * coefficients have this parameter set to true. + /** + * @} + * @name Derivatives of Thermodynamic Variables needed for Applications + * @{ */ - bool chargeNeutralityNecessary() const { - return m_chargeNeutralityNecessary; + + //! Get the change in activity coefficients wrt changes in state (temp, mole fraction, etc) along + //! a line in parameter space or along a line in physical space + /*! + * + * @param dTds Input of temperature change along the path + * @param dXds Input vector of changes in mole fraction along the path. length = m_kk + * Along the path length it must be the case that the mole fractions sum to one. + * @param dlnActCoeffds Output vector of the directional derivatives of the + * log Activity Coefficients along the path. length = m_kk + * units are 1/units(s). if s is a physical coordinate then the units are 1/m. + */ + virtual void getdlnActCoeffds(const doublereal dTds, const doublereal * const dXds, + doublereal *dlnActCoeffds) const { + err("getdlnActCoeffds"); } + //! Get the array of ln mole fraction derivatives of the log activity coefficients - diagonal component only + /*! + * This function is a virtual method. For ideal mixtures + * (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the mole fraction variable + * that represents the standard state. + * This quantity is to be used in conjunction with derivatives of + * that mole fraction variable when the derivative of the chemical + * potential is taken. + * + * units = dimensionless + * + * @param dlnActCoeffdlnX_diag Output vector of derivatives of the + * log Activity Coefficients wrt the mole fractions. length = m_kk + */ + virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const { + err("getdlnActCoeffdlnX_diag"); + } + + //! Get the array of log species mole number derivatives of the log activity coefficients + /*! + * This function is a virtual method. + * For ideal mixtures (unity activity coefficients), this can return zero. + * Implementations should take the derivative of the + * logarithm of the activity coefficient with respect to the + * logarithm of the concentration-like variable (i.e. moles) + * that represents the standard state. + * This quantity is to be used in conjunction with derivatives of + * that species mole number variable when the derivative of the chemical + * potential is taken. + * + * units = dimensionless + * + * @param dlnActCoeffdlnN_diag Output vector of derivatives of the + * log Activity Coefficients. length = m_kk + */ + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + err("getdlnActCoeffdlnN_diag"); + } + + //! Get the array of derivatives of the log activity coefficients with respect to the log of the species mole numbers + /*! + * Implementations should take the derivative of the logarithm of the activity coefficient with respect to a + * species log mole number (with all other species mole numbers held constant). The default treatment in the + * %ThermoPhase object is to set this vector to zero. + * + * units = 1 / kmol + * + * dlnActCoeffdlnN[ ld * k + m] will contain the derivative of log act_coeff for the mth + * species with respect to the number of moles of the kth species. + * + * \f[ + * \frac{d \ln(\gamma_m) }{d \ln( n_k ) }\Bigg|_{n_i} + * \f] + * + * @param ld Number of rows in the matrix + * @param dlnActCoeffdlnN Output vector of derivatives of the + * log Activity Coefficients. length = m_kk * m_kk + */ + virtual void getdlnActCoeffdlnN(const int ld, doublereal * const dlnActCoeffdlnN); + + virtual void getdlnActCoeffdlnN_numderiv(const int ld, doublereal * const dlnActCoeffdlnN); + + /** + * @} + * @name Printing + * @{ + */ //! returns a summary of the state of the phase as a string /*! @@ -2118,7 +2209,9 @@ namespace Cantera { * the phase */ virtual void reportCSV(std::ofstream& csvFile) const; - + + //@} + protected: //! Pointer to the calculation manager for species diff --git a/Cantera/src/thermo/VPSSMgrFactory.cpp b/Cantera/src/thermo/VPSSMgrFactory.cpp index 5b78568a7..d3ab29edc 100644 --- a/Cantera/src/thermo/VPSSMgrFactory.cpp +++ b/Cantera/src/thermo/VPSSMgrFactory.cpp @@ -60,13 +60,23 @@ namespace Cantera { boost::mutex VPSSMgrFactory::vpss_species_thermo_mutex; #endif - /* - * Examine the types of species thermo parameterizations, - * and return a flag indicating the type of parameterization - * needed by the species. + + //! Examine the types of species thermo parameterizations, and return a flag indicating the type of parameterization + //! needed by the species. + /*! * - * @param spData_node Species Data XML node. This node contains a list - * of species XML nodes underneath it. + * @param spDataNodeList Species Data XML node. This node contains a list + * of species XML nodes underneath it. + * @param has_nasa_idealGas Boolean indicating that one species has a nasa ideal gas standard state + * @param has_nasa_constVol Boolean indicating that one species has a nasa ideal solution standard state + * @param has_shomate_idealGas Boolean indicating that one species has a shomate ideal gas standard state + * @param has_shomate_constVol Boolean indicating that one species has a shomate ideal solution standard state + * @param has_simple_idealGas Boolean indicating that one species has a simple ideal gas standard state + * @param has_simple_constVol Boolean indicating that one species has a simple ideal solution standard state + * @param has_water Boolean indicating that one species has a water standard state + * @param has_tpx Boolean indicating that one species has a tpx standard state + * @param has_hptx Boolean indicating that one species has a htpx standard state + * @param has_other Boolean indicating that one species has different standard state than the ones listed above * * @todo Make sure that spDadta_node is species Data XML node by checking * its name is speciesData diff --git a/Cantera/src/thermo/VPSSMgr_ConstVol.cpp b/Cantera/src/thermo/VPSSMgr_ConstVol.cpp index 12bc083be..1734384ca 100644 --- a/Cantera/src/thermo/VPSSMgr_ConstVol.cpp +++ b/Cantera/src/thermo/VPSSMgr_ConstVol.cpp @@ -154,7 +154,7 @@ namespace Cantera { throw CanteraError("VPSSMgr_ConstVol::initThermoXML", "standardState model for species isn't constant_incompressible: " + s->name()); } - m_Vss[k] = getFloat(*ss, "molarVolume", "toSI"); + m_Vss[k] = ctml::getFloat(*ss, "molarVolume", "toSI"); } } @@ -181,7 +181,7 @@ namespace Cantera { if ((int) m_Vss.size() < k+1) { m_Vss.resize(k+1, 0.0); } - m_Vss[k] = getFloat(*ss, "molarVolume", "toSI"); + m_Vss[k] = ctml::getFloat(*ss, "molarVolume", "toSI"); installSTSpecies(k, speciesNode, phaseNode_ptr); diff --git a/Cantera/src/thermo/VPSSMgr_Water_ConstVol.cpp b/Cantera/src/thermo/VPSSMgr_Water_ConstVol.cpp index 40a65a8eb..c9d803cff 100644 --- a/Cantera/src/thermo/VPSSMgr_Water_ConstVol.cpp +++ b/Cantera/src/thermo/VPSSMgr_Water_ConstVol.cpp @@ -249,7 +249,7 @@ namespace Cantera { "standardState model for species isn't " "constant_incompressible: " + sName); } - m_Vss[k] = getFloat(*ss, "molarVolume", "toSI"); + m_Vss[k] = ctml::getFloat(*ss, "molarVolume", "toSI"); } } @@ -300,7 +300,7 @@ namespace Cantera { if ((int) m_Vss.size() < k+1) { m_Vss.resize(k+1, 0.0); } - m_Vss[k] = getFloat(*ss, "molarVolume", "toSI"); + m_Vss[k] = ctml::getFloat(*ss, "molarVolume", "toSI"); // instantiate a new kPDSS object kPDSS = new PDSS_ConstVol(m_vptp_ptr, k, speciesNode, *phaseNode_ptr, true); diff --git a/Cantera/src/thermo/VPStandardStateTP.h b/Cantera/src/thermo/VPStandardStateTP.h index 7990b2cff..4bf25fb97 100644 --- a/Cantera/src/thermo/VPStandardStateTP.h +++ b/Cantera/src/thermo/VPStandardStateTP.h @@ -135,36 +135,14 @@ namespace Cantera { * * units = dimensionless * - * @param dlnActCoeffdlnN Output vector of derivatives of the + * @param dlnActCoeffdlnN_diag Output vector of derivatives of the * log Activity Coefficients. length = m_kk */ - virtual void getdlnActCoeffdlnN(doublereal *dlnActCoeffdlnN) const { - err("getdlnActCoeffdlnN"); + virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const { + err("getdlnActCoeffdlnN_diag"); } - //! Get the array of log concentration-like derivatives of the - //! log activity coefficients - /*! - * This function is a virtual method. For ideal mixtures - * (unity activity coefficients), this can return zero. - * Implementations should take the derivative of the - * logarithm of the activity coefficient with respect to the - * logarithm of the concentration-like variable (i.e. mole fraction) - * that represents the standard state. - * This quantity is to be used in conjunction with derivatives of - * that concentration-like variable when the derivative of the chemical - * potential is taken. - * - * units = dimensionless - * - * @param dlnActCoeffdlnX Output vector of derivatives of the - * log Activity Coefficients. length = m_kk - */ - virtual void getdlnActCoeffdlnX(doublereal *dlnActCoeffdlnX) const { - err("getdlnActCoeffdlnX"); - } - //@} /// @name Partial Molar Properties of the Solution (VPStandardStateTP) //@{ diff --git a/Cantera/src/thermo/WaterProps.cpp b/Cantera/src/thermo/WaterProps.cpp index f9a4421a0..f9e5a236a 100644 --- a/Cantera/src/thermo/WaterProps.cpp +++ b/Cantera/src/thermo/WaterProps.cpp @@ -496,13 +496,12 @@ namespace Cantera { // Parameters for the viscosityWater() function - //@{ + // \cond const doublereal H[4] = {1., 0.978197, 0.579829, -0.202354}; - //! parameter const doublereal Hij[6][7] = { { 0.5132047, 0.2151778, -0.2818107, 0.1778064, -0.04176610, 0., 0.}, @@ -516,7 +515,7 @@ namespace Cantera { const doublereal rhoStar = 317.763; // kg / m3 const doublereal presStar = 22.115E6; // Pa const doublereal muStar = 55.071E-6; //Pa s - //@} + // \endcond // Returns the viscosity of water at the current conditions // (kg/m/s) diff --git a/Cantera/src/thermo/WaterPropsIAPWS.cpp b/Cantera/src/thermo/WaterPropsIAPWS.cpp index 1fd721c83..57225efb0 100644 --- a/Cantera/src/thermo/WaterPropsIAPWS.cpp +++ b/Cantera/src/thermo/WaterPropsIAPWS.cpp @@ -33,13 +33,13 @@ const doublereal Rho_c = 322.; //! Molecular Weight of water that is consistent with the paper (kg kmol-1) static const doublereal M_water = 18.015268; +//! Gas constant that is quoted in the paper /* * Note, this is the Rgas value quoted in the paper. For consistency * we have to use that value and not the updated value * * The Ratio of R/M = 0.46151805 kJ kg-1 K-1 , which is Eqn. (6.3) in the paper. */ -//static const doublereal Rgas = 8.314472E3; // Joules kmol-1 K-1 static const doublereal Rgas = 8.314371E3; // Joules kmol-1 K-1 //@{ #ifndef MAX diff --git a/Cantera/src/thermo/WaterPropsIAPWSphi.cpp b/Cantera/src/thermo/WaterPropsIAPWSphi.cpp index 5f8a382de..51d623e22 100644 --- a/Cantera/src/thermo/WaterPropsIAPWSphi.cpp +++ b/Cantera/src/thermo/WaterPropsIAPWSphi.cpp @@ -29,10 +29,12 @@ using std::fabs; * routine, except for internal checks. All calculations here are done * in dimensionless units. */ +// \cond static const doublereal T_c = 647.096; // Kelvin static const doublereal P_c = 22.064E6; // Pascals static const doublereal Rho_c = 322.; // kg m-3 static const doublereal M_water = 18.015268; // kg kmol-1 +// \endcond /* * The added constants were calculated so that u = s = 0 @@ -42,6 +44,7 @@ static const doublereal M_water = 18.015268; // kg kmol-1 * H didn't turn out to be .611872 J/kg, but .611782 J/kg. * There may be a slight error here somehow. */ +// \cond static const doublereal ni0[9] = { 0.0, -8.32044648201 - 0.000000001739715, @@ -240,7 +243,6 @@ static const int tiR[55] = { 1, 4 // 54 }; - static const doublereal ni[57] = { +0.0, +0.12533547935523E-1, // 1 @@ -360,8 +362,9 @@ static const doublereal Bbetai[2] = { +0.3, +0.3 }; +// \endcond -/** +/* * Constructor for the object. */ WaterPropsIAPWSphi::WaterPropsIAPWSphi() : @@ -1106,7 +1109,7 @@ doublereal WaterPropsIAPWSphi::phiR_dt() const { return val; } -/** +/* * This program computes the reduced density, given the reduced pressure * and the reduced temperature, tau. It takes an initial guess, deltaGuess. * DeltaGuess is important as this is a multivalued function below the diff --git a/Cantera/src/thermo/WaterSSTP.cpp b/Cantera/src/thermo/WaterSSTP.cpp index 0d3f0ac93..5727ea3de 100644 --- a/Cantera/src/thermo/WaterSSTP.cpp +++ b/Cantera/src/thermo/WaterSSTP.cpp @@ -162,13 +162,13 @@ namespace Cantera { void WaterSSTP::constructPhaseFile(std::string inputFile, std::string id) { if (inputFile.size() == 0) { - throw CanteraError("WaterTp::initThermo", + throw CanteraError("WaterSSTP::constructPhaseFile", "input file is null"); } std::string path = findInputFile(inputFile); std::ifstream fin(path.c_str()); if (!fin) { - throw CanteraError("WaterSSTP::initThermo","could not open " + throw CanteraError("WaterSSTP::constructPhaseFile","could not open " +path+" for reading."); } /* @@ -180,7 +180,7 @@ namespace Cantera { fxml->build(fin); XML_Node *fxml_phase = findXMLPhase(fxml, id); if (!fxml_phase) { - throw CanteraError("WaterSSTP::initThermo", + throw CanteraError("WaterSSTP::constructPhaseFile", "ERROR: Can not find phase named " + id + " in file named " + inputFile); } diff --git a/Cantera/src/thermo/mix_defs.h b/Cantera/src/thermo/mix_defs.h index 50482d169..a74fb4ccf 100644 --- a/Cantera/src/thermo/mix_defs.h +++ b/Cantera/src/thermo/mix_defs.h @@ -47,7 +47,7 @@ namespace Cantera { const int cMetalSHEelectrons = 9; // SHE electrode electrons const int cLatticeSolid = 20; // LatticeSolidPhase.h - const int cLattice = 21; + const int cLattice = 21; //LatticePhase.h // pure fluids with liquid/vapor eqs of state const int cPureFluid = 10; @@ -55,6 +55,9 @@ namespace Cantera { /// An edge between two 2D surfaces const int cEdge = 6; + //! Stoichiometric compound with a constant chemical potential + const int cFixedChemPot = 70; + /// Constant partial molar volume solution IdealSolidSolnPhase.h const int cIdealSolidSolnPhase = 5009; @@ -70,8 +73,18 @@ namespace Cantera { const int cIdealSolnGasVPSS = 500; const int cIdealSolnGasVPSS_iscv = 501; + //! Fugacity Models + const int cMixtureFugacityTP = 700; + const int cRedlichKwongMFTP = 701; + const int cMargulesVPSSTP = 301; + const int cRedlichKisterVPSSTP = 303; + + const int cMolarityIonicVPSSTP = 401; + const int cMixedSolventElectrolyte = 402; + + const int cPhaseCombo_Interaction = 305; const int cIonsFromNeutral = 2000; diff --git a/Cantera/src/transport/AqueousTransport.cpp b/Cantera/src/transport/AqueousTransport.cpp index f46ff0dc1..96adb885f 100644 --- a/Cantera/src/transport/AqueousTransport.cpp +++ b/Cantera/src/transport/AqueousTransport.cpp @@ -1,6 +1,6 @@ /** - * @file MixTransport.cpp - * Mixture-averaged transport properties for ideal gas mixtures. + * @file AqueousTransport.cpp + * Transport properties for aqueous systems */ /* * $Revision$ @@ -36,9 +36,8 @@ using namespace std; namespace Cantera { - //////////////////// class AqueousTransport methods ////////////// - + //==================================================================================================================== AqueousTransport::AqueousTransport() : m_nsp(0), m_tmin(-1.0), @@ -68,7 +67,7 @@ namespace Cantera { } - + //==================================================================================================================== // Initialize the object /* * This is where we dimension everything. @@ -87,9 +86,12 @@ namespace Cantera { m_thermo->molecularWeights().end(), m_mw.begin()); // copy polynomials and parameters into local storage - m_visccoeffs = tr.visccoeffs; - m_condcoeffs = tr.condcoeffs; - m_diffcoeffs = tr.diffcoeffs; + //m_visccoeffs = tr.visccoeffs; + //m_condcoeffs = tr.condcoeffs; + //m_diffcoeffs = tr.diffcoeffs; + cout << "In AqueousTransport::initLiquid we need to replace" << endl + << "LiquidTransportParams polyniomial coefficients with" << endl + << "those in LiquidTransportData as in SimpleTransport." << endl; m_mode = tr.mode_; @@ -133,17 +135,7 @@ namespace Cantera { return true; } - - - /********************************************************* - * - * Public methods - * - *********************************************************/ - - - /****************** viscosity ******************************/ - + //==================================================================================================================== /* * The viscosity is computed using the Wilke mixture rule. * \f[ @@ -176,12 +168,19 @@ namespace Cantera { } return m_viscmix; } - - - /******************* binary diffusion coefficients **************/ - - - //================================================================================================ + //==================================================================================================================== + // Returns the pure species viscosities + /* + * + * Controlling update boolean = m_viscwt_ok + * + * @param visc Vector of species viscosities + */ + void AqueousTransport::getSpeciesViscosities(doublereal * const visc) { + updateViscosity_T(); + copy(m_visc.begin(), m_visc.end(), visc); + } + //==================================================================================================================== void AqueousTransport::getBinaryDiffCoeffs(const int ld, doublereal* const d) { int i,j; @@ -198,7 +197,7 @@ namespace Cantera { d[ld*j + i] = rp * m_bdiff(i,j); } } - //================================================================================================ + //==================================================================================================================== // Get the electrical Mobilities (m^2/V/s). /* * This function returns the mobilities. In some formulations @@ -223,7 +222,7 @@ namespace Cantera { mobil[k] = c1 * m_spwork[k]; } } - //================================================================================================ + //==================================================================================================================== void AqueousTransport::getFluidMobilities(doublereal* const mobil) { getMixDiffCoeffs(DATA_PTR(m_spwork)); doublereal c1 = 1.0 / (GasConstant * m_temp); @@ -231,29 +230,26 @@ namespace Cantera { mobil[k] = c1 * m_spwork[k]; } } - //================================================================================================ + //==================================================================================================================== void AqueousTransport::set_Grad_V(const doublereal* const grad_V) { for (int a = 0; a < m_nDim; a++) { m_Grad_V[a] = grad_V[a]; } } - //================================================================================================ + //==================================================================================================================== void AqueousTransport::set_Grad_T(const doublereal* const grad_T) { for (int a = 0; a < m_nDim; a++) { m_Grad_T[a] = grad_T[a]; } } - //================================================================================================ - void AqueousTransport::set_Grad_X(const doublereal* const grad_X) { - int itop = m_nDim * m_nsp; - for (int i = 0; i < itop; i++) { - m_Grad_X[i] = grad_X[i]; - } - } - - - /****************** thermal conductivity **********************/ - + //==================================================================================================================== + void AqueousTransport::set_Grad_X(const doublereal* const grad_X) { + int itop = m_nDim * m_nsp; + for (int i = 0; i < itop; i++) { + m_Grad_X[i] = grad_X[i]; + } + } + //==================================================================================================================== /* * The thermal conductivity is computed from the following mixture rule: * \[ @@ -278,15 +274,24 @@ namespace Cantera { } return m_lambda; } - - - /****************** thermal diffusion coefficients ************/ - - /** - * Thermal diffusion is not considered in this mixture-averaged - * model. To include thermal diffusion, use transport manager - * MultiTransport instead. This methods fills out array dt with - * zeros. + //==================================================================================================================== + // Return a vector of Thermal diffusion coefficients [kg/m/sec]. + /* + * The thermal diffusion coefficient \f$ D^T_k \f$ is defined + * so that the diffusive mass flux of species k<\I> induced by the + * local temperature gradient is given by the following formula + * + * \f[ + * M_k J_k = -D^T_k \nabla \ln T. + * \f] + * + * The thermal diffusion coefficient can be either positive or negative. + * + * In this method we set it to zero. + * + * @param dt On return, dt will contain the species thermal + * diffusion coefficients. Dimension dt at least as large as + * the number of species. Units are kg/m/s. */ void AqueousTransport::getThermalDiffCoeffs(doublereal* const dt) { int k; @@ -294,43 +299,70 @@ namespace Cantera { dt[k] = 0.0; } } - - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from + //==================================================================================================================== + // Get the species diffusive mass fluxes wrt to the specified solution averaged velocity, + // given the gradients in mole fraction and temperature + /* + * Units for the returned fluxes are kg m-2 s-1. * - * \f[ - * \vec{j}_k = -n M_k D_k \nabla X_k. - * \f] + * Usually the specified solution average velocity is the mass averaged velocity. + * This is changed in some subclasses, however. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - void AqueousTransport::getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, const doublereal* grad_X, - int ldf, doublereal* fluxes) { + void AqueousTransport::getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes) { set_Grad_T(grad_T); set_Grad_X(grad_X); getSpeciesFluxesExt(ldf, fluxes); } - - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from + //==================================================================================================================== + // Return the species diffusive mass fluxes wrt to the specified averaged velocity, + /* + * This method acts similarly to getSpeciesFluxesES() but + * requires all gradients to be preset using methods set_Grad_X(), set_Grad_V(), set_Grad_T(). + * See the documentation of getSpeciesFluxesES() for details. * - * \f[ - * \vec{j}_k = -n M_k D_k \nabla X_k. - * \f] + * units = kg/m2/s + * + * Internally, gradients in the in mole fraction, temperature + * and electrostatic potential contribute to the diffusive flux + * + * The diffusive mass flux of species \e k is computed from the following formula + * + * \f[ + * j_k = - \rho M_k D_k \nabla X_k - Y_k V_c + * \f] + * + * where V_c is the correction velocity + * + * \f[ + * V_c = - \sum_j {\rho M_j D_j \nabla X_j} + * \f] + * + * @param ldf Stride of the fluxes array. Must be equal to or greater than the number of species. + * @param fluxes Output of the diffusive fluxes. Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - void AqueousTransport::getSpeciesFluxesExt(int ldf, doublereal* fluxes) { + void AqueousTransport::getSpeciesFluxesExt(int ldf, doublereal * const fluxes) { int n, k; update_T(); update_C(); - getMixDiffCoeffs(DATA_PTR(m_spwork)); @@ -352,7 +384,7 @@ namespace Cantera { } } } - + //==================================================================================================================== /** * Mixture-averaged diffusion coefficients [m^2/s]. * @@ -393,7 +425,7 @@ namespace Cantera { } } - + //==================================================================================================================== // Handles the effects of changes in the Temperature, internally // within the object. /* @@ -444,7 +476,7 @@ namespace Cantera { // For now, for a concentration redo also m_iStateMF = -1; } - + //==================================================================================================================== /** * @internal This is called the first time any transport property * is requested from Mixture after the concentrations @@ -483,15 +515,8 @@ namespace Cantera { m_molefracs[k] = fmaxx(MIN_X, m_molefracs[k]); } } - - - /************************************************************************* - * - * methods to update temperature-dependent properties - * - *************************************************************************/ - - /** + //==================================================================================================================== + /* * Update the temperature-dependent parts of the mixture-averaged * thermal conductivity. */ @@ -511,9 +536,8 @@ namespace Cantera { m_spcond_ok = true; m_condmix_ok = false; } - - - /** + //==================================================================================================================== + /* * Update the binary diffusion coefficients. These are evaluated * from the polynomial fits at unit pressure (1 Pa). */ @@ -545,9 +569,8 @@ namespace Cantera { m_bindiff_ok = true; m_diffmix_ok = false; } - - - /** + //==================================================================================================================== + /* * Update the pure-species viscosities. */ void AqueousTransport::updateSpeciesViscosities() { @@ -568,9 +591,8 @@ namespace Cantera { } m_spvisc_ok = true; } - - - /** + //==================================================================================================================== + /* * Update the temperature-dependent viscosity terms. * Updates the array of pure species viscosities, and the * weighting functions in the viscosity mixture rule. @@ -598,25 +620,20 @@ namespace Cantera { } m_viscwt_ok = true; } - - /** + //==================================================================================================================== + /* * This function returns a Transport data object for a given species. * */ - struct LiquidTransportData AqueousTransport:: - getLiquidTransportData(int kSpecies) + struct LiquidTransportData AqueousTransport::getLiquidTransportData(int kSpecies) { struct LiquidTransportData td; td.speciesName = m_thermo->speciesName(kSpecies); - /* NEEDS WORK - td.hydroradius = ???; - */ return td; } - - + //==================================================================================================================== /* * * Solve for the diffusional velocities in the Stefan-Maxwell equations @@ -627,15 +644,15 @@ namespace Cantera { int VIM = 2; m_B.resize(m_nsp, VIM); - //! grab a local copy of the molecular weights + // grab a local copy of the molecular weights const vector_fp& M = m_thermo->molecularWeights(); - //! get the mean molecular weight of the mixture + // get the mean molecular weight of the mixture //double M_mix = m_thermo->meanMolecularWeight(); - //! get the concentration of the mixture + // get the concentration of the mixture //double rho = m_thermo->density(); //double c = rho/M_mix; @@ -748,4 +765,6 @@ namespace Cantera { } + //==================================================================================================================== } +//====================================================================================================================== diff --git a/Cantera/src/transport/AqueousTransport.h b/Cantera/src/transport/AqueousTransport.h index 96594606a..c2d9b47d5 100644 --- a/Cantera/src/transport/AqueousTransport.h +++ b/Cantera/src/transport/AqueousTransport.h @@ -1,5 +1,5 @@ /** - * @file LiquidTransport.h + * @file AqueousTransport.h * Header file defining class AqueousTransport */ /* @@ -13,7 +13,6 @@ #ifndef CT_AQUEOUSTRAN_H #define CT_AQUEOUSTRAN_H -using namespace std; // Cantera includes #include "TransportBase.h" @@ -35,7 +34,7 @@ namespace Cantera { //! Class AqueousTransport implements mixture-averaged transport - //! properties for liquid phases. + //! properties for brine phases. /*! * The model is based on that * described by Newman, Electrochemical Systems @@ -135,9 +134,9 @@ namespace Cantera { virtual ~AqueousTransport() {} //! Return the model id for this transport parameterization - virtual int model() const { return cAqueousTransport; } - - //! overloaded base class methods + virtual int model() const { + return cAqueousTransport; + } //! Returns the viscosity of the solution /*! @@ -162,11 +161,30 @@ namespace Cantera { /*! * * Controlling update boolean = m_viscwt_ok + * + * @param visc Vector of species viscosities */ - virtual void getSpeciesViscosities(doublereal* visc) - { updateViscosity_T(); copy(m_visc.begin(), m_visc.end(), visc); } + virtual void getSpeciesViscosities(doublereal * const visc); - virtual void getThermalDiffCoeffs(doublereal* const dt); + //! Return a vector of Thermal diffusion coefficients [kg/m/sec]. + /*! + * The thermal diffusion coefficient \f$ D^T_k \f$ is defined + * so that the diffusive mass flux of species k induced by the + * local temperature gradient is given by the following formula + * + * \f[ + * M_k J_k = -D^T_k \nabla \ln T. + * \f] + * + * The thermal diffusion coefficient can be either positive or negative. + * + * In this method we set it to zero. + * + * @param dt On return, dt will contain the species thermal + * diffusion coefficients. Dimension dt at least as large as + * the number of species. Units are kg/m/s. + */ + virtual void getThermalDiffCoeffs(doublereal* const dt); //! Return the thermal conductivity of the solution /*! @@ -242,7 +260,7 @@ namespace Cantera { //! Specify the value of the gradient of the temperature /*! * - * @param grad_V Gradient of the temperature (length num dimensions); + * @param grad_T Gradient of the temperature (length num dimensions); */ virtual void set_Grad_T(const doublereal* const grad_T); @@ -276,28 +294,61 @@ namespace Cantera { */ virtual void update_C(); - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from - * - * - */ - virtual void getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, const doublereal* grad_X, - int ldf, doublereal* fluxes); - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from - * + //! Get the species diffusive mass fluxes wrt to the specified solution averaged velocity, + //! given the gradients in mole fraction and temperature + /*! + * Units for the returned fluxes are kg m-2 s-1. * + * Usually the specified solution average velocity is the mass averaged velocity. + * This is changed in some subclasses, however. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - virtual void getSpeciesFluxesExt(int ldf, doublereal* fluxes); + virtual void getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes); + + //! Return the species diffusive mass fluxes wrt to the specified averaged velocity, + /*! + * This method acts similarly to getSpeciesFluxesES() but + * requires all gradients to be preset using methods set_Grad_X(), set_Grad_V(), set_Grad_T(). + * See the documentation of getSpeciesFluxesES() for details. + * + * units = kg/m2/s + * + * Internally, gradients in the in mole fraction, temperature + * and electrostatic potential contribute to the diffusive flux + * + * The diffusive mass flux of species \e k is computed from the following formula + * + * \f[ + * j_k = - \rho M_k D_k \nabla X_k - Y_k V_c + * \f] + * + * where V_c is the correction velocity + * + * \f[ + * V_c = - \sum_j {\rho M_j D_j \nabla X_j} + * \f] + * + * @param ldf Stride of the fluxes array. Must be equal to or greater than the number of species. + * @param fluxes Output of the diffusive fluxes. Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesFluxesExt(int ldf, doublereal* const fluxes); //! Initialize the transport object @@ -346,22 +397,19 @@ namespace Cantera { */ vector_fp m_mw; - // polynomial fits - vector > m_poly; - //! Polynomial coefficients of the viscosity /*! * These express the temperature dependendence of the pures * species viscosities. */ - vector m_visccoeffs; + std::vector m_visccoeffs; //! Polynomial coefficients of the conductivities /*! * These express the temperature dependendence of the pures * species conductivities */ - vector m_condcoeffs; + std::vector m_condcoeffs; //! Polynomial coefficients of the binary diffusion coefficients /*! @@ -369,7 +417,7 @@ namespace Cantera { * binary diffusivities. An overall pressure dependence is then * added. */ - vector m_diffcoeffs; + std::vector m_diffcoeffs; //! Internal value of the gradient of the mole fraction vector @@ -564,11 +612,9 @@ namespace Cantera { //! Saved value of the mixture viscosity doublereal m_viscmix; - // work space + //! work space of size m_nsp vector_fp m_spwork; - //! Internal Function - //! Update the temperature-dependent viscosity terms. //! Updates the array of pure species viscosities, and the //! weighting functions in the viscosity mixture rule. diff --git a/Cantera/src/transport/DustyGasTransport.cpp b/Cantera/src/transport/DustyGasTransport.cpp index 677862726..827a0bdd6 100644 --- a/Cantera/src/transport/DustyGasTransport.cpp +++ b/Cantera/src/transport/DustyGasTransport.cpp @@ -38,245 +38,458 @@ using namespace std; namespace Cantera { + //==================================================================================================================== + DustyGasTransport::DustyGasTransport(thermo_t* thermo) : + Transport(thermo), + m_nsp(0), + m_mw(0), + m_dk(0), + m_temp(-1.0), + m_multidiff(0,0), + m_spwork(0), + m_spwork2(0), + m_gradP(0.0), + m_knudsen_ok(false), + m_bulk_ok(false), + m_porosity(0.0), + m_tortuosity(1.0), + m_pore_radius(0.0), + m_diam(0.0), + m_perm(-1.0), + m_gastran(0) + { + } + //==================================================================================================================== + DustyGasTransport::DustyGasTransport(const DustyGasTransport &right) : + Transport(), + m_nsp(0), + m_mw(0), + m_dk(0), + m_temp(-1.0), + m_multidiff(0,0), + m_spwork(0), + m_spwork2(0), + m_gradP(0.0), + m_knudsen_ok(false), + m_bulk_ok(false), + m_porosity(0.0), + m_tortuosity(1.0), + m_pore_radius(0.0), + m_diam(0.0), + m_perm(-1.0), + m_gastran(0) + { + *this = right; + } + //==================================================================================================================== + // Assignment operator + /* + * This is NOT a virtual function. + * + * @param right Reference to %DustyGasTransport object to be copied + * into the current one. + */ + DustyGasTransport& DustyGasTransport::operator=(const DustyGasTransport& right) + { + if (&right == this) { + return *this; + } + Transport::operator=(right); - //////////////////// class DustyGasTransport methods ////////////// + m_nsp = right.m_nsp; + m_mw = right.m_mw; + m_d = right.m_d; + m_x = right.m_x; + m_dk = right.m_dk; + m_temp = m_temp; + m_multidiff = right.m_multidiff; + m_spwork = right.m_spwork; + m_spwork2 = right.m_spwork2; + m_gradP = right.m_gradP; + m_knudsen_ok = right.m_knudsen_ok; + m_bulk_ok= right.m_bulk_ok; + m_porosity = right.m_porosity; + m_tortuosity = right.m_tortuosity; + m_pore_radius = right.m_pore_radius; + m_diam = right.m_diam; + m_perm = right.m_perm; + + // Warning -> gastran may not point to the correct object + // after this copy. The routine initialize() must be called + if (m_gastran) { + delete m_gastran; + } + m_gastran = right.duplMyselfAsTransport(); - DustyGasTransport::DustyGasTransport(thermo_t* thermo) - : Transport(thermo), - m_temp(-1.0), - m_porosity(0.0), - m_tortuosity(1.0), - m_pore_radius(0.0), - m_diam(0.0), - m_perm(-1.0), - m_gastran(0) - {} + return *this; + } + //==================================================================================================================== + DustyGasTransport::~DustyGasTransport() { + delete m_gastran; + } + //==================================================================================================================== + // Duplication routine for objects which inherit from %Transport + /* + * This virtual routine can be used to duplicate %Transport objects + * inherited from %Transport even if the application only has + * a pointer to %Transport to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + */ + Transport *DustyGasTransport::duplMyselfAsTransport() const { + DustyGasTransport* tr = new DustyGasTransport(*this); + return (dynamic_cast(tr)); + } + //==================================================================================================================== + // Set the Parameters in the model + /* + * @param type Type of the parameter to set + * 0 - porosity + * 1 - tortuosity + * 2 - mean pore radius + * 3 - mean particle radius + * 4 - permeability + * @param k Unused int + * @param p pointer to double for the input list of parameters + * + */ + void DustyGasTransport::setParameters(const int type, const int k, const doublereal* const p) { + switch(type) { + case 0: + setPorosity(p[0]); break; + case 1: + setTortuosity(p[0]); break; + case 2: + setMeanPoreRadius(p[0]); break; + case 3: + setMeanParticleDiameter(p[0]); break; + case 4: + setPermeability(p[0]); break; + default: + throw CanteraError("DustyGasTransport::init", "unknown parameter"); + } + } + //==================================================================================================================== + // Initialization routine called by TransportFactory + /* + * The DustyGas model is a subordinate model to the gas phase transport model. Here we + * set the gas phase models. + * + * This is a protected routine, so that initialiation of the Model must occur within Cantera's setup + * + * @param phase Pointer to the underlying ThermoPhase model for the gas phase + * @param gastr Pointer to the underlying Transport model for transport in the gas phse. + */ + void DustyGasTransport::initialize(ThermoPhase* phase, Transport* gastr) { - void DustyGasTransport::setParameters(const int type, const int k, const doublereal* const p) { - switch(type) { - case 0: - setPorosity(p[0]); break; - case 1: - setTortuosity(p[0]); break; - case 2: - setMeanPoreRadius(p[0]); break; - case 3: - setMeanParticleDiameter(p[0]); break; - case 4: - setPermeability(p[0]); break; - default: - throw CanteraError("DustyGasTransport::init", - "unknown parameter"); - } - } - - void DustyGasTransport::initialize(ThermoPhase* phase, Transport* gastr) { - - // constant mixture attributes - m_thermo = phase; - m_nsp = m_thermo->nSpecies(); - m_tmin = m_thermo->minTemp(); - m_tmax = m_thermo->maxTemp(); - - m_gastran = gastr; - - // make a local copy of the molecular weights - m_mw.resize(m_nsp); - copy(m_thermo->molecularWeights().begin(), - m_thermo->molecularWeights().end(), m_mw.begin()); - - m_multidiff.resize(m_nsp, m_nsp); - m_d.resize(m_nsp, m_nsp); - m_dk.resize(m_nsp, 0.0); - m_x.resize(m_nsp); - //m_gradConc.resize(m_nsp); - //m_conc.resize(m_nsp); - - // set flags all false - m_knudsen_ok = false; - m_bulk_ok = false; - - // some work space - m_spwork.resize(m_nsp); - m_spwork2.resize(m_nsp); + // constant mixture attributes + m_thermo = phase; + m_nsp = m_thermo->nSpecies(); + if (m_gastran != gastr) { + if (m_gastran) { + delete m_gastran; + } + m_gastran = gastr; } + // make a local copy of the molecular weights + m_mw.resize(m_nsp); + copy(m_thermo->molecularWeights().begin(), m_thermo->molecularWeights().end(), m_mw.begin()); - /******************* binary diffusion coefficients **************/ + m_multidiff.resize(m_nsp, m_nsp); + m_d.resize(m_nsp, m_nsp); + m_dk.resize(m_nsp, 0.0); + m_x.resize(m_nsp, 0.0); + m_thermo->getMoleFractions(DATA_PTR(m_x)); - void DustyGasTransport::updateBinaryDiffCoeffs() { - if (m_bulk_ok) return; - int n,m; + // set flags all false + m_knudsen_ok = false; + m_bulk_ok = false; + + m_spwork.resize(m_nsp); + m_spwork2.resize(m_nsp); + } + //==================================================================================================================== + // Private routine to update the dusty gas binary diffusion coefficients + /* + * The dusty gas binary diffusion coefficients \f$ D^{dg}_{i,j} \f$ are evaluated from the binary + * gas-phase diffusion coefficients \f$ D^{bin}_{i,j} \f$ using the following formula + * + * \f[ + * D^{dg}_{i,j} = \frac{\phi}{\tau} D^{bin}_{i,j} + * \f] + * + * where \f$ \phi \f$ is the porosity of the media and \f$ \tau \f$ is the tortuosity of the media. + * + */ + void DustyGasTransport::updateBinaryDiffCoeffs() { + if (m_bulk_ok) return; + int n,m; + // get the gaseous binary diffusion coefficients + m_gastran->getBinaryDiffCoeffs(m_nsp, m_d.ptrColumn(0)); + doublereal por2tort = m_porosity / m_tortuosity; + for (n = 0; n < m_nsp; n++) { + for (m = 0; m < m_nsp; m++) { + m_d(n,m) *= por2tort; + } + } + m_bulk_ok = true; + } + //==================================================================================================================== + // Private routine to update the Knudsen diffusion coefficients + /* + * The Knudsen diffusion coefficients are given by the following form + * + * \f[ + * \mathcal{D}^{knud}_k = \frac{2}{3} \frac{r_{pore} \phi}{\tau} \left( \frac{8 R T}{\pi W_k} \right)^{1/2} + * \f] + * + */ + void DustyGasTransport::updateKnudsenDiffCoeffs() { + if (m_knudsen_ok) return; + doublereal K_g = m_pore_radius * m_porosity / m_tortuosity; + const doublereal TwoThirds = 2.0/3.0; + for (int k = 0; k < m_nsp; k++) { + m_dk[k] = TwoThirds * K_g * sqrt((8.0 * GasConstant * m_temp)/ + (Pi * m_mw[k])); + } + m_knudsen_ok = true; + } - // get the gaseous binary diffusion coefficients - m_gastran->getBinaryDiffCoeffs(m_nsp, m_d.ptrColumn(0)); - doublereal por2tort = m_porosity / m_tortuosity; - for (n = 0; n < m_nsp; n++) - for (m = 0; m < m_nsp; m++) - m_d(n,m) *= por2tort; - m_bulk_ok = true; + //==================================================================================================================== + // Private routine to calculate the H matrix + /* + * The H matrix is the term we have given to the matrix of coefficients in the equation for the molar + * fluxes. The matrix must be inverted in order to calculate the molar fluxes. + * + * The multicomponent diffusion H matrix \f$ H_{k,l} \f$ is given by the following formulas + * + * \f[ + * H_{k,l} = - \frac{X_k}{D^e_{k,l}} + * \f] + * \f[ + * H_{k,k} = \frac{1}{\mathcal(D)^{e}_{k, knud}} + \sum_{j \ne k}^N{ \frac{X_j}{D^e_{k,j}} } + * \f] + */ + void DustyGasTransport::eval_H_matrix() { + updateBinaryDiffCoeffs(); + updateKnudsenDiffCoeffs(); + int k,l,j; + doublereal sum; + for (k = 0; k < m_nsp; k++) { + + // evaluate off-diagonal terms + for (l = 0; l < m_nsp; l++) { + m_multidiff(k,l) = -m_x[k]/m_d(k,l); + } + + // evaluate diagonal term + sum = 0.0; + for (j = 0; j < m_nsp; j++) { + if (j != k) { + sum += m_x[j]/m_d(k,j); + } + } + m_multidiff(k,k) = 1.0/m_dk[k] + sum; + } + } + //==================================================================================================================== + void DustyGasTransport::getMolarFluxes(const doublereal* const state1, + const doublereal * const state2, + const doublereal delta, + doublereal * const fluxes) { + + int k; + doublereal conc1, conc2; + + // cbar will be the average concentration between the two points + doublereal * const cbar = DATA_PTR(m_spwork); + doublereal * const gradc = DATA_PTR(m_spwork2); + const doublereal t1 = state1[0]; + const doublereal t2 = state2[0]; + const doublereal rho1 = state1[1]; + const doublereal rho2 = state2[1]; + const doublereal* const y1 = state1 + 2; + const doublereal* const y2 = state2 + 2; + doublereal c1sum = 0.0, c2sum = 0.0; + + for (k = 0; k < m_nsp; k++) { + conc1 = rho1 * y1[k] / m_mw[k]; + conc2 = rho2 * y2[k] / m_mw[k]; + cbar[k] = 0.5*(conc1 + conc2); + gradc[k] = (conc2 - conc1) / delta; + c1sum += conc1; + c2sum += conc2; } - void DustyGasTransport::updateKnudsenDiffCoeffs() { - if (m_knudsen_ok) return; - doublereal K_g = m_pore_radius * m_porosity / m_tortuosity; - const doublereal TwoThirds = 2.0/3.0; - for (int k = 0; k < m_nsp; k++) { - m_dk[k] = TwoThirds * K_g * sqrt((8.0 * GasConstant * m_temp)/ - (Pi * m_mw[k])); - } - m_knudsen_ok = true; + // Calculate the pressures at p1 p2 and pbar + doublereal p1 = c1sum * GasConstant * t1; + doublereal p2 = c2sum * GasConstant * t2; + doublereal pbar = 0.5*(p1 + p2); + doublereal gradp = (p2 - p1)/delta; + doublereal tbar = 0.5*(t1 + t2); + + m_thermo->setState_TPX(tbar, pbar, cbar); + + updateMultiDiffCoeffs(); + + // Multiply m_multidiff and gradc together and store the result in fluxes[] + multiply(m_multidiff, gradc, fluxes); + + divide_each(cbar, cbar + m_nsp, m_dk.begin()); + + // if no permeability has been specified, use result for + // close-packed spheres + double b = 0.0; + if (m_perm < 0.0) { + double p = m_porosity; + double d = m_diam; + double t = m_tortuosity; + b = p*p*p*d*d/(72.0*t*(1.0-p)*(1.0-p)); } - - - void DustyGasTransport::eval_H_matrix() { - updateBinaryDiffCoeffs(); - updateKnudsenDiffCoeffs(); - int k,l,j; - doublereal sum; - for (k = 0; k < m_nsp; k++) { - - // evaluate off-diagonal terms - for (l = 0; l < m_nsp; l++) m_multidiff(k,l) = -m_x[k]/m_d(k,l); - - // evaluate diagonal term - sum = 0.0; - for (j = 0; j < m_nsp; j++) if (j != k) sum += m_x[j]/m_d(k,j); - m_multidiff(k,k) = 1.0/m_dk[k] + sum; - } + else { + b = m_perm; } + b *= gradp / m_gastran->viscosity(); + scale(cbar, cbar + m_nsp, cbar, b); -// void DustyGasTransport::getMolarFluxes(const double* grad_conc, -// double grad_P, double* fluxes) { -// updateMultiDiffCoeffs(); -// copy(grad_conc, grad_conc + m_nsp, m_spwork.begin()); -// multiply(m_multidiff, m_spwork.begin(), fluxes); -// m_thermo->getConcentrations(m_spwork.begin()); -// divide_each(m_spwork.begin(), m_spwork.end(), m_dk.begin()); + // Multiply m_multidiff with cbar and add it to fluxes + increment(m_multidiff, cbar, fluxes); + scale(fluxes, fluxes + m_nsp, fluxes, -1.0); + } + //==================================================================================================================== + // Private routine to update the Multicomponent diffusion coefficients that are used in the approximation + /* + * This routine updates the H matrix and then inverts it. + */ + void DustyGasTransport::updateMultiDiffCoeffs() { + // see if temperature has changed + updateTransport_T(); -// // if no permeability has been specified, use result for -// // close-packed spheres -// double b = 0.0; -// if (m_perm < 0.0) { -// double p = m_porosity; -// double d = m_diam; -// double t = m_tortuosity; -// b = p*p*p*d*d/(72.0*t*(1.0-p)*(1.0-p)); -// } -// else { -// b = m_perm; -// } -// b *= grad_P / m_gastran->viscosity(); -// scale(m_spwork.begin(), m_spwork.end(), m_spwork.begin(), b); -// increment(m_multidiff, m_spwork.begin(), fluxes); -// scale(fluxes, fluxes + m_nsp, fluxes, -1.0); -// } + // update the mole fractions + updateTransport_C(); + eval_H_matrix(); - void DustyGasTransport::getMolarFluxes(const doublereal* state1, - const doublereal* state2, double delta, double* fluxes) { - int k; - doublereal conc1, conc2; - doublereal* cbar = DATA_PTR(m_spwork); - doublereal* gradc = DATA_PTR(m_spwork2); - doublereal t1 = state1[0]; - doublereal t2 = state2[0]; - doublereal rho1 = state1[1]; - doublereal rho2 = state2[1]; - const doublereal* y1 = state1 + 2; - const doublereal* y2 = state2 + 2; - doublereal c1sum = 0.0, c2sum = 0.0; - for (k = 0; k < m_nsp; k++) { - conc1 = rho1*y1[k]/m_mw[k]; - conc2 = rho2*y2[k]/m_mw[k]; - cbar[k] = 0.5*(conc1 + conc2); - gradc[k] = (conc2 - conc1)/delta; - c1sum += conc1; - c2sum += conc2; - } - doublereal p1 = c1sum * GasConstant * state1[0]; - doublereal p2 = c2sum * GasConstant * state2[0]; - doublereal pbar = 0.5*(p1 + p2); - doublereal gradp = (p2 - p1)/delta; - doublereal tbar = 0.5*(t1 + t2); + // invert H + int ierr = invert(m_multidiff); - m_thermo->setState_TPX(tbar, pbar, cbar); - - updateMultiDiffCoeffs(); - - multiply(m_multidiff, gradc, fluxes); - divide_each(cbar, cbar + m_nsp, m_dk.begin()); - - // if no permeability has been specified, use result for - // close-packed spheres - double b = 0.0; - if (m_perm < 0.0) { - double p = m_porosity; - double d = m_diam; - double t = m_tortuosity; - b = p*p*p*d*d/(72.0*t*(1.0-p)*(1.0-p)); - } - else { - b = m_perm; - } - b *= gradp / m_gastran->viscosity(); - scale(cbar, cbar + m_nsp, cbar, b); - increment(m_multidiff, cbar, fluxes); - scale(fluxes, fluxes + m_nsp, fluxes, -1.0); + if (ierr != 0) { + throw CanteraError("DustyGasTransport::updateMultiDiffCoeffs", + "invert returned ierr = "+int2str(ierr)); } - - - void DustyGasTransport::updateMultiDiffCoeffs() { - // see if temperature has changed - updateTransport_T(); - - // update the mole fractions - updateTransport_C(); - - eval_H_matrix(); - - // invert H - int ierr = invert(m_multidiff); - - if (ierr != 0) { - throw CanteraError("DustyGasTransport::updateMultiDiffCoeffs", - "invert returned ierr = "+int2str(ierr)); - } + } + //==================================================================================================================== + // Return the Multicomponent diffusion coefficients. Units: [m^2/s]. + /* + * Returns the array of multicomponent diffusion coefficients. + * + * @param ld The dimension of the inner loop of d (usually equal to m_nsp) + * @param d flat vector of diffusion coefficients, fortran ordering. + * d[ld*j+i] is the D_ij diffusion coefficient (the diffusion + * coefficient for species i due to species j). + */ + void DustyGasTransport::getMultiDiffCoeffs(const int ld, doublereal* const d) { + int i,j; + updateMultiDiffCoeffs(); + for (i = 0; i < m_nsp; i++) { + for (j = 0; j < m_nsp; j++) { + d[ld*j + i] = m_multidiff(i,j); + } } + } + //==================================================================================================================== + // Update temperature-dependent quantities within the object + /* + * The object keeps a value m_temp, which is the temperature at which quantities were last evaluated + * at. If the temperature is changed, update Booleans are set false, triggering recomputation. + */ + void DustyGasTransport::updateTransport_T() + { + if (m_temp == m_thermo->temperature()) return; + m_temp = m_thermo->temperature(); + m_knudsen_ok = false; + m_bulk_ok = false; + } + //==================================================================================================================== + void DustyGasTransport::updateTransport_C() + { + m_thermo->getMoleFractions(DATA_PTR(m_x)); - void DustyGasTransport::getMultiDiffCoeffs(const int ld, doublereal* const d) { - int i,j; - updateMultiDiffCoeffs(); - for (i = 0; i < m_nsp; i++) { - for (j = 0; j < m_nsp; j++) { - d[ld*j + i] = m_multidiff(i,j); - } - } - } - - - /** - * Update temperature-dependent quantities. - */ - void DustyGasTransport::updateTransport_T() - { - if (m_temp == m_thermo->temperature()) return; - m_temp = m_thermo->temperature(); - m_knudsen_ok = false; - m_bulk_ok = false; - } - - void DustyGasTransport::updateTransport_C() - { - m_thermo->getMoleFractions(DATA_PTR(m_x)); - - // add an offset to avoid a pure species condition - // (check - this may be unnecessary) - int k; - for (k = 0; k < m_nsp; k++) { - m_x[k] = fmaxx(MIN_X, m_x[k]); - } + // add an offset to avoid a pure species condition + // (check - this may be unnecessary) + for (int k = 0; k < m_nsp; k++) { + m_x[k] = fmaxx(MIN_X, m_x[k]); } + // diffusion coeffs depend on Pressure + m_bulk_ok = false; + } + //==================================================================================================================== + // Set the porosity (dimensionless) + /* + * @param porosity Set the value of the porosity + */ + void DustyGasTransport::setPorosity(doublereal porosity) { + m_porosity = porosity; + m_knudsen_ok = false; + m_bulk_ok = false; + } + //==================================================================================================================== + // Set the tortuosity (dimensionless) + /* + * @param tort Value of the tortuosity + */ + void DustyGasTransport::setTortuosity(doublereal tort) { + m_tortuosity = tort; + m_knudsen_ok = false; + m_bulk_ok = false; + } + //==================================================================================================================== + // Set the mean pore radius (m) + /* + * @param rbar Value of the pore radius ( m) + */ + void DustyGasTransport::setMeanPoreRadius(doublereal rbar) { + m_pore_radius = rbar; + m_knudsen_ok = false; + } + //==================================================================================================================== + // Set the mean particle diameter + /* + * @param dbar Set the mean particle diameter (m) + */ + void DustyGasTransport::setMeanParticleDiameter(doublereal dbar) { + m_diam = dbar; + } + //==================================================================================================================== + // Set the permeability of the media + /* + * If not set, the value for close-packed spheres will be used by default. + * + * The value for close-packed spheres is given below, where p is the porosity, + * t is the tortuosity, and d is the diameter of the sphere + * + * \f[ + * \kappa = \frac{p^3 d^2}{72 t (1 - p)^2} + * \f] + * + * @param B set the permeability of the media (units = m^2) + */ + void DustyGasTransport::setPermeability(doublereal B) { + m_perm = B; + } + //==================================================================================================================== + // Return a reference to the transport manager used to compute the gas + // binary diffusion coefficients and the visdcosity. + /* + * @return Returns a reference to the gas transport object + */ + Transport& DustyGasTransport::gasTransport() { + return *m_gastran; + } + + //==================================================================================================================== } diff --git a/Cantera/src/transport/DustyGasTransport.h b/Cantera/src/transport/DustyGasTransport.h index e28fa4ae5..83304364b 100644 --- a/Cantera/src/transport/DustyGasTransport.h +++ b/Cantera/src/transport/DustyGasTransport.h @@ -1,10 +1,14 @@ -/// -/// -/// @file DustyGasTransport.h -/// Interface for class DustyGasTransport -/// -/// - +/** + * @file DustyGasTransport.h + * Headers for the DustyGasTransport object, which models transport properties + * in porous media using the dusty gas approximation + * (see \ref tranprops and \link Cantera::DustyGasTransport DustyGasTransport \endlink) . + * + */ +/* + * $Revision$ + * $Date$ + */ // Copyright 2003 California Institute of Technology @@ -19,143 +23,367 @@ namespace Cantera { - /// - /// Class DustyGasTransport implements the Dusty Gas model for - /// transport in porous media. As implemented here, only species - /// transport is handled. The viscosity, thermal conductivity, and - /// thermal diffusion coefficients are not implemented. - /// - class DustyGasTransport : public Transport { + //! Class DustyGasTransport implements the Dusty Gas model for transport in porous media. + /*! + * As implemented here, only species transport is handled. The viscosity, thermal conductivity, and thermal + * diffusion coefficients are not implemented. + * + * The dusty gas model includes the effects of Darcy's law. There is a net flux of species due to a pressure gradient + * that is part of Darcy's law. + * + * The dusty gas model expresses the value of the molar flux of species \f$ k \f$, \f$ J_k \f$ by the following formula. + * + * \f[ + * \sum_{j \ne k}{\frac{X_j J_k - X_k J_j}{D^e_{kj}}} + \frac{J_k}{\mathcal{D}^{e}_{k,knud}} = + * - \nabla C_k - \frac{C_k}{\mathcal{D}^{e}_{k,knud}} \frac{\kappa}{\mu} \nabla p + * \f] + * + * \f$ j \f$ is a sum over all species in the gas. + * + * The effective Knudsen diffusion coefficients are given by the following form + * + * \f[ + * \mathcal{D}^e_{k,knud} = \frac{2}{3} \frac{r_{pore} \phi}{\tau} \left( \frac{8 R T}{\pi W_k} \right)^{1/2} + * \f] + * + * The effective knudsen diffusion coefficients take into account the effects of collisions of gas-phase + * molecules with the wall. + * + * References for the Dusty Gas Model + * + * (1) H. Zhu, R. J. Kee, "Modeling Electrochemical Impedance Spectra in SOFC Button Cells with + * Internal Methane Reforming," J. Electrochem. Soc., 153(9) A1765-1772 (2006). + * + * (2) H. Zhu, R. J. Kee, V. M. Janardhanan, O. Deutschmann, D. G. Goodwin, J. Electrochem. Soc., 152, A2427 (2005). + * + * (3) E. A. Mason, A. P. Malinauskas," Gas Transport in Porous Media: the Dusty-Gas Model", + * American Elsevier, New York (1983). + * + * (4) J. W. Veldsink, R. M. J. van Damme, G. F. Versteeg, W. P. M. van Swaaij, + * "The use of the dusty gas model for the description of mass transport with chemical reaction in porous media," + * Chemical Engineering Journal, 57, 115 - 125 (1995). + */ + class DustyGasTransport : public Transport { - public: + public: - /// default constructor - DustyGasTransport(thermo_t* thermo=0); + //! default constructor + /*! + * @param thermo Pointer to the %ThermoPhase object for this phase. Defaults to zero. + */ + DustyGasTransport(thermo_t* thermo=0); + + //! Copy Constructor for the %DustyGasTransport object. + /*! + * @param right %LiquidTransport to be copied + */ + DustyGasTransport(const DustyGasTransport &right); + + //! Assignment operator + /*! + * + * Warning -> Shallow pointer copies are made of m_thermo and m_gastran.. gastran may not point to the correct + * object after this copy. The routine initialize() must be called after this + * routine to complete the copy. + * + * @param right Reference to %DustyGasTransport object to be copied + * into the current one. + */ + DustyGasTransport& operator=(const DustyGasTransport& right); - /// Destructor. Does nothing, since class allocates no memory - /// on the heap. - virtual ~DustyGasTransport() {} + //! Destructor. + virtual ~DustyGasTransport(); + + //! Duplication routine for objects which inherit from %Transport + /*! + * This virtual routine can be used to duplicate %Transport objects + * inherited from %Transport even if the application only has + * a pointer to %Transport to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + */ + virtual Transport *duplMyselfAsTransport() const; + + //--------------------------------------------------------- + // overloaded base class methods + + virtual int model() const { return cDustyGasTransport; } + + + //! Set the Parameters in the model + /*! + * @param type Type of the parameter to set + * 0 - porosity + * 1 - tortuosity + * 2 - mean pore radius + * 3 - mean particle radius + * 4 - permeability + * @param k Unused int + * @param p pointer to double for the input list of parameters + * + */ + virtual void setParameters(const int type, const int k, const doublereal* const p); + + + //! Return the Multicomponent diffusion coefficients. Units: [m^2/s]. + /*! + * Returns the array of multicomponent diffusion coefficients. + * + * @param ld The dimension of the inner loop of d (usually equal to m_nsp) + * @param d flat vector of diffusion coefficients, fortran ordering. + * d[ld*j+i] is the D_ij diffusion coefficient (the diffusion + * coefficient for species i due to species j). + */ + virtual void getMultiDiffCoeffs(const int ld, doublereal* const d); + + //! Get the molar fluxes [kmol/m^2/s], given the thermodynamic state at two nearby points. + /*! + * + * \f[ + * J_k = - \sum_{j = 1, N} \left[D^{multi}_{kj}\right]^{-1} \left( \nabla C_j + \frac{C_j}{\mathcal{D}^{knud}_j} \frac{\kappa}{\mu} \nabla p \right) + * \f] + * + * @param state1 Array of temperature, density, and mass fractions for state 1. + * @param state2 Array of temperature, density, and mass fractions for state 2. + * @param delta Distance from state 1 to state 2 (m). + * + * @param fluxes Vector of species molar fluxes due to diffusional driving force + */ + virtual void getMolarFluxes(const doublereal * const state1, + const doublereal* const state2, const doublereal delta, + doublereal* const fluxes); + + //----------------------------------------------------------- + // new methods added in this class + + //! Set the porosity (dimensionless) + /*! + * @param porosity Set the value of the porosity + */ + void setPorosity(doublereal porosity); + + //! Set the tortuosity (dimensionless) + /*! + * Tortuosity is considered to be constant within the object + * + * @param tort Value of the tortuosity + */ + void setTortuosity(doublereal tort); + + //! Set the mean pore radius (m) + /*! + * @param rbar Value of the pore radius ( m) + */ + void setMeanPoreRadius(doublereal rbar); + + //! Set the mean particle diameter + /*! + * @param dbar Set the mean particle diameter (m) + */ + void setMeanParticleDiameter(doublereal dbar); + + //! Set the permeability of the media + /*! + * If not set, the value for close-packed spheres will be used by default. + * + * The value for close-packed spheres is given below, where p is the porosity, + * t is the tortuosity, and d is the diameter of the sphere + * + * \f[ + * \kappa = \frac{p^3 d^2}{72 t (1 - p)^2} + * \f] + * + * @param B set the permeability of the media (units = m^2) + */ + void setPermeability(doublereal B); + + //! Return a reference to the transport manager used to compute the gas + //! binary diffusion coefficients and the visdcosity. + /*! + * @return Returns a reference to the gas transport object + */ + Transport& gasTransport(); - //--------------------------------------------------------- - // overloaded base class methods - - virtual int model() const { return cDustyGasTransport; } - - virtual void setParameters(const int type, const int k, const doublereal* const p); - - virtual void getMultiDiffCoeffs(const int ld, doublereal* const d); - - virtual void getMolarFluxes(const doublereal* state1, - const doublereal* state2, doublereal delta, - doublereal* fluxes); - - //----------------------------------------------------------- - // new methods added in this class - - /// Set the porosity (dimensionless) - void setPorosity(doublereal porosity) { - m_porosity = porosity; - m_knudsen_ok = false; - m_bulk_ok = false; - } - - /// Set the tortuosity (dimensionless) - void setTortuosity(doublereal tort) { - m_tortuosity = tort; - m_knudsen_ok = false; - m_bulk_ok = false; - } - - /// Set the mean pore radius (m) - void setMeanPoreRadius(doublereal rbar) { - m_pore_radius = rbar; - m_knudsen_ok = false; - } - - /// Set the mean particle diameter - void setMeanParticleDiameter(doublereal dbar) { - m_diam = dbar; - } - - /// Set the permeability. If not set, the value for - /// close-packed spheres will be used by default. - void setPermeability(doublereal B) { - m_perm = B; - } - - /// Return a reference to the transport manager used to compute the gas - /// binary diffusion coefficients and the visdcosity. - Transport& gasTransport() { return *m_gastran; } + //! Make the TransportFactory object a friend, because this object has restricted its + //! instantiation to classes which are friends. + friend class TransportFactory; - friend class TransportFactory; + protected: + + //! Initialization routine called by TransportFactory + /*! + * The DustyGas model is a subordinate model to the gas phase transport model. Here we + * set the gas phase models. + * + * This is a protected routine, so that initialiation of the Model must occur within Cantera's setup + * + * @param phase Pointer to the underlying ThermoPhase model for the gas phase + * @param gastr Pointer to the underlying Transport model for transport in the gas phse. + */ + void initialize(ThermoPhase* phase, Transport* gastr); - protected: + private: - // called by TransportFactory - void initialize(ThermoPhase* phase, Transport* gastr); - - - private: + //! Update temperature-dependent quantities within the object + /*! + * The object keeps a value m_temp, which is the temperature at which quantities were last evaluated + * at. If the temperature is changed, update Booleans are set false, triggering recomputation. + */ + void updateTransport_T(); - void updateTransport_T(); - void updateTransport_C(); + //! Update concentration-dependent quantities within the object + /*! + * The object keeps a value m_temp, which is the temperature at which quantities were last evaluated + * at. If the temperature is changed, update Booleans are set false, triggering recomputation. + */ + void updateTransport_C(); - void updateBinaryDiffCoeffs(); - void updateMultiDiffCoeffs(); - void updateKnudsenDiffCoeffs(); - void eval_H_matrix(); + //! Private routine to update the dusty gas binary diffusion coefficients + /*! + * The dusty gas binary diffusion coefficients \f$ D^{dg}_{i,j} \f$ are evaluated from the binary + * gas-phase diffusion coefficients \f$ D^{bin}_{i,j} \f$ using the following formula + * + * \f[ + * D^{dg}_{i,j} = \frac{\phi}{\tau} D^{bin}_{i,j} + * \f] + * + * where \f$ \phi \f$ is the porosity of the media and \f$ \tau \f$ is the tortuosity of the media. + * + */ + void updateBinaryDiffCoeffs(); + + //! Private routine to update the Multicomponent diffusion coefficients that are used in the approximation + /*! + * This routine updates the H matrix and then inverts it. + */ + void updateMultiDiffCoeffs(); + + //! Private routine to update the Knudsen diffusion coefficients + /*! + * The Knudsen diffusion coefficients are given by the following form + * + * \f[ + * \mathcal{D}^{knud}_k = \frac{2}{3} \frac{r_{pore} \phi}{\tau} \left( \frac{8 R T}{\pi W_k} \right)^{1/2} + * \f] + * + */ + void updateKnudsenDiffCoeffs(); + + //! Private routine to calculate the H matrix + /*! + * The multicomponent diffusion H matrix \f$ H_{k,l} \f$ is given by the following form + * + * \f[ + * H_{k,l} = - \frac{X_k}{D_{k,l}} + * \f] + * \f[ + * H_{k,k} = \frac{1}{\mathcal(D)^{knud}_{k}} + \sum_{j \ne k}^N{ \frac{X_j}{D_{k,j}} } + * \f] + */ + void eval_H_matrix(); - // gas attributes - int m_nsp; - doublereal m_tmin, m_tmax; - vector_fp m_mw; + //! Number of species in the gas phase + int m_nsp; + + //! Local copy of the species molecular weights + /*! + * units kg /kmol + * length = m_nsp; + */ + vector_fp m_mw; - // property values + //! binary diffusion coefficients + DenseMatrix m_d; - /// binary diffusion coefficients - DenseMatrix m_d; + //! mole fractions + vector_fp m_x; - /// mole fractions - vector_fp m_x; + //! Knudsen diffusion coefficients + /*! + * The Knudsen diffusion coefficients are given by the following form + * + * \f[ + * \mathcal{D}^{knud}_k = \frac{2}{3} \frac{r_{pore} \phi}{\tau} \left( \frac{8 R T}{\pi W_k} \right)^{1/2} + * \f] + * + */ + vector_fp m_dk; - /// Knudsen diffusion coefficients - vector_fp m_dk; + //! temperature + doublereal m_temp; - /// temperature - doublereal m_temp; + //! Multicomponent diffusion coefficients + /*! + * The multicomponent diffusion matrix \f$ H_{k,l} \f$ is given by the following form + * + * \f[ + * H_{k,l} = - \frac{X_k}{D_{k,l}} + * \f] + * \f[ + * H_{k,k} = \frac{1}{\mathcal(D)^{knud}_{k}} + \sum_{j \ne k}^N{ \frac{X_j}{D_{k,j}} } + * \f] + */ + DenseMatrix m_multidiff; - /// multicomponent diffusion coefficients - DenseMatrix m_multidiff; + //! work space of size m_nsp; + vector_fp m_spwork; + + //! work space of size m_nsp; + vector_fp m_spwork2; + + //! Pressure Gradient + doublereal m_gradP; - // work space - vector_fp m_spwork; - vector_fp m_spwork2; + //! Update-to-date variable for Knudsen diffusion coefficients + bool m_knudsen_ok; - // concentration gradients - //vector_fp m_gradConc; - //vector_fp m_conc; + //! Update-to-date variable for Binary diffusion coefficients + bool m_bulk_ok; - doublereal m_gradP; /// pressure gradient + //! Porosity + doublereal m_porosity; - bool m_knudsen_ok; - bool m_bulk_ok; - bool m_conc_set; - bool m_gradConc_set; - bool m_gradP_set; + //! Tortuosity + doublereal m_tortuosity; - doublereal m_porosity; /// porosity - doublereal m_tortuosity; /// tortuosity - doublereal m_pore_radius; /// pore radius (m) - doublereal m_diam; /// particle diameter (m) - doublereal m_perm; /// permeability + //! Pore radius (meter) + doublereal m_pore_radius; - Transport* m_gastran; /// pointer to gas transport manager + //! Particle diameter + /*! + * The medium is assumed to consist of particles of size m_diam + * units = m + */ + doublereal m_diam; - }; + //! Permeability of the media + /*! + * The permeability is the proportionality constant for Darcy's + * law which relates discharge rate and viscosity to the applied + * pressure gradient. + * + * Below is Darcy's law, where \f$ \kappa \f$ is the permeability + * + * \f[ + * v = \frac{\kappa}{\mu} \frac{\delta P}{\delta x} + * \f] + * + * units are m2 + */ + doublereal m_perm; + + //! Pointer to the transport object for the gas phase + /*! + * Note, this object owns the gastran object + */ + Transport* m_gastran; + + }; } #endif diff --git a/Cantera/src/transport/FtnTransport.h b/Cantera/src/transport/FtnTransport.h old mode 100755 new mode 100644 index 7df1de947..793a1352d --- a/Cantera/src/transport/FtnTransport.h +++ b/Cantera/src/transport/FtnTransport.h @@ -38,6 +38,7 @@ extern "C" { + doublereal __VISC__(doublereal* t, doublereal* p, doublereal* x); doublereal __BULKVISC__(doublereal* t, doublereal* p, doublereal* x); doublereal __TCON__(doublereal* t, doublereal* p, doublereal* x); diff --git a/Cantera/src/transport/LTPspecies.cpp b/Cantera/src/transport/LTPspecies.cpp new file mode 100644 index 000000000..7fa8b4cb7 --- /dev/null +++ b/Cantera/src/transport/LTPspecies.cpp @@ -0,0 +1,465 @@ +/** + * @file LTPspecies.cpp \ + * definitions for the LTPspecies objects and its children, which is the virtual base class + * for describing temperature dependence of submodels for transport parameters + * (see \ref tranprops and \link Cantera::LTPspecies LTPspecies \endlink) . + * + */ +/* + * $Author$ + * $Date$ + * $Revision$ + * + */ +#include "LTPspecies.h" +using namespace std; +using namespace ctml; + +namespace Cantera { + //==================================================================================================================== + //! Exception thrown if an error is encountered while reading the transport database. + class LTPError : public CanteraError { + public: + + //! Constructor is a wrapper around CanteraError + /*! + * @param msg Informative message + */ + LTPError(std::string msg) : + CanteraError("LTPspecies", "error parsing transport data: " + msg + "\n") + { + } + }; + //==================================================================================================================== + //! getArrhenius() parses the xml element called Arrhenius. + /*! + * The Arrhenius expression is + * \f[ + * k = A T^(b) exp (-E_a / RT) + * \f] + * + * @param node XML_Node to be read + * @param A Output pre-exponential factor. The units are variable. + * @param b output temperature power + * @param E Output activation energy in units of Kelvin + */ + static void getArrhenius(const XML_Node& node, + doublereal& A, doublereal& b, doublereal& E) { + /* parse the children for the A, b, and E conponents. + */ + A = getFloat(node, "A", "toSI"); + b = getFloat(node, "b"); + E = getFloat(node, "E", "actEnergy"); + E /= GasConstant; + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property. + /* + * The species transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node in the species block and specifies a type of transport + * property (like viscosity) + * + * @param propNode Pointer to the XML node that contains the property information + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + */ + LTPspecies::LTPspecies(const XML_Node * const propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t * thermo) : + m_speciesName(name), + m_model(LTP_TD_NOTSET), + m_property(tp_ind), + m_thermo(thermo), + m_mixWeight(1.0) + { + if (propNode) { + if (propNode->hasChild("mixtureWeighting") ) { + m_mixWeight = getFloat(*propNode, "mixtureWeighting"); + } + } + } + //==================================================================================================================== + // Copy constructor + LTPspecies::LTPspecies(const LTPspecies &right) + { + *this = right; + } + //==================================================================================================================== + // Assignment operator + LTPspecies& LTPspecies::operator=(const LTPspecies& right) + { + if (&right != this) { + m_speciesName = right.m_speciesName; + m_property = right.m_property; + m_model = right.m_model; + m_coeffs = right.m_coeffs; + m_thermo = right.m_thermo; + m_mixWeight = right.m_mixWeight; + } + return *this; + } + //==================================================================================================================== + // Duplication routine + /* + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + LTPspecies * LTPspecies::duplMyselfAsLTPspecies() const + { + LTPspecies *prp = new LTPspecies(*this); + return prp; + } + //==================================================================================================================== + LTPspecies::~LTPspecies() + { + } + //==================================================================================================================== + // Returns the vector of pure species tranport property + /* + * The pure species transport property (i.e. pure species viscosity) + * is returned. Any temperature and composition dependence will be + * adjusted internally according to the information provided by the + * subclass object. + */ + doublereal LTPspecies::getSpeciesTransProp() + { + return 0.0; + } + //==================================================================================================================== + // Check to see if the property evaluation will be positive + bool LTPspecies::checkPositive() const + { + return (m_coeffs[0] > 0); + } + //==================================================================================================================== + doublereal LTPspecies::getMixWeight() const + { + return m_mixWeight; + } + //==================================================================================================================== + // Internal model to adjust species-specific properties for composition. + /* + * Currently just a place holder, but this method could take + * the composition from the thermo object and adjust coefficients + * accoding to some unspecified model. + */ + void LTPspecies::adjustCoeffsForComposition() + { + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property + // expressed as a constant value. + /* The transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of + * transport property (like viscosity) + */ + LTPspecies_Const::LTPspecies_Const(const XML_Node &propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t * const thermo) : + LTPspecies(&propNode, name, tp_ind, thermo) + { + m_model = LTP_TD_CONSTANT; + double A_k = getFloatCurrent(propNode, "toSI"); + if (A_k > 0.0) { + m_coeffs.push_back(A_k); + } else { + throw LTPError("negative or zero " + propNode.name()); + } + } + //==================================================================================================================== + // Copy constructor + LTPspecies_Const::LTPspecies_Const(const LTPspecies_Const &right) + : LTPspecies() + { + *this = right; //use assignment operator to do other work + } + //==================================================================================================================== + // Assignment operator + LTPspecies_Const& LTPspecies_Const::operator=(const LTPspecies_Const& right) + { + if (&right != this) { + LTPspecies::operator=(right); + } + return *this; + } + //==================================================================================================================== + LTPspecies_Const::~LTPspecies_Const() + { + } + //==================================================================================================================== + // Duplication routine + /* + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + LTPspecies * LTPspecies_Const::duplMyselfAsLTPspecies() const + { + LTPspecies_Const *prp = new LTPspecies_Const(*this); + return (dynamic_cast(prp)); + } + //==================================================================================================================== + // Return the (constant) value for this transport property + doublereal LTPspecies_Const::getSpeciesTransProp() { + return m_coeffs[0]; + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property + // expressed in extended Arrhenius form. + /* + * The transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity) + * + * + * @param propNode Referenc to the XML node that contains the property information.This class + * is assumed to be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_Arrhenius::LTPspecies_Arrhenius(const XML_Node &propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t* thermo) : + LTPspecies(&propNode, name, tp_ind, thermo) + { + m_model = LTP_TD_ARRHENIUS; + m_temp = 0.0; + m_prop = 0.0; + + doublereal A_k, n_k, Tact_k; + getArrhenius(propNode, A_k, n_k, Tact_k); + if (A_k <= 0.0) { + throw LTPError("negative or zero " + propNode.name()); + } + m_coeffs.push_back(A_k); + m_coeffs.push_back(n_k); + m_coeffs.push_back(Tact_k); + m_coeffs.push_back(log(A_k)); + } + //==================================================================================================================== + // Copy constructor + LTPspecies_Arrhenius::LTPspecies_Arrhenius(const LTPspecies_Arrhenius &right) + : LTPspecies() + { + *this = right; + } + //==================================================================================================================== + // Assignment operator + LTPspecies_Arrhenius& LTPspecies_Arrhenius::operator=(const LTPspecies_Arrhenius& right) + { + if (&right != this) { + LTPspecies::operator=(right); + m_temp = right.m_temp; + m_logt = right.m_logt; + m_prop = right.m_prop; + m_logProp = right.m_logProp; + } + return *this; + } + //==================================================================================================================== + // Destructor + LTPspecies_Arrhenius::~LTPspecies_Arrhenius() + { + } + //==================================================================================================================== + // Duplication routine + /* + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + LTPspecies * LTPspecies_Arrhenius::duplMyselfAsLTPspecies() const + { + LTPspecies_Arrhenius *prp = new LTPspecies_Arrhenius(*this); + return (dynamic_cast(prp)); + } + //=================================================================================================================== + // Return the pure species value for this transport property evaluated + // from the Arrhenius expression + /* + * In general the Arrhenius expression is + * + * \f[ + * \mu = A T^n \exp(- E / R T). + * \f] + * + * Note that for viscosity, the convention is such that + * a positive activation energy corresponds to the typical + * case of a positive argument to the exponential so that + * the Arrhenius expression is + * + * \f[ + * \mu = A T^n \exp(+ E / R T). + * \f] + * + * Any temperature and composition dependence will be + * adjusted internally according to the information provided. + */ + doublereal LTPspecies_Arrhenius::getSpeciesTransProp() { + + doublereal t = m_thermo->temperature(); + //m_coeffs[0] holds A + //m_coeffs[1] holds n + //m_coeffs[2] holds Tact + //m_coeffs[3] holds log(A) + if (t != m_temp) { + m_prop = 0; + m_logProp = 0; + m_temp = t; + m_logt = log(m_temp); + //For viscosity the sign convention on positive activation energy is swithced + if (m_property == TP_VISCOSITY) + m_logProp = m_coeffs[3] + m_coeffs[1] * m_logt + m_coeffs[2] / m_temp ; + else + m_logProp = m_coeffs[3] + m_coeffs[1] * m_logt - m_coeffs[2] / m_temp ; + m_prop = exp(m_logProp); + } + return m_prop; + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property expressed as a polynomial in temperature. + /* + * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). + * + * + * @param propNode Referenc to the XML node that contains the property information. This class + * must be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_Poly::LTPspecies_Poly(const XML_Node &propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t* thermo) : + LTPspecies(&propNode, name, tp_ind, thermo), + m_temp(-1.0), + m_prop(0.0) + { + m_model = LTP_TD_POLY; + getFloatArray(propNode, m_coeffs, "true", "toSI"); + } + //==================================================================================================================== + // Copy constructor + LTPspecies_Poly::LTPspecies_Poly(const LTPspecies_Poly &right) + : LTPspecies() + { + *this = right; + } + //==================================================================================================================== + // Assignment operator + LTPspecies_Poly& LTPspecies_Poly::operator=(const LTPspecies_Poly& right) + { + if (&right != this) { + LTPspecies::operator=(right); + m_temp = right.m_temp; + m_prop = right.m_prop; + } + return *this; + } + //==================================================================================================================== + LTPspecies_Poly::~LTPspecies_Poly() + { + } + //==================================================================================================================== + // Duplication routine + /* + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + LTPspecies * LTPspecies_Poly::duplMyselfAsLTPspecies() const + { + LTPspecies_Poly *prp = new LTPspecies_Poly(*this); + return (dynamic_cast(prp)); + } + //==================================================================================================================== + // Return the value for this transport property evaluated from the polynomial expression + doublereal LTPspecies_Poly::getSpeciesTransProp() { + doublereal t = m_thermo->temperature(); + if (t != m_temp) { + m_prop = 0.0; + m_temp = t; + double tempN = 1.0; + for (int i = 0; i < (int) m_coeffs.size() ; i++) { + m_prop += m_coeffs[i] * tempN; + tempN *= m_temp; + } + } + return m_prop; + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property + // expressed as an exponential in temperature. + /* + * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). + * + * + * @param propNode Referenc to the XML node that contains the property information. This class + * must be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_ExpT::LTPspecies_ExpT(const XML_Node &propNode, std::string name, TransportPropertyType tp_ind, + const thermo_t* thermo) : + LTPspecies(&propNode, name, tp_ind, thermo), + m_temp(-1.0), + m_prop(0.0) + { + m_model = LTP_TD_EXPT; + getFloatArray(propNode, m_coeffs, "true", "toSI"); + } + //==================================================================================================================== + // Copy constructor + LTPspecies_ExpT::LTPspecies_ExpT(const LTPspecies_ExpT &right) + : LTPspecies() + { + *this = right; //use assignment operator to do other work + } + //==================================================================================================================== + // Assignment operator + LTPspecies_ExpT& LTPspecies_ExpT::operator=(const LTPspecies_ExpT& right) + { + if (&right != this) { + LTPspecies::operator=(right); + m_temp = right.m_temp; + m_prop = right.m_prop; + } + return *this; + } + //==================================================================================================================== + LTPspecies_ExpT::~LTPspecies_ExpT() + { + } + //==================================================================================================================== + // Duplication routine + /* + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + LTPspecies * LTPspecies_ExpT::duplMyselfAsLTPspecies() const + { + LTPspecies_ExpT *prp = new LTPspecies_ExpT(*this); + return (dynamic_cast(prp)); + } + //==================================================================================================================== + // Return the value for this transport property evaluated + // from the exponential in temperature expression + doublereal LTPspecies_ExpT::getSpeciesTransProp() { + doublereal t = m_thermo->temperature(); + if (t != m_temp) { + m_temp=t; + m_prop = m_coeffs[0]; + doublereal tempN = 1.0; + doublereal tmp = 0.0; + for (int i = 1; i < (int) m_coeffs.size() ; i++) { + tempN *= m_temp; + tmp += m_coeffs[i] * tempN; + } + m_prop *= exp(tmp); + } + return m_prop; + } + //==================================================================================================================== +} diff --git a/Cantera/src/transport/LTPspecies.h b/Cantera/src/transport/LTPspecies.h new file mode 100644 index 000000000..008a07263 --- /dev/null +++ b/Cantera/src/transport/LTPspecies.h @@ -0,0 +1,553 @@ +/** + * @file LTPspecies.h + * Header file defining class LTPspecies and its child classes + */ +/* + * $Author$ + * $Date$ + * $Revision$ + + */ + +#ifndef CT_LTPSPECIES_H +#define CT_LTPSPECIES_H + +// Cantera includes +#include "ct_defs.h" +#include "TransportBase.h" +#include "FactoryBase.h" + +// STL includes +#include +#include + + +namespace Cantera { + + //==================================================================================================================== + //! Enumeration of the types of transport properties that can be + //! handled by the variables in the various Transport classes. + /*! + * Not all of these are handled by each class and each class + * should handle exceptions where the transport property is not handled. + * + * Tranport properties currently on the list + * + * 0 - viscosity + * 1 - Ionic conductivity + * 2 - Mobility Ratio + * 3 - Self Diffusion coefficient + * 4 - Thermal conductivity + * 5 - species diffusivity + * 6 - hydrodynamic radius + * 7 - electrical conductivity + */ + enum TransportPropertyType { + TP_UNKNOWN = -1, + TP_VISCOSITY = 0, + TP_IONCONDUCTIVITY, + TP_MOBILITYRATIO, + TP_SELFDIFFUSION, + TP_THERMALCOND, + TP_DIFFUSIVITY, + TP_HYDRORADIUS, + TP_ELECTCOND + }; + + //==================================================================================================================== + //! Temperature dependence type for pure (liquid) species properties + /*! + * Types of temperature dependencies: + * 0 - Independent of temperature + * 1 - extended arrhenius form + * 2 - polynomial in temperature form + * 3 - exponential temperature polynomial + */ + enum LTPTemperatureDependenceType { + LTP_TD_NOTSET=-1, + LTP_TD_CONSTANT, + LTP_TD_ARRHENIUS, + LTP_TD_POLY, + LTP_TD_EXPT + }; + + //==================================================================================================================== + //! Class LTPspecies holds transport parameters for a specific liquid-phase species. + /*! + * Subclasses handle different means of specifying transport properties + * like constant, %Arrhenius or polynomial fits. In its current state, + * it is primarily suitable for specifying temperature dependence, but + * the adjustCoeffsForComposition() method can be implemented to + * adjust for composition dependence. + * + * Mixing rules for computing mixture transport properties are handled + * separately in LiquidTranInteraction subclasses. + */ + class LTPspecies { + + public: + + //! Construct an LTPspecies object for a liquid tranport property. + /*! + * The species transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node in the species block and specifies a type of transport + * property (like viscosity) + * + * @param propNode Pointer to the XML node that contains the property information. A default + * value of 0 is allowed for the base class, but not for classes which + * are assumed to be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + */ + LTPspecies(const XML_Node * const propNode = 0, std::string name = "-", + TransportPropertyType tp_ind = TP_UNKNOWN, const thermo_t* thermo = 0); + + //! Copy constructor + /*! + * @param right Object to be copied + */ + LTPspecies(const LTPspecies &right); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + LTPspecies& operator=(const LTPspecies& right); + + //! Destructor + virtual ~LTPspecies(); + + //! Duplication routine + /*! + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + virtual LTPspecies * duplMyselfAsLTPspecies() const; + + //! Returns the vector of pure species tranport property + /*! + * The pure species transport property (i.e. pure species viscosity) + * is returned. Any temperature and composition dependence will be + * adjusted internally according to the information provided by the + * subclass object. + * + * @return Returns a single double containing the property evaluation + * at the current ThermoPhase temperature. + */ + virtual doublereal getSpeciesTransProp(); + + //! Check to see if the property evaluation will be positive + /*! + * @return Returns a boolean + */ + virtual bool checkPositive() const; + + //! Return the weight mixture + /*! + * @return Returns a single double which is used as a weight + */ + doublereal getMixWeight() const; + + private: + //! Internal model to adjust species-specific properties for composition. + /*! + * Currently just a place holder, but this method could take + * the composition from the thermo object and adjust coefficients + * accoding to some unspecified model. + */ + virtual void adjustCoeffsForComposition(); + + protected: + + //! Species Name + std::string m_speciesName; + + //! Model type for the temperature dependence + LTPTemperatureDependenceType m_model; + + //! enum indicating which property this is (i.e viscosity) + TransportPropertyType m_property; + + //! Model temperature-dependence ceofficients + vector_fp m_coeffs; + + //! Pointer to a const thermo object to get current temperature + const thermo_t * m_thermo; + + //! Weighting used for mixing. + /*! + * This weighting can be employed to allow salt transport + * properties to be represented by specific ions. + * For example, to have Li+ and Ca+ represent the mixing + * transport properties of LiCl and CaCl2, the weightings for + * Li+ would be 2.0, for K+ would be 3.0 and for Cl- would be 0.0. + * The tranport properties for Li+ would be those for LiCl and + * the tranport properties for Ca+ would be those for CaCl2. + * The transport properties for Cl- should be something innoccuous like + * 1.0--note that 0.0 is not innocuous if there are logarithms involved. + */ + doublereal m_mixWeight; + }; + + //==================================================================================================================== + //! Class LTPspecies_Const holds transport parameters for a + //! specific liquid-phase species (LTPspecies) when the + //! transport property is just a constant value. + /*! + * As an example of the input required for LTPspecies_Const + * consider the following XML fragment + * + * \verbatim + * + * + * + * + * 1.000 + * + * + * + * + * \endverbatim + */ + class LTPspecies_Const : public LTPspecies { + + public: + + //! Construct an LTPspecies object for a liquid tranport property + //! expressed as a constant value. + /** The transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of + * transport property (like viscosity). + * + * + * @param propNode Reference to the XML node that contains the property information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + */ + LTPspecies_Const(const XML_Node &propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t * const thermo); + + //! Copy constructor + /*! + * @param right Object to be copied + */ + LTPspecies_Const(const LTPspecies_Const &right); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + LTPspecies_Const& operator=(const LTPspecies_Const& right); + + //! Destructor + virtual ~LTPspecies_Const(); + + //! duplication routine + /*! + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + virtual LTPspecies * duplMyselfAsLTPspecies() const; + + //! Returns the pure species tranport property + /*! + * The pure species transport property (i.e. pure species viscosity) + * is returned. Any temperature and composition dependence will be + * adjusted internally according to the information provided. + */ + doublereal getSpeciesTransProp(); + + }; + + //==================================================================================================================== + //! Class LTPspecies_Arrhenius holds transport parameters for a + //! specific liquid-phase species (LTPspecies) when the + //! transport property is expressed in Arrhenius form. + /*! + * Used for pure species properties with equations of the form + * \f[ + * x = A T^b \exp( - E / RT ) + * \f] + * where A, b, and E are passed in the xml input file. + * + * As an example of the input required for LTPspecies_Arrhenius + * consider the following XML fragment + * + * \verbatim + * + * + * + * + * + * 6.578e-5 + * 0.0 + * 23788.e3 + * + * + * + * + * \endverbatim + */ + class LTPspecies_Arrhenius : public LTPspecies { + + public: + + //! Construct an LTPspecies object for a liquid tranport property + //! expressed in extended Arrhenius form. + /*! + * The transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity) + * + * + * @param propNode Referenc to the XML node that contains the property information.This class + * is assumed to be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_Arrhenius(const XML_Node &propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t * thermo); + + //! Copy constructor + /*! + * @param right Object to be copied + */ + LTPspecies_Arrhenius(const LTPspecies_Arrhenius &right); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + LTPspecies_Arrhenius& operator=(const LTPspecies_Arrhenius& right); + + //! Destructor + virtual ~LTPspecies_Arrhenius(); + + //! duplication routine + /*! + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + virtual LTPspecies * duplMyselfAsLTPspecies() const; + + //! Return the pure species value for this transport property evaluated + //! from the Arrhenius expression + /*! + * In general the Arrhenius expression is + * + * \f[ + * \mu = A T^n \exp( - E / R T ). + * \f] + * + * Note that for viscosity, the convention is such that + * a positive activation energy corresponds to the typical + * case of a positive argument to the exponential so that + * the Arrhenius expression is + * + * \f[ + * \mu = A T^n \exp( + E / R T ). + * \f] + * + * Any temperature and composition dependence will be + * adjusted internally according to the information provided. + */ + doublereal getSpeciesTransProp(); + + protected: + + //! temperature from thermo object + doublereal m_temp; + + //! logarithm of current temperature + doublereal m_logt; + + //! most recent evaluation of transport property + doublereal m_prop; + + //! logarithm of most recent evaluation of transport property + doublereal m_logProp; + }; + + //==================================================================================================================== + //! Class LTPspecies_Poly holds transport parameters for a + //! specific liquid-phase species (LTPspecies) when the transport + //! property is expressed as a polynomial in temperature. + /*! + * Used for pure species properties with equations of the form + * \f[ + * x = f[0] + f[1] T + ... + f[N] T^N + * \f] + * where f[i] are elements of the float array passed in. + * + * As an example of the input required for LTPspecies_Poly + * consider the following XML fragment + * + * \verbatim + * + * + * + * + * 0.6, -15.0e-5 + * + * + * + * + * \endverbatim + */ + class LTPspecies_Poly : public LTPspecies { + + public: + + //! Construct an LTPspecies object for a liquid tranport property expressed as a polynomial in temperature. + /*! + * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). + * + * + * @param propNode Referenc to the XML node that contains the property information. This class + * must be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_Poly(const XML_Node &propNode, std::string name, TransportPropertyType tp_ind, const thermo_t * thermo); + + //! Copy constructor + /*! + * @param right Object to be copied + */ + LTPspecies_Poly(const LTPspecies_Poly &right); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + LTPspecies_Poly& operator=(const LTPspecies_Poly& right); + + //! Destructor + virtual ~LTPspecies_Poly(); + + //! Duplication routine + /*! + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + virtual LTPspecies * duplMyselfAsLTPspecies() const; + + //! Returns the pure species tranport property + /*! + * The pure species transport property (i.e. pure species viscosity) + * is returned. Any temperature and composition dependence will be + * adjusted internally according to the information provided. + */ + doublereal getSpeciesTransProp(); + + protected: + + //! temperature from thermo object + doublereal m_temp; + + //! most recent evaluation of transport property + doublereal m_prop; + + }; + + //==================================================================================================================== + //! Class LTPspecies_ExpT holds transport parameters for a specific liquid-phase species (LTPspecies) + //! when the transport property is expressed as an exponential in temperature. + /*! + * Used for pure species properties with equations of the form + * + * \f[ + * x = f[0] \exp( f[1] T + ... + f[N] T^{N} ) + * \f] + * + * where f[i] are elements of the float array passed in. + * + * As an example of the input required for LTPspecies_ExpT + * consider the following XML fragment + * + * \verbatim + * + * + * + * + * 0.6, -15.0e-5 + * + * + * + * + * \endverbatim + */ + class LTPspecies_ExpT : public LTPspecies { + + public: + + //! Construct an LTPspecies object for a liquid tranport property + //! expressed as an exponential in temperature. + /*! + * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). + * + * + * @param propNode Referenc to the XML node that contains the property information. This class + * must be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_ExpT(const XML_Node &propNode, std::string name, + TransportPropertyType tp_ind, const thermo_t* thermo); + + //! Copy constructor + /*! + * @param right Object to be copied + */ + LTPspecies_ExpT(const LTPspecies_ExpT &right); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + LTPspecies_ExpT& operator=(const LTPspecies_ExpT& right); + + //! Destructor + virtual ~LTPspecies_ExpT(); + + //! Duplication routine + /*! + * @return Returns a copy of this routine as a pointer to LTPspecies + */ + virtual LTPspecies * duplMyselfAsLTPspecies() const; + + //! Returns the pure species tranport property + /*! + * The pure species transport property (i.e. pure species viscosity) + * is returned. Any temperature and composition dependence will be + * adjusted internally according to the information provided. + */ + doublereal getSpeciesTransProp(); + + protected: + + //! temperature from thermo object + doublereal m_temp; + + //! most recent evaluation of transport property + doublereal m_prop; + + }; + + //==================================================================================================================== + +} +#endif diff --git a/Cantera/src/transport/L_matrix.h b/Cantera/src/transport/L_matrix.h old mode 100755 new mode 100644 index 238d68370..f5990d238 --- a/Cantera/src/transport/L_matrix.h +++ b/Cantera/src/transport/L_matrix.h @@ -1,10 +1,13 @@ /** * @file L_matrix.h - * - * functions to evaluate portions of the L matrix needed for + * Functions to evaluate portions of the L matrix needed for * multicomponent transport properties. */ +/* + * $Id$ + */ + #ifndef CT_LMATRIX_H #define CT_LMATRIX_H @@ -20,234 +23,218 @@ #include - ///////////////////////////////////////////////////////////////////// namespace Cantera { + //==================================================================================================================== + // #define CHEMKIN_COMPATIBILITY_MODE - // #define CHEMKIN_COMPATIBILITY_MODE - - const doublereal Min_C_Internal = 0.001; - - bool MultiTransport::hasInternalModes(int j) { + //! Constant to compare dimensionless heat capacities against zero + const doublereal Min_C_Internal = 0.001; + //==================================================================================================================== + bool MultiTransport::hasInternalModes(int j) { #ifdef CHEMKIN_COMPATIBILITY_MODE - return (m_crot[j] > Min_C_Internal); + return (m_crot[j] > Min_C_Internal); #else - return (m_cinternal[j] > Min_C_Internal); + return (m_cinternal[j] > Min_C_Internal); #endif + } + + //==================================================================================================================== + /* + * Evaluate the upper-left block of the L matrix. + */ + void MultiTransport::eval_L0000(const doublereal* const x) { + + doublereal prefactor = 16.0*m_temp/25.0; + doublereal sum; + int i, j, k; + for (i = 0; i < m_nsp; i++) { + // subtract-off the k=i term to account for the first delta + // function in Eq. (12.121) + + sum = -x[i]/m_bdiff(i,i); + for (k = 0; k < m_nsp; k++) sum += x[k]/m_bdiff(i,k); + + sum /= m_mw[i]; + for (j = 0; j != m_nsp; ++j) { + m_Lmatrix(i,j) = prefactor * x[j] + * ( m_mw[j] * sum + x[i]/m_bdiff(i,j) ); + } + // diagonal term is zero + m_Lmatrix(i,i) = 0.0; } + } + //==================================================================================================================== + void MultiTransport::eval_L0010(const doublereal* const x) { + doublereal prefactor = 1.6*m_temp; - /** - * Evaluate the upper-left block of the L matrix. - */ - void MultiTransport::eval_L0000(const doublereal* x) { + doublereal sum, wj, xj; + int i, j; + for (j = 0; j < m_nsp; j++) { + //constant = prefactor * x[j]; + xj = x[j]; + wj = m_mw[j]; + sum = 0.0; + for (i = 0; i < m_nsp; i++) { + m_Lmatrix(i,j + m_nsp) = - prefactor * x[i] * xj * m_mw[i] * + (1.2 * m_cstar(j,i) - 1.0) / + ( (wj + m_mw[i]) * m_bdiff(j,i) ); - doublereal prefactor = 16.0*m_temp/25.0; - doublereal sum; - int i, j, k; - for (i = 0; i < m_nsp; i++) - { - // subtract-off the k=i term to account for the first delta - // function in Eq. (12.121) - - sum = -x[i]/m_bdiff(i,i); - for (k = 0; k < m_nsp; k++) sum += x[k]/m_bdiff(i,k); - - sum /= m_mw[i]; - for (j = 0; j != m_nsp; ++j) { - m_Lmatrix(i,j) = prefactor * x[j] - * ( m_mw[j] * sum + x[i]/m_bdiff(i,j) ); - } - // diagonal term is zero - m_Lmatrix(i,i) = 0.0; - } + // the next term is independent of "j"; + // need to do it for the "j,j" term + sum -= m_Lmatrix(i,j+m_nsp); + } + m_Lmatrix(j,j+m_nsp) += sum; } - - - //////////////////////////////////////////////////////////////////////////// - - - void MultiTransport::eval_L0010(const doublereal* x) { - - doublereal prefactor = 1.6*m_temp; - - doublereal sum, wj, xj; - int i, j; - for (j = 0; j < m_nsp; j++) { - //constant = prefactor * x[j]; - xj = x[j]; - wj = m_mw[j]; - sum = 0.0; - for (i = 0; i < m_nsp; i++) { - m_Lmatrix(i,j + m_nsp) = - prefactor * x[i] * xj * m_mw[i] * - (1.2 * m_cstar(j,i) - 1.0) / - ( (wj + m_mw[i]) * m_bdiff(j,i) ); - - // the next term is independent of "j"; - // need to do it for the "j,j" term - sum -= m_Lmatrix(i,j+m_nsp); - } - m_Lmatrix(j,j+m_nsp) += sum; - } + } + //==================================================================================================================== + void MultiTransport::eval_L1000() { + int i, j; + for (j = 0; j < m_nsp; j++) { + for (i = 0; i < m_nsp; i++) { + m_Lmatrix(i+m_nsp,j) = m_Lmatrix(j,i+m_nsp); + } } + } + //==================================================================================================================== + void MultiTransport::eval_L1010(const doublereal* x) { + const doublereal fiveover3pi = 5.0/(3.0*Pi); + doublereal prefactor = (16.0*m_temp)/25.0; + int i, j; + doublereal constant1, wjsq, constant2, constant3, constant4, + fourmj, threemjsq, sum, sumwij;; + doublereal term1, term2; - //////////////////////////////////////////////////////////////////////// + for (j = 0; j < m_nsp; j++) { - void MultiTransport::eval_L1000() { - int i, j; - for (j = 0; j < m_nsp; j++) - for (i = 0; i < m_nsp; i++) - m_Lmatrix(i+m_nsp,j) = m_Lmatrix(j,i+m_nsp); - } + // get constant terms that depend on just species "j" + constant1 = prefactor*x[j]; + wjsq = m_mw[j]*m_mw[j]; + constant2 = 13.75*wjsq; + constant3 = m_crot[j]/m_rotrelax[j]; + constant4 = 7.5*wjsq; + fourmj = 4.0*m_mw[j]; + threemjsq = 3.0*m_mw[j]*m_mw[j]; + sum = 0.0; + for (i = 0; i < m_nsp; i++) { - ////////////////////////////////////////////////////////////////////// + sumwij = m_mw[i] + m_mw[j]; + term1 = m_bdiff(i,j) * sumwij*sumwij; + term2 = fourmj*m_astar(i,j)*(1.0 + fiveover3pi* + (constant3 + + (m_crot[i]/m_rotrelax[i]))); // see Eq. (12.125) - void MultiTransport::eval_L1010(const doublereal* x) { + m_Lmatrix(i+m_nsp,j+m_nsp) = constant1*x[i]*m_mw[i] /(m_mw[j]*term1) * + (constant2 - threemjsq*m_bstar(i,j) + - term2*m_mw[j]); - const doublereal fiveover3pi = 5.0/(3.0*Pi); - doublereal prefactor = (16.0*m_temp)/25.0; - - int i, j; - doublereal constant1, wjsq, constant2, constant3, constant4, - fourmj, threemjsq, sum, sumwij;; - doublereal term1, term2; - - for (j = 0; j < m_nsp; j++) { - - // get constant terms that depend on just species "j" - - constant1 = prefactor*x[j]; - wjsq = m_mw[j]*m_mw[j]; - constant2 = 13.75*wjsq; - constant3 = m_crot[j]/m_rotrelax[j]; - constant4 = 7.5*wjsq; - fourmj = 4.0*m_mw[j]; - threemjsq = 3.0*m_mw[j]*m_mw[j]; - sum = 0.0; - for (i = 0; i < m_nsp; i++) { - - sumwij = m_mw[i] + m_mw[j]; - term1 = m_bdiff(i,j) * sumwij*sumwij; - term2 = fourmj*m_astar(i,j)*(1.0 + fiveover3pi* - (constant3 + - (m_crot[i]/m_rotrelax[i]))); // see Eq. (12.125) - - m_Lmatrix(i+m_nsp,j+m_nsp) = constant1*x[i]*m_mw[i] /(m_mw[j]*term1) * - (constant2 - threemjsq*m_bstar(i,j) - - term2*m_mw[j]); - - sum += x[i] /(term1) * - (constant4 + m_mw[i]*m_mw[i]* - (6.25 - 3.0*m_bstar(i,j)) + term2*m_mw[i]); - } + sum += x[i] /(term1) * + (constant4 + m_mw[i]*m_mw[i]* + (6.25 - 3.0*m_bstar(i,j)) + term2*m_mw[i]); + } - m_Lmatrix(j+m_nsp,j+m_nsp) -= sum*constant1; - } - } - - - ////////////////////////////////////////////////////////////////////////////////// - - void MultiTransport::eval_L1001(const doublereal* x) { - - doublereal prefactor = 32.00*m_temp/(5.00*Pi); - int i,j; - doublereal constant, sum; - int n2 = 2*m_nsp; - int npoly = 0; - for (j = 0; j < m_nsp; j++) { - // collect terms that depend only on "j" - if (hasInternalModes(j)) { - constant = prefactor*m_mw[j]*x[j]*m_crot[j]/(m_cinternal[j]*m_rotrelax[j]); - sum = 0.0; - for (i = 0; i < m_nsp; i++) { - // see Eq. (12.127) - m_Lmatrix(i+m_nsp,j+n2) = constant * m_astar(j,i) * x[i] / - ( (m_mw[j] + m_mw[i] ) * m_bdiff(j,i)); - sum += m_Lmatrix(i+m_nsp,j+n2); - } - npoly++; - m_Lmatrix(j+m_nsp,j+n2) += sum; - } - else { - for (i = 0; i < m_nsp; i++) m_Lmatrix(i+m_nsp,j+n2) = 0.0; - } - } - } - - //////////////////////////////////////////////////////////////////////// - - void MultiTransport::eval_L0001() { - int i, j; - int n2 = 2*m_nsp; - for (j = 0; j < m_nsp; j++) - for (i = 0; i < m_nsp; i++) - m_Lmatrix(i,j+n2) = 0.0; - } - - //////////////////////////////////////////////////////////////////////// - - void MultiTransport::eval_L0100() { - int i, j; - int n2 = 2*m_nsp; - for (j = 0; j < m_nsp; j++) - for (i = 0; i < m_nsp; i++) - m_Lmatrix(i+n2,j) = 0.0; // see Eq. (12.123) - } - - //////////////////////////////////////////////////////////////////////// - - void MultiTransport::eval_L0110() { - int i, j; - int n2 = 2*m_nsp; - for (j = 0; j < m_nsp; j++) - for (i = 0; i < m_nsp; i++) - m_Lmatrix(i+n2,j+m_nsp) = m_Lmatrix(j+m_nsp,i+n2); // see Eq. (12.123) - } - - //////////////////////////////////////////////////////////////////////// - - - void MultiTransport::eval_L0101(const doublereal* x) { - - const doublereal fivepi = 5.00*Pi; - const doublereal eightoverpi = 8.0 / Pi; - - doublereal prefactor = 4.00*m_temp; - int n2 = 2*m_nsp; - int i,k; - doublereal constant1, constant2, diff_int, sum; - for (i = 0; i < m_nsp; i++) { - if (hasInternalModes(i)) { - // collect terms that depend only on "i" - constant1 = prefactor*x[i]/m_cinternal[i]; - constant2 = 12.00*m_mw[i]*m_crot[i] / - (fivepi*m_cinternal[i]*m_rotrelax[i]); - sum = 0.0; - for (k = 0; k < m_nsp; k++) { - // see Eq. (12.131) - diff_int = m_bdiff(i,k); - m_Lmatrix(k+n2,i+n2) = 0.0; - sum += x[k]/diff_int; - if (k != i) sum += x[k]*m_astar(i,k)*constant2 / - (m_mw[k]*diff_int); - } - // see Eq. (12.130) - m_Lmatrix(i+n2,i+n2) = - - eightoverpi*m_mw[i]*x[i]*x[i]*m_crot[i] / - (m_cinternal[i]*m_cinternal[i]*GasConstant*m_visc[i]*m_rotrelax[i]) - - constant1*sum; - } - else { - for (k = 0; k < m_nsp; k++) - m_Lmatrix(i+n2,i+n2) = 1.0; - } + m_Lmatrix(j+m_nsp,j+m_nsp) -= sum*constant1; + } + } + //==================================================================================================================== + void MultiTransport::eval_L1001(const doublereal* x) { + + doublereal prefactor = 32.00*m_temp/(5.00*Pi); + int i,j; + doublereal constant, sum; + int n2 = 2*m_nsp; + int npoly = 0; + for (j = 0; j < m_nsp; j++) { + // collect terms that depend only on "j" + if (hasInternalModes(j)) { + constant = prefactor*m_mw[j]*x[j]*m_crot[j]/(m_cinternal[j]*m_rotrelax[j]); + sum = 0.0; + for (i = 0; i < m_nsp; i++) { + // see Eq. (12.127) + m_Lmatrix(i+m_nsp,j+n2) = constant * m_astar(j,i) * x[i] / + ( (m_mw[j] + m_mw[i] ) * m_bdiff(j,i)); + sum += m_Lmatrix(i+m_nsp,j+n2); + } + npoly++; + m_Lmatrix(j+m_nsp,j+n2) += sum; + } + else { + for (i = 0; i < m_nsp; i++) m_Lmatrix(i+m_nsp,j+n2) = 0.0; + } + } + } + //==================================================================================================================== + + void MultiTransport::eval_L0001() { + int i, j; + int n2 = 2*m_nsp; + for (j = 0; j < m_nsp; j++) { + for (i = 0; i < m_nsp; i++) { + m_Lmatrix(i,j+n2) = 0.0; + } + } + } + //==================================================================================================================== + + void MultiTransport::eval_L0100() { + int i, j; + int n2 = 2*m_nsp; + for (j = 0; j < m_nsp; j++) + for (i = 0; i < m_nsp; i++) + m_Lmatrix(i+n2,j) = 0.0; // see Eq. (12.123) + } + //==================================================================================================================== + + void MultiTransport::eval_L0110() { + int i, j; + int n2 = 2*m_nsp; + for (j = 0; j < m_nsp; j++) + for (i = 0; i < m_nsp; i++) + m_Lmatrix(i+n2,j+m_nsp) = m_Lmatrix(j+m_nsp,i+n2); // see Eq. (12.123) + } + //==================================================================================================================== + void MultiTransport::eval_L0101(const doublereal* x) { + + const doublereal fivepi = 5.00*Pi; + const doublereal eightoverpi = 8.0 / Pi; + + doublereal prefactor = 4.00*m_temp; + int n2 = 2*m_nsp; + int i,k; + doublereal constant1, constant2, diff_int, sum; + for (i = 0; i < m_nsp; i++) { + if (hasInternalModes(i)) { + // collect terms that depend only on "i" + constant1 = prefactor*x[i]/m_cinternal[i]; + constant2 = 12.00*m_mw[i]*m_crot[i] / + (fivepi*m_cinternal[i]*m_rotrelax[i]); + sum = 0.0; + for (k = 0; k < m_nsp; k++) { + // see Eq. (12.131) + diff_int = m_bdiff(i,k); + m_Lmatrix(k+n2,i+n2) = 0.0; + sum += x[k]/diff_int; + if (k != i) sum += x[k]*m_astar(i,k)*constant2 / + (m_mw[k]*diff_int); + } + // see Eq. (12.130) + m_Lmatrix(i+n2,i+n2) = + - eightoverpi*m_mw[i]*x[i]*x[i]*m_crot[i] / + (m_cinternal[i]*m_cinternal[i]*GasConstant*m_visc[i]*m_rotrelax[i]) + - constant1*sum; + } + else { + for (k = 0; k < m_nsp; k++) { + m_Lmatrix(i+n2,i+n2) = 1.0; } + } } + } } - +//====================================================================================================================== #endif diff --git a/Cantera/src/transport/LiquidTranInteraction.cpp b/Cantera/src/transport/LiquidTranInteraction.cpp new file mode 100644 index 000000000..7d52b2127 --- /dev/null +++ b/Cantera/src/transport/LiquidTranInteraction.cpp @@ -0,0 +1,866 @@ +/** + * @file LiquidTransportParams.cpp + * Source code for liquid mixture transport property evaluations. + */ +/* + * Latest Checkin: + * $Author$ + * $Date$ + * $Revision$ + */ + +#include "LiquidTransportParams.h" +#include +#include "IonsFromNeutralVPSSTP.h" +#include "MargulesVPSSTP.h" +#include +using namespace std; +using namespace ctml; + +namespace Cantera { + + /** + * Exception thrown if an error is encountered while reading the + * transport database. + */ + class LTPError : public CanteraError { + public: + LTPError(std::string msg ) + : CanteraError("LTPspecies", + "error parsing transport data: " + + msg + "\n") {} + }; + + /** + * Exception thrown if an error is encountered while reading the + * transport database. + */ + class LTPmodelError : public CanteraError { + public: + LTPmodelError(std::string msg ) + : CanteraError("LTPspecies", + "error parsing transport data: " + + msg + "\n") {} + }; + + + // Constructor + /* + * @param tp_ind Index indicating transport property type (i.e. viscosity) + */ + LiquidTranInteraction::LiquidTranInteraction(TransportPropertyType tp_ind ) : + m_model(LTI_MODEL_NOTSET), + m_property(tp_ind) + { + } + + LiquidTranInteraction::~LiquidTranInteraction() { + int kmax = m_Aij.size(); + for (int k = 0; k < kmax; k++) { + if (m_Aij[k] ) delete m_Aij[k]; + } + kmax = m_Bij.size(); + for (int k = 0; k < kmax; k++) { + if (m_Bij[k] ) delete m_Bij[k]; + } + kmax = m_Hij.size(); + for (int k = 0; k < kmax; k++) { + if (m_Hij[k] ) delete m_Hij[k]; + } + kmax = m_Sij.size(); + for (int k = 0; k < kmax; k++) { + if (m_Sij[k] ) delete m_Sij[k]; + } + } + + //==================================================================================================================== + + void LiquidTranInteraction::init(const XML_Node &compModelNode, + thermo_t* thermo ) + { + + m_thermo = thermo; + + int nsp = thermo->nSpecies(); + m_Dij.resize(nsp, nsp, 0.0 ); + m_Eij.resize(nsp, nsp, 0.0 ); + /* + m_Aij.resize(nsp); + m_Bij.resize(nsp); + m_Hij.resize(nsp); + m_Sij.resize(nsp); + for (int k = 0; k < nsp; k++ ){ + (*m_Aij[k]).resize(nsp, nsp, 0.0); + (*m_Bij[k]).resize(nsp, nsp, 0.0); + (*m_Hij[k]).resize(nsp, nsp, 0.0); + (*m_Sij[k]).resize(nsp, nsp, 0.0); + } + */ + + std::string speciesA; + std::string speciesB; + + int num = compModelNode.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = compModelNode.child(iChild); + std::string nodeName = lowercase(xmlChild.name()); + if (nodeName != "interaction") { + throw CanteraError("TransportFactory::getLiquidInteractionsTransportData", + "expected element and got <" + nodeName + ">" ); + } + speciesA = xmlChild.attrib("speciesA"); + speciesB = xmlChild.attrib("speciesB"); + int iSpecies = m_thermo->speciesIndex(speciesA ); + if (iSpecies < 0) { + throw CanteraError("TransportFactory::getLiquidInteractionsTransportData", + "Unknown species " + speciesA ); + } + int jSpecies = m_thermo->speciesIndex(speciesB ); + if (jSpecies < 0) { + throw CanteraError("TransportFactory::getLiquidInteractionsTransportData", + "Unknown species " + speciesB ); + } + /* if (xmlChild.hasChild("Aij" ) ) { + m_Aij(iSpecies,jSpecies) = getFloat(xmlChild, "Aij", "toSI" ); + m_Aij(jSpecies,iSpecies) = m_Aij(iSpecies,jSpecies) ; + }*/ + + if (xmlChild.hasChild("Eij" ) ) { + m_Eij(iSpecies,jSpecies) = getFloat(xmlChild, "Eij", "actEnergy" ); + m_Eij(iSpecies,jSpecies) /= GasConstant; + m_Eij(jSpecies,iSpecies) = m_Eij(iSpecies,jSpecies) ; + } + + if (xmlChild.hasChild("Aij")) { + vector_fp poly; + // poly0 = getFloat(poly, xmlChild, "Aij", "toSI" ); + getFloatArray(xmlChild, poly, true, "toSI", "Aij"); + // if (!poly.size() ) poly.push_back(poly0); + while (m_Aij.size()resize(nsp, nsp, 0.0); + m_Aij.push_back(aTemp); + } + for (int i = 0; i < (int)poly.size(); i++ ) { + (*m_Aij[i])(iSpecies,jSpecies) = poly[i]; + //(*m_Aij[i])(jSpecies,iSpecies) = (*m_Aij[i])(iSpecies,jSpecies) ; + } + } + + if (xmlChild.hasChild("Bij" ) ) { + vector_fp poly; + getFloatArray(xmlChild, poly, true, "toSI", "Bij"); + //if (!poly.size() ) poly.push_back(poly0); + while (m_Bij.size() < poly.size()) { + DenseMatrix * bTemp = new DenseMatrix(); + bTemp->resize(nsp, nsp, 0.0); + m_Bij.push_back(bTemp); + } + for(int i=0; i<(int)poly.size(); i++ ){ + (*m_Bij[i])(iSpecies,jSpecies) = poly[i]; + //(*m_Bij[i])(jSpecies,iSpecies) = (*m_Bij[i])(iSpecies,jSpecies) ; + } + } + + if (xmlChild.hasChild("Hij" ) ) { + vector_fp poly; + // poly0 = getFloat(poly, xmlChild, "Hij", "actEnergy" ); + getFloatArray(xmlChild, poly, true, "actEnergy", "Hij"); + // if (!poly.size() ) poly.push_back(poly0); + while (m_Hij.size()resize(nsp, nsp, 0.0); + m_Hij.push_back(hTemp); + } + for(int i=0; i<(int)poly.size(); i++ ){ + (*m_Hij[i])(iSpecies,jSpecies) = poly[i]; + (*m_Hij[i])(iSpecies,jSpecies) /= GasConstant; + //(*m_Hij[i])(jSpecies,iSpecies) = (*m_Hij[i])(iSpecies,jSpecies) ; + } + } + + if (xmlChild.hasChild("Sij" ) ) { + vector_fp poly; + // poly0 = getFloat(poly, xmlChild, "Sij", "actEnergy" ); + getFloatArray(xmlChild, poly, true, "actEnergy", "Sij"); + // if (!poly.size() ) poly.push_back(poly0); + while (m_Sij.size()resize(nsp, nsp, 0.0); + m_Sij.push_back(sTemp); + } + for(int i=0; i<(int)poly.size(); i++ ){ + (*m_Sij[i])(iSpecies,jSpecies) = poly[i]; + (*m_Sij[i])(iSpecies,jSpecies) /= GasConstant; + //(*m_Sij[i])(jSpecies,iSpecies) = (*m_Sij[i])(iSpecies,jSpecies) ; + } + } + + /*0 if (xmlChild.hasChild("Sij" ) ) { + m_Sij(iSpecies,jSpecies) = getFloat(xmlChild, "Sij", "toSI" ); + m_Sij(iSpecies,jSpecies) /= GasConstant; + //m_Sij(jSpecies,iSpecies) = m_Sij(iSpecies,jSpecies) ; + }*/ + + if (xmlChild.hasChild("Dij" ) ) { + m_Dij(iSpecies,jSpecies) = getFloat(xmlChild, "Dij", "toSI" ); + m_Dij(jSpecies,iSpecies) = m_Dij(iSpecies,jSpecies) ; + } + } + } + + // Copy constructor + LiquidTranInteraction::LiquidTranInteraction(const LiquidTranInteraction &right ) { + *this = right; //use assignment operator to do other work + } + + // Assignment operator + LiquidTranInteraction& LiquidTranInteraction::operator=(const LiquidTranInteraction &right ) + { + if (&right != this) { + m_model = right.m_model; + m_property = right.m_property; + m_thermo = right.m_thermo; + //m_trParam = right.m_trParam; + m_Aij = right.m_Aij; + m_Bij = right.m_Bij; + m_Eij = right.m_Eij; + m_Hij = right.m_Hij; + m_Sij = right.m_Sij; + m_Dij = right.m_Dij; + } + return *this; + } + + + //==================================================================================================================== + LTI_Solvent::LTI_Solvent(TransportPropertyType tp_ind) : + LiquidTranInteraction(tp_ind) + { + m_model = LTI_MODEL_SOLVENT; + } + //==================================================================================================================== + + doublereal LTI_Solvent::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0.0; + + //if weightings are specified, use those + if (speciesWeight) { + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]; + // should be: molefracs[k] = molefracs[k]*speciesWeight[k]; for consistency, but weight(solvent)=1? + } + } + else { + throw CanteraError("LTI_Solvent::getMixTransProp","You should be specifying the speciesWeight"); + /* //This does not follow directly a solvent model + //although if the solvent mole fraction is dominant + //and the other species values are given or zero, + //it should work. + for (int k = 0; k < nsp; k++) { + value += speciesValues[k] * molefracs[k]; + }*/ + } + + for (int i = 0; i < nsp; i++ ){ + //presume that the weighting is set to 1.0 for solvent and 0.0 for everything else. + value += speciesValues[i] * speciesWeight[i]; + if (i == 0) { + AssertTrace(speciesWeight[i] == 1.0); + } else { + AssertTrace(speciesWeight[i] == 0.0); + } + for (int j = 0; j < nsp; j++ ) { + for (int k = 0; k < (int)m_Aij.size(); k++) { + value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i],k); + } + for (int k = 0; k < (int)m_Bij.size(); k++) { + value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i],k); + } + } + } + + return value; + } + //==================================================================================================================== + doublereal LTI_Solvent::getMixTransProp(std::vector LTPptrs ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0.0; + + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]; + // should be: molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight(); for consistency, but weight(solvent)=1? + } + + for (int i = 0; i < nsp; i++) { + //presume that the weighting is set to 1.0 for solvent and 0.0 for everything else. + value += LTPptrs[i]->getSpeciesTransProp() * LTPptrs[i]->getMixWeight(); + for (int j = 0; j < nsp; j++) { + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i],k); + } + for (int k = 0; k < (int)m_Bij.size(); k++) { + value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i],k); + } + } + } + + return value; + } + //==================================================================================================================== + void LTI_Solvent::getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues) { + mat = (*m_Aij[0]); + } + //==================================================================================================================== + + + doublereal LTI_MoleFracs::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + //if weightings are specified, use those + if (speciesWeight) { + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]*speciesWeight[k]; + } + } + else { + throw CanteraError("LTI_MoleFracs::getMixTransProp","You should be specifying the speciesWeight"); + } + + for (int i = 0; i < nsp; i++ ){ + value += speciesValues[i] * molefracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i],k); + } + for (int k = 0; k < (int)m_Bij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i],k); + } + } + } + + return value; + } + + + doublereal LTI_MoleFracs::getMixTransProp(std::vector LTPptrs ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight(); + } + + for (int i = 0; i < nsp; i++ ){ + value += LTPptrs[i]->getSpeciesTransProp() * molefracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i],k); + } + for (int k = 0; k < (int)m_Bij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i],k); + } + } + } + return value; + } + + + doublereal LTI_MassFracs::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal massfracs[nsp]; + m_thermo->getMassFractions(massfracs); + + doublereal value = 0; + + //if weightings are specified, use those + if (speciesWeight ) { + for (int k = 0; k < nsp; k++) { + massfracs[k] = massfracs[k]*speciesWeight[k]; + } + } + else { + throw CanteraError("LTI_MassFracs::getMixTransProp","You should be specifying the speciesWeight"); + } + + for (int i = 0; i < nsp; i++ ){ + value += speciesValues[i] * massfracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += massfracs[i]*massfracs[j]*(*m_Aij[k])(i,j)*pow(massfracs[i],k); + } + for (int k = 0; k < (int)m_Bij.size(); k++ ){ + value += massfracs[i]*massfracs[j]*(*m_Bij[k])(i,j)*temp*pow(massfracs[i],k); + } + } + } + + return value; + } + + + doublereal LTI_MassFracs::getMixTransProp(std::vector LTPptrs ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal massfracs[nsp]; + m_thermo->getMassFractions(massfracs); + + doublereal value = 0; + + for (int k = 0; k < nsp; k++) { + massfracs[k] = massfracs[k]*LTPptrs[k]->getMixWeight(); + } + + for (int i = 0; i < nsp; i++ ){ + value += LTPptrs[i]->getSpeciesTransProp() * massfracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += massfracs[i]*massfracs[j]*(*m_Aij[k])(i,j)*pow(massfracs[i],k); + } + for (int k = 0; k < (int)m_Bij.size(); k++ ){ + value += massfracs[i]*massfracs[j]*(*m_Bij[k])(i,j)*temp*pow(massfracs[i],k); + } + } + } + + return value; + } + + + + + doublereal LTI_Log_MoleFracs::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + + + doublereal value = 0; + + //if weightings are specified, use those + if (speciesWeight ) { + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]*speciesWeight[k]; + } + } + else{ + throw CanteraError("LTI_Log_MoleFracs::getMixTransProp","You probably should have a speciesWeight when you call getMixTransProp to convert ion mole fractions to molecular mole fractions"); + } + + for (int i = 0; i < nsp; i++ ){ + value += log(speciesValues[i] ) * molefracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Hij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Hij[k])(i,j)/temp*pow(molefracs[i],k); + //cout << "value = " << value << ", m_Sij = " << (*m_Sij[k])(i,j) << ", m_Hij = " << (*m_Hij[k])(i,j) << endl; + } + for (int k = 0; k < (int)m_Sij.size(); k++ ){ + value -= molefracs[i]*molefracs[j]*(*m_Sij[k])(i,j)*pow(molefracs[i],k); + //cout << "value = " << value << ", m_Sij = " << (*m_Sij[k])(i,j) << ", m_Hij = " << (*m_Hij[k])(i,j) << endl; + } + } + } + + value = exp(value ); + return value; + } + + + doublereal LTI_Log_MoleFracs::getMixTransProp(std::vector LTPptrs) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + + doublereal value = 0; + + //if weightings are specified, use those + + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight(); + } + + for (int i = 0; i < nsp; i++ ){ + value += log(LTPptrs[i]->getSpeciesTransProp() ) * molefracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Hij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Hij[k])(i,j)/temp*pow(molefracs[i],k); + //cout << "1 = " << molefracs[i]+molefracs[j] << endl; + //cout << "value = " << value << ", m_Sij = " << (*m_Sij[k])(i,j) << ", m_Hij = " << (*m_Hij[k])(i,j) << endl; + } + for (int k = 0; k < (int)m_Sij.size(); k++ ){ + value -= molefracs[i]*molefracs[j]*(*m_Sij[k])(i,j)*pow(molefracs[i],k); + //cout << "1 = " << molefracs[i]+molefracs[j] << endl; + //cout << "value = " << value << ", m_Sij = " << (*m_Sij[k])(i,j) << ", m_Hij = " << (*m_Hij[k])(i,j) << endl; + } + } + } + + value = exp(value ); + // cout << ", viscSpeciesA = " << LTPptrs[0]->getSpeciesTransProp() << endl; + //cout << ", viscSpeciesB = " << LTPptrs[1]->getSpeciesTransProp() << endl; + //cout << "value = " << value << " FINAL" << endl; + return value; + } + + + + + + void LTI_Pairwise_Interaction::setParameters(LiquidTransportParams& trParam) { + int nsp = m_thermo->nSpecies(); + m_diagonals.resize(nsp, 0); + + for (int k = 0; k < nsp; k++) { + Cantera::LiquidTransportData <d = trParam.LTData[k]; + if (ltd.speciesDiffusivity) + m_diagonals[k] = ltd.speciesDiffusivity; + } + } + + doublereal LTI_Pairwise_Interaction::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight) { + + int nsp = m_thermo->nSpecies(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + throw LTPmodelError("Calling LTI_Pairwise_Interaction::getMixTransProp does not make sense." ); + + return value; + } + + + doublereal LTI_Pairwise_Interaction::getMixTransProp(std::vector LTPptrs) { + + int nsp = m_thermo->nSpecies(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + throw LTPmodelError("Calling LTI_Pairwise_Interaction::getMixTransProp does not make sense." ); + + return value; + } + + void LTI_Pairwise_Interaction::getMatrixTransProp(DenseMatrix &mat, doublereal *speciesValues ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs ); + + mat.resize(nsp, nsp, 0.0 ); + for (int i = 0; i < nsp; i++ ) + for (int j = 0; j < i; j++ ) + mat(i,j) = mat(j,i) = exp(m_Eij(i,j) / temp ) / m_Dij(i,j); + + for (int i = 0; i < nsp; i++ ) + if (mat(i,i) == 0.0 && m_diagonals[i] ) + mat(i,i) = 1.0 / m_diagonals[i]->getSpeciesTransProp() ; + } + + + void LTI_StefanMaxwell_PPN::setParameters(LiquidTransportParams& trParam ) { + int nsp = m_thermo->nSpecies(); + int nsp2 = nsp*nsp; + //vectornSpecies(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + throw LTPmodelError("Calling LTI_StefanMaxwell_PPN::getMixTransProp does not make sense." ); + + return value; + } + + + doublereal LTI_StefanMaxwell_PPN::getMixTransProp(std::vector LTPptrs ) { + + int nsp = m_thermo->nSpecies(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + throw LTPmodelError("Calling LTI_StefanMaxwell_PPN::getMixTransProp does not make sense." ); + + return value; + } + + void LTI_StefanMaxwell_PPN::getMatrixTransProp(DenseMatrix &mat, doublereal *speciesValues ) { + //CAL + + IonsFromNeutralVPSSTP * ions_thermo = dynamic_cast(m_thermo); + int i, j, k; + int nsp = m_thermo->nSpecies(); + if (nsp != 3) { + throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Function may only be called with a 3-ion system"); + } + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs ); + vector_fp neut_molefracs; + ions_thermo->getNeutralMolecMoleFractions(neut_molefracs); + vector cation; + vector anion; + ions_thermo->getCationList(cation); + ions_thermo->getAnionList(anion); + + // Reaction Coeffs and Charges + std::vector viS(6); + std::vector charges(3); + std::vector neutMolIndex(3); + ions_thermo->getDissociationCoeffs(viS,charges,neutMolIndex); + + if ((int)anion.size() != 1) { + throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Must have one anion only for StefanMaxwell_PPN"); + } + if ((int)cation.size() != 2) { + throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Must have two cations of equal charge for StefanMaxwell_PPN"); + } + if (charges[cation[0]] != charges[cation[1]]) { + throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Cations must be of equal charge for StefanMaxwell_PPN"); + } + + m_ionCondMix = m_ionCondMixModel->getMixTransProp(m_ionCondSpecies); + + MargulesVPSSTP * marg_thermo = dynamic_cast (ions_thermo->neutralMoleculePhase_); + doublereal vol = m_thermo->molarVolume(); + + k = 0; + for (j = 0; j < nsp; j++) { + for (i = 0; i < nsp; i++) { + if (m_mobRatMixModel[k]) { + m_mobRatMix(i,j) = m_mobRatMixModel[k]->getMixTransProp(m_mobRatSpecies[k] ); + if (m_mobRatMix(i,j) > 0.0) { + m_mobRatMix(j,i) = 1.0/m_mobRatMix(i,j); + } + } + k++; + } + } + + + for (k = 0; k < nsp; k++) { + m_selfDiffMix[k] = m_selfDiffMixModel[k]->getMixTransProp(m_selfDiffSpecies[k] ); + } + + int vP = max(viS[cation[0]],viS[cation[1]]); + int vM = viS[anion[0]]; + int zP = charges[cation[0]]; + int zM = charges[anion[0]]; + doublereal xA, xB, eps; + doublereal inv_vP_vM_MutualDiff; + vector_fp dlnActCoeffdlnN_diag; + dlnActCoeffdlnN_diag.resize(neut_molefracs.size(),0.0); + marg_thermo->getdlnActCoeffdlnN_diag(&dlnActCoeffdlnN_diag[0]); + + xA = neut_molefracs[neutMolIndex[cation[0]]]; + xB = neut_molefracs[neutMolIndex[cation[1]]]; + eps = (1-m_mobRatMix(cation[1],cation[0]))/(xA+xB*m_mobRatMix(cation[1],cation[0])); + inv_vP_vM_MutualDiff = (xA*(1-xB+dlnActCoeffdlnN_diag[neutMolIndex[cation[1]]])/m_selfDiffMix[cation[1]]+xB*(1-xA+dlnActCoeffdlnN_diag[neutMolIndex[cation[0]]])/m_selfDiffMix[cation[0]]); + + mat.resize(nsp, nsp, 0.0 ); + mat(cation[0],cation[1]) = mat(cation[1],cation[0]) = (1+vM/vP)*(1+eps*xB)*(1-eps*xA)*inv_vP_vM_MutualDiff-zP*zP*Faraday*Faraday/GasConstant/temp/m_ionCondMix/vol; + mat(cation[0],anion[0]) = mat(anion[0],cation[0]) = (1+vP/vM)*(-eps*xB*(1-eps*xA)*inv_vP_vM_MutualDiff)-zP*zM*Faraday*Faraday/GasConstant/temp/m_ionCondMix/vol; + mat(cation[1],anion[0]) = mat(anion[0],cation[1]) = (1+vP/vM)*(eps*xA*(1+eps*xB)*inv_vP_vM_MutualDiff)-zP*zM*Faraday*Faraday/GasConstant/temp/m_ionCondMix/vol; + + } + + + doublereal LTI_StokesEinstein::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight ) { + + int nsp = m_thermo->nSpecies(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + throw LTPmodelError("Calling LTI_StokesEinstein::getMixTransProp does not make sense." ); + + return value; + } + + + doublereal LTI_StokesEinstein::getMixTransProp(std::vector LTPptrs ) { + + int nsp = m_thermo->nSpecies(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + throw LTPmodelError("Calling LTI_StokesEinstein::getMixTransProp does not make sense." ); + + return value; + } + + + + void LTI_StokesEinstein::setParameters(LiquidTransportParams& trParam ) { + int nsp = m_thermo->nSpecies(); + m_viscosity.resize(nsp, 0 ); + m_hydroRadius.resize(nsp, 0 ); + for (int k = 0; k < nsp; k++) { + Cantera::LiquidTransportData <d = trParam.LTData[k]; + m_viscosity[k] = ltd.viscosity; + m_hydroRadius[k] = ltd.hydroRadius; + } + } + + void LTI_StokesEinstein::getMatrixTransProp(DenseMatrix &mat, doublereal *speciesValues ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + + double *viscSpec = new double(nsp); + double *radiusSpec = new double(nsp); + + for (int k = 0; k < nsp; k++) { + viscSpec[k] = m_viscosity[k]->getSpeciesTransProp() ; + radiusSpec[k] = m_hydroRadius[k]->getSpeciesTransProp() ; + } + + mat.resize(nsp,nsp, 0.0); + for (int i = 0; i < nsp; i++) + for (int j = 0; j < nsp; j++) { + mat(i,j) = (6.0 * Pi * radiusSpec[i] * viscSpec[j] ) / GasConstant / temp; + } + delete radiusSpec; + delete viscSpec; + } + + doublereal LTI_MoleFracs_ExpT::getMixTransProp(doublereal *speciesValues, doublereal *speciesWeight ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + //if weightings are specified, use those + if (speciesWeight ) { + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]*speciesWeight[k]; + } + } + else { + throw CanteraError("LTI_MoleFracs_ExpT::getMixTransProp","You should be specifying the speciesWeight"); + } + + for (int i = 0; i < nsp; i++ ){ + value += speciesValues[i] * molefracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i],k)*exp((*m_Bij[k])(i,j)*temp); + } + } + } + + return value; + } + + + doublereal LTI_MoleFracs_ExpT::getMixTransProp(std::vector LTPptrs ) { + + int nsp = m_thermo->nSpecies(); + doublereal temp = m_thermo->temperature(); + doublereal molefracs[nsp]; + m_thermo->getMoleFractions(molefracs); + + doublereal value = 0; + + for (int k = 0; k < nsp; k++) { + molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight(); + } + + for (int i = 0; i < nsp; i++ ){ + value += LTPptrs[i]->getSpeciesTransProp() * molefracs[i]; + for (int j = 0; j < nsp; j++ ){ + for (int k = 0; k < (int)m_Aij.size(); k++ ){ + value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i],k)*exp((*m_Bij[k])(i,j)*temp); + } + } + } + return value; + } + + + +} //namespace Cantera diff --git a/Cantera/src/transport/LiquidTranInteraction.h b/Cantera/src/transport/LiquidTranInteraction.h new file mode 100644 index 000000000..5b8353911 --- /dev/null +++ b/Cantera/src/transport/LiquidTranInteraction.h @@ -0,0 +1,685 @@ +/** + * @file LiquidTranInteraction.h + * Header file defining the class LiquidTranInteraction and classes which + * derive from LiquidTranInteraction. + */ +/* + * $Author: christopher.lueth@gmail.com $ + * $Date: 2010-03-30 12:30:39 -0600 (Tue, 30 Mar 2010) $ + * $Revision: 427 $ + * + */ +#ifndef CT_LIQUIDTRANINTERACTION_H +#define CT_LIQUIDTRANINTERACTION_H + +#include "ct_defs.h" +#include "TransportBase.h" +#include "TransportParams.h" +#include "LiquidTransportData.h" +#include "xml.h" +#include "XML_Writer.h" + +namespace Cantera { + + + //! Composition dependence type for liquid mixture transport properties + /*! + * Types of temperature dependencies: + * - 0 - Mixture calculations with this property are not allowed + * - 1 - Use solvent (species 0) properties + * - 2 - Properties weighted linearly by mole fractions + * - 3 - Properties weighted linearly by mass fractions + * - 4 - Properties weighted logarithmically by mole fractions (interaction energy weighting) + * - 5 - Interactions given pairwise between each possible species (i.e. D_ij) + * + * \verbatim + * + * + * + * + * LiCl(L) + * KCl(L) + * -1.0 + * 1.0E-1 + * -or- + * 1.0E-1, 0.001 0.01 + * + * -same form for Hij,Aij,Bij- + * + * + * + * + * + * + * Li+ + * K+ + * 1.5 + * + * + * K+ + * Cl- + * 1.0 + * + * + * Li+ + * Cl- + * 1.2 + * + * + * + * + * + * + * + * + * + * + * \endverbatim + * + */ + + enum LiquidTranMixingModel { + LTI_MODEL_NOTSET=-1, + LTI_MODEL_NONE, + LTI_MODEL_SOLVENT, + LTI_MODEL_MOLEFRACS, + LTI_MODEL_MASSFRACS, + LTI_MODEL_LOG_MOLEFRACS, + LTI_MODEL_PAIRWISE_INTERACTION, + LTI_MODEL_STEFANMAXWELL_PPN, + LTI_MODEL_STOKES_EINSTEIN, + LTI_MODEL_MOLEFRACS_EXPT + }; + + + //! Base class to handle transport property evaluation in a mixture. + /*! + * In a mixture, the mixture transport properties will generally depend on + * the contributions of each of the pure species transport properties. + * Many composition dependencies are possible. This class, + * LiquidTranInteraction, is designed to be a base class for the + * implementation of various models for the mixing of pure species + * transport properties. + * + * There are two very broad types of transport properties to consider. + * First, there are properties for which a mixture value can be + * obtained through some mixing rule. These are obtained using the + * method getMixTransProp(). Viscosity is typical of this. + * Second there are properties for which a matrix of properties may + * @param tp_ind + * exist. This matrix of properties is obtained from the method + * getMatrixTransProp(). Diffusion coefficients are of this type. + * Subclasses should implement the appropriate one or both of + * these methods. + * + */ + class LiquidTranInteraction { + + public: + //! Constructor + /** + * @param tp_ind Index indicating transport property type (i.e. viscosity) + */ + LiquidTranInteraction(TransportPropertyType tp_ind = TP_UNKNOWN); + + //! Copy constructor + LiquidTranInteraction(const LiquidTranInteraction &right); + + //! Assignment operator + LiquidTranInteraction& operator=(const LiquidTranInteraction &right ); + + //! destructor + virtual ~LiquidTranInteraction(); + + //! initialize LiquidTranInteraction objects with thermo and XML node + /** + * @param compModelNode \verbatim \endverbatim XML node + * @param thermo Pointer to thermo object + */ + virtual void init(const XML_Node &compModelNode = 0, + thermo_t* thermo = 0 ); + + virtual void setParameters( LiquidTransportParams& trParam ) { ; } + + //! Return the mixture transport property value. + //! (Must be implemented in subclasses.) + virtual doublereal getMixTransProp(doublereal* speciesValues, doublereal *weightSpecies = 0 ) { + throw NotImplemented("LiquidTranInteraction::getMixTransProp"); + } + + virtual doublereal getMixTransProp(std::vector LTPptrs ) { + throw NotImplemented("LiquidTranInteraction::getMixTransProp"); + } + + virtual void getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues = 0 ) { + //mat = m_Dij; + throw NotImplemented("LiquidTranInteraction::getMixTransProp"); + } + + protected: + //! Model for species interaction effects + //! Takes enum LiquidTranMixingModel + LiquidTranMixingModel m_model; + + //! enum indicating what property this is (i.e viscosity) + TransportPropertyType m_property; + + //! pointer to thermo object to get current temperature + thermo_t* m_thermo; + + //LiquidTransportParams* m_trParam; + + //! Matrix of interaction coefficients for polynomial in molefraction*weight of + //! speciesA (no temperature dependence, dimensionless) + std::vector m_Aij; + + //! Matrix of interaction coefficients for polynomial in molefraction*weight of + //! speciesA (linear temperature dependence, units 1/K) + std::vector m_Bij; + + //! Matrix of interactions (in energy units, 1/RT temperature dependence) + DenseMatrix m_Eij; + + //! Matrix of interaction coefficients for polynomial in molefraction*weight of + //! speciesA (in energy units, 1/RT temperature dependence) + std::vector m_Hij; + + //! Matrix of interaction coefficients for polynomial in molefraction*weight of + //! speciesA (in entropy units, divided by R) + std::vector m_Sij; + + //! Matrix of interactions + DenseMatrix m_Dij; + }; + + class LTI_Solvent : public LiquidTranInteraction { + + public: + LTI_Solvent(TransportPropertyType tp_ind = TP_UNKNOWN); + + //! Copy constructor + // LTI_Solvent( const LTI_Solvent &right ); + + //! Assignment operator + // LTI_Solvent& operator=( const LTI_Solvent &right ); + + virtual ~LTI_Solvent( ) { } + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point). + */ + doublereal getMixTransProp(doublereal *valueSpecies, doublereal *weightSpecies = 0); + doublereal getMixTransProp(std::vector LTPptrs) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them: Not implemented for this mixing rule. + */ + void getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues = 0 ); + + protected: + + }; + + //! Simple mole fraction weighting of transport properties + /** + * This model weights the transport property by the mole + * fractions. + * The overall formula for the mixture viscosity is + * + * \f[ + * \eta_{mix} = \sum_i X_i \eta_i + \sum_i \sum_j X_i X_j A_{i,j} + * \f] + */ + class LTI_MoleFracs : public LiquidTranInteraction { + + public: + LTI_MoleFracs( TransportPropertyType tp_ind = TP_UNKNOWN ) : + LiquidTranInteraction( tp_ind ) + { + m_model = LTI_MODEL_MOLEFRACS; + } + + + //! Copy constructor + // LTI_MoleFracs( const LTI_MoleFracs &right ); + + //! Assignment operator + // LTI_MoleFracs& operator=( const LTI_MoleFracs &right ); + + virtual ~LTI_MoleFracs( ) { } + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp( doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp( std::vector LTPptrs ) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them: Not Implemented for this Mixing rule; + */ + void getMatrixTransProp( DenseMatrix &mat, doublereal* speciesValues = 0 ) { mat = (*m_Aij[0]); } + + protected: + + }; + + + //! Simple mass fraction weighting of transport properties + /*! + * This model weights the transport property by the mass + * fractions. + * The overall formula for the mixture viscosity is + * + * \f[ + * \eta_{mix} = \sum_i Y_i \eta_i + * + \sum_i \sum_j Y_i Y_j A_{i,j} + * \f]. + */ + class LTI_MassFracs : public LiquidTranInteraction { + + public: + + LTI_MassFracs(TransportPropertyType tp_ind = TP_UNKNOWN) : + LiquidTranInteraction( tp_ind ) + { + m_model = LTI_MODEL_MASSFRACS; + } + + + //! Copy constructor + // LTI_MassFracs( const LTI_MassFracs &right ); + + //! Assignment operator + // LTI_MassFracs& operator=( const LTI_MassFracs &right ); + + virtual ~LTI_MassFracs( ) { } + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp(doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp(std::vector LTPptrs) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them: Not implemented for this mixing rule. + */ + void getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues = 0 ) { mat = (*m_Aij[0]); } + + protected: + + }; + + + //! Mixing rule using logarithms of the mole fractions + /** + * This model is based on the idea that liquid molecules are + * generally interacting with some energy and entropy of interaction. + * For transport properties that depend on these energies of + * interaction, the mixture transport property can be written + * in terms of its logarithm + * + * \f[ \ln \eta_{mix} = \sum_i X_i \ln \eta_i + * + \sum_i \sum_j X_i X_j ( S_{i,j} + E_{i,j} / T ) + * \f]. + * + * These additional interaction terms multiply the mixture property by + * \f[ \exp( \sum_{i} \sum_{j} X_i X_j ( S_{i,j} + E_{i,j} / T ) ) \f] + * so that the self-interaction terms \f$ S_{i,j} \f$ and + * \f$ E_{i,j} \f$ should be zero. + * + * Note that the energies and entropies of interaction should be + * a function of the composition themselves, but this is not yet + * implemented. (We might follow the input of Margules model + * thermodynamic data for the purpose of implementing this.) + * + * Sample input for this method is + * \verbatim + * + * + * + * + * + * -1.0e3 + * 80.0e-5 + * + * + * + * + * \endverbatim + */ + class LTI_Log_MoleFracs : public LiquidTranInteraction { + + public: + LTI_Log_MoleFracs( TransportPropertyType tp_ind = TP_UNKNOWN ) : + LiquidTranInteraction( tp_ind ) + { + m_model = LTI_MODEL_LOG_MOLEFRACS; + } + + + //! Copy constructor + // LTI_Log_MoleFracs( const LTI_Log_MoleFracs &right ); + + //! Assignment operator + // LTI_Log_MoleFracs& operator=( const LTI_Log_MoleFracs &right ); + + virtual ~LTI_Log_MoleFracs( ) { } + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp(doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp(std::vector LTPptrs ) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them: Not implemented for this mixing rule. + */ + void getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues = 0 ) { mat = m_Eij; } + + protected: + + }; + + + //! Transport properties that act like pairwise interactions + //! as in binary diffusion coefficients. + /** + * This class holds parameters for transport properties expressed + * as a matrix of pairwise interaction parameters. + * Input can be provided for constant or Arrhenius forms of the + * separate parameters. + * + * Sample input for this method is + * \verbatim + * + * + * + * + * 1.0e-8 + * 24.0e6 + * + * + * + * + * \endverbatim + * + */ + class LTI_Pairwise_Interaction : public LiquidTranInteraction { + + public: + LTI_Pairwise_Interaction( TransportPropertyType tp_ind = TP_UNKNOWN ) : + LiquidTranInteraction( tp_ind ) + { + m_model = LTI_MODEL_PAIRWISE_INTERACTION; + } + + + //! Copy constructor + // LTI_Pairwise_Interaction( const LTI_Pairwise_Interaction &right ); + + //! Assignment operator + // LTI_Pairwise_Interaction& operator=( const LTI_Pairwise_Interaction &right ); + + virtual ~LTI_Pairwise_Interaction( ) { } + + void setParameters( LiquidTransportParams& trParam ) ; + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp( doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp( std::vector LTPptrs ) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them + */ + void getMatrixTransProp( DenseMatrix &mat, doublereal* speciesValues = 0 ) ; + protected: + + std::vector m_diagonals; + }; + + + //! Stefan Maxwell Diffusion Coefficients can be solved for given + //! ion conductivity, mobility ratios, and self diffusion coeffs. + //! This class is only valid for a common anion mixture of two + //! salts with cations of equal charge. Hence the name _PPN. + /** + * + * This class requres you specify + * + * 1 - ion conductivity + * + * 2 - mobility ratio of the two cations (set all other ratios to zero) + * + * 3 - Self diffusion coefficients of the cations (set others to zero) + * is used to calculate the "mutual diffusion coefficient". The + * approximation needed to do so requires the cations have equal charge. + * + * We than calculate the Stefan Maxwell Diffusion Coefficients by + * \f[ + * \frac{1}{D_{12}} = (1-\epsilon X_A)(1+\epsilon X_B) + * \frac{\nu_- + \nu_+}{\nu_-\nu_+^2D} + * + \frac{z_-z_+ F^2}{\kappa V R T} + * \f] + * \f[ + * \frac{1}{D_{12}} = -\epsilon X_B(1-\epsilon X_A) + * \frac{\nu_- + \nu_+}{\nu_-^2\nu_+D} + * - \frac{z_-z_+ F^2}{\kappa V R T} + * \f] + * \f[ + * \frac{1}{D_{23}} = \epsilon X_A(1+\epsilon X_B) + * \frac{\nu_- + \nu_+}{\nu_-^2\nu_+D} + * - \frac{z_-z_+ F^2}{\kappa V R T} + * \f] + * where F is Faraday's constant, RT is the gas constant times the + * tempurature, and V is the molar volume (basis is moles of ions) that is + * calculated by the thermophase member. X_A and X_B are the mole fractions + * of the salts composed of cation(1) and cation(2), respectively, that share + * a common anion(3). \f$\nu_{+,-}\f$ are the stoichiometric coefficients in + * the dissociation reaction of the salts to the ions with charges of + * \f$z_{+,-}\f$. Assuming that the cations have equal charge, the "mutual + * diffusion coefficient" is calculated using the cation self diffusion + * coefficients. + * \f[ + * \frac{1}{\nu_-\nu_+D} = \left(1+\frac{\partial \gamma_B}{\partial N_B} + * \right)\frac{X_A}{D_2^*}+\left(1+\frac{\partial \gamma_A}{\partial N_A} + * \right)\frac{X_B}{D_1^*} + * \f] + * where the self diffusion coefficients, \f$D_i^*\f$, are temperature and + * composition parameterized inputs and the derivative of the activity + * coefficient, \f$\frac{\partial \gamma_B}{\partial N_B}\f$, is calculated + * by the thermophase member using the excess enthalpy and entropy upon mixing. + * + * Finally, the deviation of the transferrence numbers from ideality, + * \f$\epsilon\f$, is calculated from the mobility ratio of the cations. + * \f[ + * \epsilon = \frac{1-b_2/b_1}{X_A+X_Bb_2/b_1} + * \f] + * Where \f$b_i\f$ are the mobilities of the two cations. Everywhere, + * cation 1 corresponds with salt A and cation 2 with salt B. + * + * Sample input for this method is + * \verbatim + * + * + * + * + * + * + * \endverbatim + * + */ + class LTI_StefanMaxwell_PPN : public LiquidTranInteraction { + + public: + LTI_StefanMaxwell_PPN(TransportPropertyType tp_ind = TP_UNKNOWN) : + LiquidTranInteraction(tp_ind) + { + m_model = LTI_MODEL_STEFANMAXWELL_PPN; + } + + + //! Copy constructor + // LTI_StefanMaxwell_PPN( const LTI_StefanMaxwell_PPN &right ); + + //! Assignment operator + // LTI_StefanMaxwell_PPN& operator=( const LTI_StefanMaxwell_PPN &right ); + + virtual ~LTI_StefanMaxwell_PPN( ) { } + + void setParameters(LiquidTransportParams& trParam ) ; + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp( doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp( std::vector LTPptrs ) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them + */ + void getMatrixTransProp( DenseMatrix &mat, doublereal* speciesValues = 0 ) ; + + protected: + + doublereal m_ionCondMix; + LiquidTranInteraction * m_ionCondMixModel; + std::vector m_ionCondSpecies; + typedef std::vector LTPvector; + DenseMatrix m_mobRatMix; + std::vector m_mobRatMixModel; + std::vector m_mobRatSpecies; + + std::vector m_selfDiffMixModel; + vector_fp m_selfDiffMix; + std::vector m_selfDiffSpecies; + }; + + + class LTI_StokesEinstein : public LiquidTranInteraction { + + public: + LTI_StokesEinstein(TransportPropertyType tp_ind = TP_UNKNOWN) : + LiquidTranInteraction(tp_ind) + { + m_model = LTI_MODEL_STOKES_EINSTEIN; + } + + + //! Copy constructor + // LTI_StokesEinstein( const LTI_StokesEinstein &right ); + + //! Assignment operator + // LTI_StokesEinstein& operator=( const LTI_StokesEinstein &right ); + + virtual ~LTI_StokesEinstein( ) { } + + void setParameters(LiquidTransportParams& trParam); + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp(doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp(std::vector LTPptrs ) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them + */ + void getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues = 0 ) ; + protected: + + std::vector m_viscosity; + std::vector m_hydroRadius; + + }; + + //! Simple mole fraction weighting of transport properties + /** + * This model weights the transport property by the mole + * fractions. + * The overall formula for the mixture viscosity is + * + * \f[ \eta_{mix} = \sum_i X_i \eta_i + * + \sum_i \sum_j X_i X_j A_{i,j} \f]. + */ + class LTI_MoleFracs_ExpT : public LiquidTranInteraction { + + public: + LTI_MoleFracs_ExpT(TransportPropertyType tp_ind = TP_UNKNOWN) : + LiquidTranInteraction(tp_ind) + { + m_model = LTI_MODEL_MOLEFRACS_EXPT; + } + + + //! Copy constructor + // LTI_MoleFracs_ExpT( const LTI_MoleFracs_ExpT &right ); + + //! Assignment operator + // LTI_MoleFracs_ExpT& operator=( const LTI_MoleFracs_ExpT &right ); + + virtual ~LTI_MoleFracs_ExpT( ) { } + + //! Return the mixture transport property value. + /** + * Takes the separate species transport properties + * as input (this method does not know what + * transport property it is at this point. + */ + doublereal getMixTransProp(doublereal *valueSpecies, doublereal *weightSpecies = 0 ); + doublereal getMixTransProp(std::vector LTPptrs ) ; + + //! Return the matrix of binary interaction parameters. + /** + * Takes the proper mixing rule for the binary interaction parameters + * and calculates them: Not Implemented for this mixing rule + */ + void getMatrixTransProp(DenseMatrix &mat, doublereal* speciesValues = 0 ) { mat = (*m_Aij[0]); } + //CAL void getMatrixTransProp( DenseMatrix &mat, LiquidTransport* lt, doublereal* speciesValues = 0 ) { mat = (*m_Aij[0]); } + + protected: + + }; + +} + +#endif diff --git a/Cantera/src/transport/LiquidTransport.cpp b/Cantera/src/transport/LiquidTransport.cpp index f31a1d5a4..92cbd8651 100644 --- a/Cantera/src/transport/LiquidTransport.cpp +++ b/Cantera/src/transport/LiquidTransport.cpp @@ -34,47 +34,95 @@ namespace Cantera { LiquidTransport::LiquidTransport(thermo_t* thermo, int ndim) : Transport(thermo, ndim), m_nsp(0), + m_nsp2(0), m_tmin(-1.0), m_tmax(100000.), + m_viscMixModel(0), + m_ionCondMixModel(0), + m_lambdaMixModel(0), + m_diffMixModel(0), + m_radiusMixModel(0), m_iStateMF(-1), + concTot_(0.0), + concTot_tran_(0.0), + dens_(0.0), m_temp(-1.0), - m_logt(0.0), m_press(-1.0), m_lambda(-1.0), m_viscmix(-1.0), + m_ionCondmix(-1.0), + m_mobRatMix(0), + m_selfDiffMix(0), m_visc_mix_ok(false), m_visc_temp_ok(false), m_visc_conc_ok(false), + m_ionCond_mix_ok(false), + m_ionCond_temp_ok(false), + m_ionCond_conc_ok(false), + m_mobRat_mix_ok(false), + m_mobRat_temp_ok(false), + m_mobRat_conc_ok(false), + m_selfDiff_mix_ok(false), + m_selfDiff_temp_ok(false), + m_selfDiff_conc_ok(false), + m_radi_mix_ok(false), + m_radi_temp_ok(false), + m_radi_conc_ok(false), m_diff_mix_ok(false), m_diff_temp_ok(false), - m_cond_temp_ok(false), - m_cond_mix_ok(false), + m_lambda_temp_ok(false), + m_lambda_mix_ok(false), m_mode(-1000), - m_debug(false) + m_debug(false), + m_nDim(1) { } - LiquidTransport::LiquidTransport(const LiquidTransport &right) : - Transport(), + LiquidTransport::LiquidTransport(const LiquidTransport &right) : + Transport(right.m_thermo, right.m_nDim), m_nsp(0), + m_nsp2(0), m_tmin(-1.0), m_tmax(100000.), + m_viscMixModel(0), + m_ionCondMixModel(0), + m_lambdaMixModel(0), + m_diffMixModel(0), + m_radiusMixModel(0), m_iStateMF(-1), + concTot_(0.0), + concTot_tran_(0.0), + dens_(0.0), m_temp(-1.0), - m_logt(0.0), m_press(-1.0), m_lambda(-1.0), m_viscmix(-1.0), + m_ionCondmix(-1.0), + m_mobRatMix(0), + m_selfDiffMix(0), m_visc_mix_ok(false), m_visc_temp_ok(false), m_visc_conc_ok(false), + m_ionCond_mix_ok(false), + m_ionCond_temp_ok(false), + m_ionCond_conc_ok(false), + m_mobRat_mix_ok(false), + m_mobRat_temp_ok(false), + m_mobRat_conc_ok(false), + m_selfDiff_mix_ok(false), + m_selfDiff_temp_ok(false), + m_selfDiff_conc_ok(false), + m_radi_mix_ok(false), + m_radi_temp_ok(false), + m_radi_conc_ok(false), m_diff_mix_ok(false), m_diff_temp_ok(false), - m_cond_temp_ok(false), - m_cond_mix_ok(false), + m_lambda_temp_ok(false), + m_lambda_mix_ok(false), m_mode(-1000), - m_debug(false) + m_debug(false), + m_nDim(1) { /* * Use the assignment operator to do the brunt @@ -84,57 +132,81 @@ namespace Cantera { } LiquidTransport& LiquidTransport::operator=(const LiquidTransport& right) { - if (&right != this) { + if (&right == this) { return *this; } Transport::operator=(right); m_nsp = right.m_nsp; + m_nsp2 = right.m_nsp2; m_tmin = right.m_tmin; m_tmax = right.m_tmax; m_mw = right.m_mw; - m_visc_A = right.m_visc_A; - m_visc_logA = right.m_visc_logA; - m_visc_n = right.m_visc_n; - m_visc_Tact = right.m_visc_Tact; - m_visc_Eij = right.m_visc_Eij; - m_visc_Sij = right.m_visc_Sij; - m_thermCond_A = right.m_thermCond_A; - m_thermCond_n = right.m_thermCond_n; - m_thermCond_Tact = right.m_thermCond_Tact; + m_viscTempDep_Ns = right.m_viscTempDep_Ns; + m_ionCondTempDep_Ns = right.m_ionCondTempDep_Ns; + m_mobRatTempDep_Ns = right.m_mobRatTempDep_Ns; + m_selfDiffTempDep_Ns = right.m_selfDiffTempDep_Ns; + m_lambdaTempDep_Ns = right.m_lambdaTempDep_Ns; + m_diffTempDep_Ns = right.m_diffTempDep_Ns; + m_radiusTempDep_Ns = right.m_radiusTempDep_Ns; m_hydrodynamic_radius = right.m_hydrodynamic_radius; - m_diffcoeffs = right.m_diffcoeffs; m_Grad_X = right.m_Grad_X; m_Grad_T = right.m_Grad_T; m_Grad_V = right.m_Grad_V; - m_ck_Grad_mu = right.m_ck_Grad_mu; + m_Grad_mu = right.m_Grad_mu; m_bdiff = right.m_bdiff; m_viscSpecies = right.m_viscSpecies; - m_logViscSpecies = right.m_logViscSpecies; - m_condSpecies = right.m_condSpecies; + m_ionCondSpecies = right.m_ionCondSpecies; + m_mobRatSpecies = right.m_mobRatSpecies; + m_selfDiffSpecies = right.m_selfDiffSpecies; + m_hydrodynamic_radius = right.m_hydrodynamic_radius; + m_lambdaSpecies = right.m_lambdaSpecies; + m_viscMixModel = right.m_viscMixModel; + m_ionCondMixModel = right.m_ionCondMixModel; + m_mobRatMixModel = right.m_mobRatMixModel; + m_selfDiffMixModel = right.m_selfDiffMixModel; + m_lambdaMixModel = right.m_lambdaMixModel; + m_diffMixModel = right.m_diffMixModel; m_iStateMF = -1; + m_massfracs = right.m_massfracs; + m_massfracs_tran = right.m_massfracs_tran; m_molefracs = right.m_molefracs; + m_molefracs_tran = right.m_molefracs_tran; m_concentrations = right.m_concentrations; + m_actCoeff = right.m_actCoeff; + m_Grad_lnAC = right.m_Grad_lnAC; m_chargeSpecies = right.m_chargeSpecies; - m_DiffCoeff_StefMax = right.m_DiffCoeff_StefMax; - viscosityModel_ = right.viscosityModel_; m_B = right.m_B; m_A = right.m_A; m_temp = right.m_temp; - m_logt = right.m_logt; m_press = right.m_press; m_flux = right.m_flux; + m_Vdiff = right.m_Vdiff; m_lambda = right.m_lambda; m_viscmix = right.m_viscmix; + m_ionCondmix = right.m_ionCondmix; + m_mobRatMix = right.m_mobRatMix; + m_selfDiffMix = right.m_selfDiffMix; m_spwork = right.m_spwork; m_visc_mix_ok = false; m_visc_temp_ok = false; m_visc_conc_ok = false; + m_ionCond_mix_ok = false; + m_ionCond_temp_ok = false; + m_ionCond_conc_ok = false; + m_mobRat_mix_ok = false; + m_mobRat_temp_ok = false; + m_mobRat_conc_ok = false; + m_selfDiff_mix_ok = false; + m_selfDiff_temp_ok = false; + m_selfDiff_conc_ok = false; + m_radi_mix_ok = false; + m_radi_temp_ok = false; + m_radi_conc_ok = false; m_diff_mix_ok = false; m_diff_temp_ok = false; - m_cond_temp_ok = false; - m_cond_mix_ok = false; + m_lambda_temp_ok = false; + m_lambda_mix_ok = false; m_mode = right.m_mode; - m_diam = right.m_diam; m_debug = right.m_debug; m_nDim = right.m_nDim; @@ -147,70 +219,222 @@ namespace Cantera { return (dynamic_cast(tr)); } - // Initialize the object + LiquidTransport::~LiquidTransport() { + + //These are constructed in TransportFactory::newLTP + for ( int k = 0; k < m_nsp; k++) { + if ( m_viscTempDep_Ns[k] ) delete m_viscTempDep_Ns[k]; + if ( m_ionCondTempDep_Ns[k] ) delete m_ionCondTempDep_Ns[k]; + for (int l = 0; l < m_nsp; l++ ) { + if (m_selfDiffTempDep_Ns[l][k]) { + delete m_selfDiffTempDep_Ns[l][k]; + } + } + for ( int l=0;l < m_nsp2; l++ ){ + if (m_mobRatTempDep_Ns[l][k]) delete m_mobRatTempDep_Ns[l][k]; + } + if ( m_lambdaTempDep_Ns[k] ) delete m_lambdaTempDep_Ns[k]; + if ( m_radiusTempDep_Ns[k] ) delete m_radiusTempDep_Ns[k]; + if ( m_diffTempDep_Ns[k] ) delete m_diffTempDep_Ns[k]; + //These are constructed in TransportFactory::newLTI + if (m_selfDiffMixModel[k]) delete m_selfDiffMixModel[k]; + } + + for ( int k = 0; k < m_nsp2; k++) { + if ( m_mobRatMixModel[k] ) delete m_mobRatMixModel[k]; + } + + if ( m_viscMixModel ) delete m_viscMixModel; + if ( m_ionCondMixModel ) delete m_ionCondMixModel; + if ( m_lambdaMixModel ) delete m_lambdaMixModel; + if ( m_diffMixModel ) delete m_diffMixModel; + //if ( m_radiusMixModel ) delete m_radiusMixModel; + + } + + // Initialize the transport object /* - * This is where we dimension everything. + * Here we change all of the internal dimensions to be sufficient. + * We get the object ready to do property evaluations. + * A lot of the input required to do property evaluations is + * contained in the LiquidTransportParams class that is + * filled in TransportFactory. + * + * @param tr Transport parameters for all of the species + * in the phase. */ bool LiquidTransport::initLiquid(LiquidTransportParams& tr) { + int k; // constant substance attributes m_thermo = tr.thermo; + tr.thermo = 0; + m_velocityBasis = tr.velocityBasis_; m_nsp = m_thermo->nSpecies(); + m_nsp2 = m_nsp*m_nsp; m_tmin = m_thermo->minTemp(); m_tmax = m_thermo->maxTemp(); // make a local copy of the molecular weights - m_mw.resize(m_nsp); + m_mw.resize(m_nsp, 0.0); copy(m_thermo->molecularWeights().begin(), m_thermo->molecularWeights().end(), m_mw.begin()); - // copy parameters into local storage - m_visc_A = tr.visc_A ; - m_visc_n = tr.visc_n ; - m_visc_Tact = tr.visc_Tact ; + /* + * Get the input Viscosities, and stuff + */ + m_viscSpecies.resize(m_nsp, 0.0); + m_viscTempDep_Ns.resize(m_nsp, 0); + m_ionCondSpecies.resize(m_nsp, 0.0); + m_ionCondTempDep_Ns.resize(m_nsp, 0); + m_mobRatTempDep_Ns.resize(m_nsp2); + m_mobRatMixModel.resize(m_nsp2); + m_mobRatSpecies.resize(m_nsp2, m_nsp, 0.0); + m_mobRatMix.resize(m_nsp2,0.0); + m_selfDiffTempDep_Ns.resize(m_nsp); + m_selfDiffMixModel.resize(m_nsp); + m_selfDiffSpecies.resize(m_nsp, m_nsp, 0.0); + m_selfDiffMix.resize(m_nsp,0.0); + for (k=0; k < m_nsp; k++){ + m_selfDiffTempDep_Ns[k].resize(m_nsp, 0); + } + for (k=0; k < m_nsp2; k++){ + m_mobRatTempDep_Ns[k].resize(m_nsp, 0); + } + m_lambdaSpecies.resize(m_nsp, 0.0); + m_lambdaTempDep_Ns.resize(m_nsp, 0); + m_hydrodynamic_radius.resize(m_nsp, 0.0); + m_radiusTempDep_Ns.resize(m_nsp, 0); - //The following two are not yet filled in LiquidTransportParams - m_visc_Eij = tr.visc_Eij ; - m_visc_Sij = tr.visc_Sij ; + //first populate mixing rules and indices + for (k = 0; k < m_nsp; k++) { + m_selfDiffMixModel[k] = tr.selfDiffusion[k]; + tr.selfDiffusion[k] = 0; + } + for (k = 0; k < m_nsp2; k++) { + m_mobRatMixModel[k] = tr.mobilityRatio[k]; + tr.mobilityRatio[k] = 0; + } - //save logarithm of pre-exponential for easier computation - m_visc_logA.resize(m_nsp); - for ( int i = 0; i < m_nsp; i++ ) - m_visc_logA[i] = log( m_visc_A[i] ); + //for each species, assign viscosity model and coefficients + for (k = 0; k < m_nsp; k++) { + Cantera::LiquidTransportData <d = tr.LTData[k]; + m_viscTempDep_Ns[k] = ltd.viscosity; + ltd.viscosity = 0; + m_ionCondTempDep_Ns[k] = ltd.ionConductivity; + ltd.ionConductivity = 0; + for (int j = 0; j < m_nsp2; j++){ + m_mobRatTempDep_Ns[j][k] = ltd.mobilityRatio[j]; + ltd.mobilityRatio[j] = 0; + } + for (int j = 0; j < m_nsp; j++){ + m_selfDiffTempDep_Ns[j][k] = ltd.selfDiffusion[j]; + ltd.selfDiffusion[j] = 0; + } + m_lambdaTempDep_Ns[k] = ltd.thermalCond; + ltd.thermalCond = 0; + m_radiusTempDep_Ns[k] = ltd.hydroRadius; + ltd.hydroRadius = 0; + } + + + /* + * Get the input Species Diffusivities + * Note that species diffusivities are not what is needed. + * Rather the Stefan Boltzmann interaction parameters are + * needed for the current model. This section may, therefore, + * be extraneous. + */ + m_diffTempDep_Ns.resize(m_nsp, 0); + //for each species, assign viscosity model and coefficients + for (k = 0; k < m_nsp; k++) { + Cantera::LiquidTransportData <d = tr.LTData[k]; + if (ltd.speciesDiffusivity != 0) { + cout << "Warning: diffusion coefficient data for " + << m_thermo->speciesName(k) + << endl + << "in the input file is not used for LiquidTransport model." + << endl + << "LiquidTransport model uses Stefan-Maxwell interaction " + << endl + << "parameters defined in the input block." + << endl; + } + } + + /* + * Here we get interaction parameters from LiquidTransportParams + * that were filled in TransportFactory::getLiquidInteractionsTransportData + * Interaction models are provided here for viscosity, thermal conductivity, + * species diffusivity and hydrodynamics radius (perhaps not needed in the + * present class). + */ - m_thermCond_A = tr.thermCond_A ; - m_thermCond_n = tr.thermCond_n ; - m_thermCond_Tact = tr.thermCond_Tact ; - m_hydrodynamic_radius = tr.hydroRadius ; + m_viscMixModel = tr.viscosity; + tr.viscosity = 0; + + m_ionCondMixModel = tr.ionConductivity; + tr.ionConductivity = 0; + //m_mobRatMixModel = tr.mobilityRatio; + + m_lambdaMixModel = tr.thermalCond; + tr.thermalCond = 0; + + m_diffMixModel = tr.speciesDiffusivity; + tr.speciesDiffusivity = 0; - //m_diffcoeffs = tr.diffcoeffs; + m_bdiff.resize(m_nsp,m_nsp, 0.0); + + //Don't really need to update this here. + //It is updated in updateDiff_T() + m_diffMixModel->getMatrixTransProp( m_bdiff ); + m_mode = tr.mode_; - m_viscSpecies.resize(m_nsp); - m_logViscSpecies.resize(m_nsp); - m_condSpecies.resize(m_nsp); - m_bdiff.resize(m_nsp, m_nsp); - - m_molefracs.resize(m_nsp); - m_spwork.resize(m_nsp); + m_massfracs.resize(m_nsp, 0.0); + m_massfracs_tran.resize(m_nsp, 0.0); + m_molefracs.resize(m_nsp, 0.0); + m_molefracs_tran.resize(m_nsp, 0.0); + m_concentrations.resize(m_nsp, 0.0); + m_actCoeff.resize(m_nsp, 0.0); + m_chargeSpecies.resize(m_nsp, 0.0); + for ( int i = 0; i < m_nsp; i++ ) { + m_chargeSpecies[i] = m_thermo->charge(i); + } + m_volume_spec.resize(m_nsp, 0.0); + m_Grad_lnAC.resize(m_nsp, 0.0); + m_spwork.resize(m_nsp, 0.0); // resize the internal gradient variables m_Grad_X.resize(m_nDim * m_nsp, 0.0); m_Grad_T.resize(m_nDim, 0.0); m_Grad_V.resize(m_nDim, 0.0); - m_ck_Grad_mu.resize(m_nDim * m_nsp, 0.0); + m_Grad_mu.resize(m_nDim * m_nsp, 0.0); + + m_flux.resize(m_nsp, m_nDim, 0.0); + m_Vdiff.resize(m_nsp, m_nDim, 0.0); // set all flags to false m_visc_mix_ok = false; m_visc_temp_ok = false; m_visc_conc_ok = false; - - m_cond_temp_ok = false; - m_cond_mix_ok = false; + m_ionCond_mix_ok = false; + m_ionCond_temp_ok = false; + m_ionCond_conc_ok = false; + m_mobRat_mix_ok = false; + m_mobRat_temp_ok = false; + m_mobRat_conc_ok = false; + m_selfDiff_mix_ok = false; + m_selfDiff_temp_ok = false; + m_selfDiff_conc_ok = false; + m_radi_temp_ok = false; + m_radi_conc_ok = false; + m_lambda_temp_ok = false; + m_lambda_mix_ok = false; m_diff_temp_ok = false; m_diff_mix_ok = false; @@ -221,104 +445,322 @@ namespace Cantera { /****************** viscosity ******************************/ + // Returns the viscosity of the solution /* - * The viscosity is computed using the Wilke mixture rule. - * \f[ - * \mu = \sum_k \frac{\mu_k X_k}{\sum_j \Phi_{k,j} X_j}. - * \f] - * Here \f$ \mu_k \f$ is the viscosity of pure species \e k, - * and - * \f[ - * \Phi_{k,j} = \frac{\left[1 - * + \sqrt{\left(\frac{\mu_k}{\mu_j}\sqrt{\frac{M_j}{M_k}}\right)}\right]^2} - * {\sqrt{8}\sqrt{1 + M_k/M_j}} - * \f] - * @see updateViscosity_T(); + * The viscosity calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species viscosities. */ doublereal LiquidTransport::viscosity() { - update_temp(); - update_conc(); + update_T(); + update_C(); if (m_visc_mix_ok) return m_viscmix; - // update m_viscSpecies[] if necessary - if (!m_visc_temp_ok) { - updateViscosity_temp(); - } + ////// LiquidTranInteraction method + m_viscmix = m_viscMixModel->getMixTransProp( m_viscTempDep_Ns ); - if (!m_visc_conc_ok) { - updateViscosities_conc(); - } - - /* We still need to implement interaction parameters */ - /* This constant viscosity model has no input */ - if (viscosityModel_ == LVISC_CONSTANT) { - - err("constant viscosity not implemented for LiquidTransport."); - //return m_viscmix; - - } else if (viscosityModel_ == LVISC_AVG_ENERGIES) { - - m_viscmix = exp( dot_product(m_logViscSpecies, m_molefracs) ); - - } else if (viscosityModel_ == LVISC_INTERACTION) { - - // log_visc_mix = sum_i (X_i log_visc_i) + sum_i sum_j X_i X_j G_ij - double interaction = dot_product(m_logViscSpecies, m_molefracs); - for ( int i = 0; i < m_nsp; i++ ) - for ( int j = 0; j < i; j++ ) - interaction += m_molefracs[i] * m_molefracs[j] - * ( m_visc_Sij(i,j) + m_visc_Eij(i,j) / m_temp ); - m_viscmix = exp( interaction ); - - } - return m_viscmix; } + // Returns the pure species viscosities for all species + /* + * The pure species viscosities are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param visc array of length "number of species" + * to hold returned viscosities. + */ void LiquidTransport::getSpeciesViscosities(doublereal* visc) { - update_temp(); + update_T(); if (!m_visc_temp_ok) { - updateViscosity_temp(); + updateViscosity_T(); } copy(m_viscSpecies.begin(), m_viscSpecies.end(), visc); } + /****************** ionConductivity ******************************/ + + // Returns the ionic conductivity of the solution + /* + * The ionConductivity calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species ionic conductivities. + */ + doublereal LiquidTransport:: ionConductivity() { + + update_T(); + update_C(); + + if (m_ionCond_mix_ok) return m_ionCondmix; + + ////// LiquidTranInteraction method + m_ionCondmix = m_ionCondMixModel->getMixTransProp( m_ionCondTempDep_Ns ); + + return m_ionCondmix; + + /* + // update m_ionCondSpecies[] if necessary + if (!m_ionCond_temp_ok) { + updateIonConductivity_T(); + } + + if (!m_ionCond_conc_ok) { + updateIonConductivity_C(); + } + */ + } + + // Returns the pure species ionic conductivities for all species + /* + * The pure species ionic conductivities are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param ionCond array of length "number of species" + * to hold returned ionic conductivities. + */ + void LiquidTransport::getSpeciesIonConductivity(doublereal* ionCond) { + update_T(); + if (!m_ionCond_temp_ok) { + updateIonConductivity_T(); + } + copy(m_ionCondSpecies.begin(), m_ionCondSpecies.end(), ionCond); + } + + /****************** mobilityRatio ******************************/ + + // Returns the mobility ratios of the solution + /* + * The mobility ratio calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species mobility ratios. + */ + void LiquidTransport:: mobilityRatio(doublereal* mobRat) { + + update_T(); + update_C(); + + // LiquidTranInteraction method + if (!m_mobRat_mix_ok) { + for (int k = 0; k < m_nsp2; k++){ + if (m_mobRatMixModel[k]) { + m_mobRatMix[k] = m_mobRatMixModel[k]->getMixTransProp(m_mobRatTempDep_Ns[k]); + if (m_mobRatMix[k] > 0.0) { + m_mobRatMix[k / m_nsp + m_nsp * (k % m_nsp)] = 1.0 / m_mobRatMix[k]; // Also must be off diagonal: k%(1+n)!=0, but then m_mobRatMixModel[k] shouldn't be initialized anyway + } + } + } + } + for (int k = 0; k < m_nsp2; k++){ + mobRat[k] = m_mobRatMix[k]; + } + } + + // Returns the pure species mobility ratios for all species + /* + * The pure species mobility ratios are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param mobRat array of length "number of species" + * to hold returned mobility ratio. + */ + void LiquidTransport::getSpeciesMobilityRatio(doublereal** mobRat) { + update_T(); + if (!m_mobRat_temp_ok) { + updateMobilityRatio_T(); + } + for (int k = 0; k < m_nsp2; k++) { + for (int j = 0; j < m_nsp; j++) { + mobRat[k][j] = m_mobRatSpecies(k,j); + } + } + } + //==================================================================================================================== + // Returns the self diffusion coefficients of the species in the phase + /* + * The self diffusion coefficient is the diffusion coefficient of a tracer species + * at the current temperature and composition of the species. Therefore, + * the dilute limit of transport is assumed for the tracer species. + * The effective formula may be calculated from the stefan-maxwell formulation by + * adding another row for the tracer species, assigning all D's to be equal + * to the respective species D's, and then taking the limit as the + * tracer species mole fraction goes to zero. The corresponding flux equation + * for the tracer species k in units of kmol m-2 s-1 is. + * + * \f[ + * J_k = - D^{sd}_k \frac{C_k}{R T} \nabla \mu_k + * \f] + * + * The derivative is taken at constant T and P. + * + * The self diffusion calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species self diffusion coeffs. + * + * @param selfDiff Vector of self-diffusion coefficients + * Length = number of species in phase + * units = m**2 s-1 + */ + void LiquidTransport::selfDiffusion(doublereal * const selfDiff) { + update_T(); + update_C(); + if (!m_selfDiff_mix_ok) { + for (int k = 0; k < m_nsp; k++) { + m_selfDiffMix[k] = m_selfDiffMixModel[k]->getMixTransProp(m_selfDiffTempDep_Ns[k]); + } + } + for (int k = 0; k < m_nsp; k++) { + selfDiff[k] = m_selfDiffMix[k]; + } + } + //==================================================================================================================== + // Returns the pure species self diffusion for all species + /* + * The pure species self diffusion coeffs are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param selfDiff array of size "number of species"^2 + * to hold returned self diffusion. + */ + void LiquidTransport::getSpeciesSelfDiffusion(doublereal** selfDiff) { + update_T(); + if (!m_selfDiff_temp_ok) { + updateSelfDiffusion_T(); + } + for (int k=0; kgetMixTransProp( m_lambdaTempDep_Ns ); + m_cond_mix_ok = true; + } + + return m_lambda; + } + + + /****************** thermal diffusion coefficients ************/ + + // Return the thermal diffusion coefficients + /* + * These are all zero for this simple implementaion + * + * @param dt thermal diffusion coefficients + */ + void LiquidTransport::getThermalDiffCoeffs(doublereal* const dt) { + for (int k = 0; k < m_nsp; k++) { + dt[k] = 0.0; + } + } /******************* binary diffusion coefficients **************/ + // Returns the binary diffusion coefficients + /* + * The binary diffusion coefficients are specified in the input + * file through the LiquidTransportInteractions class. These + * are the binary interaction coefficients employed in the + * Stefan-Maxwell equation. + * + * @param ld number of species in system + * @param d vector of binary diffusion coefficients + * units = m2 s-1. length = ld*ld = (number of species)^2 + */ void LiquidTransport::getBinaryDiffCoeffs(int ld, doublereal* d) { int i,j; - update_temp(); + if ( ld != m_nsp ) + throw CanteraError("LiquidTransport::getBinaryDiffCoeffs", + "First argument does not correspond to number of species in model.\nDiff Coeff matrix may be misdimensioned"); + update_T(); // if necessary, evaluate the binary diffusion coefficents // from the polynomial fits - if (!m_diff_temp_ok) updateDiff_temp(); - doublereal pres = m_thermo->pressure(); + if (!m_diff_temp_ok) updateDiff_T(); - doublereal rp = 1.0/pres; - for (i = 0; i < m_nsp; i++) - for (j = 0; j < m_nsp; j++) { - d[ld*j + i] = rp * m_bdiff(i,j); + for (i = 0; i < m_nsp; i++) { + for (j = 0; j < m_nsp; j++){ + //if (!( ( m_bdiff(i,j) > 0.0 ) | ( m_bdiff(i,j) < 0.0 ))){ + // throw CanteraError("LiquidTransport::getBinaryDiffCoeffs ", + // "m_bdiff has zero entry in non-diagonal.");} + d[ld*j + i] = 1.0 / m_bdiff(i,j); + } + } } - //================================================================================================ - // Get the electrical Mobilities (m^2/V/s). + //================================================================================================ + // Get the Electrical mobilities (m^2/V/s). /* - * This function returns the mobilities. In some formulations - * this is equal to the normal mobility multiplied by faraday's constant. + * The electrical mobilities are not well defined + * in the context of LiquidTransport because the Stefan Maxwell + * equation is solved. Here the electrical mobilities + * are calculated from the mixture-averaged + * diffusion coefficients through a call to getMixDiffCoeffs() + * using the Einstein relation * - * Frequently, but not always, the mobility is calculated from the - * diffusion coefficient using the Einstein relation - * - * \f[ + * \f[ * \mu^e_k = \frac{F D_k}{R T} * \f] * - * @param mobil_e Returns the mobilities of + * Note that this call to getMixDiffCoeffs() requires + * a solve of the Stefan Maxwell equation making this + * determination of the mixture averaged diffusion coefficients + * a {\em slow} method for obtaining diffusion coefficients. + * + * Also note that the Stefan Maxwell solve will be based upon + * the thermodynamic state (including gradients) most recently + * set. Gradients can be set specifically using set_Grad_V, + * set_Grad_X and set_Grad_T or through calls to + * getSpeciesFluxes, getSpeciesFluxesES, getSpeciesVdiff, + * getSpeciesVdiffES, etc. + * + * @param mobil_e Returns the electrical mobilities of * the species in array \c mobil_e. The array must be * dimensioned at least as large as the number of species. */ @@ -330,24 +772,34 @@ namespace Cantera { mobil[k] = c1 * m_spwork[k]; } } - //================================================================================================ - //! Get the fluid mobilities (s kmol/kg). - /*! - * This function returns the fluid mobilities. Usually, you have - * to multiply Faraday's constant into the resulting expression - * to general a species flux expression. - * - * Frequently, but not always, the mobility is calculated from the - * diffusion coefficient using the Einstein relation + // Get the fluid mobilities (s kmol/kg). + /* + * The fluid mobilities are not well defined + * in the context of LiquidTransport because the Stefan Maxwell + * equation is solved. Here the fluid mobilities + * are calculated from the mixture-averaged + * diffusion coefficients through a call to getMixDiffCoeffs() + * using the Einstein relation * * \f[ * \mu^f_k = \frac{D_k}{R T} * \f] * + * Note that this call to getMixDiffCoeffs() requires + * a solve of the Stefan Maxwell equation making this + * determination of the mixture averaged diffusion coefficients + * a {\em slow} method for obtaining diffusion coefficients. + * + * Also note that the Stefan Maxwell solve will be based upon + * the thermodynamic state (including gradients) most recently + * set. Gradients can be set specifically using set_Grad_V, + * set_Grad_X and set_Grad_T or through calls to + * getSpeciesFluxes, getSpeciesFluxesES, getSpeciesVdiff, + * getSpeciesVdiffES, etc. * - * @param mobil_f Returns the mobilities of - * the species in array \c mobil. The array must be + * @param mobil_f Returns the fluid mobilities of + * the species in array \c mobil_f. The array must be * dimensioned at least as large as the number of species. */ void LiquidTransport::getFluidMobilities(doublereal* const mobil_f) { @@ -357,73 +809,176 @@ namespace Cantera { mobil_f[k] = c1 * m_spwork[k]; } } - //================================================================================================ - void LiquidTransport::set_Grad_V(const doublereal* const grad_V) { - for (int a = 0; a < m_nDim; a++) { - m_Grad_V[a] = grad_V[a]; - } - } - //================================================================================================ + //============================================================== + // Specify the value of the gradient of the temperature + /* + * @param grad_T Gradient of the temperature (length num dimensions); + */ void LiquidTransport::set_Grad_T(const doublereal* const grad_T) { for (int a = 0; a < m_nDim; a++) { m_Grad_T[a] = grad_T[a]; } } - //================================================================================================ + //============================================================== + // Specify the value of the gradient of the voltage + /* + * + * @param grad_V Gradient of the voltage (length num dimensions); + */ + void LiquidTransport::set_Grad_V(const doublereal* const grad_V) { + for (int a = 0; a < m_nDim; a++) { + m_Grad_V[a] = grad_V[a]; + } + } + //============================================================== + // Specify the value of the gradient of the MoleFractions + /* + * + * @param grad_X Gradient of the mole fractions(length nsp * num dimensions); + */ void LiquidTransport::set_Grad_X(const doublereal* const grad_X) { int itop = m_nDim * m_nsp; for (int i = 0; i < itop; i++) { m_Grad_X[i] = grad_X[i]; } - update_Grad_lnAC(); } - //================================================================================================ - /****************** thermal conductivity **********************/ + //============================================================== + + // Compute the mixture electrical conductivity from + // the Stefan-Maxwell equation. + /* + * To compute the mixture electrical conductance, the Stefan + * Maxwell equation is solved for zero species gradients and + * for unit potential gradient, \f$ \nabla V \f$. + * The species fluxes are converted to current by summing over + * the charge-weighted fluxes according to + * \f[ + * \vec{i} = \sum_{i} z_i F \rho \vec{V_i} / W_i + * \f] + * where \f$ z_i \f$ is the charge on species i, + * \f$ F \f$ is Faradays constant, \f$ \rho \f$ is the density, + * \f$ W_i \f$ is the molecular mass of species i. + * The conductance, \f$ \kappa \f$ is obtained from + * \f[ + * \kappa = \vec{i} / \nabla V. + * \f] + */ + doublereal LiquidTransport::getElectricConduct( ) { + doublereal gradT = 0.0; + doublereal gradX[m_nDim * m_nsp]; + doublereal gradV[m_nDim]; + for (int i = 0; i < m_nDim; i++) { + for (int k = 0; k < m_nsp; k++) + gradX[ i*m_nDim + k] = 0.0; + gradV[i] = 1.0; + } + + set_Grad_T(&gradT); + set_Grad_X(gradX); + set_Grad_V(gradV); + + doublereal *fluxes = new doublereal( m_nsp * m_nDim ); + doublereal current; + + getSpeciesFluxesExt(m_nDim, fluxes); + + //sum over species charges, fluxes, Faraday to get current + // Since we want the scalar conductivity, we need only consider one-dim + for (int i = 0; i < 1; i++) { + current = 0.0; + for (int k = 0; k < m_nsp; k++) + current += m_chargeSpecies[k] * Faraday * fluxes[k] / m_mw[k]; + //divide by unit potential gradient + current /= - gradV[i]; + } + delete fluxes; + return current; + + } + + // Compute the electric current density in A/m^2 + /* + * The electric current is computed first by computing the + * species diffusive fluxes using the Stefan Maxwell solution + * and then the current, \f$ \vec{i} \f$ by summing over + * the charge-weighted fluxes according to + * \f[ + * \vec{i} = \sum_{i} z_i F \rho \vec{V_i} / W_i + * \f] + * where \f$ z_i \f$ is the charge on species i, + * \f$ F \f$ is Faradays constant, \f$ \rho \f$ is the density, + * \f$ W_i \f$ is the molecular mass of species i. + * + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * @param ldx Leading dimension of the grad_X array. + * @param grad_T The temperature gradient (ignored in this model). + * @param ldf Leading dimension of the grad_V and current vectors. + * @param grad_V The electrostatic potential gradient. + * @param current The electric current in A/m^2. + */ + void LiquidTransport::getElectricCurrent(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_V, + doublereal* current) { + + set_Grad_T(grad_T); + set_Grad_X(grad_X); + set_Grad_V(grad_V); + + doublereal *fluxes = new doublereal(m_nsp * m_nDim); + + getSpeciesFluxesExt(ldf, fluxes); + + //sum over species charges, fluxes, Faraday to get current + for (int i = 0; i < m_nDim; i++) { + current[i] = 0.0; + for (int k = 0; k < m_nsp; k++) + current[i] += m_chargeSpecies[k] * Faraday * fluxes[k] / m_mw[k]; + //divide by unit potential gradient + } + delete fluxes; + + } + + // Get the species diffusive velocities wrt to + // the averaged velocity, + // given the gradients in mole fraction and temperature + /* + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. + * + * Units for the returned fluxes are kg m-2 s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param Vdiff Output of the diffusive velocities. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + void LiquidTransport::getSpeciesVdiff(int ndim, + const doublereal* grad_T, + int ldx, const doublereal* grad_X, + int ldf, doublereal* Vdiff) { + set_Grad_T(grad_T); + set_Grad_X(grad_X); + getSpeciesVdiffExt(ldf, Vdiff); + } /* - * The thermal conductivity is computed from the following mixture rule: - * \[ - * \lambda = 0.5 \left( \sum_k X_k \lambda_k - * + \frac{1}{\sum_k X_k/\lambda_k}\right) - * \] - */ - doublereal LiquidTransport::thermalConductivity() { - - update_temp(); - update_conc(); - - if (!m_cond_temp_ok) { - updateCond_temp(); - } - if (!m_cond_mix_ok) { - doublereal sum1 = 0.0, sum2 = 0.0; - for (int k = 0; k < m_nsp; k++) { - sum1 += m_molefracs[k] * m_condSpecies[k]; - sum2 += m_molefracs[k] / m_condSpecies[k]; - } - m_lambda = 0.5*(sum1 + 1.0/sum2); - m_cond_mix_ok = true; - } - - return m_lambda; - } - - - /****************** thermal diffusion coefficients ************/ - - /** - * Thermal diffusion is not considered in this mixture-averaged - * model. To include thermal diffusion, use transport manager - * MultiTransport instead. This methods fills out array dt with - * zeros. - */ - void LiquidTransport::getThermalDiffCoeffs(doublereal* const dt) { - for (int k = 0; k < m_nsp; k++) { - dt[k] = 0.0; - } - } - - /** * @param ndim The number of spatial dimensions (1, 2, or 3). * @param grad_T The temperature gradient (ignored in this model). * @param ldx Leading dimension of the grad_X array. @@ -433,6 +988,68 @@ namespace Cantera { * \vec{j}_k = -n M_k D_k \nabla X_k. * \f] */ + void LiquidTransport::getSpeciesVdiffES(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_V, + doublereal* Vdiff) { + set_Grad_T(grad_T); + set_Grad_X(grad_X); + set_Grad_V(grad_V); + getSpeciesVdiffExt(ldf, Vdiff); + } + + // Return the species diffusive mass fluxes wrt to + // the averaged velocity in [kmol/m^2/s]. + /* + * + * The diffusive mass flux of species \e k is computed + * using the Stefan-Maxwell equation + * \f[ + * X_i \nabla \mu_i + * = RT \sum_i \frac{X_i X_j}{D_{ij}} + * ( \vec{V}_j - \vec{V}_i ) + * \f] + * to determine the diffusion velocity and + * \f[ + * \vec{N}_i = C_T X_i \vec{V}_i + * \f] + * to determine the diffusion flux. Here \f$ C_T \f$ is the + * total concentration of the mixture [kmol/m^3], \f$ D_{ij} \f$ + * are the Stefa-Maxwell interaction parameters in [m^2/s], + * \f$ \vec{V}_{i} \f$ is the diffusion velocity of species \e i, + * \f$ \mu_i \f$ is the electrochemical potential of species \e i. + * + * Note that for this method, there is no argument for the + * gradient of the electric potential (voltage). Electric + * potential gradients can be set with set_Grad_V() or + * method getSpeciesFluxesES() can be called.x + * + * The diffusion velocity is relative to an average velocity + * that can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the \verbatim + * \endverbatim input parameter. + + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * (length = ndim) + * @param ldx Leading dimension of the grad_X array. + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * length = ndim + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ void LiquidTransport::getSpeciesFluxes(int ndim, const doublereal* grad_T, int ldx, const doublereal* grad_X, @@ -442,87 +1059,160 @@ namespace Cantera { getSpeciesFluxesExt(ldf, fluxes); } - /** + // Return the species diffusive mass fluxes wrt to + // the averaged velocity in [kmol/m^2/s]. + /* + * + * The diffusive mass flux of species \e k is computed + * using the Stefan-Maxwell equation + * \f[ + * X_i \nabla \mu_i + * = RT \sum_i \frac{X_i X_j}{D_{ij}} + * ( \vec{V}_j - \vec{V}_i ) + * \f] + * to determine the diffusion velocity and + * \f[ + * \vec{N}_i = C_T X_i \vec{V}_i + * \f] + * to determine the diffusion flux. Here \f$ C_T \f$ is the + * total concentration of the mixture [kmol/m^3], \f$ D_{ij} \f$ + * are the Stefa-Maxwell interaction parameters in [m^2/s], + * \f$ \vec{V}_{i} \f$ is the diffusion velocity of species \e i, + * \f$ \mu_i \f$ is the electrochemical potential of species \e i. + * + * The diffusion velocity is relative to an average velocity + * that can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the \verbatim + * \endverbatim input parameter. + * @param ndim The number of spatial dimensions (1, 2, or 3). * @param grad_T The temperature gradient (ignored in this model). + * (length = ndim) * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from - * - * \f[ - * \vec{j}_k = -n M_k D_k \nabla X_k. - * \f] + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * length = ndim + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - void LiquidTransport::getSpeciesFluxesExt(int ldf, doublereal* fluxes) { + void LiquidTransport::getSpeciesFluxesES(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_V, + doublereal* fluxes) { + set_Grad_T(grad_T); + set_Grad_X(grad_X); + set_Grad_V(grad_V); + getSpeciesFluxesExt(ldf, fluxes); + } + + // Return the species diffusive velocities relative to + // the averaged velocity. + /* + * This method acts similarly to getSpeciesVdiffES() but + * requires all gradients to be preset using methods + * set_Grad_X(), set_Grad_V(), set_Grad_T(). + * See the documentation of getSpeciesVdiffES() for details. + * + * @param ldf Leading dimension of the Vdiff array. + * @param Vdiff Output of the diffusive velocities. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + void LiquidTransport::getSpeciesVdiffExt(int ldf, doublereal* Vdiff) { int n, k; - update_temp(); - update_conc(); + stefan_maxwell_solve(); - - getMixDiffCoeffs(DATA_PTR(m_spwork)); - - - const array_fp& mw = m_thermo->molecularWeights(); - const doublereal* y = m_thermo->massFractions(); - doublereal rhon = m_thermo->molarDensity(); - // Unroll wrt ndim - vector_fp sum(m_nDim,0.0); for (n = 0; n < m_nDim; n++) { for (k = 0; k < m_nsp; k++) { - fluxes[n*ldf + k] = -rhon * mw[k] * m_spwork[k] * m_Grad_X[n*m_nsp + k]; - sum[n] += fluxes[n*ldf + k]; - } - } - // add correction flux to enforce sum to zero - for (n = 0; n < m_nDim; n++) { - for (k = 0; k < m_nsp; k++) { - fluxes[n*ldf + k] -= y[k]*sum[n]; + Vdiff[n*ldf + k] = m_Vdiff(k,n); } } } - /** - * Mixture-averaged diffusion coefficients [m^2/s]. + // Return the species diffusive fluxes relative to + // the averaged velocity. + /* + * This method acts similarly to getSpeciesFluxesES() but + * requires all gradients to be preset using methods + * set_Grad_X(), set_Grad_V(), set_Grad_T(). + * See the documentation of getSpeciesFluxesES() for details. + * + * units = kg/m2/s * - * For the single species case or the pure fluid case - * the routine returns the self-diffusion coefficient. - * This is need to avoid a Nan result in the formula - * below. + * @param ldf Leading dimension of the Vdiff array. + * @param fluxes Output of the diffusive fluxes. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + void LiquidTransport::getSpeciesFluxesExt(int ldf, doublereal* fluxes) { + int n, k; + + stefan_maxwell_solve(); + + for (n = 0; n < m_nDim; n++) { + for (k = 0; k < m_nsp; k++) { + fluxes[n*ldf + k] = m_flux(k,n); + } + } + } + + // Get the Mixture diffusion coefficients [m^2/s] + /* + * The mixture diffusion coefficients are not well defined + * in the context of LiquidTransport because the Stefan Maxwell + * equation is solved. Here the mixture diffusion coefficients + * are defined according to Ficks law: + * \f[ + * X_i \vec{V_i} = -D_i \nabla X_i. + * \f] + * Solving Ficks Law for \f$ D_i \f$ gives a mixture diffusion + * coefficient + * \f[ + * D_i = - X_i \vec{V_i} / ( \nabla X_i ). + * \f] + * If \f$ \nabla X_i = 0 \f$ this is undefined and the + * nonsensical value -1 is returned. + * + * Note that this evaluation of \f$ \vec{V_i} \f$ requires + * a solve of the Stefan Maxwell equation making this + * determination of the mixture averaged diffusion coefficients + * a {\em slow} method for obtaining diffusion coefficients. + * + * Also note that the Stefan Maxwell solve will be based upon + * the thermodynamic state (including gradients) most recently + * set. Gradients can be set specifically using set_Grad_V, + * set_Grad_X and set_Grad_T or through calls to + * getSpeciesFluxes, getSpeciesFluxesES, getSpeciesVdiff, + * getSpeciesVdiffES, etc. + * + * @param d vector of mixture diffusion coefficients + * units = m2 s-1. length = number of species */ void LiquidTransport::getMixDiffCoeffs(doublereal* const d) { - update_temp(); - update_conc(); + stefan_maxwell_solve(); - // update the binary diffusion coefficients if necessary - if (!m_diff_temp_ok) { - updateDiff_temp(); - } - - int k, j; - doublereal mmw = m_thermo->meanMolecularWeight(); - doublereal sumxw_tran = 0.0; - doublereal sum2; - - if (m_nsp == 1) { - d[0] = m_bdiff(0,0); - } else { - for (k = 0; k < m_nsp; k++) { - sumxw_tran += m_molefracs_tran[k] * m_mw[k]; - } - for (k = 0; k < m_nsp; k++) { - sum2 = 0.0; - for (j = 0; j < m_nsp; j++) { - if (j != k) { - sum2 += m_molefracs_tran[j] / m_bdiff(j,k); - } + for ( int n = 0; n < m_nDim; n++) { + for (int k = 0; k < m_nsp; k++) { + if ( m_Grad_X[n*m_nsp + k] != 0.0 ) { + d[n*m_nsp + k] = - m_Vdiff(k,n) * m_molefracs[k] + / m_Grad_X[n*m_nsp + k]; + } else { + //avoid divide by zero with nonsensical response + d[n*m_nsp + k] = - 1.0; } - // Because we use m_molefracs_tran, sum2 must be positive definate - // if (sum2 <= 0.0) { - // d[k] = m_bdiff(k,k); - // } else { - d[k] = (sumxw_tran - m_molefracs_tran[k] * m_mw[k])/(mmw * sum2); - // } } } } @@ -534,43 +1224,51 @@ namespace Cantera { * This is called whenever a transport property is * requested. * The first task is to check whether the temperature has changed - * since the last call to update_temp(). + * since the last call to update_T(). * If it hasn't then an immediate return is carried out. * * @internal */ - void LiquidTransport::update_temp() + bool LiquidTransport::update_T() { // First make a decision about whether we need to recalculate doublereal t = m_thermo->temperature(); - if (t == m_temp) return; + if (t == m_temp) return false; // Next do a reality check on temperature value if (t < 0.0) { - throw CanteraError("LiquidTransport::update_temp()", + throw CanteraError("LiquidTransport::update_T()", "negative temperature "+fp2str(t)); } // Compute various direct functions of temperature m_temp = t; - m_logt = log(m_temp); - m_kbt = Boltzmann * m_temp; // temperature has changed so temp flags are flipped m_visc_temp_ok = false; + m_ionCond_temp_ok = false; + m_mobRat_temp_ok = false; + m_selfDiff_temp_ok = false; + m_radi_temp_ok = false; m_diff_temp_ok = false; + m_lambda_temp_ok = false; // temperature has changed, so polynomial temperature // interpolations will need to be reevaluated. // This means that many concentration m_visc_conc_ok = false; - m_cond_temp_ok = false; + m_ionCond_conc_ok = false; + m_mobRat_conc_ok = false; + m_selfDiff_conc_ok = false; // Mixture stuff needs to be evaluated m_visc_mix_ok = false; + m_ionCond_mix_ok = false; + m_mobRat_mix_ok = false; + m_selfDiff_mix_ok = false; m_diff_mix_ok = false; - // m_cond_mix_ok = false; (don't need it because a lower lvl flag is set - + m_lambda_mix_ok = false; //(don't need it because a lower lvl flag is set + return true; } @@ -586,7 +1284,7 @@ namespace Cantera { * * @internal */ - void LiquidTransport::update_conc() { + bool LiquidTransport::update_C() { // If the pressure has changed then the concentrations // have changed. doublereal pres = m_thermo->pressure(); @@ -598,6 +1296,7 @@ namespace Cantera { int iStateNew = m_thermo->stateMFNumber(); if (iStateNew != m_iStateMF) { qReturn = false; + m_thermo->getMassFractions(DATA_PTR(m_massfracs)); m_thermo->getMoleFractions(DATA_PTR(m_molefracs)); m_thermo->getConcentrations(DATA_PTR(m_concentrations)); concTot_ = 0.0; @@ -605,6 +1304,7 @@ namespace Cantera { for (int k = 0; k < m_nsp; k++) { m_molefracs[k] = fmaxx(0.0, m_molefracs[k]); m_molefracs_tran[k] = fmaxx(MIN_X, m_molefracs[k]); + m_massfracs_tran[k] = fmaxx(MIN_X, m_massfracs[k]); concTot_tran_ += m_molefracs_tran[k]; concTot_ += m_concentrations[k]; } @@ -613,189 +1313,265 @@ namespace Cantera { concTot_tran_ *= concTot_; } if (qReturn) { - return; + return false; } // signal that concentration-dependent quantities will need to // be recomputed before use, and update the local mole // fractions. m_visc_conc_ok = false; + m_ionCond_conc_ok = false; + m_mobRat_conc_ok = false; + m_selfDiff_conc_ok = false; // Mixture stuff needs to be evaluated m_visc_mix_ok = false; + m_ionCond_mix_ok = false; + m_mobRat_mix_ok = false; + m_selfDiff_mix_ok = false; m_diff_mix_ok = false; - m_cond_mix_ok = false; - } - - - // We formulate the directional derivative - /* - * We only calculate the change in ac due to composition. - * The pressure and the temperature are taken care of in - * other parts of the expression. - * - */ - void LiquidTransport::update_Grad_lnAC() { - int k; - - - for (int a = 0; a < m_nDim; a++) { - // We form the directional derivative - double * ma_Grad_X = &m_Grad_X[a*m_nsp]; - double sum = 0.0; - for (k = 0; k < m_nsp; k++) { - sum += ma_Grad_X[k] * ma_Grad_X[k]; - } - if (sum == 0.0) { - for (k = 0; k < m_nsp; k++) { - m_Grad_lnAC[m_nsp * a + k] = 0.0; - } - continue; - } - double mag = 1.0E-7 / sum; - - for (k = 0; k < m_nsp; k++) { - Xdelta_[k] = m_molefracs[k] + mag * ma_Grad_X[k]; - if (Xdelta_[k] > 1.0) { - Xdelta_[k] = 1.0; - } - if (Xdelta_[k] < 0.0) { - Xdelta_[k] = 0.0; - } - } - m_thermo->setMoleFractions(DATA_PTR(Xdelta_)); - m_thermo->getActivityCoefficients(DATA_PTR(lnActCoeffMolarDelta_)); - for (k = 0; k < m_nsp; k++) { - lnActCoeffMolarDelta_[k] = log(lnActCoeffMolarDelta_[k]); - } - - for (k = 0; k < m_nsp; k++) { - m_Grad_lnAC[m_nsp * a + k] = - sum * (lnActCoeffMolarDelta_[k] - log(actCoeffMolar_[k])) / mag; - } - } - m_thermo->setMoleFractions(DATA_PTR(m_molefracs)); + m_lambda_mix_ok = false; + return true; } /************************************************************************* * - * methods to update temperature-dependent properties + * methods to update species temperature-dependent properties * *************************************************************************/ /** - * Update the temperature-dependent parts of the mixture-averaged - * thermal conductivity. + * Update the temperature-dependent parts of the species + * thermal conductivity internally using calls to the + * appropriate LTPspecies subclass. */ - void LiquidTransport::updateCond_temp() { + void LiquidTransport::updateCond_T() { + int k; - /* - if (m_mode == CK_Mode) { - for (k = 0; k < m_nsp; k++) { - m_condSpecies[k] = exp(m_condcoeffs[k]); - } - } else { - for (k = 0; k < m_nsp; k++) { - m_condSpecies[k] = m_sqrt_t * m_condcoeffs[k]; - } + for (k = 0; k < m_nsp; k++) { + m_lambdaSpecies[k] = m_lambdaTempDep_Ns[k]->getSpeciesTransProp() ; } - m_cond_temp_ok = true; - m_cond_mix_ok = false; - */ + m_lambda_temp_ok = true; + m_lambda_mix_ok = false; } - /** - * Update the binary diffusion coefficients. These are evaluated - * from the polynomial fits at unit pressure (1 Pa). - */ - void LiquidTransport::updateDiff_temp() { - - // evaluate binary diffusion coefficients at unit pressure - - /* - if (m_mode == CK_Mode) { - for (i = 0; i < m_nsp; i++) { - for (j = i; j < m_nsp; j++) { - m_bdiff(i,j) = exp(m_diffcoeffs[ic]); - m_bdiff(j,i) = m_bdiff(i,j); - ic++; - } - } - } - else { - for (i = 0; i < m_nsp; i++) { - for (j = i; j < m_nsp; j++) { - m_bdiff(i,j) = m_temp * m_sqrt_t*m_diffcoeffs[ic]; - m_bdiff(j,i) = m_bdiff(i,j); - ic++; - } - } - } + // Update the binary Stefan-Maxwell diffusion coefficients + // wrt T using calls to the appropriate LTPspecies subclass + void LiquidTransport::updateDiff_T() { + m_diffMixModel->getMatrixTransProp( m_bdiff ); m_diff_temp_ok = true; m_diff_mix_ok = false; - */ } - /** - * Update the pure-species viscosities. - */ - void LiquidTransport::updateViscosities_conc() { + // Update the pure-species viscosities functional dependence on concentration. + void LiquidTransport::updateViscosities_C() { m_visc_conc_ok = true; } - /** - * Update the temperature-dependent viscosity terms. - * Updates the array of pure species viscosities, and the - * weighting functions in the viscosity mixture rule. + /* + * Updates the array of pure species viscosities internally + * using calls to the appropriate LTPspecies subclass. * The flag m_visc_ok is set to true. + * + * Note that for viscosity, a positive activation energy + * corresponds to the typical case of a positive argument + * to the exponential so that the Arrhenius expression is + * + * \f[ + * \mu = A T^n \exp( + E / R T ) + * \f] */ - void LiquidTransport::updateViscosity_temp() { + void LiquidTransport::updateViscosity_T() { int k; for (k = 0; k < m_nsp; k++) { - m_logViscSpecies[k] = m_visc_logA[k] + m_visc_n[k] * m_logt - + m_visc_Tact[k] / m_temp ; - m_viscSpecies[k] = exp( m_logViscSpecies[k] ); + m_viscSpecies[k] = m_viscTempDep_Ns[k]->getSpeciesTransProp() ; } - //for (k = 0; k < m_nsp; k++) { - //m_viscSpecies[k] = m_visc_A[k] * exp( m_visc_n[k] * m_logt - // + m_visc_Tact[k] / m_temp ); - //} m_visc_temp_ok = true; m_visc_mix_ok = false; } + // Update the pure-species ionic conductivities functional dependence on concentration. + void LiquidTransport::updateIonConductivity_C() { + m_ionCond_conc_ok = true; + } + + + /* + * Updates the array of pure species ionic conductivities internally + * using calls to the appropriate LTPspecies subclass. + * The flag m_ionCond_ok is set to true. + */ + void LiquidTransport::updateIonConductivity_T() { + int k; + + for (k = 0; k < m_nsp; k++) { + m_ionCondSpecies[k] = m_ionCondTempDep_Ns[k]->getSpeciesTransProp() ; + } + m_ionCond_temp_ok = true; + m_ionCond_mix_ok = false; + } + + + // Update the pure-species mobility ratios functional dependence on concentration. + void LiquidTransport::updateMobilityRatio_C() { + m_mobRat_conc_ok = true; + } + + /* + * Updates the array of pure species mobility ratios internally + * using calls to the appropriate LTPspecies subclass. + * The flag m_mobRat_ok is set to true. + */ + void LiquidTransport::updateMobilityRatio_T() { + int k; + int j; + + for (k = 0; k < m_nsp2; k++) { + for (j = 0; j < m_nsp; j++) { + m_mobRatSpecies(k,j) = m_mobRatTempDep_Ns[k][j]->getSpeciesTransProp(); + } + } + m_mobRat_temp_ok = true; + m_mobRat_mix_ok = false; + } + + + // Update the pure-species self diffusion functional dependence on concentration. + void LiquidTransport::updateSelfDiffusion_C() { + m_selfDiff_conc_ok = true; + } + + + /* + * Updates the array of pure species self diffusion internally + * using calls to the appropriate LTPspecies subclass. + * The flag m_selfDiff_ok is set to true. + */ + void LiquidTransport::updateSelfDiffusion_T() { + int k; + int j; + + for (k = 0; k < m_nsp2; k++) { + for (j = 0; j < m_nsp; j++) { + m_selfDiffSpecies(k,j) = m_selfDiffTempDep_Ns[k][j]->getSpeciesTransProp() ; + } + } + m_selfDiff_temp_ok = true; + m_selfDiff_mix_ok = false; + } + //============================================================================================================= + void LiquidTransport::updateHydrodynamicRadius_C() { + m_radi_conc_ok = true; + } + //============================================================================================================= + // Update the temperature-dependent hydrodynamic radius terms + // for each species internally using calls to the + // appropriate LTPspecies subclass + void LiquidTransport::updateHydrodynamicRadius_T() { + int k; + + for (k = 0; k < m_nsp; k++) { + m_hydrodynamic_radius[k] = m_radiusTempDep_Ns[k]->getSpeciesTransProp() ; + } + m_radi_temp_ok = true; + m_radi_mix_ok = false; + } + + void LiquidTransport::update_Grad_lnAC() { + + int k; + + doublereal grad_T; + vector_fp grad_lnAC(m_nsp), grad_X(m_nsp); + // IonsFromNeutralVPSSTP * tempIons = dynamic_cast m_thermo; + //MargulesVPSSTP * tempMarg = dynamic_cast (tempIons->neutralMoleculePhase_); + + + //m_thermo->getdlnActCoeffdlnX( DATA_PTR(grad_lnAC) ); + for (k = 0; k < m_nDim; k++ ) { + grad_T = m_Grad_T[k]; + grad_X.assign(m_Grad_X.begin()+m_nsp*k,m_Grad_X.begin()+m_nsp*(k+1)); + m_thermo->getdlnActCoeffds( grad_T, DATA_PTR(grad_X), DATA_PTR(grad_lnAC) ); + for ( int i = 0; i < m_nsp; i++ ) + if (m_molefracs[i] < 1.e-15) + grad_lnAC[i] = 0; + else + grad_lnAC[i] += grad_X[i]/m_molefracs[i]; + copy(grad_lnAC.begin(),grad_lnAC.end(),m_Grad_lnAC.begin()+m_nsp*k); + // std::cout << k << " m_Grad_lnAC = " << m_Grad_lnAC[k] << std::endl; + } + + return; + } + //==================================================================================================================== /* * * Solve for the diffusional velocities in the Stefan-Maxwell equations * */ + // Solve the stefan_maxell equations for the diffusive fluxes. + /* + * The diffusive mass flux of species \e k is computed + * using the Stefan-Maxwell equation + * \f[ + * X_i \nabla \mu_i + * = RT \sum_i \frac{X_i X_j}{D_{ij}} + * ( \vec{V}_j - \vec{V}_i ) + * \f] + * to determine the diffusion velocity and + * \f[ + * \vec{N}_i = C_T X_i \vec{V}_i + * \f] + * to determine the diffusion flux. Here \f$ C_T \f$ is the + * total concentration of the mixture [kmol/m^3], \f$ D_{ij} \f$ + * are the Stefa-Maxwell interaction parameters in [m^2/s], + * \f$ \vec{V}_{i} \f$ is the diffusion velocity of species \e i, + * \f$ \mu_i \f$ is the electrochemical potential of species \e i. + * + * The diffusion velocity is relative to an average velocity + * that can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the \verbatim + * \endverbatim input parameter. + * + * One of the Stefan Maxwell equations is replaced by the appropriate + * definition of the mass-averaged velocity, the mole-averaged velocity + * or the specification that velocities are relative to that + * of one species. + */ void LiquidTransport::stefan_maxwell_solve() { int i, j, a; doublereal tmp; - int VIM = m_nDim; - m_B.resize(m_nsp, VIM); + m_B.resize(m_nsp, m_nDim, 0.0); + m_A.resize(m_nsp, m_nsp, 0.0); + //! grab a local copy of the molecular weights const vector_fp& M = m_thermo->molecularWeights(); - - + //! grad a local copy of the ion molar volume (inverse total ion concentration) + const doublereal vol = m_thermo->molarVolume(); + /* - * Update the concentrations in the mixture. + * Update the temperature, concentrations and diffusion coefficients in the mixture. */ - update_conc(); + update_T(); + update_C(); + if ( !m_diff_temp_ok ) updateDiff_T(); double T = m_thermo->temperature(); + update_Grad_lnAC() ; - m_thermo->getStandardVolumes(DATA_PTR(volume_specPM_)); - m_thermo->getActivityCoefficients(DATA_PTR(actCoeffMolar_)); + //m_thermo->getStandardVolumes(DATA_PTR(m_volume_spec)); + m_thermo->getActivityCoefficients(DATA_PTR(m_actCoeff)); /* * Calculate the electrochemical potential gradient. This is the @@ -803,7 +1579,7 @@ namespace Cantera { * * Here we calculate * - * c_i * (grad (mu_i) + S_i grad T - M_i / dens * grad P + * X_i * (grad (mu_i) + S_i grad T - M_i / dens * grad P * * This is Eqn. 13-1 p. 318 Newman. The original equation is from * Hershfeld, Curtis, and Bird. @@ -823,13 +1599,11 @@ namespace Cantera { * */ for (i = 0; i < m_nsp; i++) { - double xi_denom = m_molefracs_tran[i]; - for (a = 0; a < VIM; a++) { - m_ck_Grad_mu[a*m_nsp + i] = - m_chargeSpecies[i] * concTot_ * Faraday * m_Grad_V[a] - + concTot_ * (volume_specPM_[i] - M[i]/dens_) * m_Grad_P[a] - + concTot_ * GasConstant * T * m_Grad_lnAC[a*m_nsp+i] / actCoeffMolar_[i] - + concTot_ * GasConstant * T * m_Grad_X[a*m_nsp+i] / xi_denom; + for (a = 0; a < m_nDim; a++) { + m_Grad_mu[a*m_nsp + i] = + m_chargeSpecies[i] * Faraday * m_Grad_V[a] + //+ (m_volume_spec[i] - M[i]/dens_) * m_Grad_P[a] + + GasConstant * T * m_Grad_lnAC[a*m_nsp+i]; } } @@ -839,9 +1613,9 @@ namespace Cantera { double mnaught = mwSolvent/ 1000.; double lnmnaught = log(mnaught); for (i = 1; i < m_nsp; i++) { - for (a = 0; a < VIM; a++) { - m_ck_Grad_mu[a*m_nsp + i] -= - m_concentrations[i] * GasConstant * m_Grad_T[a] * lnmnaught; + for (a = 0; a < m_nDim; a++) { + m_Grad_mu[a*m_nsp + i] -= + m_molefracs[i] * GasConstant * m_Grad_T[a] * lnmnaught; } } } @@ -850,43 +1624,99 @@ namespace Cantera { * Just for Note, m_A(i,j) refers to the ith row and jth column. * They are still fortran ordered, so that i varies fastest. */ - switch (VIM) { + + double condSum1; + switch (m_nDim) { case 1: /* 1-D approximation */ + m_B(0,0) = 0.0; + //equation for the reference velocity for (j = 0; j < m_nsp; j++) { - m_A(0,j) = M[j] * m_concentrations[j]; + if ( m_velocityBasis == VB_MOLEAVG ) + m_A(0,j) = m_molefracs_tran[j]; + else if ( m_velocityBasis == VB_MASSAVG ) + m_A(0,j) = m_massfracs_tran[j]; + else if ( ( m_velocityBasis >= 0 ) + && ( m_velocityBasis < m_nsp ) ) + // use species number m_velocityBasis as reference velocity + if ( m_velocityBasis == j ) m_A(0,j) = 1.0; + else m_A(0,j) = 0.0; + else + throw CanteraError("LiquidTransport::stefan_maxwell_solve", + "Unknown reference velocity provided."); } for (i = 1; i < m_nsp; i++){ - m_B(i,0) = m_ck_Grad_mu[i] / (GasConstant * T); + m_B(i,0) = m_Grad_mu[i] / (GasConstant * T); m_A(i,i) = 0.0; for (j = 0; j < m_nsp; j++){ if (j != i) { - tmp = m_concentrations[j] / m_DiffCoeff_StefMax(i,j); - m_A(i,i) += tmp; - m_A(i,j) = - tmp; + //if ( !( m_bdiff(i,j) > 0.0 ) ) + //throw CanteraError("LiquidTransport::stefan_maxwell_solve", + // "m_bdiff has zero entry in non-diagonal."); + tmp = m_molefracs_tran[j] * m_bdiff(i,j); + m_A(i,i) -= tmp; + m_A(i,j) = + tmp; } } } //! invert and solve the system Ax = b. Answer is in m_B solve(m_A, m_B); - + + /* + condSum2 = m_chargeSpecies[1]*m_chargeSpecies[1]*m_molefracs_tran[1]*m_bdiff(2,3) + + m_chargeSpecies[2]*m_chargeSpecies[2]*m_molefracs_tran[2]*m_bdiff(1,3) + + m_chargeSpecies[3]*m_chargeSpecies[3]*m_molefracs_tran[3]*m_bdiff(1,2); + condSum1 = m_molefracs_tran[1]*m_bdiff(1,2)*m_bdiff(1,3) + + m_molefracs_tran[2]*m_bdiff(2,3)*m_bdiff(1,2) + + m_molefracs_tran[3]*m_bdiff(1,3)*m_bdiff(2,3); + condSum2 = condSum2/condSum1*Faraday*Faraday/GasConstant/T/vol; + */ + + condSum1 = 0; + for (i = 0; i < m_nsp; i++){ + condSum1 -= Faraday*m_chargeSpecies[i]*m_B(i,0)*m_molefracs_tran[i]/vol; + } + + /* + Check Mobility Ratio of Cations + cout << "mobility ratio = " << m_chargeSpecies[1]*(m_B(1,0)-m_B(2,0))/m_chargeSpecies[0]/(m_B(0,0)-m_B(2,0)) << endl; + */ + + // cout << condSum1 << " = " << condSum2 << endl; + + break; case 2: /* 2-D approximation */ m_B(0,0) = 0.0; m_B(0,1) = 0.0; + //equation for the reference velocity for (j = 0; j < m_nsp; j++) { - m_A(0,j) = M[j] * m_concentrations[j]; + if ( m_velocityBasis == VB_MOLEAVG ) + m_A(0,j) = m_molefracs_tran[j]; + else if ( m_velocityBasis == VB_MASSAVG ) + m_A(0,j) = m_massfracs_tran[j]; + else if ( ( m_velocityBasis >= 0 ) + && ( m_velocityBasis < m_nsp ) ) + // use species number m_velocityBasis as reference velocity + if ( m_velocityBasis == j ) m_A(0,j) = 1.0; + else m_A(0,j) = 0.0; + else + throw CanteraError("LiquidTransport::stefan_maxwell_solve", + "Unknown reference velocity provided."); } for (i = 1; i < m_nsp; i++){ - m_B(i,0) = m_ck_Grad_mu[i] / (GasConstant * T); - m_B(i,1) = m_ck_Grad_mu[m_nsp + i] / (GasConstant * T); + m_B(i,0) = m_Grad_mu[i] / (GasConstant * T); + m_B(i,1) = m_Grad_mu[m_nsp + i] / (GasConstant * T); m_A(i,i) = 0.0; for (j = 0; j < m_nsp; j++) { if (j != i) { - tmp = m_concentrations[j] / m_DiffCoeff_StefMax(i,j); - m_A(i,i) += tmp; - m_A(i,j) = - tmp; + //if ( !( m_bdiff(i,j) > 0.0 ) ) + //throw CanteraError("LiquidTransport::stefan_maxwell_solve", + // "m_bdiff has zero entry in non-diagonal."); + tmp = m_molefracs_tran[j] * m_bdiff(i,j); + m_A(i,i) -= tmp; + m_A(i,j) = + tmp; } } } @@ -901,19 +1731,34 @@ namespace Cantera { m_B(0,0) = 0.0; m_B(0,1) = 0.0; m_B(0,2) = 0.0; + //equation for the reference velocity for (j = 0; j < m_nsp; j++) { - m_A(0,j) = M[j] * m_concentrations[j]; + if ( m_velocityBasis == VB_MOLEAVG ) + m_A(0,j) = m_molefracs_tran[j]; + else if ( m_velocityBasis == VB_MASSAVG ) + m_A(0,j) = m_massfracs_tran[j]; + else if ( ( m_velocityBasis >= 0 ) + && ( m_velocityBasis < m_nsp ) ) + // use species number m_velocityBasis as reference velocity + if ( m_velocityBasis == j ) m_A(0,j) = 1.0; + else m_A(0,j) = 0.0; + else + throw CanteraError("LiquidTransport::stefan_maxwell_solve", + "Unknown reference velocity provided."); } for (i = 1; i < m_nsp; i++){ - m_B(i,0) = m_ck_Grad_mu[i] / (GasConstant * T); - m_B(i,1) = m_ck_Grad_mu[m_nsp + i] / (GasConstant * T); - m_B(i,2) = m_ck_Grad_mu[2*m_nsp + i] / (GasConstant * T); + m_B(i,0) = m_Grad_mu[i] / (GasConstant * T); + m_B(i,1) = m_Grad_mu[m_nsp + i] / (GasConstant * T); + m_B(i,2) = m_Grad_mu[2*m_nsp + i] / (GasConstant * T); m_A(i,i) = 0.0; for (j = 0; j < m_nsp; j++) { if (j != i) { - tmp = m_concentrations[j] / m_DiffCoeff_StefMax(i,j); - m_A(i,i) += tmp; - m_A(i,j) = - tmp; + //if ( !( m_bdiff(i,j) > 0.0 ) ) + //throw CanteraError("LiquidTransport::stefan_maxwell_solve", + // "m_bdiff has zero entry in non-diagonal."); + tmp = m_molefracs_tran[j] * m_bdiff(i,j); + m_A(i,i) -= tmp; + m_A(i,j) = + tmp; } } } @@ -928,26 +1773,25 @@ namespace Cantera { break; } - for (a = 0; a < VIM; a++) { + for (a = 0; a < m_nDim; a++) { for (j = 0; j < m_nsp; j++) { - m_flux(j,a) = M[j] * m_concentrations[j] * m_B(j,a); + m_Vdiff(j,a) = m_B(j,a); + m_flux(j,a) = concTot_ * M[j] * m_molefracs_tran[j] * m_B(j,a); } } } - - - /** - * Throw an exception if this method is invoked. - * This probably indicates something is not yet implemented. + //==================================================================================================================== + // Throw an exception indicating something is not yet implemented. + /* + * @param msg String with an informative message */ - doublereal LiquidTransport::err(std::string msg) const { - throw CanteraError("Liquid Transport Class", - "\n\n\n**** Method "+ msg +" not implemented in model " - + int2str(model()) + " ****\n" - "(Did you forget to specify a transport model?)\n\n\n"); - - return 0.0; - } - - + doublereal LiquidTransport::err(std::string msg) const { + throw CanteraError("LiquidTransport::err()", + "\n\n\n**** Method "+ msg +" not implemented in model " + + int2str(model()) + " ****\n" + "(Did you forget to specify a transport model?)\n\n\n"); + return 0.0; + } + //==================================================================================================================== } +//====================================================================================================================== diff --git a/Cantera/src/transport/LiquidTransport.h b/Cantera/src/transport/LiquidTransport.h index 2733ed1af..080790f5f 100644 --- a/Cantera/src/transport/LiquidTransport.h +++ b/Cantera/src/transport/LiquidTransport.h @@ -1,5 +1,4 @@ /** - * * @file LiquidTransport.h * Header file defining class LiquidTransport */ @@ -20,8 +19,6 @@ #include #include -using namespace std; - // Cantera includes #include "TransportBase.h" #include "DenseMatrix.h" @@ -30,112 +27,77 @@ using namespace std; namespace Cantera { - const int LVISC_CONSTANT = 0; - const int LVISC_INTERACTION = 1; - const int LVISC_AVG_ENERGIES = 2; - - const int LDIFF_MIXDIFF_UNCORRECTED = 0; - const int LDIFF_MIXDIFF_FLUXCORRECTED = 1; - const int LDIFF_MULTICOMP_STEFANMAXWELL = 2; - - - + // Forward references class LiquidTransportParams; - //! Class LiquidTransport implements mixture-averaged transport - //! properties for liquid phases. + //! Class LiquidTransport implements models for transport + //! properties for liquid phases. /*! - * The model is based on that - * described by Newman, Electrochemical Systems + * Liquid Transport is set up with some flexibility in + * this class. Transport properties like viscostiy + * and thermal conductivity are allowed flexibility within + * the constraints of the LiquidTransportProperty and + * LiquidTransportInteractions classes. For species + * diffusion, the LiquidTransport class focuses on + * the Stefan-Maxwell equation to determine the diffusion + * velocities. Other options for liquid diffusion include + * solvent-dominated diffusion, and a class SolventTransport + * should be forthcoming. * - * The velocity of species i may be described by the - * following equation p. 297 (12.1) - * - * \f[ - * c_i \nabla \mu_i = R T \sum_j \frac{c_i c_j}{c_T D_{ij}} - * (\mathbf{v}_j - \mathbf{v}_i) - * \f] - * - * This as written is degenerate by 1 dof. - * - * To fix this we must add in the definition of the mass averaged - * velocity of the solution. We will call the simple bold-faced - * \f$\mathbf{v} \f$ - * symbol the mass-averaged velocity. Then, the relation - * between \f$\mathbf{v}\f$ and the individual species velocities is - * \f$\mathbf{v}_i\f$ - * - * \f[ - * \rho_i \mathbf{v}_i = \rho_i \mathbf{v} + \mathbf{j}_i - * \f] - * where \f$\mathbf{j}_i\f$ are the diffusional fluxes of species i - * with respect to the mass averaged velocity and - * - * \f[ - * \sum_i \mathbf{j}_i = 0 - * \f] - * - * and - * - * \f[ - * \sum_i \rho_i \mathbf{v}_i = \rho \mathbf{v} - * \f] - * - * Using these definitions, we can write - * - * \f[ - * \mathbf{v}_i = \mathbf{v} + \frac{\mathbf{j}_i}{\rho_i} - * \f] - * - * - * \f[ - * c_i \nabla \mu_i = R T \sum_j \frac{c_i c_j}{c_T D_{ij}} - * (\frac{\mathbf{j}_j}{\rho_j} - \frac{\mathbf{j}_i}{\rho_i}) - * = R T \sum_j \frac{1}{D_{ij}} - * (\frac{x_i \mathbf{j}_j}{M_j} - \frac{x_j \mathbf{j}_i}{M_i}) - * \f] - * - * The equations that we actually solve are - * - * \f[ - * c_i \nabla \mu_i = - * = R T \sum_j \frac{1}{D_{ij}} - * (\frac{x_i \mathbf{j}_j}{M_j} - \frac{x_j \mathbf{j}_i}{M_i}) - * \f] - * and we replace the 0th equation with the following: - * - * \f[ - * \sum_i \mathbf{j}_i = 0 - * \f] - * - * When there are charged species, we replace the rhs with the - * gradient of the electrochemical potential to obtain the - * modified equation + * The class LiquidTransport has several roles. + * -# It brings together the individual species transport + * properties, expressed as subclasses of LTPspecies + * (Liquid Transport Properties of Species) through + * LiquidTransportData, with models for + * the composition dependence of liquid transport properties + * expressed as subclasses of LiquidTranInteraction + * (mixing rules) through LiquidTransportParams. Calculating + * mixture properties generally consists of calling the + * getMixTansProp member of LiquidTranInteraction by passing + * a vector of LTPSpecies + * -# It calculates the bulk velocity \f$ \vec{v} \f$ and + * individual species diffusion velocities, \f$ \vec{V_i} \f$ + * using the Stefan-Maxwell equations. It is possible to set a + * flag to calculate relative to a mass-averaged bulk velocity, + * relative to a mole-averaged bulk velocity or relative to a + * single species velocity using the \, + * \, or \ + * keyword. Mass-averaged velocities are the default for which + * the diffusion velocities satisfy + * \f[ + * \sum_{i} Y_i \vec{V_i} = 0 + * \f] + * for mass fraction \f$ Y_i \f$. For mole-averaged velocities + * \f[ + * \sum_{i} X_i \vec{V_i} = 0 + * \f] + * for mole fraction \f$ X_i \f$. or + * \f[ + * \vec{V_i} = 0 + * \f] + * for reference species \f$ i \f$. + * -# It provides access to a number of derived quantities + * related to transport properties as described in the + * various methods below. + * * - * \f[ - * c_i \nabla \mu_i + c_i F z_i \nabla \Phi - * = R T \sum_j \frac{1}{D_{ij}} - * (\frac{x_i \mathbf{j}_j}{M_j} - \frac{x_j \mathbf{j}_i}{M_i}) - * \f] - * - * With this formulation we may solve for the diffusion velocities, - * without having to worry about what the mass averaged velocity - * is. - * - *

Viscosity Calculation

- * - * The viscosity calculation may be broken down into two parts. - * In the first part, the viscosity of the pure species are calculated - * In the second part, a mixing rule is applied, based on the - * Wilkes correlation, to yield the mixture viscosity. + * Within LiquidTransport, the state is presumed to be + * defined in terms of the species mole fraction, + * temperature and pressure. Charged species are expected + * and quantities like the electric current are computed + * based on a combined electrochemcial potential. * * - * + * @ingroup tranprops */ class LiquidTransport : public Transport { public: + //! Typedef equating vector_fp with Coeff_T_ + typedef vector_fp Coeff_T_; + + //! Default constructor. /*! * This requires call to initLiquid(LiquidTransportParams& tr) @@ -148,7 +110,7 @@ namespace Cantera { */ LiquidTransport(thermo_t* thermo = 0, int ndim = 1); - //!Copy Constructor for the %LiquidThermo object. + //! Copy Constructor for the %LiquidThermo object. /*! * @param right %LiquidTransport to be copied */ @@ -177,12 +139,15 @@ namespace Cantera { //! virtual destructor - virtual ~LiquidTransport() {} + virtual ~LiquidTransport(); //! Initialize the transport object /*! * Here we change all of the internal dimensions to be sufficient. * We get the object ready to do property evaluations. + * A lot of the input required to do property evaluations is + * contained in the LiquidTransportParams class that is + * filled in TransportFactory. * * @param tr Transport parameters for all of the species * in the phase. @@ -197,72 +162,215 @@ namespace Cantera { return cLiquidTransport; } - //! overloaded base class methods //! Returns the viscosity of the solution /*! - * The viscosity is computed using mixture averaging plus - * any information on interaction parameters - * \f[ - * \mu = \sum_k {\mu_k X_k} {\sum_j \sum_k {G_{j,k} X_k X_j} }. - * \f] - * Here \f$ \mu_k \f$ is the viscosity of pure species \e k, - * and \f$ G_{k,j} \f$ is the interaction parameter. - - * @see updateViscosity_T(); - * - * Controlling update boolean m_viscmix_ok + * The viscosity calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species viscosities. */ virtual doublereal viscosity(); - - //! Returns the pure species viscosities + + //! Returns the pure species viscosities for all species /*! - * The pure species viscosities are to be given in an Arrhenius - * form in accordance with activated-jump-process dominated transport. + * The pure species viscosities are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param visc array of length "number of species" + * to hold returned viscosities. */ virtual void getSpeciesViscosities(doublereal* const visc); + //! Returns the ionic conductivity of the solution + /*! + * The ionic conductivity calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species ionic conductivities. + */ + virtual doublereal ionConductivity(); + + //! Returns the pure species ionic conductivities for all species + /*! + * The pure species ionic conductivities are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param ionCond Array of length "number of species" to hold returned ionic conductivities. + */ + virtual void getSpeciesIonConductivity(doublereal* const ionCond); + + //! Returns the pointer to the mobility ratios of the binary + //! combinations of the transported species for the solution + //! Has size of the number of binary interactions = nsp*nsp + /*! + * The mobility ratio calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the mobility ratios in the pure species. + * + * @param mobRat Vector of mobility ratios + */ + virtual void mobilityRatio(doublereal* mobRat); + + //! Returns a double pointer to the mobility ratios of the + //! transported species in each pure species phase. + /*! + * Has size of the number of binary interactions by the number + * of species (nsp*nsp X nsp) + * The pure species mobility ratios are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param mobRat array of length "number of species" + * to hold returned mobility ratios. + */ + virtual void getSpeciesMobilityRatio(doublereal** mobRat); + + //! Returns the self diffusion coefficients of the species in the phase. + //! Has size of nsp(coeffs) + /*! + * The self diffusion coefficient is the diffusion coefficient of a tracer species + * at the current temperature and composition of the species. Therefore, + * the dilute limit of transport is assumed for the tracer species. + * The effective formula may be calculated from the stefan-maxwell formulation by + * adding another row for the tracer species, assigning all D's to be equal + * to the respective species D's, and then taking the limit as the + * tracer species mole fraction goes to zero. The corresponding flux equation + * for the tracer species k in units of kmol m-2 s-1 is. + * + * \f[ + * J_k = - D^{sd}_k \frac{C_k}{R T} \nabla \mu_k + * \f] + * + * The derivative is taken at constant T and P. + * + * The self diffusion calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species self diffusion coeffs. + * + * @param selfDiff Vector of self-diffusion coefficients + * Length = number of species in phase + * units = m**2 s-1 + */ + virtual void selfDiffusion(doublereal* const selfDiff); + + //! Returns the self diffusion coefficients in the pure species phases. + //! Has size of nsp(coeffs) x nsp(phases) + /*! + * The pure species molar volumes are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param selfDiff array of length "number of species" + * to hold returned self diffusion coeffs. + */ + virtual void getSpeciesSelfDiffusion(doublereal** selfDiff); + + //! Returns the hydrodynamic radius for all species + /*! + * The species hydrodynamic radii are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param radius array of length "number of species" + * to hold returned radii. + */ + virtual void getSpeciesHydrodynamicRadius(doublereal* const radius); + //! Returns the binary diffusion coefficients /*! - * @param ld - * @param d + * The binary diffusion coefficients are specified in the input + * file through the LiquidTransportInteractions class. These + * are the binary interaction coefficients employed in the + * Stefan-Maxwell equation. + * + * @param ld number of species in system + * @param d vector of binary diffusion coefficients + * units = m2 s-1. length = ld*ld = (number of species)^2 */ virtual void getBinaryDiffCoeffs(const int ld, doublereal* const d); //! Get the Mixture diffusion coefficients /*! + * The mixture diffusion coefficients are not well defined + * in the context of LiquidTransport because the Stefan Maxwell + * equation is solved. Here the mixture diffusion coefficients + * are defined according to Ficks law: + * \f[ + * X_i \vec{V_i} = -D_i \nabla X_i. + * \f] + * Solving Ficks Law for \f$ D_i \f$ gives a mixture diffusion + * coefficient + * \f[ + * D_i = - X_i \vec{V_i} / ( \nabla X_i ). + * \f] + * If \f$ \nabla X_i = 0 \f$ this is undefined and the + * nonsensical value -1 is returned. + * + * Note that this evaluation of \f$ \vec{V_i} \f$ requires + * a solve of the Stefan Maxwell equation making this + * determination of the mixture averaged diffusion coefficients + * a \e slow method for obtaining diffusion coefficients. + * + * Also note that the Stefan Maxwell solve will be based upon + * the thermodynamic state (including gradients) most recently + * set. Gradients can be set specifically using set_Grad_V, + * set_Grad_X and set_Grad_T or through calls to + * getSpeciesFluxes, getSpeciesFluxesES, getSpeciesVdiff, + * getSpeciesVdiffES, etc. + * * @param d vector of mixture diffusion coefficients * units = m2 s-1. length = number of species */ virtual void getMixDiffCoeffs(doublereal* const d); + //! Return the thermal diffusion coefficients + /*! + * These are all zero for this simple implementaion + * + * @param dt thermal diffusion coefficients + */ virtual void getThermalDiffCoeffs(doublereal* const dt); //! Return the thermal conductivity of the solution /*! - * The thermal conductivity is computed from the following mixture rule: - * \f[ - * \lambda = 0.5 \left( \sum_k X_k \lambda_k - * + \frac{1}{\sum_k X_k/\lambda_k}\right) - * \f] - * - * Controlling update boolean = m_condmix_ok - */ + * The thermal conductivity calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species thermal condictivities. + */ virtual doublereal thermalConductivity(); //! Get the Electrical mobilities (m^2/V/s). /*! - * This function returns the mobilities. In some formulations - * this is equal to the normal mobility multiplied by faraday's constant. - * - * The mobility is calculated from the - * diffusion coefficient using the Einstein relation + * The electrical mobilities are not well defined + * in the context of LiquidTransport because the Stefan Maxwell + * equation is solved. Here the electrical mobilities + * are calculated from the mixture-averaged + * diffusion coefficients through a call to getMixDiffCoeffs() + * using the Einstein relation * * \f[ * \mu^e_k = \frac{F D_k}{R T} * \f] * + * Note that this call to getMixDiffCoeffs() requires + * a solve of the Stefan Maxwell equation making this + * determination of the mixture averaged diffusion coefficients + * a \e slow method for obtaining diffusion coefficients. + * + * Also note that the Stefan Maxwell solve will be based upon + * the thermodynamic state (including gradients) most recently + * set. Gradients can be set specifically using set_Grad_V, + * set_Grad_X and set_Grad_T or through calls to + * getSpeciesFluxes, getSpeciesFluxesES, getSpeciesVdiff, + * getSpeciesVdiffES, etc. + * * @param mobil_e Returns the electrical mobilities of * the species in array \c mobil_e. The array must be * dimensioned at least as large as the number of species. @@ -271,17 +379,29 @@ namespace Cantera { //! Get the fluid mobilities (s kmol/kg). /*! - * This function returns the fluid mobilities. Usually, you have - * to multiply Faraday's constant into the resulting expression - * to general a species flux expression. - * - * The mobility is calculated from the - * diffusion coefficient using the Einstein relation + * The fluid mobilities are not well defined + * in the context of LiquidTransport because the Stefan Maxwell + * equation is solved. Here the fluid mobilities + * are calculated from the mixture-averaged + * diffusion coefficients through a call to getMixDiffCoeffs() + * using the Einstein relation * * \f[ * \mu^f_k = \frac{D_k}{R T} * \f] * + * Note that this call to getMixDiffCoeffs() requires + * a solve of the Stefan Maxwell equation making this + * determination of the mixture averaged diffusion coefficients + * a \e slow method for obtaining diffusion coefficients. + * + * Also note that the Stefan Maxwell solve will be based upon + * the thermodynamic state (including gradients) most recently + * set. Gradients can be set specifically using set_Grad_V, + * set_Grad_X and set_Grad_T or through calls to + * getSpeciesFluxes, getSpeciesFluxesES, getSpeciesVdiff, + * getSpeciesVdiffES, etc. + * * @param mobil_f Returns the fluid mobilities of * the species in array \c mobil_f. The array must be * dimensioned at least as large as the number of species. @@ -297,8 +417,7 @@ namespace Cantera { //! Specify the value of the gradient of the temperature /*! - * - * @param grad_V Gradient of the temperature (length num dimensions); + * @param grad_T Gradient of the temperature (length num dimensions); */ virtual void set_Grad_T(const doublereal* const grad_T); @@ -309,14 +428,265 @@ namespace Cantera { */ virtual void set_Grad_X(const doublereal* const grad_X); - virtual void update_Grad_lnAC(); + //! Compute the mixture electrical conductivity from + //! the Stefan-Maxwell equation. + /*! + * To compute the mixture electrical conductance, the Stefan + * Maxwell equation is solved for zero species gradients and + * for unit potential gradient, \f$ \nabla V \f$. + * The species fluxes are converted to current by summing over + * the charge-weighted fluxes according to + * \f[ + * \vec{i} = \sum_{i} z_i F \rho \vec{V_i} / W_i + * \f] + * where \f$ z_i \f$ is the charge on species i, + * \f$ F \f$ is Faradays constant, \f$ \rho \f$ is the density, + * \f$ W_i \f$ is the molecular mass of species i. + * The conductance, \f$ \kappa \f$ is obtained from + * \f[ + * \kappa = \vec{i} / \nabla V. + * \f] + * + */ + virtual doublereal getElectricConduct(); + + //! Compute the electric current density in A/m^2 + /*! + * The electric current is computed first by computing the + * species diffusive fluxes using the Stefan Maxwell solution + * and then the current, \f$ \vec{i} \f$ by summing over + * the charge-weighted fluxes according to + * \f[ + * \vec{i} = \sum_{i} z_i F \rho \vec{V_i} / W_i + * \f] + * where \f$ z_i \f$ is the charge on species i, + * \f$ F \f$ is Faradays constant, \f$ \rho \f$ is the density, + * \f$ W_i \f$ is the molecular mass of species \c i. + * + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * @param ldx Leading dimension of the grad_X array. + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the grad_V and current vectors. + * @param grad_V The electrostatic potential gradient. + * @param current The electric current in A/m^2. + */ + virtual void getElectricCurrent(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_V, + doublereal* current); + + + //! Get the species diffusive velocities wrt to the averaged velocity, + //! given the gradients in mole fraction and temperature + /*! + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. + * + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param Vdiff Output of the diffusive velocities. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesVdiff(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + doublereal* Vdiff); + + //! Get the species diffusive velocities wrt to the averaged velocity, + //! given the gradients in mole fraction, temperature and electrostatic potential. + /*! + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. + * + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * (length = ndim) + * @param Vdiff Output of the species diffusion velocities + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesVdiffES(int ndim, const doublereal* grad_T, + int ldx, const doublereal* grad_X, + int ldf, const doublereal* grad_Phi, + doublereal* Vdiff) ; + + + //! Return the species diffusive mass fluxes wrt to + //! the averaged velocity in [kmol/m^2/s]. + /*! + * + * The diffusive mass flux of species \e k [kmol/m^2/s] is computed + * using the Stefan-Maxwell equation + * + * \f[ + * X_i \nabla \mu_i = RT \sum_i \frac{X_i X_j}{D_{ij}} + * ( \vec{V}_j - \vec{V}_i ) + * \f] + * + * to determine the diffusion velocity and + * + * \f[ + * \vec{N}_i = C_T X_i \vec{V}_i + * \f] + * + * to determine the diffusion flux. Here \f$ C_T \f$ is the + * total concentration of the mixture [kmol/m^3], \f$ D_{ij} \f$ + * are the Stefa-Maxwell interaction parameters in [m^2/s], + * \f$ \vec{V}_{i} \f$ is the diffusion velocity of species \e i, + * \f$ \mu_i \f$ is the electrochemical potential of species \e i. + * + * Note that for this method, there is no argument for the + * gradient of the electric potential (voltage). Electric + * potential gradients can be set with set_Grad_V() or + * method getSpeciesFluxesES() can be called.x + * + * The diffusion velocity is relative to an average velocity + * that can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the \verbatim \endverbatim input parameter. + * + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * (length = ndim) + * @param ldx Leading dimension of the grad_X array. + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes); + + //! Return the species diffusive mass fluxes wrt to + //! the averaged velocity in [kmol/m^2/s]. + /*! + * + * The diffusive mass flux of species \e k is computed + * using the Stefan-Maxwell equation + * \f[ + * X_i \nabla \mu_i + * = RT \sum_i \frac{X_i X_j}{D_{ij}} + * ( \vec{V}_j - \vec{V}_i ) + * \f] + * to determine the diffusion velocity and + * \f[ + * \vec{N}_i = C_T X_i \vec{V}_i + * \f] + * to determine the diffusion flux. Here \f$ C_T \f$ is the + * total concentration of the mixture [kmol/m^3], \f$ D_{ij} \f$ + * are the Stefa-Maxwell interaction parameters in [m^2/s], + * \f$ \vec{V}_{i} \f$ is the diffusion velocity of species \e i, + * \f$ \mu_i \f$ is the electrochemical potential of species \e i. + * + * The diffusion velocity is relative to an average velocity + * that can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the \verbatim + * \endverbatim input parameter. + + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * (length = ndim) + * @param ldx Leading dimension of the grad_X array. + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * length = ndim + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesFluxesES(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_Phi, + doublereal* fluxes); + + //! Return the species diffusive velocities relative to + //! the averaged velocity. + /*! + * This method acts similarly to getSpeciesVdiffES() but + * requires all gradients to be preset using methods + * set_Grad_X(), set_Grad_V(), set_Grad_T(). + * See the documentation of getSpeciesVdiffES() for details. + * + * @param ldf Leading dimension of the Vdiff array. + * @param Vdiff Output of the diffusive velocities. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesVdiffExt(int ldf, doublereal* Vdiff); + + //! Return the species diffusive fluxes relative to + //! the averaged velocity. + /*! + * This method acts similarly to getSpeciesFluxesES() but + * requires all gradients to be preset using methods + * set_Grad_X(), set_Grad_V(), set_Grad_T(). + * See the documentation of getSpeciesFluxesES() for details. + * + * units = kg/m2/s + * + * @param ldf Leading dimension of the Vdiff array. + * @param fluxes Output of the diffusive fluxes. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesFluxesExt(int ldf, doublereal* fluxes); protected: - //! Handles the effects of changes in the Temperature, internally - //! within the object. + //! Returns true if temperature has changed, + //! in which case flags are set to recompute transport properties. /*! - * This is called whenever a transport property is - * requested. + * This is called whenever a transport property is requested. * The first task is to check whether the temperature has changed * since the last call to update_T(). * If it hasn't then an immediate return is carried out. @@ -326,10 +696,13 @@ namespace Cantera { * part of all of the interfaces. * * @internal - */ - virtual void update_temp(); + * + * @return Returns true if the temperature has changed, and false otherwise + */ + virtual bool update_T(); - //! Handles the effects of changes in the mixture concentration + //! Returns true if mixture composition has changed, + //! in which case flags are set to recompute transport properties. /*! * This is called for every interface call to check whether * the concentrations have changed. Concentrations change @@ -340,94 +713,341 @@ namespace Cantera { * part of all of the interfaces. * * @internal + * + * @return Returns true if the mixture composition has changed, and false otherwise. */ - virtual void update_conc(); - - public: - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from - * - * - */ - virtual void getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, const doublereal* grad_X, - int ldf, doublereal* fluxes); + virtual bool update_C(); - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from - * + //! Updates the internal value of the gradient of the + //! logarithm of the activity, which is + //! used in the gradient of the chemical potential. + /*! + * Evaluate the gradients of the activity + * as they alter the diffusion coefficient. * + * The gradient of the chemical potential can be written in terms of + * gradient of the logarithm of the mole fraction times a correction + * associated with the gradient of the activity coefficient relative to + * that of the mole fraction. Specifically, the gradients of the + * logarithms of each are involved according to the formula + * + * \f[ + * \nabla \mu_k = RT \left[ \nabla ( \ln X_k ) + + * \nabla ( \ln \gamma_k ) \right] = RT \left[ + * \nabla ( \ln a_k ) \right] + * \f] + * + * The gradient in the activity coefficient requires the use of thermophase + * getdlnActCoeff that calculates its change based on a chane in the state + * (i.e. temperature and composition of each species) which was first + * implemented in MargulesVPSSTP.cpp (LiquidTransport.h doxygen) */ - virtual void getSpeciesFluxesExt(int ldf, doublereal* fluxes); + virtual void update_Grad_lnAC(); //! Solve the stefan_maxell equations for the diffusive fluxes. + /*! + * The diffusive mass flux of species \e k is computed + * using the Stefan-Maxwell equation + * \f[ + * X_i \nabla \mu_i + * = RT \sum_i \frac{X_i X_j}{D_{ij}} + * ( \vec{V}_j - \vec{V}_i ) + * \f] + * to determine the diffusion velocity and + * \f[ + * \vec{N}_i = C_T X_i \vec{V}_i + * \f] + * to determine the diffusion flux. Here \f$ C_T \f$ is the + * total concentration of the mixture [kmol/m^3], \f$ D_{ij} \f$ + * are the Stefa-Maxwell interaction parameters in [m^2/s], + * \f$ \vec{V}_{i} \f$ is the diffusion velocity of species \e i, + * \f$ \mu_i \f$ is the electrochemical potential of species \e i. + * + * The diffusion velocity is relative to an average velocity + * that can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the \verbatim + * \endverbatim input para + * The gradient in the activity coefficient requires the use of thermophase + * getdlnActCoeff that calculates its change based on a change in the state + * i.e. temperature and composition of each species. + * First implemented in MargulesVPSSTP.cppmeter. + * + * One of the Stefan Maxwell equations is replaced by the appropriate + * definition of the mass-averaged velocity, the mole-averaged velocity + * or the specification that velocities are relative to that + * of one species. + */ void stefan_maxwell_solve(); + //! Updates the array of pure species viscosities internally. + /*! + * The flag m_visc_ok is set to true. + * + * Note that for viscosity, a positive activation energy + * corresponds to the typical case of a positive argument + * to the exponential so that the Arrhenius expression is + * + * \f[ + * \mu = A T^n \exp( + E / R T ) + * \f] + */ + void updateViscosity_T(); + + //! Update the temperature-dependent ionic conductivity terms + //! for each species internally + /*! + * The flag m_ionCond_temp_ok is set to true. + */ + void updateIonConductivity_T(); + + //! Updates the array of pure species mobility ratios internally. + /*! + * The flag m_mobRat_ok is set to true. + */ + void updateMobilityRatio_T(); + + //! Updates the array of pure species self diffusion coeffs internally. + /*! + * The flag m_selfDiff_ok is set to true. + */ + void updateSelfDiffusion_T(); + + //! Update the temperature-dependent hydrodynamic radius terms + //! for each species internally + /*! + * The flag m_radi_temp_ok is set to true. + */ + void updateHydrodynamicRadius_T(); + + //! Update the temperature-dependent parts of the mixture-averaged + //! thermal conductivity internally + void updateCond_T(); + + //! Update the concentration parts of the viscosities + /*! + * Internal routine is run whenever the update_boolean + * m_visc_conc_ok is false. Currently there is no concentration + * dependence for the pure species viscosities. + * + * @internal + */ + void updateViscosities_C(); + + //! Update the concentration parts of the ionic conductivity + /*! + * Internal routine is run whenever the update_boolean + * m_ionCond_conc_ok is false. Currently there is no concentration + * dependence for the pure species ionic conductivity. + * + * @internal + */ + void updateIonConductivity_C(); + + //! Update the concentration parts of the mobility ratio + /*! + * Internal routine is run whenever the update_boolean + * m_mobRat_conc_ok is false. Currently there is no concentration + * dependence for the pure species mobility ratio. + * + * @internal + */ + void updateMobilityRatio_C(); + + //! Update the concentration parts of the self diffusion + /*! + * Internal routine is run whenever the update_boolean + * m_selfDiff_conc_ok is false. Currently there is no concentration + * dependence for the pure species self diffusion. + * + * @internal + */ + void updateSelfDiffusion_C(); + + //! Update the concentration dependence of the hydrodynamic radius + /*! + * Internal routine is run whenever the update_boolean + * m_radi_conc_ok is false. Currently there is no concentration + * dependence for the hydrodynamic radius. + * + * @internal + */ + void updateHydrodynamicRadius_C(); + + //! Update the binary Stefan-Maxwell diffusion coefficients + //! wrt T using calls to the appropriate LTPspecies subclass + void updateDiff_T(); + private: - - - //! Number of species in the mixture + //! Number of species in the phase int m_nsp; + //! Number of species squared + int m_nsp2; + //! Minimum temperature applicable to the transport property eval doublereal m_tmin; //! Maximum temperature applicable to the transport property evaluator doublereal m_tmax; - //! Local Copy of the molecular weights of the species + //! Local copy of the molecular weights of the species /*! - * Length is Equal to the number of species in the mechanism. + * Length is equal to the number of species in the phase */ - vector_fp m_mw; + vector_fp m_mw; - //! Pure species viscosities in Arrhenius temperature-dependent form. - vector_fp m_visc_A; - vector_fp m_visc_logA; //logarithm of coefficient - vector_fp m_visc_n; - vector_fp m_visc_Tact; - - //! Molecular interaction energies associated with viscosity - /** - * These multiply the viscosity according to - * \f[ exp( \sum_{i} \sum_{j} X_i X_j E_{i,j} / T \f]. + //! Viscosity for each species expressed as an appropriate subclass + //! of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). */ - DenseMatrix m_visc_Eij; + std::vector m_viscTempDep_Ns; - //! Molecular interaction entropies associated with viscosity - /** - * These multiply the viscosity according to - * \f[ exp( \sum_{i} \sum{j} X_i X_j S_{i,j} \f]. + //! Viscosity of the mixture expressed as a subclass of + //! LiquidTranInteraction + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). */ - DenseMatrix m_visc_Sij; + LiquidTranInteraction *m_viscMixModel; - //! Pure species thermal conductivities in Arrhenius temperature-dependent form. - vector_fp m_thermCond_A; - vector_fp m_thermCond_n; - vector_fp m_thermCond_Tact; + //! Ionic conductivity for each species expressed as an appropriate subclass + //! of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). + */ + std::vector m_ionCondTempDep_Ns; + + //! Ionic Conductivity of the mixture expressed as a subclass of + //! LiquidTranInteraction + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). + */ + LiquidTranInteraction *m_ionCondMixModel; + + //! Type def for LTPvector equating it with a vector of pointers to LTPspecies + typedef std::vector LTPvector; + + //! Mobility ratio for the binary cominations of each species in each + //! pure phase expressed as an appropriate subclass of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). + */ + std::vector m_mobRatTempDep_Ns; + + //! Mobility ratio for each binary combination of mobile species in the mixture + //! expressed as a subclass of LiquidTranInteraction + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). + */ + std::vector m_mobRatMixModel; + + //! Self Diffusion for each species in each pure species phase + //! expressed as an appropriate subclass of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). + */ + std::vector m_selfDiffTempDep_Ns; + + //! Self Diffusion for each species in the mixture expressed as a subclass of + //! LiquidTranInteraction + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). + */ + std::vector m_selfDiffMixModel; + + //! Thermal conductivity for each species expressed as an + //! appropriate subclass of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). + */ + std::vector m_lambdaTempDep_Ns; + + //! Thermal conductivity of the mixture expressed as a subclass of + //! LiquidTranInteraction + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). + */ + LiquidTranInteraction *m_lambdaMixModel; + + //! (NOT USED IN LiquidTransport.) + //! Diffusion coefficient model for each species expressed as an + //! appropriate subclass of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). + * + * Since the LiquidTransport class uses the Stefan-Maxwell equation + * to describe species diffusivity, the species-specific + * diffusivity is irrelevant. + */ + std::vector m_diffTempDep_Ns; + + //! Species diffusivity of the mixture expressed as a subclass of + //! LiquidTranInteraction. This will return an array of + //! Stefan-Maxwell interaction parameters for use in the + //! Stefan-Maxwell solution. + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). + */ + LiquidTranInteraction *m_diffMixModel; + + //! Setfan-Maxwell diffusion coefficients + DenseMatrix m_diff_Dij; + + + //! Hydrodynamic radius for each species expressed as an appropriate subclass of LTPspecies + /*! + * These subclasses of LTPspecies evaluate the species-specific + * transport properties according to the parameters parsed in + * TransportFactory::getLiquidSpeciesTransportData(). + * length = nsp + */ + std::vector m_radiusTempDep_Ns; + + //! (Not used in LiquidTransport) + //! Hydrodynamic radius of the mixture expressed as a subclass of + //! LiquidTranInteraction + /*! + * These subclasses of LiquidTranInteraction evaluate the + * mixture transport properties according to the parameters parsed in + * TransportFactory::getLiquidInteractionsTransportData(). + */ + LiquidTranInteraction *m_radiusMixModel; //! Species hydrodynamic radius vector_fp m_hydrodynamic_radius; + //! Hydrodynamic radius - //! Polynomial coefficients of the binary diffusion coefficients - /*! - * These express the temperature dependendence of the - * binary diffusivities. An overall pressure dependence is then - * added. - */ - vector m_diffcoeffs; //! Internal value of the gradient of the mole fraction vector /*! @@ -446,6 +1066,24 @@ namespace Cantera { */ vector_fp m_Grad_X; + //! Gradient of the logarithm of the activity + /*! + * This quantity appears in the gradient of the chemical potential. + * It replaces the gradient of the mole fraction, and in this way + * serves to "modify" the diffusion coefficient. + * + * \f[ + * m\_Grad\_lnAC[k] = \nabla ( \ln X_k ) + + * \nabla ( \ln \gamma_k ) + * \f] + * + * k is the species index + * n is the dimensional index (x, y, or z). It has a length + * equal to m_nDim + * + * m_Grad_X[n*m_nsp + k] + * + */ vector_fp m_Grad_lnAC; //! Internal value of the gradient of the Temperature vector @@ -490,16 +1128,18 @@ namespace Cantera { * k is the species index * n is the dimensional index (x, y, or z) * - * ck m_Grad_mu[n*m_nsp + k] + * \f[ + * m\_Grad\_mu[n*m_nsp + k] + * \f] */ - vector_fp m_ck_Grad_mu; + vector_fp m_Grad_mu; // property values //! Array of Binary Diffusivities /*! - * Depends on the temperature. We have set the pressure dependence - * to zero for this liquid phase constituitve model + * These are evaluated according to the subclass of + * LiquidTranInteraction stored in m_diffMixModel. * * This has a size equal to nsp x nsp * It is a symmetric matrix. @@ -510,33 +1150,78 @@ namespace Cantera { */ DenseMatrix m_bdiff; - //! Species viscosities and their logarithm + //! Internal value of the species viscosities /*! - * Viscosity of the species and its logarithm - * Length = number of species + * Viscosity of the species evaluated using subclass of LTPspecies + * held in m_viscTempDep_Ns. * - * Depends on the temperature. We have set the pressure dependence - * to zero for this liquid phase constituitve model + * Length = number of species * * controlling update boolean -> m_visc_temp_ok */ vector_fp m_viscSpecies; - vector_fp m_logViscSpecies; + + //! Internal value of the species ionic conductivities + /*! + * Ionic conductivity of the species evaluated using subclass of LTPspecies + * held in m_ionCondTempDep_Ns. + * + * Length = number of species + * + * controlling update boolean -> m_ionCond_temp_ok + */ + vector_fp m_ionCondSpecies; + + //! Internal value of the species mobility ratios + /*! + * Mobility ratio of the species evaluated using subclass of LTPspecies + * held in m_mobRatTempDep_Ns. + * + * Length = number of species + * + * controlling update boolean -> m_mobRat_temp_ok + */ + DenseMatrix m_mobRatSpecies; + + //! Internal value of the species self diffusion coefficients + /*! + * Self diffusion of the species evaluated using subclass of LTPspecies + * held in m_selfDiffTempDep_Ns. + * + * Length = number of species + * + * controlling update boolean -> m_selfDiff_temp_ok + */ + DenseMatrix m_selfDiffSpecies; //! Internal value of the species individual thermal conductivities /*! - * Then a mixture rule is applied to get the solution conductivities + * Thermal conductivities of the species evaluated using subclass + * of LTPspecies held in m_lambdaTempDep_Ns. * - * Depends on the temperature and perhaps pressure, but - * not the species concentrations + * Length = number of species * - * controlling update boolean -> m_cond_temp_ok */ - vector_fp m_condSpecies; + vector_fp m_lambdaSpecies; //! State of the mole fraction vector. int m_iStateMF; + //! Local copy of the mass fractions of the species in the phase + /*! + * The mass fraction vector comes from the ThermoPhase object. + * + * length = m_nsp + */ + vector_fp m_massfracs; + + //! Local copy of the mass fractions of the species in the phase + /** + * This version of the mass fraction vector is adjusted to a + * minimum lower bound of MIN_X for use in transport calculations. + */ + vector_fp m_massfracs_tran; + //! Local copy of the mole fractions of the species in the phase /*! * The mole fractions here are assumed to be bounded by 0.0 and 1.0 @@ -561,8 +1246,6 @@ namespace Cantera { */ vector_fp m_molefracs_tran; - vector_fp Xdelta_; - //! Local copy of the concentrations of the species in the phase /*! * The concentrations are consistent with the m_molefracs @@ -587,7 +1270,10 @@ namespace Cantera { */ doublereal concTot_tran_; + //! Mean molecular mass doublereal meanMolecularWeight_; + + //! Density doublereal dens_; //! Local copy of the charge of each species @@ -596,25 +1282,11 @@ namespace Cantera { */ vector_fp m_chargeSpecies; - - vector_fp volume_specPM_; + //! Specific volume for each species. Local copy from thermo object. + vector_fp m_volume_spec; - vector_fp actCoeffMolar_; - - vector_fp lnActCoeffMolarDelta_; - - //! Stefan-Maxwell Diffusion Coefficients at T, P and C - /*! - * These diffusion coefficients are considered to be - * a function of Temperature, Pressure, and Concentration. - */ - DenseMatrix m_DiffCoeff_StefMax; - - //! Viscosity model - /*! - * - */ - int viscosityModel_; + //! Vector of activity coefficients + vector_fp m_actCoeff; //! RHS to the stefan-maxwell equation DenseMatrix m_B; @@ -629,61 +1301,45 @@ namespace Cantera { */ doublereal m_temp; - //! Current log(T) - doublereal m_logt; - - //! Current value of kT - doublereal m_kbt; - //! Current value of the pressure doublereal m_press; - //! Solution of the flux system + //! Solution of the Stefan Maxwell equation in terms of flux /*! * This is the mass flux of species k * in units of kg m-3 s-1. */ Array2D m_flux; + //! Solution of the Stefan Maxwell equation + /*! + * This is the diffusion velocity of species k + * in units of m/s and relative to the mole-averaged velocity. + */ + Array2D m_Vdiff; + //! Saved value of the mixture thermal conductivity doublereal m_lambda; //! Saved value of the mixture viscosity doublereal m_viscmix; - // work space + //! Saved value of the mixture ionic conductivity + doublereal m_ionCondmix; + + //! Saved values of the mixture mobility ratios + vector_fp m_mobRatMix; + + //! Saved values of the mixture self diffusion coefficients + vector_fp m_selfDiffMix; + + //! work space + /*! + * Length is equal to m_nsp + */ vector_fp m_spwork; - //! Internal Function - protected: - //! Update the temperature-dependent viscosity terms. - //! Updates the array of pure species viscosities, and the - //! weighting functions in the viscosity mixture rule. - /*! - * The flag m_visc_ok is set to true. - */ - void updateViscosity_temp(); - //! Update the temperature-dependent parts of the mixture-averaged - //! thermal conductivity. - void updateCond_temp(); - - //! Update the concentration parts of the viscosities - /*! - * Internal routine is run whenever the update_boolean - * m_visc_conc_ok is false. This routine will calculate - * internal values for the species viscosities. - * - * @internal - */ - void updateViscosities_conc(); - - //! Update the binary diffusion coefficients wrt T. - /*! - * These are evaluated - * from the polynomial fits at unit pressure (1 Pa). - */ - void updateDiff_temp(); private: //! Boolean indicating that the top-level mixture viscosity is current @@ -696,9 +1352,62 @@ namespace Cantera { bool m_visc_temp_ok; //! Flag to indicate that the pure species viscosities - //! are current wrt the temperature + //! are current wrt the concentration bool m_visc_conc_ok; + //! Boolean indicating that the top-level mixture ionic conductivity is current + /*! + * This is turned false for every change in T, P, or C. + */ + bool m_ionCond_mix_ok; + + //! Boolean indicating that weight factors wrt ionic conductivty is current + bool m_ionCond_temp_ok; + + //! Flag to indicate that the pure species ionic conductivities + //! are current wrt the concentration + bool m_ionCond_conc_ok; + + //! Flag to indicate that the mixture conductivity is current + bool m_cond_mix_ok; + + //! Boolean indicating that the top-level mixture mobility ratio is current + /*! + * This is turned false for every change in T, P, or C. + */ + bool m_mobRat_mix_ok; + + //! Boolean indicating that weight factors wrt mobility ratio is current + bool m_mobRat_temp_ok; + + //! Flag to indicate that the pure species mobility ratios + //! are current wrt the concentration + bool m_mobRat_conc_ok; + + //! Boolean indicating that the top-level mixture self diffusion is current + /*! + * This is turned false for every change in T, P, or C. + */ + bool m_selfDiff_mix_ok; + + //! Boolean indicating that weight factors wrt self diffusion is current + bool m_selfDiff_temp_ok; + + //! Flag to indicate that the pure species self diffusion + //! are current wrt the concentration + bool m_selfDiff_conc_ok; + + //! Boolean indicating that mixture diffusion coeffs are current + bool m_radi_mix_ok; + + //! Boolean indicating that temperature dependence of + //! hydrodynamic radius is current + bool m_radi_temp_ok; + + //! Flag to indicate that the hydrodynamic radius is current + //! is current wrt the concentration + bool m_radi_conc_ok; + //! Boolean indicating that mixture diffusion coeffs are current bool m_diff_mix_ok; @@ -707,23 +1416,14 @@ namespace Cantera { //! Flag to indicate that the pure species conductivities //! are current wrt the temperature - bool m_cond_temp_ok; + bool m_lambda_temp_ok; //! Boolean indicating that mixture conductivity is current - bool m_cond_mix_ok; + bool m_lambda_mix_ok; - //! Mode for fitting the species viscosities - /*! - * Either its CK_Mode or its cantera mode - * in CK_Mode visc is fitted to a polynomial - * in Cantera mode sqrt(visc) is fitted. - */ + //! Mode indicator for transport models -- currently unused. int m_mode; - //! Internal storage for the diameter - diameter - //! species interactions - DenseMatrix m_diam; - //! Debugging flags /*! * Turn on to get debugging information @@ -736,13 +1436,11 @@ namespace Cantera { */ int m_nDim; - private: - //! Throw an exception if this method is invoked. /*! * This probably indicates something is not yet implemented. * - * @pram msg Indicates the member function which is not implemented + * @param msg Indicates the member function which is not implemented */ doublereal err(std::string msg) const; diff --git a/Cantera/src/transport/LiquidTransportData.cpp b/Cantera/src/transport/LiquidTransportData.cpp new file mode 100644 index 000000000..93115ea68 --- /dev/null +++ b/Cantera/src/transport/LiquidTransportData.cpp @@ -0,0 +1,115 @@ +/** + * @file LiquidTransportData.cpp + * Source code for liquid transport property evaluations. + */ +/* + * $Author$ + * $Date$ + * $Revision$ + */ + +#include "LiquidTransportData.h" +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if (x) { delete (x); x = 0; } +#endif +namespace Cantera { + + //==================================================================================================================== + LiquidTransportData::LiquidTransportData() : + speciesName("-"), + hydroRadius(0), + viscosity(0), + ionConductivity(0), + mobilityRatio(0), + selfDiffusion(0), + thermalCond(0), + electCond(0), + speciesDiffusivity(0) + { + + } + //==================================================================================================================== + // Copy constructor + LiquidTransportData::LiquidTransportData(const LiquidTransportData &right) : + speciesName("-"), + hydroRadius(0), + viscosity(0), + ionConductivity(0), + mobilityRatio(0), + selfDiffusion(0), + thermalCond(0), + electCond(0), + speciesDiffusivity(0) + { + *this = right; //use assignment operator to do other work + } + //==================================================================================================================== + // Assignment operator + LiquidTransportData& LiquidTransportData::operator=(const LiquidTransportData& right) + { + if (&right != this) { + // These are all shallow pointer copies - yes, yes, yes horrible crime. + speciesName = right.speciesName; + if (right.hydroRadius) { + hydroRadius = (right.hydroRadius)->duplMyselfAsLTPspecies(); + } + if (right.viscosity) { + viscosity = (right.viscosity)->duplMyselfAsLTPspecies(); + } + if (right.ionConductivity) { + ionConductivity = (right.ionConductivity)->duplMyselfAsLTPspecies(); + } + + mobilityRatio = right.mobilityRatio; + for (size_t k = 0; k < mobilityRatio.size(); k++) { + if (right.mobilityRatio[k]) { + mobilityRatio[k] = (right.mobilityRatio[k])->duplMyselfAsLTPspecies(); + } + } + + selfDiffusion = right.selfDiffusion; + for (size_t k = 0; k < selfDiffusion.size(); k++) { + if (right.selfDiffusion[k]) { + selfDiffusion[k] = (right.selfDiffusion[k])->duplMyselfAsLTPspecies(); + } + } + + if (right.thermalCond) { + thermalCond = (right.thermalCond)->duplMyselfAsLTPspecies(); + } + if (right.electCond) { + electCond = (right.electCond)->duplMyselfAsLTPspecies(); + } + if (right.speciesDiffusivity) { + speciesDiffusivity = (right.speciesDiffusivity)->duplMyselfAsLTPspecies(); + } + } + return *this; + } + //==================================================================================================================== + LiquidTransportData::~LiquidTransportData() { + + SAFE_DELETE(hydroRadius); + SAFE_DELETE(viscosity); + SAFE_DELETE(ionConductivity); + + for (size_t k = 0; k < mobilityRatio.size(); k++) { + if (mobilityRatio[k]) { + SAFE_DELETE(mobilityRatio[k]); + } + } + for (size_t k = 0; k < selfDiffusion.size(); k++) { + if (selfDiffusion[k]) { + SAFE_DELETE(selfDiffusion[k]); + } + } + + SAFE_DELETE(thermalCond); + SAFE_DELETE(electCond); + SAFE_DELETE(speciesDiffusivity); + + } + //==================================================================================================================== +} diff --git a/Cantera/src/transport/LiquidTransportData.h b/Cantera/src/transport/LiquidTransportData.h index a664bedc1..e7196cf08 100644 --- a/Cantera/src/transport/LiquidTransportData.h +++ b/Cantera/src/transport/LiquidTransportData.h @@ -1,15 +1,11 @@ /** - * @file TransportFactory.h - * Header file defining class TransportFactory - * (see \link Cantera::TransportFactory TransportFactory\endlink) + * @file LiquidTransportData.h + * Header file defining class LiquidTransportData */ /* - * $Author: hkmoffa $ - * $Date: 2008/12/24 18:19:01 $ - * $Revision: 1.14 $ - * - * - * + * $Author$ + * $Date$ + * $Revision$ */ #ifndef CT_LIQUIDTRANSPORTDATA_H @@ -19,62 +15,100 @@ // STL includes #include #include -#include -#include - - // Cantera includes #include "ct_defs.h" #include "TransportBase.h" #include "FactoryBase.h" - +#include "LTPspecies.h" namespace Cantera { - enum LiquidTR_Model { - LTR_MODEL_NOTSET=-1, - LTR_MODEL_CONSTANT, - LTR_MODEL_ARRHENIUS, - LTR_MODEL_COEFF - }; - + //! Class LiquidTransportData holds transport parameters for a + //! specific liquid-phase species. + /*! + * A LiquidTransportData object is created for each species. + * + * This class is mainly used to collect transport properties + * from the parse phase in the TranportFactory and transfer + * them to the Transport class. Transport properties are + * expressed by subclasses of LTPspecies. + * One may need to be careful about deleting pointers to LTPspecies + * objects created in the TransportFactory. + * + * All of the pointers in this class are shallow pointers. Therefore, this + * is a passthrough class, which keeps track of pointer ownership by zeroing + * pointers as we go. Yes, Yes, yes, this is not good. + */ class LiquidTransportData { public: - LiquidTransportData() : - speciesName("-"), - model_hydroradius(LTR_MODEL_NOTSET), - hydroradius(-1.0), - model_viscosity(LTR_MODEL_NOTSET), - model_thermalCond(LTR_MODEL_NOTSET), - model_speciesDiffusivity(LTR_MODEL_NOTSET) - { - } + //! Default constructor + LiquidTransportData(); - std::string speciesName; + //! Copy constructor + LiquidTransportData(const LiquidTransportData &right); + + //! Assignment operator + LiquidTransportData& operator=(const LiquidTransportData& right ); + + //! Destructor + ~LiquidTransportData(); + + //! A LiquidTransportData object is instantiated for each species. + //! This is the species name for which this object is instantiated. + std::string speciesName; + + //! Model type for the hydroradius + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* hydroRadius; + + //! Model type for the viscosity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* viscosity; + + //! Model type for the ionic conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* ionConductivity; + + //! Model type for the mobility ratio + /*! + * shallow pointers that should be zero during destructor + */ + std::vector mobilityRatio; + + //! Model type for the self diffusion coefficients + /*! + * shallow pointers that should be zero during destructor + */ + std::vector selfDiffusion; + + //! Model type for the thermal conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* thermalCond; - //! Model type for the hydroradius - LiquidTR_Model model_hydroradius; - - //! Actual value of the hydroradius - doublereal hydroradius; - - //! Model type for the hydroradius - LiquidTR_Model model_viscosity; - vector_fp viscCoeffs; - - //! Model type for the hydroradius - LiquidTR_Model model_thermalCond; + //! Model type for the electrical conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* electCond; - vector_fp thermalCondCoeffs; - - //! Model type for the hydroradius - LiquidTR_Model model_speciesDiffusivity; - - vector_fp speciesDiffusivityCoeffs; + //! Model type for the speciesDiffusivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* speciesDiffusivity; }; } #endif + diff --git a/Cantera/src/transport/LiquidTransportParams.cpp b/Cantera/src/transport/LiquidTransportParams.cpp new file mode 100644 index 000000000..73323b97e --- /dev/null +++ b/Cantera/src/transport/LiquidTransportParams.cpp @@ -0,0 +1,128 @@ +/** + * @file LiquidTransportParams.cpp + * Source code for liquid mixture transport property evaluations. + */ +/* + * Latest Checkin: + * $Author$ + * $Date$ + * $Revision$ + */ + +#include "LiquidTransportParams.h" +#include +#include "IonsFromNeutralVPSSTP.h" +#include "MargulesVPSSTP.h" +#include +using namespace std; + + +namespace Cantera { + + //==================================================================================================================== + //! Exception thrown if an error is encountered while reading the transport database. + class LTPmodelError : public CanteraError { + public: + LTPmodelError(std::string msg) : + CanteraError("LTPspecies", "error parsing transport data: " + msg + "\n") + { + } + }; + //==================================================================================================================== + LiquidTransportParams::LiquidTransportParams() : + TransportParams(), + LTData(0), + viscosity(0), + ionConductivity(0), + mobilityRatio(0), + selfDiffusion(0), + thermalCond(0), + speciesDiffusivity(0), + electCond(0), + hydroRadius(0), + model_viscosity(LTI_MODEL_NOTSET), + model_speciesDiffusivity(LTI_MODEL_NOTSET), + model_hydroradius(LTI_MODEL_NOTSET) + { + + } + //==================================================================================================================== + LiquidTransportParams::~LiquidTransportParams() + { + delete viscosity; + delete ionConductivity; + delete thermalCond; + delete speciesDiffusivity; + delete electCond; + delete hydroRadius; + } + //==================================================================================================================== + LiquidTransportParams::LiquidTransportParams(const LiquidTransportParams &right) : + TransportParams(), + LTData(0), + viscosity(0), + thermalCond(0), + speciesDiffusivity(0), + electCond(0), + hydroRadius(0), + model_viscosity(LTI_MODEL_NOTSET), + model_speciesDiffusivity(LTI_MODEL_NOTSET), + model_hydroradius(LTI_MODEL_NOTSET) + { + operator=(right); + } + //==================================================================================================================== + + LiquidTransportParams& LiquidTransportParams::operator=(const LiquidTransportParams & right) + { + if (&right != this) { + return *this; + } + + LTData = right.LTData; + + delete viscosity; + if (right.viscosity) { + viscosity = new LiquidTranInteraction(*(right.viscosity)); + } + delete ionConductivity; + if (right.ionConductivity) { + ionConductivity = new LiquidTranInteraction(*(right.ionConductivity)); + } + deepStdVectorPointerCopy(right.mobilityRatio, mobilityRatio); + deepStdVectorPointerCopy(right.selfDiffusion, selfDiffusion); + + delete thermalCond; + if (right.thermalCond) { + thermalCond = new LiquidTranInteraction(*(right.thermalCond)); + } + delete speciesDiffusivity; + if (right.speciesDiffusivity) { + speciesDiffusivity = new LiquidTranInteraction(*(right.speciesDiffusivity)); + } + + delete electCond; + if (right.electCond) { + electCond = new LiquidTranInteraction(*(right.electCond)); + } + delete hydroRadius; + if (right.hydroRadius) { + hydroRadius = new LiquidTranInteraction(*(right.hydroRadius)); + } + model_viscosity = right.model_viscosity; + model_ionConductivity = right.model_ionConductivity; + deepStdVectorPointerCopy(right.model_mobilityRatio, model_mobilityRatio); + deepStdVectorPointerCopy(right.model_selfDiffusion, model_selfDiffusion); + thermalCond_Aij = right.thermalCond_Aij; + model_speciesDiffusivity = right.model_speciesDiffusivity; + diff_Dij = right.diff_Dij; + model_hydroradius = right.model_hydroradius; + radius_Aij = right.radius_Aij; + + throw CanteraError("LiquidTransportParams(const LiquidTransportParams &right)", "not tested"); + + return *this; + } + //==================================================================================================================== + +} //namespace Cantera diff --git a/Cantera/src/transport/LiquidTransportParams.h b/Cantera/src/transport/LiquidTransportParams.h index 713ab1c52..a459ea212 100644 --- a/Cantera/src/transport/LiquidTransportParams.h +++ b/Cantera/src/transport/LiquidTransportParams.h @@ -1,90 +1,219 @@ +/** + * @file LiquidTransportParams.h + * Header file defining class LiquidTransportParams + */ +/* + * $Author$ + * $Date$ + * $Revision$ + * + * + * + */ #ifndef CT_LIQUIDTRANSPORTPARAMS_H #define CT_LIQUIDTRANSPORTPARAMS_H -#include - #include "ct_defs.h" #include "TransportBase.h" #include "TransportParams.h" #include "LiquidTransportData.h" +#include "LiquidTranInteraction.h" #include "xml.h" #include "XML_Writer.h" + +#include + + namespace Cantera { - /** - * Holds transport model parameters relevant to transport in - * liquids for which activated jump processes limit transport - * (giving Arrhenius type transport properties). - * Used by TransportFactory. + + + //! Composition dependence type for liquid mixture transport properties + /*! + * Types of temperature dependencies: + * - 0 - Mixture calculations with this property are not allowed + * - 1 - Use solvent (species 0) properties + * - 2 - Properties weighted linearly by mole fractions + * - 3 - Properties weighted linearly by mass fractions + * - 4 - Properties weighted logarithmically by mole fractions (interaction energy weighting) + * - 5 - Interactions given pairwise between each possible species (i.e. D_ij) + * + * \verbatim + * + * + * + * + * LiCl(L) + * KCl(L) + * -1.0 + * 1.0E-1 + * -or- + * 1.0E-1, 0.001 0.01 + * + * -same form for Hij,Aij,Bij- + * + * + * + * + * + * + * Li+ + * K+ + * 1.5 + * + * + * K+ + * Cl- + * 1.0 + * + * + * Li+ + * Cl- + * 1.2 + * + * + * + * + * + * + * + * + * + * + * \endverbatim + * */ - class LiquidTransportParams :public TransportParams { - - public: - - LiquidTransportParams() {} - ~LiquidTransportParams() {} - //section for liquid transport properties - //Arrhenius parameters for transport coefficients: + + //! Class LiquidTransportParams holds transport model parameters + //! relevant to transport in mixtures. + /*! + * This class is used by TransportFactory to initialize transport objects. + */ + class LiquidTransportParams : public TransportParams { + + public: + + //! Constructor + LiquidTransportParams(); - //!Arrhenius pre-exponential parameter for viscosity. - vector_fp visc_A; - //!Temperature exponent for viscosity. - vector_fp visc_n; - //!Arrhenius activation temperature for viscosity. - vector_fp visc_Tact; + //! Destructor + ~LiquidTransportParams(); - //!Arrhenius pre-exponential parameter for thermal conductivity. - vector_fp thermCond_A; - //!Temperature exponent for thermal conductivity. - vector_fp thermCond_n; - //!Arrhenius activation temperature for thermal conductivity. - vector_fp thermCond_Tact; + //! Copy constructor + /*! + * @param right Object to be copied + */ + LiquidTransportParams(const LiquidTransportParams &right); - //! Energies of molecular interaction associated with viscosity. - /** - * These multiply the mixture viscosity by - * \f[ \exp( \sum_{i} \sum_{j} X_i X_j ( S_{i,j} + E_{i,j} / T ) ) \f]. - * - * The overall formula for the logarithm of the mixture viscosity is - * - * \f[ \ln \eta_{mix} = \sum_i X_i \ln \eta_i - * + \sum_i \sum_j X_i X_j ( S_{i,j} + E_{i,j} / T ) \f]. - */ - DenseMatrix visc_Eij; + //! Assignment operator + /*! + * @param right Object to be copied + */ + LiquidTransportParams & operator=(const LiquidTransportParams &right); + + //! Species transport parameters + std::vector LTData; - //! Entropies of molecular interaction associated with viscosity. - DenseMatrix visc_Sij; + //! Object that specifies the viscosity interaction for the mixture + LiquidTranInteraction* viscosity; - //Hydrodynamic radius of transported molecule - vector_fp hydroRadius; + //! Object that specifes the ionic Conductivity of the mixture + LiquidTranInteraction* ionConductivity; - //! Coefficients for the limiting conductivity of ions - //! in solution: A_k - /*! - * This is used in the following formula for the - * limiting conductivity of the kth ion. - * - * ln (lambda^o_k nu_solv) = A_k + B_k / T - * - * nu_solv is the pure component solvent viscosity - * - * Note the limiting conductivities of ions will also - * be used to input the diffusion coefficients. - */ - vector_fp A_k_cond; + //! Vector of pointer to the LiquidTranInteraction object which handles the calculation of + //! each species' mobility ratios for the phase + /*! + * mobRat(i,j) = mu_i / mu_j + * + * It is returned in fortran-ordering format. ie. it is returned as mobRat[k], where + * + * k = j * nsp + i + */ + std::vector mobilityRatio; - //! Coefficients for the limiting conductivity of ions - //! in solution: B_k - vector_fp B_k_cond; + //! Vector of pointer to the LiquidTranInteraction object which handles the calculation of + //! each species' self diffusion coefficient for the phase + std::vector selfDiffusion; + + //! Pointer to the LiquidTranInteraction object which handles the calculation of the + //! mixture thermal conductivity for the phase + LiquidTranInteraction* thermalCond; + + //! Pointer to the LiquidTranInteraction object which handles the calculation of the + //! species diffusivity for the phase + LiquidTranInteraction* speciesDiffusivity; + + //! Pointer to the LiquidTranInteraction object which handles the calculation of the + //! electrical conductivity for the phase + LiquidTranInteraction* electCond; + + //! Pointer to the LiquidTranInteraction object which handles the calculation of the hydrodynamic + //! radius for the phase + /*! + * @note I don't understand at the moment how one can define a hydrodynamic + * radius for the phase + */ + LiquidTranInteraction* hydroRadius; + + //! Model for species interaction effects for viscosity + //! Takes enum LiquidTranMixingModel + LiquidTranMixingModel model_viscosity; + + //! Model for species interaction effects for ionic conductivity + //! Takes enum LiquidTranMixingModel + LiquidTranMixingModel model_ionConductivity; + + //! Model for species interaction effects for mobility ratio + //! Takes enum LiquidTranMixingModel + std::vector model_mobilityRatio; + + //! Model for species interaction effects for mobility ratio + //! Takes enum LiquidTranMixingModel + std::vector model_selfDiffusion; + + //! Interaction associated with linear weighting of + //! thermal conductivity. + /** + * This is used for either LTI_MODEL_MASSFRACS + * or LTI_MODEL_MOLEFRACS. + * The overall formula for the mixture viscosity is + * + * \f[ \eta_{mix} = \sum_i X_i \eta_i + * + \sum_i \sum_j X_i X_j A_{i,j} \f]. + */ + DenseMatrix thermalCond_Aij; + + //! Model for species interaction effects for mass diffusivity + //! Takes enum LiquidTranMixingModel + LiquidTranMixingModel model_speciesDiffusivity; + + //! Interaction associated with linear weighting of + //! thermal conductivity. + /** + * This is used for either LTI_MODEL_PAIRWISE_INTERACTION or LTI_MODEL_STEFANMAXWELL_PPN. + * These provide species interaction coefficients associated with + * the Stefan-Maxwell formulation. + */ + DenseMatrix diff_Dij; + + //! Model for species interaction effects for hydrodynamic radius + //! Takes enum LiquidTranMixingModel + LiquidTranMixingModel model_hydroradius; + + //! Interaction associated with hydrodynamic radius. + /** + * Not yet implemented + */ + DenseMatrix radius_Aij; + }; + + - std::vector LTData; - - }; } #endif diff --git a/Cantera/src/transport/MMCollisionInt.cpp b/Cantera/src/transport/MMCollisionInt.cpp old mode 100755 new mode 100644 index c50855c32..a1b7d5750 --- a/Cantera/src/transport/MMCollisionInt.cpp +++ b/Cantera/src/transport/MMCollisionInt.cpp @@ -27,522 +27,549 @@ using namespace std; namespace Cantera { - const int DeltaDegree = 6; - double MMCollisionInt::delta[8] = {0.0, 0.25, 0.50, 0.75, 1.0, - 1.5, 2.0, 2.5}; + //! \cond + const int DeltaDegree = 6; - doublereal quadInterp(doublereal x0, doublereal* x, doublereal* y) { - doublereal dx21, dx32, dx31, dy32, dy21, a; - dx21 = x[1] - x[0]; - dx32 = x[2] - x[1]; - dx31 = dx21 + dx32; - dy32 = y[2] - y[1]; - dy21 = y[1] - y[0]; - a = (dx21*dy32 - dy21*dx32)/(dx21*dx31*dx32); - return a*(x0 - x[0])*(x0 - x[1]) + (dy21/dx21)*(x0 - x[1]) + y[1]; - } + double MMCollisionInt::delta[8] = {0.0, 0.25, 0.50, 0.75, 1.0, + 1.5, 2.0, 2.5}; + + doublereal quadInterp(doublereal x0, doublereal* x, doublereal* y) { + doublereal dx21, dx32, dx31, dy32, dy21, a; + dx21 = x[1] - x[0]; + dx32 = x[2] - x[1]; + dx31 = dx21 + dx32; + dy32 = y[2] - y[1]; + dy21 = y[1] - y[0]; + a = (dx21*dy32 - dy21*dx32)/(dx21*dx31*dx32); + return a*(x0 - x[0])*(x0 - x[1]) + (dy21/dx21)*(x0 - x[1]) + y[1]; + } - double MMCollisionInt::tstar22[37] = + double MMCollisionInt::tstar22[37] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 35.0, 40.0, 50.0, 75.0, 100.0}; - double MMCollisionInt::omega22_table[37*8] = { - 4.1005, 4.266, 4.833, 5.742, 6.729, 8.624, 10.34, 11.89, - 3.2626, 3.305, 3.516, 3.914, 4.433, 5.57, 6.637, 7.618, - 2.8399, 2.836, 2.936, 3.168, 3.511, 4.329, 5.126, 5.874, - 2.531, 2.522, 2.586, 2.749, 3.004, 3.64, 4.282, 4.895, - 2.2837, 2.277, 2.329, 2.46, 2.665, 3.187, 3.727, 4.249, - 2.0838, 2.081, 2.13, 2.243, 2.417, 2.862, 3.329, 3.786, - 1.922, 1.924, 1.97, 2.072, 2.225, 2.614, 3.028, 3.435, - 1.7902, 1.795, 1.84, 1.934, 2.07, 2.417, 2.788, 3.156, - 1.6823, 1.689, 1.733, 1.82, 1.944, 2.258, 2.596, 2.933, - 1.5929, 1.601, 1.644, 1.725, 1.838, 2.124, 2.435, 2.746, - 1.4551, 1.465, 1.504, 1.574, 1.67, 1.913, 2.181, 2.451, - 1.3551, 1.365, 1.4, 1.461, 1.544, 1.754, 1.989, 2.228, - 1.28, 1.289, 1.321, 1.374, 1.447, 1.63, 1.838, 2.053, - 1.2219, 1.231, 1.259, 1.306, 1.37, 1.532, 1.718, 1.912, - 1.1757, 1.184, 1.209, 1.251, 1.307, 1.451, 1.618, 1.795, - 1.0933, 1.1, 1.119, 1.15, 1.193, 1.304, 1.435, 1.578, - 1.0388, 1.044, 1.059, 1.083, 1.117, 1.204, 1.31, 1.428, - 0.99963, 1.004, 1.016, 1.035, 1.062, 1.133, 1.22, 1.319, - 0.96988, 0.9732, 0.983, 0.9991, 1.021, 1.079, 1.153, 1.236, - 0.92676, 0.9291, 0.936, 0.9473, 0.9628, 1.005, 1.058, 1.121, - 0.89616, 0.8979, 0.903, 0.9114, 0.923, 0.9545, 0.9955, 1.044, - 0.87272, 0.8741, 0.878, 0.8845, 0.8935, 0.9181, 0.9505, 0.9893, - 0.85379, 0.8549, 0.858, 0.8632, 0.8703, 0.8901, 0.9164, 0.9482, - 0.83795, 0.8388, 0.8414, 0.8456, 0.8515, 0.8678, 0.8895, 0.916, - 0.82435, 0.8251, 0.8273, 0.8308, 0.8356, 0.8493, 0.8676, 0.8901, - 0.80184, 0.8024, 0.8039, 0.8065, 0.8101, 0.8201, 0.8337, 0.8504, - 0.78363, 0.784, 0.7852, 0.7872, 0.7899, 0.7976, 0.8081, 0.8212, - 0.76834, 0.7687, 0.7696, 0.7712, 0.7733, 0.7794, 0.7878, 0.7983, - 0.75518, 0.7554, 0.7562, 0.7575, 0.7592, 0.7642, 0.7711, 0.7797, - 0.74364, 0.7438, 0.7445, 0.7455, 0.747, 0.7512, 0.7569, 0.7642, - 0.71982, 0.72, 0.7204, 0.7211, 0.7221, 0.725, 0.7289, 0.7339, - 0.70097, 0.7011, 0.7014, 0.7019, 0.7026, 0.7047, 0.7076, 0.7112, - 0.68545, 0.6855, 0.6858, 0.6861, 0.6867, 0.6883, 0.6905, 0.6932, - 0.67232, 0.6724, 0.6726, 0.6728, 0.6733, 0.6743, 0.6762, 0.6784, - 0.65099, 0.651, 0.6512, 0.6513, 0.6516, 0.6524, 0.6534, 0.6546, - 0.61397, 0.6141, 0.6143, 0.6145, 0.6147, 0.6148, 0.6148, 0.6147, - 0.5887, 0.5889, 0.5894, 0.59, 0.5903, 0.5901, 0.5895, 0.5885 - }; + double MMCollisionInt::omega22_table[37*8] = { + 4.1005, 4.266, 4.833, 5.742, 6.729, 8.624, 10.34, 11.89, + 3.2626, 3.305, 3.516, 3.914, 4.433, 5.57, 6.637, 7.618, + 2.8399, 2.836, 2.936, 3.168, 3.511, 4.329, 5.126, 5.874, + 2.531, 2.522, 2.586, 2.749, 3.004, 3.64, 4.282, 4.895, + 2.2837, 2.277, 2.329, 2.46, 2.665, 3.187, 3.727, 4.249, + 2.0838, 2.081, 2.13, 2.243, 2.417, 2.862, 3.329, 3.786, + 1.922, 1.924, 1.97, 2.072, 2.225, 2.614, 3.028, 3.435, + 1.7902, 1.795, 1.84, 1.934, 2.07, 2.417, 2.788, 3.156, + 1.6823, 1.689, 1.733, 1.82, 1.944, 2.258, 2.596, 2.933, + 1.5929, 1.601, 1.644, 1.725, 1.838, 2.124, 2.435, 2.746, + 1.4551, 1.465, 1.504, 1.574, 1.67, 1.913, 2.181, 2.451, + 1.3551, 1.365, 1.4, 1.461, 1.544, 1.754, 1.989, 2.228, + 1.28, 1.289, 1.321, 1.374, 1.447, 1.63, 1.838, 2.053, + 1.2219, 1.231, 1.259, 1.306, 1.37, 1.532, 1.718, 1.912, + 1.1757, 1.184, 1.209, 1.251, 1.307, 1.451, 1.618, 1.795, + 1.0933, 1.1, 1.119, 1.15, 1.193, 1.304, 1.435, 1.578, + 1.0388, 1.044, 1.059, 1.083, 1.117, 1.204, 1.31, 1.428, + 0.99963, 1.004, 1.016, 1.035, 1.062, 1.133, 1.22, 1.319, + 0.96988, 0.9732, 0.983, 0.9991, 1.021, 1.079, 1.153, 1.236, + 0.92676, 0.9291, 0.936, 0.9473, 0.9628, 1.005, 1.058, 1.121, + 0.89616, 0.8979, 0.903, 0.9114, 0.923, 0.9545, 0.9955, 1.044, + 0.87272, 0.8741, 0.878, 0.8845, 0.8935, 0.9181, 0.9505, 0.9893, + 0.85379, 0.8549, 0.858, 0.8632, 0.8703, 0.8901, 0.9164, 0.9482, + 0.83795, 0.8388, 0.8414, 0.8456, 0.8515, 0.8678, 0.8895, 0.916, + 0.82435, 0.8251, 0.8273, 0.8308, 0.8356, 0.8493, 0.8676, 0.8901, + 0.80184, 0.8024, 0.8039, 0.8065, 0.8101, 0.8201, 0.8337, 0.8504, + 0.78363, 0.784, 0.7852, 0.7872, 0.7899, 0.7976, 0.8081, 0.8212, + 0.76834, 0.7687, 0.7696, 0.7712, 0.7733, 0.7794, 0.7878, 0.7983, + 0.75518, 0.7554, 0.7562, 0.7575, 0.7592, 0.7642, 0.7711, 0.7797, + 0.74364, 0.7438, 0.7445, 0.7455, 0.747, 0.7512, 0.7569, 0.7642, + 0.71982, 0.72, 0.7204, 0.7211, 0.7221, 0.725, 0.7289, 0.7339, + 0.70097, 0.7011, 0.7014, 0.7019, 0.7026, 0.7047, 0.7076, 0.7112, + 0.68545, 0.6855, 0.6858, 0.6861, 0.6867, 0.6883, 0.6905, 0.6932, + 0.67232, 0.6724, 0.6726, 0.6728, 0.6733, 0.6743, 0.6762, 0.6784, + 0.65099, 0.651, 0.6512, 0.6513, 0.6516, 0.6524, 0.6534, 0.6546, + 0.61397, 0.6141, 0.6143, 0.6145, 0.6147, 0.6148, 0.6148, 0.6147, + 0.5887, 0.5889, 0.5894, 0.59, 0.5903, 0.5901, 0.5895, 0.5885 + }; - //----------------------------- + //----------------------------- - // changed upper limit to 500 from 1.0e10 dgg 5/21/04 - double MMCollisionInt::tstar[39] = { - 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, - 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0, 3.5, 4.0, - 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, - 18.0, 20.0, 25.0, 30.0, 35.0, 40.0, 50.0, 75.0, 100.0, 500.0}; + // changed upper limit to 500 from 1.0e10 dgg 5/21/04 + double MMCollisionInt::tstar[39] = { + 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0, 3.5, 4.0, + 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, + 18.0, 20.0, 25.0, 30.0, 35.0, 40.0, 50.0, 75.0, 100.0, 500.0}; - double MMCollisionInt::astar_table[39*8] = { - 1.0065, 1.0840, 1.0840, 1.0840, 1.0840, 1.0840, 1.0840, 1.0840, - 1.0231, 1.0660, 1.0380, 1.0400, 1.0430, 1.0500, 1.0520, 1.0510, - 1.0424, 1.0450, 1.0480, 1.0520, 1.0560, 1.0650, 1.0660, 1.0640, - 1.0719, 1.0670, 1.0600, 1.0550, 1.0580, 1.0680, 1.0710, 1.0710, - 1.0936, 1.0870, 1.0770, 1.0690, 1.0680, 1.0750, 1.0780, 1.0780, - 1.1053, 1.0980, 1.0880, 1.0800, 1.0780, 1.0820, 1.0840, 1.0840, - 1.1104, 1.1040, 1.0960, 1.0890, 1.0860, 1.0890, 1.0900, 1.0900, - 1.1114, 1.1070, 1.1000, 1.0950, 1.0930, 1.0950, 1.0960, 1.0950, - 1.1104, 1.1070, 1.1020, 1.0990, 1.0980, 1.1000, 1.1000, 1.0990, - 1.1086, 1.1060, 1.1020, 1.1010, 1.1010, 1.1050, 1.1050, 1.1040, - 1.1063, 1.1040, 1.1030, 1.1030, 1.1040, 1.1080, 1.1090, 1.1080, - 1.1020, 1.1020, 1.1030, 1.1050, 1.1070, 1.1120, 1.1150, 1.1150, - 1.0985, 1.0990, 1.1010, 1.1040, 1.1080, 1.1150, 1.1190, 1.1200, - 1.0960, 1.0960, 1.0990, 1.1030, 1.1080, 1.1160, 1.1210, 1.1240, - 1.0943, 1.0950, 1.0990, 1.1020, 1.1080, 1.1170, 1.1230, 1.1260, - 1.0934, 1.0940, 1.0970, 1.1020, 1.1070, 1.1160, 1.1230, 1.1280, - 1.0926, 1.0940, 1.0970, 1.0990, 1.1050, 1.1150, 1.1230, 1.1300, - 1.0934, 1.0950, 1.0970, 1.0990, 1.1040, 1.1130, 1.1220, 1.1290, - 1.0948, 1.0960, 1.0980, 1.1000, 1.1030, 1.1120, 1.1190, 1.1270, - 1.0965, 1.0970, 1.0990, 1.1010, 1.1040, 1.1100, 1.1180, 1.1260, - 1.0997, 1.1000, 1.1010, 1.1020, 1.1050, 1.1100, 1.1160, 1.1230, - 1.1025, 1.1030, 1.1040, 1.1050, 1.1060, 1.1100, 1.1150, 1.1210, - 1.1050, 1.1050, 1.1060, 1.1070, 1.1080, 1.1110, 1.1150, 1.1200, - 1.1072, 1.1070, 1.1080, 1.1080, 1.1090, 1.1120, 1.1150, 1.1190, - 1.1091, 1.1090, 1.1090, 1.1100, 1.1110, 1.1130, 1.1150, 1.1190, - 1.1107, 1.1110, 1.1110, 1.1110, 1.1120, 1.1140, 1.1160, 1.1190, - 1.1133, 1.1140, 1.1130, 1.1140, 1.1140, 1.1150, 1.1170, 1.1190, - 1.1154, 1.1150, 1.1160, 1.1160, 1.1160, 1.1170, 1.1180, 1.1200, - 1.1172, 1.1170, 1.1170, 1.1180, 1.1180, 1.1180, 1.1190, 1.1200, - 1.1186, 1.1190, 1.1190, 1.1190, 1.1190, 1.1190, 1.1200, 1.1210, - 1.1199, 1.1200, 1.1200, 1.1200, 1.1200, 1.1210, 1.1210, 1.1220, - 1.1223, 1.1220, 1.1220, 1.1220, 1.1220, 1.1230, 1.1230, 1.1240, - 1.1243, 1.1240, 1.1240, 1.1240, 1.1240, 1.1240, 1.1250, 1.1250, - 1.1259, 1.1260, 1.1260, 1.1260, 1.1260, 1.1260, 1.1260, 1.1260, - 1.1273, 1.1270, 1.1270, 1.1270, 1.1270, 1.1270, 1.1270, 1.1280, - 1.1297, 1.1300, 1.1300, 1.1300, 1.1300, 1.1300, 1.1300, 1.1290, - 1.1339, 1.1340, 1.1340, 1.1350, 1.1350, 1.1340, 1.1340, 1.1320, - 1.1364, 1.1370, 1.1370, 1.1380, 1.1390, 1.1380, 1.1370, 1.1350, - 1.14187, 1.14187, 1.14187, 1.14187, 1.14187, 1.14187, 1.14187, - 1.14187 }; + double MMCollisionInt::astar_table[39*8] = { + 1.0065, 1.0840, 1.0840, 1.0840, 1.0840, 1.0840, 1.0840, 1.0840, + 1.0231, 1.0660, 1.0380, 1.0400, 1.0430, 1.0500, 1.0520, 1.0510, + 1.0424, 1.0450, 1.0480, 1.0520, 1.0560, 1.0650, 1.0660, 1.0640, + 1.0719, 1.0670, 1.0600, 1.0550, 1.0580, 1.0680, 1.0710, 1.0710, + 1.0936, 1.0870, 1.0770, 1.0690, 1.0680, 1.0750, 1.0780, 1.0780, + 1.1053, 1.0980, 1.0880, 1.0800, 1.0780, 1.0820, 1.0840, 1.0840, + 1.1104, 1.1040, 1.0960, 1.0890, 1.0860, 1.0890, 1.0900, 1.0900, + 1.1114, 1.1070, 1.1000, 1.0950, 1.0930, 1.0950, 1.0960, 1.0950, + 1.1104, 1.1070, 1.1020, 1.0990, 1.0980, 1.1000, 1.1000, 1.0990, + 1.1086, 1.1060, 1.1020, 1.1010, 1.1010, 1.1050, 1.1050, 1.1040, + 1.1063, 1.1040, 1.1030, 1.1030, 1.1040, 1.1080, 1.1090, 1.1080, + 1.1020, 1.1020, 1.1030, 1.1050, 1.1070, 1.1120, 1.1150, 1.1150, + 1.0985, 1.0990, 1.1010, 1.1040, 1.1080, 1.1150, 1.1190, 1.1200, + 1.0960, 1.0960, 1.0990, 1.1030, 1.1080, 1.1160, 1.1210, 1.1240, + 1.0943, 1.0950, 1.0990, 1.1020, 1.1080, 1.1170, 1.1230, 1.1260, + 1.0934, 1.0940, 1.0970, 1.1020, 1.1070, 1.1160, 1.1230, 1.1280, + 1.0926, 1.0940, 1.0970, 1.0990, 1.1050, 1.1150, 1.1230, 1.1300, + 1.0934, 1.0950, 1.0970, 1.0990, 1.1040, 1.1130, 1.1220, 1.1290, + 1.0948, 1.0960, 1.0980, 1.1000, 1.1030, 1.1120, 1.1190, 1.1270, + 1.0965, 1.0970, 1.0990, 1.1010, 1.1040, 1.1100, 1.1180, 1.1260, + 1.0997, 1.1000, 1.1010, 1.1020, 1.1050, 1.1100, 1.1160, 1.1230, + 1.1025, 1.1030, 1.1040, 1.1050, 1.1060, 1.1100, 1.1150, 1.1210, + 1.1050, 1.1050, 1.1060, 1.1070, 1.1080, 1.1110, 1.1150, 1.1200, + 1.1072, 1.1070, 1.1080, 1.1080, 1.1090, 1.1120, 1.1150, 1.1190, + 1.1091, 1.1090, 1.1090, 1.1100, 1.1110, 1.1130, 1.1150, 1.1190, + 1.1107, 1.1110, 1.1110, 1.1110, 1.1120, 1.1140, 1.1160, 1.1190, + 1.1133, 1.1140, 1.1130, 1.1140, 1.1140, 1.1150, 1.1170, 1.1190, + 1.1154, 1.1150, 1.1160, 1.1160, 1.1160, 1.1170, 1.1180, 1.1200, + 1.1172, 1.1170, 1.1170, 1.1180, 1.1180, 1.1180, 1.1190, 1.1200, + 1.1186, 1.1190, 1.1190, 1.1190, 1.1190, 1.1190, 1.1200, 1.1210, + 1.1199, 1.1200, 1.1200, 1.1200, 1.1200, 1.1210, 1.1210, 1.1220, + 1.1223, 1.1220, 1.1220, 1.1220, 1.1220, 1.1230, 1.1230, 1.1240, + 1.1243, 1.1240, 1.1240, 1.1240, 1.1240, 1.1240, 1.1250, 1.1250, + 1.1259, 1.1260, 1.1260, 1.1260, 1.1260, 1.1260, 1.1260, 1.1260, + 1.1273, 1.1270, 1.1270, 1.1270, 1.1270, 1.1270, 1.1270, 1.1280, + 1.1297, 1.1300, 1.1300, 1.1300, 1.1300, 1.1300, 1.1300, 1.1290, + 1.1339, 1.1340, 1.1340, 1.1350, 1.1350, 1.1340, 1.1340, 1.1320, + 1.1364, 1.1370, 1.1370, 1.1380, 1.1390, 1.1380, 1.1370, 1.1350, + 1.14187, 1.14187, 1.14187, 1.14187, 1.14187, 1.14187, 1.14187, + 1.14187 }; - double MMCollisionInt::bstar_table[39*8] = { - 1.1852, 1.2963, 1.2963, 1.2963, 1.2963, 1.2963,1.2963, 1.2963, - 1.1960, 1.216, 1.237, 1.269, 1.285, 1.290, 1.297, 1.294, - 1.2451, 1.257, 1.340, 1.389, 1.366, 1.327, 1.314, 1.278, - 1.2900, 1.294, 1.272, 1.258, 1.262, 1.282, 1.290, 1.299, - 1.2986, 1.291, 1.284, 1.278, 1.277, 1.288, 1.294, 1.297, - 1.2865, 1.281, 1.276, 1.272, 1.277, 1.286, 1.292, 1.298, - 1.2665, 1.264, 1.261, 1.263, 1.269, 1.284, 1.292, 1.298, - 1.2455, 1.244, 1.248, 1.255, 1.262, 1.278, 1.289, 1.296, - 1.2253, 1.225, 1.234, 1.240, 1.252, 1.271, 1.284, 1.295, - 1.2078, 1.210, 1.216, 1.227, 1.242, 1.264, 1.281, 1.292, - 1.1919, 1.192, 1.205, 1.216, 1.230, 1.256, 1.273, 1.287, - 1.1678, 1.172, 1.181, 1.195, 1.209, 1.237, 1.261, 1.277, - 1.1496, 1.155, 1.161, 1.174, 1.189, 1.221, 1.246, 1.266, - 1.1366, 1.141, 1.147, 1.159, 1.174, 1.202, 1.231, 1.256, - 1.1270, 1.130, 1.138, 1.148, 1.162, 1.191, 1.218, 1.242, - 1.1197, 1.122, 1.129, 1.140, 1.149, 1.178, 1.205, 1.231, - 1.1080, 1.110, 1.116, 1.122, 1.132, 1.154, 1.180, 1.205, - 1.1016, 1.103, 1.107, 1.112, 1.120, 1.138, 1.160, 1.183, - 1.0980, 1.099, 1.102, 1.106, 1.112, 1.127, 1.145, 1.165, - 1.0958, 1.097, 1.099, 1.102, 1.107, 1.119, 1.135, 1.153, - 1.0935, 1.094, 1.095, 1.097, 1.100, 1.109, 1.120, 1.134, - 1.0925, 1.092, 1.094, 1.095, 1.098, 1.104, 1.112, 1.122, - 1.0922, 1.092, 1.093, 1.094, 1.096, 1.100, 1.106, 1.115, - 1.0922, 1.092, 1.093, 1.093, 1.095, 1.098, 1.103, 1.110, - 1.0923, 1.092, 1.093, 1.093, 1.094, 1.097, 1.101, 1.106, - 1.0923, 1.092, 1.092, 1.093, 1.094, 1.096, 1.099, 1.103, - 1.0927, 1.093, 1.093, 1.093, 1.094, 1.095, 1.098, 1.101, - 1.0930, 1.093, 1.093, 1.093, 1.094, 1.094, 1.096, 1.099, - 1.0933, 1.094, 1.093, 1.094, 1.094, 1.095, 1.096, 1.098, - 1.0937, 1.093, 1.094, 1.094, 1.094, 1.094, 1.096, 1.097, - 1.0939, 1.094, 1.094, 1.094, 1.094, 1.095, 1.095, 1.097, - 1.0943, 1.094, 1.094, 1.094, 1.095, 1.095, 1.096, 1.096, - 1.0944, 1.095, 1.094, 1.094, 1.094, 1.095, 1.095, 1.096, - 1.0944, 1.094, 1.095, 1.094, 1.094, 1.095, 1.096, 1.096, - 1.0943, 1.095, 1.094, 1.094, 1.095, 1.095, 1.095, 1.095, - 1.0941, 1.094, 1.094, 1.094, 1.094, 1.094, 1.094, 1.096, - 1.0947, 1.095, 1.094, 1.094, 1.093, 1.093, 1.094, 1.095, - 1.0957, 1.095, 1.094, 1.093, 1.092, 1.093, 1.093, 1.094, - 1.10185, 1.10185, 1.10185, 1.10185, 1.10185, 1.10185, 1.10185, - 1.10185}; + double MMCollisionInt::bstar_table[39*8] = { + 1.1852, 1.2963, 1.2963, 1.2963, 1.2963, 1.2963,1.2963, 1.2963, + 1.1960, 1.216, 1.237, 1.269, 1.285, 1.290, 1.297, 1.294, + 1.2451, 1.257, 1.340, 1.389, 1.366, 1.327, 1.314, 1.278, + 1.2900, 1.294, 1.272, 1.258, 1.262, 1.282, 1.290, 1.299, + 1.2986, 1.291, 1.284, 1.278, 1.277, 1.288, 1.294, 1.297, + 1.2865, 1.281, 1.276, 1.272, 1.277, 1.286, 1.292, 1.298, + 1.2665, 1.264, 1.261, 1.263, 1.269, 1.284, 1.292, 1.298, + 1.2455, 1.244, 1.248, 1.255, 1.262, 1.278, 1.289, 1.296, + 1.2253, 1.225, 1.234, 1.240, 1.252, 1.271, 1.284, 1.295, + 1.2078, 1.210, 1.216, 1.227, 1.242, 1.264, 1.281, 1.292, + 1.1919, 1.192, 1.205, 1.216, 1.230, 1.256, 1.273, 1.287, + 1.1678, 1.172, 1.181, 1.195, 1.209, 1.237, 1.261, 1.277, + 1.1496, 1.155, 1.161, 1.174, 1.189, 1.221, 1.246, 1.266, + 1.1366, 1.141, 1.147, 1.159, 1.174, 1.202, 1.231, 1.256, + 1.1270, 1.130, 1.138, 1.148, 1.162, 1.191, 1.218, 1.242, + 1.1197, 1.122, 1.129, 1.140, 1.149, 1.178, 1.205, 1.231, + 1.1080, 1.110, 1.116, 1.122, 1.132, 1.154, 1.180, 1.205, + 1.1016, 1.103, 1.107, 1.112, 1.120, 1.138, 1.160, 1.183, + 1.0980, 1.099, 1.102, 1.106, 1.112, 1.127, 1.145, 1.165, + 1.0958, 1.097, 1.099, 1.102, 1.107, 1.119, 1.135, 1.153, + 1.0935, 1.094, 1.095, 1.097, 1.100, 1.109, 1.120, 1.134, + 1.0925, 1.092, 1.094, 1.095, 1.098, 1.104, 1.112, 1.122, + 1.0922, 1.092, 1.093, 1.094, 1.096, 1.100, 1.106, 1.115, + 1.0922, 1.092, 1.093, 1.093, 1.095, 1.098, 1.103, 1.110, + 1.0923, 1.092, 1.093, 1.093, 1.094, 1.097, 1.101, 1.106, + 1.0923, 1.092, 1.092, 1.093, 1.094, 1.096, 1.099, 1.103, + 1.0927, 1.093, 1.093, 1.093, 1.094, 1.095, 1.098, 1.101, + 1.0930, 1.093, 1.093, 1.093, 1.094, 1.094, 1.096, 1.099, + 1.0933, 1.094, 1.093, 1.094, 1.094, 1.095, 1.096, 1.098, + 1.0937, 1.093, 1.094, 1.094, 1.094, 1.094, 1.096, 1.097, + 1.0939, 1.094, 1.094, 1.094, 1.094, 1.095, 1.095, 1.097, + 1.0943, 1.094, 1.094, 1.094, 1.095, 1.095, 1.096, 1.096, + 1.0944, 1.095, 1.094, 1.094, 1.094, 1.095, 1.095, 1.096, + 1.0944, 1.094, 1.095, 1.094, 1.094, 1.095, 1.096, 1.096, + 1.0943, 1.095, 1.094, 1.094, 1.095, 1.095, 1.095, 1.095, + 1.0941, 1.094, 1.094, 1.094, 1.094, 1.094, 1.094, 1.096, + 1.0947, 1.095, 1.094, 1.094, 1.093, 1.093, 1.094, 1.095, + 1.0957, 1.095, 1.094, 1.093, 1.092, 1.093, 1.093, 1.094, + 1.10185, 1.10185, 1.10185, 1.10185, 1.10185, 1.10185, 1.10185, + 1.10185}; - double MMCollisionInt::cstar_table[39*8] = { - 0.8889, 0.77778, 0.77778,0.77778,0.77778,0.77778,0.77778,0.77778, - 0.88575, 0.8988, 0.8378, 0.8029, 0.7876, 0.7805, 0.7799, 0.7801, - 0.87268, 0.8692,0.8647,0.8479,0.8237,0.7975,0.7881,0.7784, - 0.85182, 0.8525,0.8366,0.8198,0.8054,0.7903,0.7839,0.782, - 0.83542, 0.8362,0.8306,0.8196,0.8076,0.7918,0.7842,0.7806, - 0.82629, 0.8278,0.8252,0.8169,0.8074,0.7916,0.7838,0.7802, - 0.82299, 0.8249,0.823,0.8165,0.8072,0.7922,0.7839,0.7798, - 0.82357, 0.8257,0.8241,0.8178,0.8084,0.7927,0.7839,0.7794, - 0.82657, 0.828,0.8264,0.8199,0.8107,0.7939,0.7842,0.7796, - 0.8311, 0.8234,0.8295,0.8228,0.8136,0.796,0.7854,0.7798, - 0.8363, 0.8366,0.8342,0.8267,0.8168,0.7986,0.7864,0.7805, - 0.84762, 0.8474,0.8438,0.8358,0.825,0.8041,0.7904,0.7822, - 0.85846, 0.8583,0.853,0.8444,0.8336,0.8118,0.7957,0.7854, - 0.8684, 0.8674,0.8619,0.8531,0.8423,0.8186,0.8011,0.7898, - 0.87713, 0.8755,0.8709,0.8616,0.8504,0.8265,0.8072,0.7939, - 0.88479, 0.8831,0.8779,0.8695,0.8578,0.8338,0.8133,0.799, - 0.89972, 0.8986,0.8936,0.8846,0.8742,0.8504,0.8294,0.8125, - 0.91028, 0.9089,0.9043,0.8967,0.8869,0.8649,0.8438,0.8253, - 0.91793, 0.9166,0.9125,0.9058,0.897,0.8768,0.8557,0.8372, - 0.92371, 0.9226,0.9189,0.9128,0.905,0.8861,0.8664,0.8484, - 0.93135, 0.9304,0.9274,0.9226,0.9164,0.9006,0.8833,0.8662, - 0.93607, 0.9353,0.9329,0.9291,0.924,0.9109,0.8958,0.8802, - 0.93927, 0.9387,0.9366,0.9334,0.9292,0.9162,0.905,0.8911, - 0.94149, 0.9409,0.9393,0.9366,0.9331,0.9236,0.9122,0.8997, - 0.94306, 0.9426,0.9412,0.9388,0.9357,0.9276,0.9175,0.9065, - 0.94419, 0.9437,0.9425,0.9406,0.938,0.9308,0.9219,0.9119, - 0.94571, 0.9455,0.9445,0.943,0.9409,0.9353,0.9283,0.9201, - 0.94662, 0.9464,0.9456,0.9444,0.9428,0.9382,0.9325,0.9258, - 0.94723, 0.9471,0.9464,0.9455,0.9442,0.9405,0.9355,0.9298, - 0.94764, 0.9474,0.9469,0.9462,0.945,0.9418,0.9378,0.9328, - 0.9479, 0.9478,0.9474,0.9465,0.9457,0.943,0.9394,0.9352, - 0.94827, 0.9481,0.948,0.9472,0.9467,0.9447,0.9422,0.9391, - 0.94842, 0.9484,0.9481,0.9478,0.9472,0.9458,0.9437,0.9415, - 0.94852, 0.9484,0.9483,0.948,0.9475,0.9465,0.9449,0.943, - 0.94861, 0.9487,0.9484,0.9481,0.9479,0.9468,0.9455,0.943, - 0.94872, 0.9486,0.9486,0.9483,0.9482,0.9475,0.9464,0.9452, - 0.94881, 0.9488,0.9489,0.949,0.9487,0.9482,0.9476,0.9468, - 0.94863, 0.9487,0.9489,0.9491,0.9493,0.9491,0.9483,0.9476, - 0.94444, 0.94444,0.94444,0.94444,0.94444,0.94444,0.94444,0.94444}; + double MMCollisionInt::cstar_table[39*8] = { + 0.8889, 0.77778, 0.77778,0.77778,0.77778,0.77778,0.77778,0.77778, + 0.88575, 0.8988, 0.8378, 0.8029, 0.7876, 0.7805, 0.7799, 0.7801, + 0.87268, 0.8692,0.8647,0.8479,0.8237,0.7975,0.7881,0.7784, + 0.85182, 0.8525,0.8366,0.8198,0.8054,0.7903,0.7839,0.782, + 0.83542, 0.8362,0.8306,0.8196,0.8076,0.7918,0.7842,0.7806, + 0.82629, 0.8278,0.8252,0.8169,0.8074,0.7916,0.7838,0.7802, + 0.82299, 0.8249,0.823,0.8165,0.8072,0.7922,0.7839,0.7798, + 0.82357, 0.8257,0.8241,0.8178,0.8084,0.7927,0.7839,0.7794, + 0.82657, 0.828,0.8264,0.8199,0.8107,0.7939,0.7842,0.7796, + 0.8311, 0.8234,0.8295,0.8228,0.8136,0.796,0.7854,0.7798, + 0.8363, 0.8366,0.8342,0.8267,0.8168,0.7986,0.7864,0.7805, + 0.84762, 0.8474,0.8438,0.8358,0.825,0.8041,0.7904,0.7822, + 0.85846, 0.8583,0.853,0.8444,0.8336,0.8118,0.7957,0.7854, + 0.8684, 0.8674,0.8619,0.8531,0.8423,0.8186,0.8011,0.7898, + 0.87713, 0.8755,0.8709,0.8616,0.8504,0.8265,0.8072,0.7939, + 0.88479, 0.8831,0.8779,0.8695,0.8578,0.8338,0.8133,0.799, + 0.89972, 0.8986,0.8936,0.8846,0.8742,0.8504,0.8294,0.8125, + 0.91028, 0.9089,0.9043,0.8967,0.8869,0.8649,0.8438,0.8253, + 0.91793, 0.9166,0.9125,0.9058,0.897,0.8768,0.8557,0.8372, + 0.92371, 0.9226,0.9189,0.9128,0.905,0.8861,0.8664,0.8484, + 0.93135, 0.9304,0.9274,0.9226,0.9164,0.9006,0.8833,0.8662, + 0.93607, 0.9353,0.9329,0.9291,0.924,0.9109,0.8958,0.8802, + 0.93927, 0.9387,0.9366,0.9334,0.9292,0.9162,0.905,0.8911, + 0.94149, 0.9409,0.9393,0.9366,0.9331,0.9236,0.9122,0.8997, + 0.94306, 0.9426,0.9412,0.9388,0.9357,0.9276,0.9175,0.9065, + 0.94419, 0.9437,0.9425,0.9406,0.938,0.9308,0.9219,0.9119, + 0.94571, 0.9455,0.9445,0.943,0.9409,0.9353,0.9283,0.9201, + 0.94662, 0.9464,0.9456,0.9444,0.9428,0.9382,0.9325,0.9258, + 0.94723, 0.9471,0.9464,0.9455,0.9442,0.9405,0.9355,0.9298, + 0.94764, 0.9474,0.9469,0.9462,0.945,0.9418,0.9378,0.9328, + 0.9479, 0.9478,0.9474,0.9465,0.9457,0.943,0.9394,0.9352, + 0.94827, 0.9481,0.948,0.9472,0.9467,0.9447,0.9422,0.9391, + 0.94842, 0.9484,0.9481,0.9478,0.9472,0.9458,0.9437,0.9415, + 0.94852, 0.9484,0.9483,0.948,0.9475,0.9465,0.9449,0.943, + 0.94861, 0.9487,0.9484,0.9481,0.9479,0.9468,0.9455,0.943, + 0.94872, 0.9486,0.9486,0.9483,0.9482,0.9475,0.9464,0.9452, + 0.94881, 0.9488,0.9489,0.949,0.9487,0.9482,0.9476,0.9468, + 0.94863, 0.9487,0.9489,0.9491,0.9493,0.9491,0.9483,0.9476, + 0.94444, 0.94444,0.94444,0.94444,0.94444,0.94444,0.94444,0.94444}; - - void MMCollisionInt::init(XML_Writer* xml, - doublereal tsmin, doublereal tsmax, int log_level) { -#ifdef DEBUG_MODE - ostream& logfile = xml->output(); - m_xml = xml; -#else - m_xml = 0; -#endif - m_loglevel = log_level; -#ifdef DEBUG_MODE - if (m_loglevel > 0) { - m_xml->XML_comment(logfile, "Collision Integral Polynomial Fits"); - } - char p[200]; -#endif - m_nmin = -1; - m_nmax = -1; + //! \endcond - for (int n = 0; n < 37; n++) { - if (tsmin > tstar[n+1]) m_nmin = n; - if (tsmax > tstar[n+1]) m_nmax = n+1; - } - if (m_nmin < 0 || m_nmin >= 36 || m_nmax < 0 || m_nmax > 36) { - m_nmin = 0; - m_nmax = 36; - } -#ifdef DEBUG_MODE - if (m_loglevel > 0) { - m_xml->XML_item(logfile, "Tstar_min", tstar[m_nmin + 1]); - m_xml->XML_item(logfile, "Tstar_max", tstar[m_nmax + 1]); - } -#endif - m_logTemp.resize(37); - doublereal rmserr, e22 = 0.0, ea = 0.0, eb = 0.0, ec = 0.0; - -#ifdef DEBUG_MODE - if (m_loglevel > 0) { - m_xml->XML_open(logfile, "dstar_fits"); - m_xml->XML_comment(logfile, "Collision integral fits at each " - "tabulated T* vs. delta*.\n" - "These polynomial fits are used to interpolate between " - "columns (delta*)\n in the Monchick and Mason tables." - " They are only used for nonzero delta*."); - if (log_level < 4) { - m_xml->XML_comment(logfile, - "polynomial coefficients not printed (log_level < 4)"); - } - } -#endif - - string indent = " "; - for (int i = 0; i < 37; i++) - { - m_logTemp[i] = log(tstar[i+1]); - vector_fp c(DeltaDegree+1); - - rmserr = fitDelta(0, i, DeltaDegree, DATA_PTR(c)); -#ifdef DEBUG_MODE - if (log_level > 3) { - sprintf(p, " Tstar=\"%12.6g\"", tstar[i+1]); - m_xml->XML_open(logfile, "dstar_fit", p); - m_xml->XML_item(logfile, "Tstar", tstar[i+1]); - m_xml->XML_writeVector(logfile, indent, "omega22", - c.size(), DATA_PTR(c)); - } -#endif - m_o22poly.push_back(c); - if (rmserr > e22) e22 = rmserr; - - rmserr = fitDelta(1, i, DeltaDegree, DATA_PTR(c)); - m_apoly.push_back(c); -#ifdef DEBUG_MODE - if (log_level > 3) - m_xml->XML_writeVector(logfile, indent, "astar", - c.size(), DATA_PTR(c)); -#endif - if (rmserr > ea) ea = rmserr; - - rmserr = fitDelta(2, i, DeltaDegree, DATA_PTR(c)); - m_bpoly.push_back(c); -#ifdef DEBUG_MODE - if (log_level > 3) - m_xml->XML_writeVector(logfile, indent, "bstar", - c.size(), DATA_PTR(c)); -#endif - if (rmserr > eb) eb = rmserr; - - rmserr = fitDelta(3, i, DeltaDegree, DATA_PTR(c)); - m_cpoly.push_back(c); -#ifdef DEBUG_MODE - if (log_level > 3) { - m_xml->XML_writeVector(logfile, indent, "cstar", - c.size(), DATA_PTR(c)); - } -#endif - if (rmserr > ec) ec = rmserr; - -#ifdef DEBUG_MODE - if (log_level > 3) { - m_xml->XML_close(logfile, "dstar_fit"); - } - - if (log_level > 0) { - sprintf(p, - "max RMS errors in fits vs. delta*:\n" - " omega_22 = %12.6g \n" - " A* = %12.6g \n" - " B* = %12.6g \n" - " C* = %12.6g \n", e22, ea, eb, ec); - m_xml->XML_comment(logfile, p); - m_xml->XML_close(logfile, "dstar_fits"); - } -#endif - } + //==================================================================================================================== + MMCollisionInt::MMCollisionInt() + { + } + //==================================================================================================================== + MMCollisionInt::~MMCollisionInt() + { + } + //==================================================================================================================== + // Initialize the object for calculation + /* + * + * @param xml Pointer to the log file that will receive the debug output + * messages + * @param tsmin Minimum value of Tstar to carry out the fitting + * @param tsmax Maximum value of Tstar to carry out the fitting + * @param loglevel Set the loglevel for the object. The default + * loglevel is zero, indicating no output. + */ + void MMCollisionInt::init(XML_Writer* xml, doublereal tsmin, doublereal tsmax, int log_level) { +#ifdef DEBUG_MODE + if (!xml) { + throw CanteraError("MMCollisionInt::init", "pointer to xml file is zero"); } - - MMCollisionInt::~MMCollisionInt() {} - - - - doublereal MMCollisionInt::fitDelta(int table, int ntstar, - int degree, doublereal* c) { - vector_fp w(8); - doublereal* begin = 0; - int ndeg=0; - switch (table) { - case 0: - begin = omega22_table + 8*ntstar; break; - case 1: - begin = astar_table + 8*(ntstar + 1); break; - case 2: - begin = bstar_table + 8*(ntstar + 1); break; - case 3: - begin = cstar_table + 8*(ntstar + 1); break; - default: - return 0.0; - } - w[0] = -1.0; - return polyfit(8, delta, begin, DATA_PTR(w), degree, ndeg, 0.0, c); - } - - doublereal MMCollisionInt::omega22(double ts, double deltastar) { - int i; - for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; - int i1, i2; - i1 = i - 1; - if (i1 < 0) i1 = 0; - i2 = i1+3; - if (i2 > 36) { - i2 = 36; - i1 = i2 - 3; - } - vector_fp values(3); - for (i = i1; i < i2; i++) { - if (deltastar == 0.0) values[i-i1] = omega22_table[8*i]; - else values[i-i1] = poly5(deltastar, DATA_PTR(m_o22poly[i])); - } - return quadInterp(log(ts), DATA_PTR(m_logTemp) - + i1, DATA_PTR(values)); - } - - doublereal MMCollisionInt::astar(double ts, double deltastar) { - int i; - for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; - int i1, i2; - i1 = i - 1; - if (i1 < 0) i1 = 0; - i2 = i1+3; - if (i2 > 36) { - i2 = 36; - i1 = i2 - 3; - } - vector_fp values(3); - for (i = i1; i < i2; i++) { - if (deltastar == 0.0) values[i-i1] = astar_table[8*(i + 1)]; - else values[i-i1] = poly5(deltastar, DATA_PTR(m_apoly[i])); - } - return quadInterp(log(ts), DATA_PTR(m_logTemp) - + i1, DATA_PTR(values)); - } - - - doublereal MMCollisionInt::bstar(double ts, double deltastar) { - int i; - for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; - int i1, i2; - i1 = i - 1; - if (i1 < 0) i1 = 0; - i2 = i1+3; - if (i2 > 36) { - i2 = 36; - i1 = i2 - 3; - } - vector_fp values(3); - for (i = i1; i < i2; i++) { - if (deltastar == 0.0) values[i-i1] = bstar_table[8*(i + 1)]; - else values[i-i1] = poly5(deltastar, DATA_PTR(m_bpoly[i])); - } - return quadInterp(log(ts), DATA_PTR(m_logTemp) + i1, - DATA_PTR(values)); - } - - - doublereal MMCollisionInt::cstar(double ts, double deltastar) { - int i; - for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; - int i1, i2; - i1 = i - 1; - if (i1 < 0) i1 = 0; - i2 = i1+3; - if (i2 > 36) { - i2 = 36; - i1 = i2 - 3; - } - vector_fp values(3); - for (i = i1; i < i2; i++) { - if (deltastar == 0.0) values[i-i1] = cstar_table[8*(i + 1)]; - else values[i-i1] = poly5(deltastar, DATA_PTR(m_cpoly[i])); - } - return quadInterp(log(ts), DATA_PTR(m_logTemp) + i1, - DATA_PTR(values)); } - - - void MMCollisionInt::fit_omega22(ostream& logfile, int degree, - doublereal deltastar, doublereal* o22) - { - - int i, n = m_nmax - m_nmin + 1; - int ndeg=0; - string indent = " "; - vector_fp values(n); - doublereal rmserr; - vector_fp w(n); - doublereal* logT = DATA_PTR(m_logTemp) + m_nmin; - for (i = 0; i < n; i++) { - if (deltastar == 0.0) values[i] = omega22_table[8*(i + m_nmin)]; - else values[i] = poly5(deltastar, DATA_PTR(m_o22poly[i+m_nmin])); - } - w[0]= -1.0; - rmserr = polyfit(n, logT, DATA_PTR(values), - DATA_PTR(w), degree, ndeg, 0.0, o22); -#ifdef DEBUG_MODE - if (m_loglevel > 0 && rmserr > 0.01) { - char p[100]; - sprintf(p, "Warning: RMS error = %12.6g in omega_22 fit" - "with delta* = %12.6g\n", rmserr, deltastar); - m_xml->XML_comment(logfile, p); - } + ostream& logfile = xml->output(); + m_xml = xml; +#else + m_xml = 0; + log_level = 0; #endif + m_loglevel = log_level; +#ifdef DEBUG_MODE + if (m_loglevel > 0) { + m_xml->XML_comment(logfile, "Collision Integral Polynomial Fits"); } + char p[200]; +#endif + m_nmin = -1; + m_nmax = -1; + + for (int n = 0; n < 37; n++) { + if (tsmin > tstar[n+1]) m_nmin = n; + if (tsmax > tstar[n+1]) m_nmax = n+1; + } + if (m_nmin < 0 || m_nmin >= 36 || m_nmax < 0 || m_nmax > 36) { + m_nmin = 0; + m_nmax = 36; + } +#ifdef DEBUG_MODE + if (m_loglevel > 0) { + m_xml->XML_item(logfile, "Tstar_min", tstar[m_nmin + 1]); + m_xml->XML_item(logfile, "Tstar_max", tstar[m_nmax + 1]); + } +#endif + m_logTemp.resize(37); + doublereal rmserr, e22 = 0.0, ea = 0.0, eb = 0.0, ec = 0.0; - void MMCollisionInt::fit(ostream& logfile, int degree, - doublereal deltastar, doublereal* a, doublereal* b, doublereal* c) - { - int i, n = m_nmax - m_nmin + 1; - int ndeg=0; - //char s[100]; - string indent = " "; - vector_fp values(n); - doublereal rmserr; - vector_fp w(n); - doublereal* logT = DATA_PTR(m_logTemp) + m_nmin; - for (i = 0; i < n; i++) { - if (deltastar == 0.0) values[i] = astar_table[8*(i + m_nmin + 1)]; - else values[i] = poly5(deltastar, DATA_PTR(m_apoly[i+m_nmin])); - } - w[0]= -1.0; - rmserr = polyfit(n, logT, DATA_PTR(values), - DATA_PTR(w), degree, ndeg, 0.0, a); +#ifdef DEBUG_MODE + if (m_loglevel > 0) { + m_xml->XML_open(logfile, "dstar_fits"); + m_xml->XML_comment(logfile, "Collision integral fits at each " + "tabulated T* vs. delta*.\n" + "These polynomial fits are used to interpolate between " + "columns (delta*)\n in the Monchick and Mason tables." + " They are only used for nonzero delta*."); + if (log_level < 4) { + m_xml->XML_comment(logfile, + "polynomial coefficients not printed (log_level < 4)"); + } + } +#endif + + string indent = " "; + for (int i = 0; i < 37; i++) + { + m_logTemp[i] = log(tstar[i+1]); + vector_fp c(DeltaDegree+1); + + rmserr = fitDelta(0, i, DeltaDegree, DATA_PTR(c)); +#ifdef DEBUG_MODE + if (log_level > 3) { + sprintf(p, " Tstar=\"%12.6g\"", tstar[i+1]); + m_xml->XML_open(logfile, "dstar_fit", p); + m_xml->XML_item(logfile, "Tstar", tstar[i+1]); + m_xml->XML_writeVector(logfile, indent, "omega22", + c.size(), DATA_PTR(c)); + } +#endif + m_o22poly.push_back(c); + if (rmserr > e22) e22 = rmserr; + + rmserr = fitDelta(1, i, DeltaDegree, DATA_PTR(c)); + m_apoly.push_back(c); +#ifdef DEBUG_MODE + if (log_level > 3) + m_xml->XML_writeVector(logfile, indent, "astar", + c.size(), DATA_PTR(c)); +#endif + if (rmserr > ea) ea = rmserr; + + rmserr = fitDelta(2, i, DeltaDegree, DATA_PTR(c)); + m_bpoly.push_back(c); +#ifdef DEBUG_MODE + if (log_level > 3) + m_xml->XML_writeVector(logfile, indent, "bstar", + c.size(), DATA_PTR(c)); +#endif + if (rmserr > eb) eb = rmserr; + + rmserr = fitDelta(3, i, DeltaDegree, DATA_PTR(c)); + m_cpoly.push_back(c); +#ifdef DEBUG_MODE + if (log_level > 3) { + m_xml->XML_writeVector(logfile, indent, "cstar", + c.size(), DATA_PTR(c)); + } +#endif + if (rmserr > ec) ec = rmserr; + +#ifdef DEBUG_MODE + if (log_level > 3) { + m_xml->XML_close(logfile, "dstar_fit"); + } + + if (log_level > 0) { + sprintf(p, + "max RMS errors in fits vs. delta*:\n" + " omega_22 = %12.6g \n" + " A* = %12.6g \n" + " B* = %12.6g \n" + " C* = %12.6g \n", e22, ea, eb, ec); + m_xml->XML_comment(logfile, p); + m_xml->XML_close(logfile, "dstar_fits"); + } +#endif + } + } + //==================================================================================================================== + + doublereal MMCollisionInt::fitDelta(int table, int ntstar, int degree, doublereal* c) { + vector_fp w(8); + doublereal* begin = 0; + int ndeg=0; + switch (table) { + case 0: + begin = omega22_table + 8*ntstar; break; + case 1: + begin = astar_table + 8*(ntstar + 1); break; + case 2: + begin = bstar_table + 8*(ntstar + 1); break; + case 3: + begin = cstar_table + 8*(ntstar + 1); break; + default: + return 0.0; + } + w[0] = -1.0; + return polyfit(8, delta, begin, DATA_PTR(w), degree, ndeg, 0.0, c); + } + //==================================================================================================================== + + doublereal MMCollisionInt::omega22(double ts, double deltastar) { + int i; + for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; + int i1, i2; + i1 = i - 1; + if (i1 < 0) i1 = 0; + i2 = i1+3; + if (i2 > 36) { + i2 = 36; + i1 = i2 - 3; + } + vector_fp values(3); + for (i = i1; i < i2; i++) { + if (deltastar == 0.0) values[i-i1] = omega22_table[8*i]; + else values[i-i1] = poly5(deltastar, DATA_PTR(m_o22poly[i])); + } + return quadInterp(log(ts), DATA_PTR(m_logTemp) + + i1, DATA_PTR(values)); + } + //==================================================================================================================== + + doublereal MMCollisionInt::astar(double ts, double deltastar) { + int i; + for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; + int i1, i2; + i1 = i - 1; + if (i1 < 0) i1 = 0; + i2 = i1+3; + if (i2 > 36) { + i2 = 36; + i1 = i2 - 3; + } + vector_fp values(3); + for (i = i1; i < i2; i++) { + if (deltastar == 0.0) values[i-i1] = astar_table[8*(i + 1)]; + else values[i-i1] = poly5(deltastar, DATA_PTR(m_apoly[i])); + } + return quadInterp(log(ts), DATA_PTR(m_logTemp) + + i1, DATA_PTR(values)); + } + //==================================================================================================================== + + + doublereal MMCollisionInt::bstar(double ts, double deltastar) { + int i; + for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; + int i1, i2; + i1 = i - 1; + if (i1 < 0) i1 = 0; + i2 = i1+3; + if (i2 > 36) { + i2 = 36; + i1 = i2 - 3; + } + vector_fp values(3); + for (i = i1; i < i2; i++) { + if (deltastar == 0.0) values[i-i1] = bstar_table[8*(i + 1)]; + else values[i-i1] = poly5(deltastar, DATA_PTR(m_bpoly[i])); + } + return quadInterp(log(ts), DATA_PTR(m_logTemp) + i1, + DATA_PTR(values)); + } + //==================================================================================================================== + + doublereal MMCollisionInt::cstar(double ts, double deltastar) { + int i; + for (i = 0; i < 37; i++) if (ts < tstar22[i]) break; + int i1, i2; + i1 = i - 1; + if (i1 < 0) i1 = 0; + i2 = i1+3; + if (i2 > 36) { + i2 = 36; + i1 = i2 - 3; + } + vector_fp values(3); + for (i = i1; i < i2; i++) { + if (deltastar == 0.0) values[i-i1] = cstar_table[8*(i + 1)]; + else values[i-i1] = poly5(deltastar, DATA_PTR(m_cpoly[i])); + } + return quadInterp(log(ts), DATA_PTR(m_logTemp) + i1, + DATA_PTR(values)); + } + + //==================================================================================================================== + + void MMCollisionInt::fit_omega22(ostream& logfile, int degree, + doublereal deltastar, doublereal* o22) + { + + int i, n = m_nmax - m_nmin + 1; + int ndeg=0; + string indent = " "; + vector_fp values(n); + doublereal rmserr; + vector_fp w(n); + doublereal* logT = DATA_PTR(m_logTemp) + m_nmin; + for (i = 0; i < n; i++) { + if (deltastar == 0.0) values[i] = omega22_table[8*(i + m_nmin)]; + else values[i] = poly5(deltastar, DATA_PTR(m_o22poly[i+m_nmin])); + } + w[0]= -1.0; + rmserr = polyfit(n, logT, DATA_PTR(values), + DATA_PTR(w), degree, ndeg, 0.0, o22); +#ifdef DEBUG_MODE + if (m_loglevel > 0 && rmserr > 0.01) { + char p[100]; + sprintf(p, "Warning: RMS error = %12.6g in omega_22 fit" + "with delta* = %12.6g\n", rmserr, deltastar); + m_xml->XML_comment(logfile, p); + } +#endif + } + //==================================================================================================================== + + void MMCollisionInt::fit(ostream& logfile, int degree, + doublereal deltastar, doublereal* a, doublereal* b, doublereal* c) + { + int i, n = m_nmax - m_nmin + 1; + int ndeg=0; + //char s[100]; + string indent = " "; + vector_fp values(n); + doublereal rmserr; + vector_fp w(n); + doublereal* logT = DATA_PTR(m_logTemp) + m_nmin; + for (i = 0; i < n; i++) { + if (deltastar == 0.0) values[i] = astar_table[8*(i + m_nmin + 1)]; + else values[i] = poly5(deltastar, DATA_PTR(m_apoly[i+m_nmin])); + } + w[0]= -1.0; + rmserr = polyfit(n, logT, DATA_PTR(values), + DATA_PTR(w), degree, ndeg, 0.0, a); - for (i = 0; i < n; i++) { - if (deltastar == 0.0) values[i] = bstar_table[8*(i + m_nmin + 1)]; - else values[i] = poly5(deltastar, DATA_PTR(m_bpoly[i+m_nmin])); - } - w[0]= -1.0; - rmserr = polyfit(n, logT, DATA_PTR(values), - DATA_PTR(w), degree, ndeg, 0.0, b); - - for (i = 0; i < n; i++) { - if (deltastar == 0.0) values[i] = cstar_table[8*(i + m_nmin + 1)]; - else values[i] = poly5(deltastar, DATA_PTR(m_cpoly[i+m_nmin])); - } - w[0]= -1.0; - rmserr = polyfit(n, logT, DATA_PTR(values), - DATA_PTR(w), degree, ndeg, 0.0, c); -#ifdef DEBUG_MODE - if (m_loglevel > 2) { - char p[100]; - sprintf(p, " dstar=\"%12.6g\"", deltastar); - m_xml->XML_open(logfile, "tstar_fit", p); - - m_xml->XML_writeVector(logfile, indent, "astar", degree+1, a); - if (rmserr > 0.01) { - sprintf(p, "Warning: RMS error = %12.6g for A* fit", rmserr); - m_xml->XML_comment(logfile, p); - } - - m_xml->XML_writeVector(logfile, indent, "bstar", degree+1, b); - if (rmserr > 0.01) { - sprintf(p, "Warning: RMS error = %12.6g for B* fit", rmserr); - m_xml->XML_comment(logfile, p); - } - - m_xml->XML_writeVector(logfile, indent, "cstar", degree+1, c); - - if (rmserr > 0.01) { - sprintf(p, "Warning: RMS error = %12.6g for C* fit", rmserr); - m_xml->XML_comment(logfile, p); - } - m_xml->XML_close(logfile, "tstar_fit"); - } -#endif + for (i = 0; i < n; i++) { + if (deltastar == 0.0) values[i] = bstar_table[8*(i + m_nmin + 1)]; + else values[i] = poly5(deltastar, DATA_PTR(m_bpoly[i+m_nmin])); } + w[0]= -1.0; + rmserr = polyfit(n, logT, DATA_PTR(values), + DATA_PTR(w), degree, ndeg, 0.0, b); + for (i = 0; i < n; i++) { + if (deltastar == 0.0) values[i] = cstar_table[8*(i + m_nmin + 1)]; + else values[i] = poly5(deltastar, DATA_PTR(m_cpoly[i+m_nmin])); + } + w[0]= -1.0; + rmserr = polyfit(n, logT, DATA_PTR(values), + DATA_PTR(w), degree, ndeg, 0.0, c); +#ifdef DEBUG_MODE + if (m_loglevel > 2) { + char p[100]; + sprintf(p, " dstar=\"%12.6g\"", deltastar); + m_xml->XML_open(logfile, "tstar_fit", p); + + m_xml->XML_writeVector(logfile, indent, "astar", degree+1, a); + if (rmserr > 0.01) { + sprintf(p, "Warning: RMS error = %12.6g for A* fit", rmserr); + m_xml->XML_comment(logfile, p); + } + + m_xml->XML_writeVector(logfile, indent, "bstar", degree+1, b); + if (rmserr > 0.01) { + sprintf(p, "Warning: RMS error = %12.6g for B* fit", rmserr); + m_xml->XML_comment(logfile, p); + } + + m_xml->XML_writeVector(logfile, indent, "cstar", degree+1, c); + + if (rmserr > 0.01) { + sprintf(p, "Warning: RMS error = %12.6g for C* fit", rmserr); + m_xml->XML_comment(logfile, p); + } + m_xml->XML_close(logfile, "tstar_fit"); + } +#endif + } + //==================================================================================================================== } // namespace - +//====================================================================================================================== diff --git a/Cantera/src/transport/MMCollisionInt.h b/Cantera/src/transport/MMCollisionInt.h old mode 100755 new mode 100644 index 797a30ea5..0db470d6b --- a/Cantera/src/transport/MMCollisionInt.h +++ b/Cantera/src/transport/MMCollisionInt.h @@ -3,7 +3,6 @@ * Monk and Monchick collision integrals */ /* - * $Author$ * $Revision$ * $Date$ */ @@ -29,20 +28,33 @@ namespace Cantera { class XML_Writer; + + //! Error handler class for collision integrals + /*! + * This class doesn't + */ class MMCollisionIntError { public: + + //! Constructor + /*! + * @param logfile ostream reference for writing out errors + * @param msg error message + */ MMCollisionIntError(std::ostream& logfile, std::string msg) { logfile << "#### ERROR ####" << std::endl; logfile << "MMCollisionInt: " << msg << std::endl; std::cerr << "Error in fitting collision integrals. " - << "Execution terminated." << std::endl - << "See transport log file for more information." << std::endl; + << "Execution terminated." << std::endl + << "See transport log file for more information." << std::endl; } }; - /** - * Collision integrals. This class provides functions that + + //! Calculation of Collision integrals + /*! + * This class provides functions that * interpolate the tabulated collision integrals in Monchick and * Mason, "Transport Properties of Polar Gases," J. Chem. Phys. (1961) * @@ -52,45 +64,144 @@ namespace Cantera { public: - MMCollisionInt(){} - virtual ~MMCollisionInt(); - void init(XML_Writer* xml, doublereal tsmin, - doublereal tsmax, int loglevel = 0); + //! Default Constructor + MMCollisionInt(); + //! Destructor + virtual ~MMCollisionInt(); + + + //! Initialize the object for calculation + /*! + * + * @param xml Pointer to the log file that will receive the debug output + * messages + * @param tsmin Minimum value of Tstar to carry out the fitting + * @param tsmax Maximum value of Tstar to carry out the fitting + * @param loglevel Set the loglevel for the object. The default + * loglevel is zero, indicating no output. + */ + void init(XML_Writer* xml, doublereal tsmin, doublereal tsmax, int loglevel = 0); + + //! omega22 + /*! + * @param ts + * @param deltastar + */ doublereal omega22(double ts, double deltastar); + + //! astar + /*! + * @param ts + * @param deltastar + */ doublereal astar(double ts, double deltastar); + + //! bstar + /*! + * @param ts + * @param deltastar + */ doublereal bstar(double ts, double deltastar); + + //! cstar + /*! + * @param ts + * @param deltastar + */ doublereal cstar(double ts, double deltastar); + //! fit + /*! + * @param logfile + * @param degree + * @param deltastar + * @param astar + * @param bstar + * @param cstar + */ void fit(std::ostream& logfile, int degree, doublereal deltastar, doublereal* astar, doublereal* bstar, doublereal* cstar); + //! fit_omega22 + /*! + * @param logfile + * @param degree + * @param deltastar + * @param om22 + */ void fit_omega22(std::ostream& logfile, int degree, doublereal deltastar, doublereal* om22); + + //! omega11 + /*! + * @param ts + * @param deltastar + */ doublereal omega11(double ts, double deltastar) { return omega22(ts, deltastar)/astar(ts, deltastar); } private: - doublereal fitDelta(int table, int ntstar, - int degree, doublereal* c); + //! Fit delta + /*! + * @param table + * @param ntstar + * @param degree + * @param c C is probable the output vector + * + * @return + */ + doublereal fitDelta(int table, int ntstar, int degree, doublereal* c); + //! m_o22poly std::vector m_o22poly; + + //! m_apoly std::vector m_apoly; + //! m_bpoly std::vector m_bpoly; + + //! m_cpoly std::vector m_cpoly; + //! delta static doublereal delta[8]; + + //! tstar22 static doublereal tstar22[37]; + + //! Table of omega22 values from MM static doublereal omega22_table[37*8]; + + //! tstar + /*! + * table of tstar values + */ static doublereal tstar[39]; + + //! astar table from MM static doublereal astar_table[39*8]; + + //! bstar table from MM static doublereal bstar_table[39*8]; + + //! cstar table from MM static doublereal cstar_table[39*8]; + //! Log temp vector_fp m_logTemp; - int m_nmin, m_nmax; + + //! nmin + int m_nmin; + + //! nmax + int m_nmax; + + //! XML_Writer pointer XML_Writer* m_xml; + + //! loglevel int m_loglevel; }; } diff --git a/Cantera/src/transport/Makefile.in b/Cantera/src/transport/Makefile.in index 8302e9a54..4ec69c96a 100644 --- a/Cantera/src/transport/Makefile.in +++ b/Cantera/src/transport/Makefile.in @@ -36,12 +36,15 @@ CXX_FLAGS = @CXXFLAGS@ $(CXX_OPT) $(PIC_FLAG) $(DEBUG_FLAG) # Base Transport Object Files TRAN_OBJ = TransportFactory.o MultiTransport.o MixTransport.o MMCollisionInt.o \ SolidTransport.o DustyGasTransport.o TransportBase.o WaterTransport.o \ - SimpleTransport.o + SimpleTransport.o LiquidTransportData.o LiquidTransportParams.o LiquidTranInteraction.o \ + TransportParams.o \ + TortuosityBase.o TortuosityBruggeman.o TortuosityPercolation.o TortuosityMaxwell.o TRAN_H = TransportFactory.h MultiTransport.h MixTransport.h \ MMCollisionInt.h SolidTransport.h DustyGasTransport.h \ TransportBase.h L_matrix.h TransportParams.h WaterTransport.h \ - SimpleTransport.h LiquidTransportData.h + SimpleTransport.h LiquidTranInteraction.h Tortuosity.h \ + TortuosityBase.h TortuosityBruggeman.h TortuosityPercolation.h TortuosityMaxwell.h ifeq ($(do_electro),1) do_issp = 1 @@ -50,8 +53,8 @@ ELECTRO_H = AqueousTransport.h endif ifeq ($(do_issp),1) -ISSP_OBJ = LiquidTransport.o -ISSP_H = LiquidTransport.h LiquidTransportParams.h +ISSP_OBJ = LiquidTransport.o LiquidTransportData.o LTPspecies.o +ISSP_H = LiquidTransport.h LiquidTransportParams.h LiquidTransportData.h LTPspecies.h endif @@ -69,12 +72,17 @@ all: $(LIB) .depends @(for lh in $(CATRAN_H) ; do \ $(INSTALL_TSC) "$${lh}" $(INCDIR) ; \ done) -%.d: Makefile %.o + +.cpp.d: @CXX_DEPENDS@ $(CXX_FLAGS) $(CXX_INCLUDES) $*.cpp > $*.d .cpp.o: $(PURIFY) @CXX@ -c $< $(CXX_FLAGS) $(CXX_INCLUDES) +$(DEPENDS): Makefile + +$(CATRAN_OBJ): Makefile + $(LIB): $(CATRAN_OBJ) $(CATRAN_H) @ARCHIVE@ $(LIB) $(CATRAN_OBJ) > /dev/null ifeq ($(do_ranlib),1) diff --git a/Cantera/src/transport/MixTransport.cpp b/Cantera/src/transport/MixTransport.cpp old mode 100755 new mode 100644 index 4f70664af..1f1d88a70 --- a/Cantera/src/transport/MixTransport.cpp +++ b/Cantera/src/transport/MixTransport.cpp @@ -31,26 +31,179 @@ using namespace std; * Mole fractions below MIN_X will be set to MIN_X when computing * transport properties. */ +#ifndef MIN_X #define MIN_X 1.e-20 - +#endif namespace Cantera { - //////////////////// class MixTransport methods ////////////// - + //==================================================================================================================== MixTransport::MixTransport() : m_nsp(0), m_tmin(-1.0), m_tmax(100000.), + m_mw(0), + m_visccoeffs(0), + m_condcoeffs(0), + m_diffcoeffs(0), + m_polytempvec(0), + m_bdiff(0, 0), + m_visc(0), + m_sqvisc(0), + m_cond(0), + m_molefracs(0), + m_phi(0,0), + m_wratjk(0,0), + m_wratkj1(0,0), m_temp(-1.0), - m_logt(0.0) + m_logt(0.0), + m_kbt(0.0), + m_t14(0.0), + m_t32(0.0), + m_sqrt_kbt(0.0), + m_sqrt_t(0.0), + m_lambda(0.0), + m_viscmix(0.0), + m_spwork(0), + m_viscmix_ok(false), + m_viscwt_ok(false), + m_spvisc_ok(false), + m_bindiff_ok(false), + m_spcond_ok(false), + m_condmix_ok(false), + m_mode(0), + m_eps(0), + m_diam(0, 0), + m_dipoleDiag(0), + m_alpha(0), + m_crot(0), + m_zrot(0), + m_debug(false) { - - } + //==================================================================================================================== + MixTransport::MixTransport(const MixTransport &right) : + m_nsp(0), + m_tmin(-1.0), + m_tmax(100000.), + m_mw(0), + m_visccoeffs(0), + m_condcoeffs(0), + m_diffcoeffs(0), + m_polytempvec(0), + m_bdiff(0, 0), + m_visc(0), + m_sqvisc(0), + m_cond(0), + m_molefracs(0), + m_phi(0,0), + m_wratjk(0,0), + m_wratkj1(0,0), + m_temp(-1.0), + m_logt(0.0), + m_kbt(0.0), + m_t14(0.0), + m_t32(0.0), + m_sqrt_kbt(0.0), + m_sqrt_t(0.0), + m_lambda(0.0), + m_viscmix(0.0), + m_spwork(0), + m_viscmix_ok(false), + m_viscwt_ok(false), + m_spvisc_ok(false), + m_bindiff_ok(false), + m_spcond_ok(false), + m_condmix_ok(false), + m_mode(0), + m_eps(0), + m_diam(0, 0), + m_dipoleDiag(0), + m_alpha(0), + m_crot(0), + m_zrot(0), + m_debug(false) + { + *this = right; + } + //==================================================================================================================== + // Assignment operator + /* + * This is NOT a virtual function. + * + * @param right Reference to %LiquidTransport object to be copied + * into the current one. + */ + MixTransport& MixTransport::operator=(const MixTransport& right) { + if (&right == this) { + return *this; + } + Transport::operator=(right); + + m_nsp = right.m_nsp; + m_tmin = right.m_tmin; + m_tmax = right.m_tmax; + m_mw =right.m_mw; + m_visccoeffs = right.m_visccoeffs; + m_condcoeffs = right.m_condcoeffs; + m_diffcoeffs = right.m_diffcoeffs; + m_polytempvec = right.m_polytempvec; + m_bdiff = right.m_bdiff; + m_visc = right.m_visc; + m_sqvisc = right.m_sqvisc; + m_cond = right.m_cond; + m_molefracs = right.m_molefracs; + m_phi = right.m_phi; + m_wratjk = right.m_wratjk; + m_wratkj1 = right.m_wratkj1; + m_temp = right.m_temp; + m_logt = right.m_logt; + m_kbt = right.m_kbt; + m_t14 = right.m_t14; + m_t32 = right.m_t32; + m_sqrt_kbt = right.m_sqrt_kbt; + m_sqrt_t = right.m_sqrt_t; + m_lambda = right.m_lambda; + m_viscmix = right.m_viscmix; + m_spwork = right.m_spwork; + m_viscmix_ok = right.m_viscmix_ok; + m_viscwt_ok = right.m_viscwt_ok; + m_spvisc_ok = right.m_spvisc_ok; + m_bindiff_ok = right.m_bindiff_ok; + m_spcond_ok = right.m_spcond_ok; + m_condmix_ok = right.m_condmix_ok; + m_mode = right.m_mode; + m_eps = right.m_eps; + m_diam = right.m_diam; + m_dipoleDiag = right.m_dipoleDiag; + m_alpha = right.m_alpha; + m_crot = right.m_crot; + m_zrot = right.m_zrot; + m_debug = right.m_debug; - bool MixTransport::initGas( GasTransportParams& tr ) { + return *this; + } + //==================================================================================================================== + // Duplication routine for objects which inherit from %Transport + /* + * This virtual routine can be used to duplicate %Transport objects + * inherited from %Transport even if the application only has + * a pointer to %Transport to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + */ + Transport *MixTransport::duplMyselfAsTransport() const { + MixTransport* tr = new MixTransport(*this); + return (dynamic_cast(tr)); + } + //==================================================================================================================== + MixTransport::~MixTransport() + { + } + //==================================================================================================================== + bool MixTransport::initGas(GasTransportParams& tr) { // constant substance attributes m_thermo = tr.thermo; @@ -64,14 +217,12 @@ namespace Cantera { m_thermo->molecularWeights().end(), m_mw.begin()); // copy polynomials and parameters into local storage - m_poly = tr.poly; m_visccoeffs = tr.visccoeffs; m_condcoeffs = tr.condcoeffs; m_diffcoeffs = tr.diffcoeffs; m_zrot = tr.zrot; m_crot = tr.crot; - m_epsilon = tr.epsilon; m_mode = tr.mode_; m_diam = tr.diam; m_eps = tr.eps; @@ -107,35 +258,27 @@ namespace Cantera { m_spvisc_ok = false; m_spcond_ok = false; m_condmix_ok = false; - m_spcond_ok = false; - m_diffmix_ok = false; - m_abc_ok = false; return true; } - - - /********************************************************* + //==================================================================================================================== + // Viscosity of the mixture + /* * - * Public methods - * - *********************************************************/ - - - /****************** viscosity ******************************/ - - /** * The viscosity is computed using the Wilke mixture rule. - * \f[ - * \mu = \sum_k \frac{\mu_k X_k}{\sum_j \Phi_{k,j} X_j}. - * \f] - * Here \f$ \mu_k \f$ is the viscosity of pure species \e k, - * and - * \f[ - * \Phi_{k,j} = \frac{\left[1 - * + \sqrt{\left(\frac{\mu_k}{\mu_j}\sqrt{\frac{M_j}{M_k}}\right)}\right]^2} - * {\sqrt{8}\sqrt{1 + M_k/M_j}} - * \f] + * + * \f[ + * \mu = \sum_k \frac{\mu_k X_k}{\sum_j \Phi_{k,j} X_j}. + * \f] + * + * Here \f$ \mu_k \f$ is the viscosity of pure species \e k, and + * + * \f[ + * \Phi_{k,j} = \frac{\left[1 + * + \sqrt{\left(\frac{\mu_k}{\mu_j}\sqrt{\frac{M_j}{M_k}}\right)}\right]^2} + * {\sqrt{8}\sqrt{1 + M_k/M_j}} + * \f] + * * @see updateViscosity_T(); */ doublereal MixTransport::viscosity() { @@ -158,46 +301,58 @@ namespace Cantera { m_viscmix = vismix; return vismix; } - - - /******************* binary diffusion coefficients **************/ - - + //==================================================================================================================== + // Returns the matrix of binary diffusion coefficients. + /* + * + * d[ld*j + i] = rp * m_bdiff(i,j); + * + * units of m**2 / s + * + * @param ld offset of rows in the storage + * @param d output vector of diffusion coefficients + */ void MixTransport::getBinaryDiffCoeffs(const int ld, doublereal* const d) { - int i,j; - update_T(); - - // if necessary, evaluate the binary diffusion coefficents - // from the polynomial fits + // if necessary, evaluate the binary diffusion coefficents from the polynomial fits if (!m_bindiff_ok) updateDiff_T(); - + if (ld < m_nsp) { + throw CanteraError(" MixTransport::getBinaryDiffCoeffs()", "ld is too small"); + } doublereal rp = 1.0/pressure_ig(); - for (i = 0; i < m_nsp; i++) - for (j = 0; j < m_nsp; j++) { + for (int i = 0; i < m_nsp; i++) + for (int j = 0; j < m_nsp; j++) { d[ld*j + i] = rp * m_bdiff(i,j); } } - - + //=================================================================================================================== void MixTransport::getMobilities(doublereal* const mobil) { int k; getMixDiffCoeffs(DATA_PTR(m_spwork)); doublereal c1 = ElectronCharge / (Boltzmann * m_temp); for (k = 0; k < m_nsp; k++) { - mobil[k] = c1 * m_spwork[k] * m_thermo->charge(k); + mobil[k] = c1 * m_spwork[k]; } } - - - /****************** thermal conductivity **********************/ - - /** + //=================================================================================================================== + // Returns the mixture thermal conductivity (W/m /K) + /* * The thermal conductivity is computed from the following mixture rule: - * \[ - * \lambda = 0.5 \left( \sum_k X_k \lambda_k - * + \frac{1}{\sum_k X_k/\lambda_k}\right) - * \] + * \f[ + * \lambda = 0.5 \left( \sum_k X_k \lambda_k + \frac{1}{\sum_k X_k/\lambda_k} \right) + * \f] + * + * It's used to compute the flux of energy due to a thermal gradient + * + * \f[ + * j_T = - \lambda \nabla T + * \f] + * + * The flux of energy has units of energy (kg m2 /s2) per second per area. + * + * The units of lambda are W / m K which is equivalent to kg m / s^3 K. + * + * @return Returns the mixture thermal conductivity, with units of W/m/K */ doublereal MixTransport::thermalConductivity() { int k; @@ -213,34 +368,49 @@ namespace Cantera { sum2 += m_molefracs[k] / m_cond[k]; } m_lambda = 0.5*(sum1 + 1.0/sum2); + m_condmix_ok = true; } return m_lambda; } - - - /****************** thermal diffusion coefficients ************/ - - /** - * Thermal diffusion is not considered in this mixture-averaged - * model. To include thermal diffusion, use transport manager - * MultiTransport instead. This methods fills out array dt with - * zeros. + //=================================================================================================================== + // Return the thermal diffusion coefficients + /* + * For this approximation, these are all zero. + * + * Eqns. (12.168) shows how they are used in an expression for the species flux. + * + * @param dt Vector of thermal diffusion coefficients. Units = kg/m/s */ void MixTransport::getThermalDiffCoeffs(doublereal* const dt) { - int k; - for (k = 0; k < m_nsp; k++) { + for (int k = 0; k < m_nsp; k++) { dt[k] = 0.0; } } - - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. + //=================================================================================================================== + // Get the species diffusive mass fluxes wrt to the mass averaged velocity, + // given the gradients in mole fraction and temperature + /* + * Units for the returned fluxes are kg m-2 s-1. + * + * * The diffusive mass flux of species \e k is computed from * \f[ - * \vec{j}_k = -n M_k D_k \nabla X_k. + * \vec{j}_k = -n M_k D_k \nabla X_k. * \f] + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ void MixTransport::getSpeciesFluxes(int ndim, const doublereal* grad_T, int ldx, const doublereal* grad_X, @@ -270,14 +440,16 @@ namespace Cantera { } } } - - /** - * Mixture-averaged diffusion coefficients [m^2/s]. - * - * For the single species case or the pure fluid case - * the routine returns the self-diffusion coefficient. + //=========================================================================================================== + // Mixture-averaged diffusion coefficients [m^2/s]. + /* + * Returns the mixture averaged diffusion coefficients for a gas. + * Note, for the single species case or the pure fluid case the routine returns the self-diffusion coefficient. * This is need to avoid a Nan result in the formula * below. + * + * @param d Output Vector of diffusion coefficients for each species (m^2/s) + * length m_nsp */ void MixTransport::getMixDiffCoeffs(doublereal* const d) { @@ -310,9 +482,8 @@ namespace Cantera { } } } - - - /** + //=========================================================================================================== + /* * @internal This is called whenever a transport property is * requested from ThermoSubstance if the temperature has changed * since the last call to update_T. @@ -346,13 +517,11 @@ namespace Cantera { m_spvisc_ok = false; m_viscwt_ok = false; m_spcond_ok = false; - m_diffmix_ok = false; m_bindiff_ok = false; - m_abc_ok = false; m_condmix_ok = false; } - - /** + //==================================================================================================================== + /* * @internal This is called the first time any transport property * is requested from Mixture after the concentrations * have changed. @@ -364,7 +533,6 @@ namespace Cantera { // fractions. m_viscmix_ok = false; - m_diffmix_ok = false; m_condmix_ok = false; m_thermo->getMoleFractions(DATA_PTR(m_molefracs)); @@ -375,15 +543,8 @@ namespace Cantera { m_molefracs[k] = fmaxx(MIN_X, m_molefracs[k]); } } - - - /************************************************************************* - * - * methods to update temperature-dependent properties - * - *************************************************************************/ - - /** + //==================================================================================================================== + /* * Update the temperature-dependent parts of the mixture-averaged * thermal conductivity. */ @@ -397,15 +558,14 @@ namespace Cantera { } else { for (k = 0; k < m_nsp; k++) { - m_cond[k] = m_sqrt_t*dot5(m_polytempvec, m_condcoeffs[k]); + m_cond[k] = m_sqrt_t * dot5(m_polytempvec, m_condcoeffs[k]); } } m_spcond_ok = true; m_condmix_ok = false; } - - - /** + //==================================================================================================================== + /* * Update the binary diffusion coefficients. These are evaluated * from the polynomial fits at unit pressure (1 Pa). */ @@ -433,17 +593,13 @@ namespace Cantera { } } } - m_bindiff_ok = true; - m_diffmix_ok = false; } - - - /** + //==================================================================================================================== + /* * Update the pure-species viscosities. */ void MixTransport::updateSpeciesViscosities() { - int k; if (m_mode == CK_Mode) { for (k = 0; k < m_nsp; k++) { @@ -454,19 +610,26 @@ namespace Cantera { else { for (k = 0; k < m_nsp; k++) { // the polynomial fit is done for sqrt(visc/sqrt(T)) - m_sqvisc[k] = m_t14*dot5(m_polytempvec, m_visccoeffs[k]); - m_visc[k] = (m_sqvisc[k]*m_sqvisc[k]); + m_sqvisc[k] = m_t14 * dot5(m_polytempvec, m_visccoeffs[k]); + m_visc[k] = (m_sqvisc[k] * m_sqvisc[k]); } } m_spvisc_ok = true; } - - - /** - * Update the temperature-dependent viscosity terms. - * Updates the array of pure species viscosities, and the - * weighting functions in the viscosity mixture rule. + //==================================================================================================================== + // Update the temperature-dependent viscosity terms. + /* + * Updates the array of pure species viscosities, and the weighting functions in the viscosity mixture rule. * The flag m_visc_ok is set to true. + * + * The formula for the weighting function is from Poling and Prausnitz. + * See Eq. (9-5.14) of Poling, Prausnitz, and O'Connell. The equation for the weighting function + * \f$ \phi_{ij} \f$ is reproduced below. + * + * \f[ + * \phi_{ij} = \frac{ \left[ 1 + \left( \mu_i / \mu_j \right)^{1/2} \left( M_j / M_i \right)^{1/4} \right]^2 } + * {\left[ 8 \left( 1 + M_i / M_j \right) \right]^{1/2}} + * \f] */ void MixTransport::updateViscosity_T() { doublereal vratiokj, wratiojk, factor1; @@ -483,21 +646,19 @@ namespace Cantera { // Note that m_wratjk(k,j) holds the square root of // m_wratjk(j,k)! factor1 = 1.0 + (m_sqvisc[k]/m_sqvisc[j]) * m_wratjk(k,j); - m_phi(k,j) = factor1*factor1 / - (SqrtEight * m_wratkj1(j,k)); + m_phi(k,j) = factor1*factor1 / (SqrtEight * m_wratkj1(j,k)); m_phi(j,k) = m_phi(k,j)/(vratiokj * wratiojk); } } m_viscwt_ok = true; } - - /** + //==================================================================================================================== + /* * This function returns a Transport data object for a given species. * */ - struct GasTransportData MixTransport:: - getGasTransportData(int kSpecies) - { + struct GasTransportData MixTransport::getGasTransportData(int kSpecies) const { + struct GasTransportData td; td.speciesName = m_thermo->speciesName(kSpecies); @@ -515,6 +676,6 @@ namespace Cantera { return td; } - + //==================================================================================================================== } diff --git a/Cantera/src/transport/MixTransport.h b/Cantera/src/transport/MixTransport.h index 999937969..0d0209a49 100644 --- a/Cantera/src/transport/MixTransport.h +++ b/Cantera/src/transport/MixTransport.h @@ -1,20 +1,20 @@ /** * @file MixTransport.h - * Header file defining class MixTransport + * Headers for the MixTransport object, which models transport properties + * in ideal gas solutions using a mixture averaged approximation + * (see \ref tranprops and \link Cantera::MixTransport MixTransport \endlink) . + * */ - /* $Author$ * $Revision$ * $Date$ */ - // Copyright 2001 California Institute of Technology #ifndef CT_MIXTRAN_H #define CT_MIXTRAN_H - // turn off warnings under Windows #ifdef WIN32 #pragma warning(disable:4786) @@ -28,8 +28,6 @@ #include #include -using namespace std; - // Cantera includes #include "TransportBase.h" #include "DenseMatrix.h" @@ -39,77 +37,248 @@ namespace Cantera { class GasTransportParams; - /** - * Class MixTransport implements mixture-averaged transport - * properties for ideal gas mixtures. The model is based on that - * described by Kee, Coltrin, and Glarborg, "Theoretical and - * Practical Aspects of Chemically Reacting Flow Modeling." + + //! Class MixTransport implements mixture-averaged transport properties for ideal gas mixtures. + /*! + * The model is based on that described by Kee, Coltrin, and Glarborg, "Theoretical and + * Practical Aspects of Chemically Reacting Flow Modeling." + * + * + * The viscosity is computed using the Wilke mixture rule (kg /m /s) + * + * \f[ + * \mu = \sum_k \frac{\mu_k X_k}{\sum_j \Phi_{k,j} X_j}. + * \f] + * + * Here \f$ \mu_k \f$ is the viscosity of pure species \e k, and + * + * \f[ + * \Phi_{k,j} = \frac{\left[1 + * + \sqrt{\left(\frac{\mu_k}{\mu_j}\sqrt{\frac{M_j}{M_k}}\right)}\right]^2} + * {\sqrt{8}\sqrt{1 + M_k/M_j}} + * \f] + * + * + * The thermal conductivity is computed from the following mixture rule: + * \f[ + * \lambda = 0.5 \left( \sum_k X_k \lambda_k + \frac{1}{\sum_k X_k/\lambda_k} \right) + * \f] + * + * It's used to compute the flux of energy due to a thermal gradient + * + * \f[ + * j_T = - \lambda \nabla T + * \f] + * + * The flux of energy has units of energy (kg m2 /s2) per second per area. + * + * The units of lambda are W / m K which is equivalent to kg m / s^3 K. + * + * */ class MixTransport : public Transport { - public: + protected: - virtual ~MixTransport() {} - - virtual int model() const { return cMixtureAveraged; } - - //! Viscosity of the mixture + //! Default constructor. /*! * */ + MixTransport(); + + public: + + //!Copy Constructor for the %MixTransport object. + /*! + * @param right %LiquidTransport to be copied + */ + MixTransport(const MixTransport &right); + + //! Assignment operator + /*! + * This is NOT a virtual function. + * + * @param right Reference to %LiquidTransport object to be copied + * into the current one. + */ + MixTransport& operator=(const MixTransport& right); + + //! Duplication routine for objects which inherit from + //! %Transport + /*! + * This virtual routine can be used to duplicate %Transport objects + * inherited from %Transport even if the application only has + * a pointer to %Transport to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + */ + virtual Transport *duplMyselfAsTransport() const; + + + //! Destructor + virtual ~MixTransport(); + + //! Return the model id for transport + /*! + * @return cMixtureAverage + */ + virtual int model() const { + return cMixtureAveraged; + } + + //! Viscosity of the mixture (kg /m /s) + /*! + * The viscosity is computed using the Wilke mixture rule (kg /m /s) + * + * \f[ + * \mu = \sum_k \frac{\mu_k X_k}{\sum_j \Phi_{k,j} X_j}. + * \f] + * + * Here \f$ \mu_k \f$ is the viscosity of pure species \e k, and + * + * \f[ + * \Phi_{k,j} = \frac{\left[1 + * + \sqrt{\left(\frac{\mu_k}{\mu_j}\sqrt{\frac{M_j}{M_k}}\right)}\right]^2} + * {\sqrt{8}\sqrt{1 + M_k/M_j}} + * \f] + * + * @return Returns the viscosity of the mixture ( units = Pa s = kg /m /s) + * + * @see updateViscosity_T(); + */ virtual doublereal viscosity(); + //! returns the vector of species viscosities + /*! + * @param visc Vector of species viscosities + */ virtual void getSpeciesViscosities(doublereal* visc) { update_T(); updateViscosity_T(); copy(m_visc.begin(), m_visc.end(), visc); } //! Return the thermal diffusion coefficients /*! * For this approximation, these are all zero. + * + * Eqns. (12.168) shows how they are used in an expression for the species flux. + * + * @param dt Vector of thermal diffusion coefficients. Units = kg/m/s */ virtual void getThermalDiffCoeffs(doublereal* const dt); - //! returns the mixture thermal conductivity + //! Returns the mixture thermal conductivity (W/m /K) + /*! + * The thermal conductivity is computed from the following mixture rule: + * \f[ + * \lambda = 0.5 \left( \sum_k X_k \lambda_k + \frac{1}{\sum_k X_k/\lambda_k} \right) + * \f] + * + * It's used to compute the flux of energy due to a thermal gradient + * + * \f[ + * j_T = - \lambda \nabla T + * \f] + * + * The flux of energy has units of energy (kg m2 /s2) per second per area. + * + * The units of lambda are W / m K which is equivalent to kg m / s^3 K. + * + * @return Returns the mixture thermal conductivity, with units of W/m/K + */ virtual doublereal thermalConductivity(); - virtual void getBinaryDiffCoeffs(const int ld, doublereal* const d); - - - //! Mixture-averaged diffusion coefficients [m^2/s]. + //! Returns the matrix of binary diffusion coefficients. /*! - * For the single species case or the pure fluid case - * the routine returns the self-diffusion coefficient. - * This is need to avoid a Nan result in the formula - * below. - */ + * + * d[ld*j + i] = rp * m_bdiff(i,j); + * + * units of m**2 / s + * + * @param ld offset of rows in the storage + * @param d output vector of diffusion coefficients + */ + virtual void getBinaryDiffCoeffs(const int ld, doublereal* const d); + + //! Returns the Mixture-averaged diffusion coefficients [m^2/s]. + /*! + * Returns the mixture averaged diffusion coefficients for a gas, appropriate for calculating the + * mass averged diffusive flux with respect to the mass averaged velocity using gradients of the + * mole fraction. + * Note, for the single species case or the pure fluid case the routine returns the self-diffusion coefficient. + * This is need to avoid a Nan result in the formula below. + * + * This is Eqn. 12.180 from "Chemicaly Reacting Flow" + * + * \f[ + * D_{km}' = \frac{\left( \bar{M} - X_k M_k \right)}{ \bar{\qquad M \qquad } } {\left( \sum_{j \ne k} \frac{X_j}{D_{kj}} \right) }^{-1} + * \f] + * + * + * + * @param d Output Vector of mixture diffusion coefficients, \f$ D_{km}' \f$ , for each species (m^2/s). + * length m_nsp + */ virtual void getMixDiffCoeffs(doublereal* const d); + + //! Get the Electrical mobilities (m^2/V/s). + /*! + * This function returns the mobilities. In some formulations + * this is equal to the normal mobility multiplied by Faraday's constant. + * + * Here, the mobility is calculated from the diffusion coefficient using the Einstein relation + * + * \f[ + * \mu^e_k = \frac{F D_k}{R T} + * \f] + * + * @param mobil Returns the mobilities of the species in array \c mobil. The array must be + * dimensioned at least as large as the number of species. + */ virtual void getMobilities(doublereal* const mobil); + + //! Update the internal parameters whenever the temperature has changed + /*! + * @internal + * This is called whenever a transport property is requested if the temperature has changed + * since the last call to update_T(). + */ virtual void update_T(); + + //! Update the internal parameters whenever the concentrations have changed + /*! + * @internal + * This is called whenever a transport property is requested if the concentrations have changed + * since the last call to update_C(). + */ virtual void update_C(); - //! Get the species diffusive mass fluxes wrt to - //! the mass averaged velocity, + //! Get the species diffusive mass fluxes wrt to the mass averaged velocity, //! given the gradients in mole fraction and temperature /*! * Units for the returned fluxes are kg m-2 s-1. - * - * @param ndim Number of dimensions in the flux expressions - * @param grad_T Gradient of the temperature - * (length = ndim) - * @param ldx Leading dimension of the grad_X array - * (usually equal to m_nsp but not always) - * @param grad_X Gradients of the mole fraction - * Flat vector with the m_nsp in the inner loop. - * length = ldx * ndim - * @param ldf Leading dimension of the fluxes array - * (usually equal to m_nsp but not always) - * @param fluxes Output of the diffusive mass fluxes - * Flat vector with the m_nsp in the inner loop. - * length = ldx * ndim + * + * + * The diffusive mass flux of species \e k is computed from + * \f[ + * \vec{j}_k = -n M_k D_k \nabla X_k. + * \f] + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - virtual void getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, - const doublereal* grad_X, + virtual void getSpeciesFluxes(int ndim, const doublereal* grad_T, + int ldx, const doublereal* grad_X, int ldf, doublereal* fluxes); //! Initialize the transport object @@ -124,19 +293,17 @@ namespace Cantera { friend class TransportFactory; - /** - * Return a structure containing all of the pertinent parameters - * about a species that was used to construct the Transport - * properties in this object. + + //! Return a structure containing all of the pertinent parameters about a species that was + //! used to construct the Transport properties in this object. + /*! + * @param kspec Species number to obtain the properties from. * - * @param k Species number to obtain the properties from. + * @return GasTransportData returned structure. */ - struct GasTransportData getGasTransportData(int); + struct GasTransportData getGasTransportData(int kspec) const; - protected: - - /// default constructor - MixTransport(); + private: @@ -146,79 +313,274 @@ namespace Cantera { m_thermo->temperature()); } - // mixture attributes + //! Update the temperature-dependent viscosity terms. + /*! + * Updates the array of pure species viscosities, and the weighting functions in the viscosity mixture rule. + * The flag m_visc_ok is set to true. + * + * The formula for the weighting function is from Poling and Prausnitz. + * See Eq. (9-5.14) of Poling, Prausnitz, and O'Connell. The equation for the weighting function + * \f$ \phi_{ij} \f$ is reproduced below. + * + * \f[ + * \phi_{ij} = \frac{ \left[ 1 + \left( \mu_i / \mu_j \right)^{1/2} \left( M_j / M_i \right)^{1/4} \right]^2 } + * {\left[ 8 \left( 1 + M_i / M_j \right) \right]^{1/2}} + * \f] + */ + void updateViscosity_T(); + + //! Update the temperature dependent parts of the species thermal conductivities + /*! + * These are evaluated from the polynomial fits of the temperature and are assumed to be + * independent of pressure + */ + void updateCond_T(); + + //! Update the species viscosities + /*! + * These are evaluated from the polynomial fits of the temperature and are assumed to be + * independent of pressure + */ + void updateSpeciesViscosities(); + + //! Update the binary diffusion coefficients + /*! + * These are evaluated from the polynomial fits of the temperature at the unit pressure of 1 Pa. + */ + void updateDiff_T(); + + + // --------- Member Data ------------- + private: + + //! Number of species in the phase int m_nsp; - doublereal m_tmin, m_tmax; + + //! Minimum value of the temperature that this transport parameterization is valid + doublereal m_tmin; + + //! Maximum value of the temperature that this transport parameterization is valid + doublereal m_tmax; + + //! Local copy of the species molecular weights. vector_fp m_mw; - // polynomial fits - vector m_visccoeffs; - vector m_condcoeffs; - vector m_diffcoeffs; + //! Polynomial fits to the viscosity of each species + /*! + * m_visccoeffs[k] is vector of polynomial coefficients for species k + * that fits the viscosity as a function of temperature + */ + std::vector m_visccoeffs; + + //! Polynomial fits to the thermal conductivity of each species + /*! + * m_condcoeffs[k] is vector of polynomial coefficients for species k + * that fits the thermal conductivity + */ + std::vector m_condcoeffs; + + //! Polynomial fits to the binary diffusivity of each species + /*! + * m_diffcoeff[ic] is vector of polynomial coefficients for species i species j + * that fits the binary diffusion coefficient. The relationship between i + * j and ic is determined from the following algorithm: + * + * int ic = 0; + * for (i = 0; i < m_nsp; i++) { + * for (j = i; j < m_nsp; j++) { + * ic++; + * } + * } + * + */ + std::vector m_diffcoeffs; + + //! Powers of the ln temperature + /*! + * up to fourth order + */ vector_fp m_polytempvec; - // property values - DenseMatrix m_bdiff; - vector_fp m_visc; - vector_fp m_sqvisc; - vector_fp m_cond; + //! Matrix of binary diffusion coefficients at the reference pressure and the current temperature + /*! + * Size is nsp x nsp + */ + DenseMatrix m_bdiff; - array_fp m_molefracs; + //! vector of species viscosities (kg /m /s) + /*! + * These are used in wilke's rule to calculate the viscosity of the solution + * length = m_kk + */ + vector_fp m_visc; - vector > m_poly; - vector m_astar_poly; - vector m_bstar_poly; - vector m_cstar_poly; - vector m_om22_poly; - DenseMatrix m_astar; - DenseMatrix m_bstar; - DenseMatrix m_cstar; - DenseMatrix m_om22; + //! vector of square root of species viscosities sqrt(kg /m /s) + /*! + * These are used in wilke's rule to calculate the viscosity of the solution + * length = m_kk + */ + vector_fp m_sqvisc; - DenseMatrix m_phi; // viscosity weighting functions - DenseMatrix m_wratjk, m_wratkj1; + //! vector of species thermal conductivities (W/m /K) + /*! + * These are used in wilke's rule to calculate the viscosity of the solution + * units = W /m /K = kg m /s^3 /K. + * length = m_kk + */ + vector_fp m_cond; - vector_fp m_zrot; - vector_fp m_crot; - vector_fp m_cinternal; - vector_fp m_eps; - vector_fp m_alpha; - vector_fp m_dipoleDiag; + //! Vector of species molefractions + /*! + * These are processed so that all mole fractions are >= MIN_X + * Length = m_kk + */ + vector_fp m_molefracs; - doublereal m_temp, m_logt, m_kbt, m_t14, m_t32; - doublereal m_sqrt_kbt, m_sqrt_t; + //! m_phi is a Viscosity Weighting Function + /*! + * size = m_nsp * n_nsp + */ + DenseMatrix m_phi; - vector_fp m_sqrt_eps_k; - DenseMatrix m_log_eps_k; - vector_fp m_frot_298; - vector_fp m_rotrelax; + //! Holds square roots or molecular weight ratios + /*! + * m_wratjk(j,k) = sqrt(mw[j]/mw[k]) j < k + * m_wratjk(k,j) = sqrt(sqrt(mw[j]/mw[k])) j < k + */ + DenseMatrix m_wratjk; + //! Holds square roots of molecular weight ratios + /*! + * m_wratjk1(j,k) = sqrt(1.0 + mw[k]/mw[j]) j < k + */ + DenseMatrix m_wratkj1; + + + + + + //! Current value of the temperature at which the properties in this object are calculated (Kelvin) + doublereal m_temp; + + //! Current value of the log of the temperature + doublereal m_logt; + + //! Current value of Boltzman's constant times the temperature (Joules) + doublereal m_kbt; + + //! Current value of temperature to 1/4 power + doublereal m_t14; + + //! Current value of temperature to the 3/2 power + doublereal m_t32; + + //! current value of Boltzman's constant times the temperature (Joules) to 1/2 power + doublereal m_sqrt_kbt; + + //! current value of temperature to 1/2 power + doublereal m_sqrt_t; + + //! Internal storage for the calculated mixture thermal conductivity + /*! + * Units = W /m /K + */ doublereal m_lambda; + + //! Internal storage for the viscosity of the mixture (kg /m /s) doublereal m_viscmix; - // work space + //! work space length = m_kk vector_fp m_spwork; - void updateThermal_T(); - void updateViscosity_T(); - void updateCond_T(); - void updateSpeciesViscosities(); - void updateDiff_T(); - void correctBinDiffCoeffs(); + //! Update boolean for mixture rule for the mixture viscosity bool m_viscmix_ok; + + //! Update boolean for the weighting factors for the mixture viscosity bool m_viscwt_ok; + + //! Update boolean for the species viscosities bool m_spvisc_ok; - bool m_diffmix_ok; + + //! Update boolean for the binary diffusivities at unit pressure bool m_bindiff_ok; - bool m_abc_ok; + + //! Update boolean for the species thermal conductivities bool m_spcond_ok; + + //! Update boolean for the mixture rule for the mixture thermal conductivity bool m_condmix_ok; + //! Type of the polynomial fits to temperature + /*! + * CK_Mode means chemkin mode. Currently CA_Mode is used which are different types + * of fits to temperature. + */ int m_mode; - DenseMatrix m_epsilon; + //! Lennard-Jones well-depth of the species in the current phase + /*! + * Not used in this routine -> just a passthrough + * + * length is the number of species in the phase + * Units are Joules (Note this is not Joules/kmol) (note, no kmol -> this is a per molecule amount) + */ + vector_fp m_eps; + + //! hard-sphere diameter for (i,j) collision + /*! + * Not used in this routine -> just a passthrough + * + * diam(i,j) = 0.5*(tr.sigma[i] + tr.sigma[j]); + * Units are m (note, no kmol -> this is a per molecule amount) + * + * Length nsp * nsp. This is a symmetric matrix. + */ DenseMatrix m_diam; - DenseMatrix incl; + + //! The effective dipole moment for (i,j) collisions + /*! + * tr.dipoleMoment has units of Debye's. A Debye is 10-18 cm3/2 erg1/2 + * + * Not used in this routine -> just a passthrough + * + * tr.dipole(i,i) = 1.e-25 * SqrtTen * trdat.dipoleMoment; + * tr.dipole(i,j) = sqrt(tr.dipole(i,i)*tr.dipole(j,j)); + * Units are in Debye (note, no kmol -> this is a per molecule amount) + * + * Length nsp. We store only the diagonal component here. + */ + vector_fp m_dipoleDiag; + + //! Polarizability of each species in the phase + /*! + * Not used in this routine -> just a passthrough + * + * Length = nsp + * Units = m^3 + */ + vector_fp m_alpha; + + //! Dimensionless rotational heat capacity of the species in the current phase + /*! + * Not used in this routine -> just a passthrough + * + * These values are 0, 1 and 1.5 for single-molecule, linear, and nonlinear species respectively + * length is the number of species in the pahse + * units are dimensionless (Cr / R) + */ + vector_fp m_crot; + + //! Rotational relaxation number for the species in the current phase + /*! + * Not used in this routine -> just a passthrough + * + * length is the number of species in the phase + * units are dimensionless + */ + vector_fp m_zrot; + + + //! Debug flag - turns on more printing bool m_debug; }; } diff --git a/Cantera/src/transport/MultiTransport.cpp b/Cantera/src/transport/MultiTransport.cpp old mode 100755 new mode 100644 index d44e1b418..12d0242e3 --- a/Cantera/src/transport/MultiTransport.cpp +++ b/Cantera/src/transport/MultiTransport.cpp @@ -1,9 +1,8 @@ /** - * * @file MultiTransport.cpp * Implementation file for class MultiTransport - * - * @ingroup transportProps + */ +/* * * $Author$ * $Date$ @@ -49,994 +48,1016 @@ using namespace std; namespace Cantera { -// template -// struct UpdateSpeciesVisc : public Updater { -// UpdateSpeciesVisc(S& s) : Updater(), m_s(s) {} -// void update() { m_s._update_species_visc_T(); } -// S& m_s; -// }; + /////////////////////////// constants ////////////////////////// -// template -// struct UpdateVisc_T : public Updater { -// UpdateVisc_T(S& s) : Updater(), m_s(s) {} -// void update() { m_s._update_visc_T(); } -// S& m_s; -// }; - -// template -// struct UpdateDiff_T : public Updater { -// UpdateDiff_T(S& s) : Updater(), m_s(s) {} -// void update() { m_s._update_diff_T(); } -// S& m_s; -// }; - -// template -// struct UpdateThermal_T : public Updater { -// UpdateThermal_T(S& s) : Updater(), m_s(s) {} -// void update() { m_s._update_thermal_T(); } -// S& m_s; -// }; - - - /////////////////////////// constants ////////////////////////// - - // const doublereal ThreeSixteenths = 3.0/16.0; + // const doublereal ThreeSixteenths = 3.0/16.0; - ///////////////////// helper functions ///////////////////////// + ///////////////////// helper functions ///////////////////////// - /** - * @internal - * - * The Parker temperature correction to the rotational collision - * number. - * - * @param tr Reduced temperature \f$ \epsilon/kT \f$ - * @param sqtr square root of tr. - */ - inline doublereal Frot(doublereal tr, doublereal sqtr) { - const doublereal c1 = 0.5*SqrtPi*Pi; - const doublereal c2 = 0.25*Pi*Pi + 2.0; - const doublereal c3 = SqrtPi*Pi; - return 1.0 + c1*sqtr + c2*tr + c3*sqtr*tr; - } + /** + * @internal + * + * The Parker temperature correction to the rotational collision + * number. + * + * @param tr Reduced temperature \f$ \epsilon/kT \f$ + * @param sqtr square root of tr. + */ + inline doublereal Frot(doublereal tr, doublereal sqtr) { + const doublereal c1 = 0.5*SqrtPi*Pi; + const doublereal c2 = 0.25*Pi*Pi + 2.0; + const doublereal c3 = SqrtPi*Pi; + return 1.0 + c1*sqtr + c2*tr + c3*sqtr*tr; + } - /** - * This method is used by GMRES to multiply the L matrix by a - * vector b. The L matrix has a 3x3 block structure, where each - * block is a K x K matrix. The elements of the upper-right and - * lower-left blocks are all zero. This method is defined so - * that the multiplication only involves the seven non-zero - * blocks. - */ - void L_Matrix::mult(const doublereal* b, doublereal* prod) const { - integer n = static_cast(nRows())/3; - integer n2 = 2*n; - integer n3 = 3*n; - ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, n, n2, 1.0, - DATA_PTR(data()), static_cast(nRows()), b, 1, 0.0, prod, 1); - ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, n, n3, 1.0, - DATA_PTR(data()) + n, static_cast(nRows()), - b, 1, 0.0, prod+n, 1); - ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, n, n, 1.0, - DATA_PTR(data()) + n*n3 + n2, static_cast(nRows()), - b + n, 1, 0.0, prod+n2, 1); - for (int i = 0; i < n; i++) - prod[i + n2] += b[i + n2] * value(i + n2, i + n2); - } + /** + * This method is used by GMRES to multiply the L matrix by a + * vector b. The L matrix has a 3x3 block structure, where each + * block is a K x K matrix. The elements of the upper-right and + * lower-left blocks are all zero. This method is defined so + * that the multiplication only involves the seven non-zero + * blocks. + */ + void L_Matrix::mult(const doublereal* b, doublereal* prod) const { + integer n = static_cast(nRows())/3; + integer n2 = 2*n; + integer n3 = 3*n; + ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, n, n2, 1.0, + DATA_PTR(data()), static_cast(nRows()), b, 1, 0.0, prod, 1); + ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, n, n3, 1.0, + DATA_PTR(data()) + n, static_cast(nRows()), + b, 1, 0.0, prod+n, 1); + ct_dgemv(ctlapack::ColMajor, ctlapack::NoTranspose, n, n, 1.0, + DATA_PTR(data()) + n*n3 + n2, static_cast(nRows()), + b + n, 1, 0.0, prod+n2, 1); + for (int i = 0; i < n; i++) + prod[i + n2] += b[i + n2] * value(i + n2, i + n2); + } - //////////////////// class MultiTransport methods ////////////// + //////////////////// class MultiTransport methods ////////////// - MultiTransport::MultiTransport(thermo_t* thermo) - : Transport(thermo), - m_temp(-1.0) - { - } + MultiTransport::MultiTransport(thermo_t* thermo) + : Transport(thermo), + m_temp(-1.0) + { + } MultiTransport::~MultiTransport() { } + //==================================================================================================================== + bool MultiTransport::initGas(GasTransportParams& tr) { - bool MultiTransport::initGas( GasTransportParams& tr ) { + // constant mixture attributes + //m_phase = tr.mix; + m_thermo = tr.thermo; + m_nsp = m_thermo->nSpecies(); + m_tmin = m_thermo->minTemp(); + m_tmax = m_thermo->maxTemp(); - // constant mixture attributes - //m_phase = tr.mix; - m_thermo = tr.thermo; - m_nsp = m_thermo->nSpecies(); - m_tmin = m_thermo->minTemp(); - m_tmax = m_thermo->maxTemp(); + // make a local copy of the molecular weights + m_mw.resize(m_nsp); + copy(m_thermo->molecularWeights().begin(), + m_thermo->molecularWeights().end(), m_mw.begin()); - // make a local copy of the molecular weights - m_mw.resize(m_nsp); - copy(m_thermo->molecularWeights().begin(), - m_thermo->molecularWeights().end(), m_mw.begin()); + // copy polynomials and parameters into local storage + m_poly = tr.poly; + m_visccoeffs = tr.visccoeffs; + m_diffcoeffs = tr.diffcoeffs; + m_astar_poly = tr.astar_poly; + m_bstar_poly = tr.bstar_poly; + m_cstar_poly = tr.cstar_poly; + m_om22_poly = tr.omega22_poly; + m_zrot = tr.zrot; + m_crot = tr.crot; + m_epsilon = tr.epsilon; + m_mode = tr.mode_; + m_diam = tr.diam; + m_eps = tr.eps; + m_alpha = tr.alpha; + m_dipoleDiag.resize(m_nsp); + int i; + for (i = 0; i < m_nsp; i++) { + m_dipoleDiag[i] = tr.dipole(i,i); + } - // copy polynomials and parameters into local storage - m_poly = tr.poly; - m_visccoeffs = tr.visccoeffs; - m_diffcoeffs = tr.diffcoeffs; - m_astar_poly = tr.astar_poly; - m_bstar_poly = tr.bstar_poly; - m_cstar_poly = tr.cstar_poly; - m_om22_poly = tr.omega22_poly; - m_zrot = tr.zrot; - m_crot = tr.crot; - m_epsilon = tr.epsilon; - m_mode = tr.mode_; - m_diam = tr.diam; - m_eps = tr.eps; - m_alpha = tr.alpha; - m_dipoleDiag.resize(m_nsp); - int i; - for (i = 0; i < m_nsp; i++) { - m_dipoleDiag[i] = tr.dipole(i,i); - } + // the L matrix + m_Lmatrix.resize(3*m_nsp, 3*m_nsp); + m_a.resize(3*m_nsp, 1.0); + m_b.resize(3*m_nsp, 0.0); + m_aa.resize(m_nsp, m_nsp, 0.0); - // the L matrix - m_Lmatrix.resize(3*m_nsp, 3*m_nsp); - m_a.resize(3*m_nsp, 1.0); - m_b.resize(3*m_nsp, 0.0); - m_aa.resize(m_nsp, m_nsp, 0.0); + m_frot_298.resize(m_nsp); + m_rotrelax.resize(m_nsp); - m_frot_298.resize(m_nsp); - m_rotrelax.resize(m_nsp); + m_phi.resize(m_nsp, m_nsp, 0.0); + m_wratjk.resize(m_nsp, m_nsp, 0.0); + m_wratkj1.resize(m_nsp, m_nsp, 0.0); + int j, k; + for (j = 0; j < m_nsp; j++) + for (k = j; k < m_nsp; k++) { + m_wratjk(j,k) = sqrt(m_mw[j]/m_mw[k]); + m_wratjk(k,j) = sqrt(m_wratjk(j,k)); + m_wratkj1(j,k) = sqrt(1.0 + m_mw[k]/m_mw[j]); + } - m_phi.resize(m_nsp, m_nsp, 0.0); - m_wratjk.resize(m_nsp, m_nsp, 0.0); - m_wratkj1.resize(m_nsp, m_nsp, 0.0); - int j, k; - for (j = 0; j < m_nsp; j++) - for (k = j; k < m_nsp; k++) { - m_wratjk(j,k) = sqrt(m_mw[j]/m_mw[k]); - m_wratjk(k,j) = sqrt(m_wratjk(j,k)); - m_wratkj1(j,k) = sqrt(1.0 + m_mw[k]/m_mw[j]); - } + m_cinternal.resize(m_nsp); - m_cinternal.resize(m_nsp); + m_polytempvec.resize(5); + m_visc.resize(m_nsp); + m_sqvisc.resize(m_nsp); + m_bdiff.resize(m_nsp, m_nsp); - m_polytempvec.resize(5); - m_visc.resize(m_nsp); - m_sqvisc.resize(m_nsp); - m_bdiff.resize(m_nsp, m_nsp); + //m_poly.resize(m_nsp); + m_om22.resize(m_nsp, m_nsp); + m_astar.resize(m_nsp, m_nsp); + m_bstar.resize(m_nsp, m_nsp); + m_cstar.resize(m_nsp, m_nsp); - //m_poly.resize(m_nsp); - m_om22.resize(m_nsp, m_nsp); - m_astar.resize(m_nsp, m_nsp); - m_bstar.resize(m_nsp, m_nsp); - m_cstar.resize(m_nsp, m_nsp); + m_molefracs.resize(m_nsp); - m_molefracs.resize(m_nsp); + // set flags all false + m_visc_ok = false; + m_spvisc_ok = false; + m_diff_ok = false; + m_abc_ok = false; + m_l0000_ok = false; + m_lmatrix_soln_ok = false; - // set flags all false - m_visc_ok = false; - m_spvisc_ok = false; - m_diff_ok = false; - m_abc_ok = false; - m_l0000_ok = false; - m_lmatrix_soln_ok = false; + m_diff_tlast = 0.0; + m_spvisc_tlast = 0.0; + m_visc_tlast = 0.0; + m_thermal_tlast = 0.0; - m_diff_tlast = 0.0; - m_spvisc_tlast = 0.0; - m_visc_tlast = 0.0; - m_thermal_tlast = 0.0; - - // use LU decomposition by default - m_gmres = false; + // use LU decomposition by default + m_gmres = false; - // default GMRES parameters - m_mgmres = 100; - m_eps_gmres = 1.e-4; + // default GMRES parameters + m_mgmres = 100; + m_eps_gmres = 1.e-4; - // some work space - m_spwork.resize(m_nsp); - m_spwork1.resize(m_nsp); - m_spwork2.resize(m_nsp); - m_spwork3.resize(m_nsp); + // some work space + m_spwork.resize(m_nsp); + m_spwork1.resize(m_nsp); + m_spwork2.resize(m_nsp); + m_spwork3.resize(m_nsp); - // precompute and store log(epsilon_ij/k_B) - m_log_eps_k.resize(m_nsp, m_nsp); - // int j; - for (i = 0; i < m_nsp; i++) { - for (j = i; j < m_nsp; j++) { - m_log_eps_k(i,j) = log(tr.epsilon(i,j)/Boltzmann); - m_log_eps_k(j,i) = m_log_eps_k(i,j); - } - } - - - // precompute and store constant parts of the Parker rotational - // collision number temperature correction - const doublereal sq298 = sqrt(298.0); - const doublereal kb298 = Boltzmann * 298.0; - m_sqrt_eps_k.resize(m_nsp); - //int k; - for (k = 0; k < m_nsp; k++) { - m_sqrt_eps_k[k] = sqrt(tr.eps[k]/Boltzmann); - m_frot_298[k] = Frot( tr.eps[k]/kb298, - m_sqrt_eps_k[k]/sq298); - } - -// // install updaters -// m_update_transport_T = m_thermo->installUpdater_T( -// new UpdateTransport_T(*this)); -// m_update_transport_C = m_thermo->installUpdater_C( -// new UpdateTransport_C(*this)); -// m_update_spvisc_T = m_thermo->installUpdater_T( -// new UpdateSpeciesVisc(*this)); -// m_update_visc_T = m_thermo->installUpdater_T( -// new UpdateVisc_T(*this)); -// m_update_diff_T = m_thermo->installUpdater_T( -// new UpdateDiff_T(*this)); -// m_update_thermal_T = m_thermo->installUpdater_T( -// new UpdateThermal_T(*this)); - - return true; + // precompute and store log(epsilon_ij/k_B) + m_log_eps_k.resize(m_nsp, m_nsp); + // int j; + for (i = 0; i < m_nsp; i++) { + for (j = i; j < m_nsp; j++) { + m_log_eps_k(i,j) = log(tr.epsilon(i,j)/Boltzmann); + m_log_eps_k(j,i) = m_log_eps_k(i,j); + } } - /****************** viscosity ******************************/ - - doublereal MultiTransport::viscosity() { - doublereal vismix = 0.0, denom; - int k, j; - - // update m_visc if necessary - updateViscosity_T(); - - // update the mole fractions - updateTransport_C(); - - for (k = 0; k < m_nsp; k++) { - denom = 0.0; - for (j = 0; j < m_nsp; j++) { - denom += m_phi(k,j) * m_molefracs[j]; - } - vismix += m_molefracs[k] * m_visc[k]/denom; - } - return vismix; + // precompute and store constant parts of the Parker rotational + // collision number temperature correction + const doublereal sq298 = sqrt(298.0); + const doublereal kb298 = Boltzmann * 298.0; + m_sqrt_eps_k.resize(m_nsp); + //int k; + for (k = 0; k < m_nsp; k++) { + m_sqrt_eps_k[k] = sqrt(tr.eps[k]/Boltzmann); + m_frot_298[k] = Frot( tr.eps[k]/kb298, + m_sqrt_eps_k[k]/sq298); } + // // install updaters + // m_update_transport_T = m_thermo->installUpdater_T( + // new UpdateTransport_T(*this)); + // m_update_transport_C = m_thermo->installUpdater_C( + // new UpdateTransport_C(*this)); + // m_update_spvisc_T = m_thermo->installUpdater_T( + // new UpdateSpeciesVisc(*this)); + // m_update_visc_T = m_thermo->installUpdater_T( + // new UpdateVisc_T(*this)); + // m_update_diff_T = m_thermo->installUpdater_T( + // new UpdateDiff_T(*this)); + // m_update_thermal_T = m_thermo->installUpdater_T( + // new UpdateThermal_T(*this)); + + return true; + } - /******************* binary diffusion coefficients **************/ + /****************** viscosity ******************************/ - void MultiTransport::getBinaryDiffCoeffs(int ld, doublereal* d) { - int i,j; + doublereal MultiTransport::viscosity() { + doublereal vismix = 0.0, denom; + int k, j; - // if necessary, evaluate the binary diffusion coefficents - // from the polynomial fits - updateDiff_T(); + // update m_visc if necessary + updateViscosity_T(); - doublereal p = pressure_ig(); - doublereal rp = 1.0/p; - for (i = 0; i < m_nsp; i++) - for (j = 0; j < m_nsp; j++) { - d[ld*j + i] = rp * m_bdiff(i,j); - } + // update the mole fractions + updateTransport_C(); + + for (k = 0; k < m_nsp; k++) { + denom = 0.0; + for (j = 0; j < m_nsp; j++) { + denom += m_phi(k,j) * m_molefracs[j]; + } + vismix += m_molefracs[k] * m_visc[k]/denom; } + return vismix; + } + + //==================================================================================================================== + + /******************* binary diffusion coefficients **************/ + + void MultiTransport::getBinaryDiffCoeffs(int ld, doublereal* d) { + int i,j; + + // if necessary, evaluate the binary diffusion coefficents + // from the polynomial fits + updateDiff_T(); + + doublereal p = pressure_ig(); + doublereal rp = 1.0/p; + for (i = 0; i < m_nsp; i++) + for (j = 0; j < m_nsp; j++) { + d[ld*j + i] = rp * m_bdiff(i,j); + } + } - /****************** thermal conductivity **********************/ + /****************** thermal conductivity **********************/ - /** - * @internal - */ - doublereal MultiTransport::thermalConductivity() { + /** + * @internal + */ + doublereal MultiTransport::thermalConductivity() { - solveLMatrixEquation(); - doublereal sum = 0.0; - int k; - for (k = 0; k < 2*m_nsp; k++) { - sum += m_b[k + m_nsp] * m_a[k + m_nsp]; - } - return -4.0*sum; + solveLMatrixEquation(); + doublereal sum = 0.0; + int k; + for (k = 0; k < 2*m_nsp; k++) { + sum += m_b[k + m_nsp] * m_a[k + m_nsp]; } - - - /****************** thermal diffusion coefficients ************/ - - /** - * @internal - */ - void MultiTransport::getThermalDiffCoeffs(doublereal* const dt) { - - solveLMatrixEquation(); - const doublereal c = 1.6/GasConstant; - int k; - for (k = 0; k < m_nsp; k++) { - dt[k] = c * m_mw[k] * m_molefracs[k] * m_a[k]; - } + return -4.0*sum; + } + //==================================================================================================================== + // Return the thermal diffusion coefficients for the species + /* + * + * @param dt thermal diffusion coefficients + * (length = m_nsp) + */ + void MultiTransport::getThermalDiffCoeffs(doublereal* const dt) { + solveLMatrixEquation(); + const doublereal c = 1.6/GasConstant; + for (int k = 0; k < m_nsp; k++) { + dt[k] = c * m_mw[k] * m_molefracs[k] * m_a[k]; } + } + //==================================================================================================================== + /** + * @internal + */ + void MultiTransport::solveLMatrixEquation() { - /** - * @internal - */ - void MultiTransport::solveLMatrixEquation() { - - // if T has changed, update the temperature-dependent - // properties. + // if T has changed, update the temperature-dependent + // properties. - updateThermal_T(); - updateTransport_C(); + updateThermal_T(); + updateTransport_C(); - // Copy the mole fractions twice into the last two blocks of - // the right-hand-side vector m_b. The first block of m_b was - // set to zero when it was created, and is not modified so - // doesn't need to be reset to zero. - int k; - for (k = 0; k < m_nsp; k++) { - m_b[k] = 0.0; - m_b[k + m_nsp] = m_molefracs[k]; - m_b[k + 2*m_nsp] = m_molefracs[k]; - } - - // Set the right-hand side vector to zero in the 3rd block for - // all species with no internal energy modes. The - // corresponding third-block rows and columns will be set to - // zero, except on the diagonal of L01,01, where they are set - // to 1.0. This has the effect of eliminating these equations - // from the system, since the equation becomes: m_a[2*m_nsp + - // k] = 0.0. - - // Note that this differs from the Chemkin procedure, where - // all *monatomic* species are excluded. Since monatomic - // radicals can have non-zero internal heat capacities due to - // electronic excitation, they should be retained. - // - // But if CHEMKIN_COMPATIBILITY_MODE is defined, then all - // monatomic species are excluded. - - for (k = 0; k < m_nsp; k++) { - if (!hasInternalModes(k)) m_b[2*m_nsp + k] = 0.0; - } - - // evaluate the submatrices of the L matrix - - m_Lmatrix.resize(3*m_nsp, 3*m_nsp, 0.0); - - eval_L0000(DATA_PTR(m_molefracs)); - eval_L0010(DATA_PTR(m_molefracs)); - eval_L0001(); - eval_L1000(); - eval_L1010(DATA_PTR(m_molefracs)); - eval_L1001(DATA_PTR(m_molefracs)); - eval_L0100(); - eval_L0110(); - eval_L0101(DATA_PTR(m_molefracs)); - - - // Solve it using GMRES or LU decomposition. The last solution - // in m_a should provide a good starting guess, so convergence - // should be fast. - - //if (m_gmres) { - // gmres(m_mgmres, 3*m_nsp, m_Lmatrix, m_b.begin(), - // m_a.begin(), m_eps_gmres); - // m_lmatrix_soln_ok = true; - // m_l0000_ok = true; // L matrix not modified by GMRES - //} - //else { - copy(m_b.begin(), m_b.end(), m_a.begin()); - try { - solve(m_Lmatrix, DATA_PTR(m_a)); - } - catch (CanteraError) { - //if (info != 0) { - throw CanteraError("MultiTransport::solveLMatrixEquation", - "error in solving L matrix."); - } - m_lmatrix_soln_ok = true; - m_l0000_ok = false; - // L matrix is overwritten with LU decomposition - //} - m_lmatrix_soln_ok = true; + // Copy the mole fractions twice into the last two blocks of + // the right-hand-side vector m_b. The first block of m_b was + // set to zero when it was created, and is not modified so + // doesn't need to be reset to zero. + int k; + for (k = 0; k < m_nsp; k++) { + m_b[k] = 0.0; + m_b[k + m_nsp] = m_molefracs[k]; + m_b[k + 2*m_nsp] = m_molefracs[k]; } + // Set the right-hand side vector to zero in the 3rd block for + // all species with no internal energy modes. The + // corresponding third-block rows and columns will be set to + // zero, except on the diagonal of L01,01, where they are set + // to 1.0. This has the effect of eliminating these equations + // from the system, since the equation becomes: m_a[2*m_nsp + + // k] = 0.0. - /** - * - */ - void MultiTransport::getSpeciesFluxes(int ndim, - const doublereal* grad_T, int ldx, const doublereal* grad_X, - int ldf, doublereal* fluxes) { + // Note that this differs from the Chemkin procedure, where + // all *monatomic* species are excluded. Since monatomic + // radicals can have non-zero internal heat capacities due to + // electronic excitation, they should be retained. + // + // But if CHEMKIN_COMPATIBILITY_MODE is defined, then all + // monatomic species are excluded. - // update the binary diffusion coefficients if necessary - updateDiff_T(); + for (k = 0; k < m_nsp; k++) { + if (!hasInternalModes(k)) m_b[2*m_nsp + k] = 0.0; + } - doublereal sum; - int i, j; + // evaluate the submatrices of the L matrix + + m_Lmatrix.resize(3*m_nsp, 3*m_nsp, 0.0); - // If any component of grad_T is non-zero, then get the - // thermal diffusion coefficients + eval_L0000(DATA_PTR(m_molefracs)); + eval_L0010(DATA_PTR(m_molefracs)); + eval_L0001(); + eval_L1000(); + eval_L1010(DATA_PTR(m_molefracs)); + eval_L1001(DATA_PTR(m_molefracs)); + eval_L0100(); + eval_L0110(); + eval_L0101(DATA_PTR(m_molefracs)); - bool addThermalDiffusion = false; - for (i = 0; i < ndim; i++) { - if (grad_T[i] != 0.0) addThermalDiffusion = true; - } - if (addThermalDiffusion) getThermalDiffCoeffs(DATA_PTR(m_spwork)); - const doublereal* y = m_thermo->massFractions(); - doublereal rho = m_thermo->density(); + // Solve it using GMRES or LU decomposition. The last solution + // in m_a should provide a good starting guess, so convergence + // should be fast. - for (i = 0; i < m_nsp; i++) { - sum = 0.0; - for (j = 0; j < m_nsp; j++) { - m_aa(i,j) = m_molefracs[j]*m_molefracs[i]/m_bdiff(i,j); - sum += m_aa(i,j); - } - m_aa(i,i) -= sum; - } + //if (m_gmres) { + // gmres(m_mgmres, 3*m_nsp, m_Lmatrix, m_b.begin(), + // m_a.begin(), m_eps_gmres); + // m_lmatrix_soln_ok = true; + // m_l0000_ok = true; // L matrix not modified by GMRES + //} + //else { + copy(m_b.begin(), m_b.end(), m_a.begin()); + try { + solve(m_Lmatrix, DATA_PTR(m_a)); + } + catch (CanteraError) { + //if (info != 0) { + throw CanteraError("MultiTransport::solveLMatrixEquation", + "error in solving L matrix."); + } + m_lmatrix_soln_ok = true; + m_l0000_ok = false; + // L matrix is overwritten with LU decomposition + //} + m_lmatrix_soln_ok = true; + } - // enforce the condition \sum Y_k V_k = 0. This is done by replacing - // the flux equation with the largest gradx component in the first - // coordinate direction with the flux balance condition. - int jmax = 0; - doublereal gradmax = -1.0; - for (j = 0; j < m_nsp; j++) { - if (fabs(grad_X[j]) > gradmax) { - gradmax = fabs(grad_X[j]); - jmax = j; - } - } + //==================================================================================================================== + // Get the species diffusive mass fluxes wrt to the mass averaged velocity, + // given the gradients in mole fraction and temperature + /* + * Units for the returned fluxes are kg m-2 s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + void MultiTransport::getSpeciesFluxes(int ndim, const doublereal * const grad_T, int ldx, + const doublereal * const grad_X, + int ldf, doublereal * const fluxes) { - // set the matrix elements in this row to the mass fractions, - // and set the entry in gradx to zero + // update the binary diffusion coefficients if necessary + updateDiff_T(); - for (j = 0; j < m_nsp; j++) { - m_aa(jmax,j) = y[j]; - } - vector_fp gsave(ndim), grx(ldx*m_nsp); - int n; - for (n = 0; n < ldx*ndim; n++) { - grx[n] = grad_X[n]; - } - //for (n = 0; n < ndim; n++) { - // gsave[n] = grad_X[jmax + n*ldx]; // save the input mole frac gradient - //grad_X[jmax + n*ldx] = 0.0; - // grx[jmax + n*ldx] = 0.0; - // } + doublereal sum; + int i, j; - // copy grad_X to fluxes - const doublereal* gx; - for (n = 0; n < ndim; n++) { - gx = grad_X + ldx*n; - copy(gx, gx + m_nsp, fluxes + ldf*n); - fluxes[jmax + n*ldf] = 0.0; - } + // If any component of grad_T is non-zero, then get the + // thermal diffusion coefficients - // use LAPACK to solve the equations - int info=0; - ct_dgetrf(static_cast(m_aa.nRows()), - static_cast(m_aa.nColumns()), m_aa.ptrColumn(0), - static_cast(m_aa.nRows()), - &m_aa.ipiv()[0], info); - if (info == 0) { - ct_dgetrs(ctlapack::NoTranspose, - static_cast(m_aa.nRows()), ndim, + bool addThermalDiffusion = false; + for (i = 0; i < ndim; i++) { + if (grad_T[i] != 0.0) addThermalDiffusion = true; + } + if (addThermalDiffusion) getThermalDiffCoeffs(DATA_PTR(m_spwork)); + + const doublereal* y = m_thermo->massFractions(); + doublereal rho = m_thermo->density(); + + for (i = 0; i < m_nsp; i++) { + sum = 0.0; + for (j = 0; j < m_nsp; j++) { + m_aa(i,j) = m_molefracs[j]*m_molefracs[i]/m_bdiff(i,j); + sum += m_aa(i,j); + } + m_aa(i,i) -= sum; + } + + // enforce the condition \sum Y_k V_k = 0. This is done by replacing + // the flux equation with the largest gradx component in the first + // coordinate direction with the flux balance condition. + int jmax = 0; + doublereal gradmax = -1.0; + for (j = 0; j < m_nsp; j++) { + if (fabs(grad_X[j]) > gradmax) { + gradmax = fabs(grad_X[j]); + jmax = j; + } + } + + // set the matrix elements in this row to the mass fractions, + // and set the entry in gradx to zero + + for (j = 0; j < m_nsp; j++) { + m_aa(jmax,j) = y[j]; + } + vector_fp gsave(ndim), grx(ldx*m_nsp); + int n; + for (n = 0; n < ldx*ndim; n++) { + grx[n] = grad_X[n]; + } + //for (n = 0; n < ndim; n++) { + // gsave[n] = grad_X[jmax + n*ldx]; // save the input mole frac gradient + //grad_X[jmax + n*ldx] = 0.0; + // grx[jmax + n*ldx] = 0.0; + // } + + // copy grad_X to fluxes + const doublereal* gx; + for (n = 0; n < ndim; n++) { + gx = grad_X + ldx*n; + copy(gx, gx + m_nsp, fluxes + ldf*n); + fluxes[jmax + n*ldf] = 0.0; + } + + // use LAPACK to solve the equations + int info=0; + ct_dgetrf(static_cast(m_aa.nRows()), + static_cast(m_aa.nColumns()), m_aa.ptrColumn(0), + static_cast(m_aa.nRows()), + &m_aa.ipiv()[0], info); + if (info == 0) { + ct_dgetrs(ctlapack::NoTranspose, + static_cast(m_aa.nRows()), ndim, m_aa.ptrColumn(0), static_cast(m_aa.nRows()), &m_aa.ipiv()[0], fluxes, ldf, info); - if (info != 0) info += 100; - } - else - throw CanteraError("MultiTransport::getSpeciesFluxes", - "Error in DGETRF"); - if (info > 50) - throw CanteraError("MultiTransport::getSpeciesFluxes", - "Error in DGETRS"); + if (info != 0) info += 100; + } + else + throw CanteraError("MultiTransport::getSpeciesFluxes", + "Error in DGETRF"); + if (info > 50) + throw CanteraError("MultiTransport::getSpeciesFluxes", + "Error in DGETRS"); - int offset; - doublereal pp = pressure_ig(); + int offset; + doublereal pp = pressure_ig(); - // multiply diffusion velocities by rho * V to create - // mass fluxes, and restore the gradx elements that were - // modified - for (n = 0; n < ndim; n++) { - offset = n*ldf; - for (i = 0; i < m_nsp; i++) { - fluxes[i + offset] *= rho * y[i] / pp; - } - //grad_X[jmax + n*ldx] = gsave[n]; - } - - // thermal diffusion - if (addThermalDiffusion) { - for (n = 0; n < ndim; n++) { - offset = n*ldf; - doublereal grad_logt = grad_T[n]/m_temp; - for (i = 0; i < m_nsp; i++) - fluxes[i + offset] -= m_spwork[i]*grad_logt; - } - } + // multiply diffusion velocities by rho * V to create + // mass fluxes, and restore the gradx elements that were + // modified + for (n = 0; n < ndim; n++) { + offset = n*ldf; + for (i = 0; i < m_nsp; i++) { + fluxes[i + offset] *= rho * y[i] / pp; + } + //grad_X[jmax + n*ldx] = gsave[n]; } + // thermal diffusion + if (addThermalDiffusion) { + for (n = 0; n < ndim; n++) { + offset = n*ldf; + doublereal grad_logt = grad_T[n]/m_temp; + for (i = 0; i < m_nsp; i++) + fluxes[i + offset] -= m_spwork[i]*grad_logt; + } + } + } + //==================================================================================================================== + // Get the mass diffusional fluxes [kg/m^2/s] of the species, given the thermodynamic + // state at two nearby points. + /* + * The specific diffusional fluxes are calculated with reference to the mass averaged + * velocity. This is a one-dimensional vector + * + * @param state1 Array of temperature, density, and mass + * fractions for state 1. + * @param state2 Array of temperature, density, and mass + * fractions for state 2. + * @param delta Distance from state 1 to state 2 (m). + * @param fluxes Output mass fluxes of the species. + * (length = m_nsp) + */ + void MultiTransport::getMassFluxes(const doublereal* state1, const doublereal* state2, doublereal delta, + doublereal* fluxes) { - void MultiTransport::getMassFluxes(const doublereal* state1, - const doublereal* state2, doublereal delta, - doublereal* fluxes) { + double* x1 = DATA_PTR(m_spwork1); + double* x2 = DATA_PTR(m_spwork2); + double* x3 = DATA_PTR(m_spwork3); + int n, nsp = m_thermo->nSpecies(); + m_thermo->restoreState(nsp+2, state1); + double p1 = m_thermo->pressure(); + double t1 = state1[0]; + m_thermo->getMoleFractions(x1); - double* x1 = DATA_PTR(m_spwork1); - double* x2 = DATA_PTR(m_spwork2); - double* x3 = DATA_PTR(m_spwork3); - int n, nsp = m_thermo->nSpecies(); - m_thermo->restoreState(nsp+2, state1); - double p1 = m_thermo->pressure(); - double t1 = state1[0]; - m_thermo->getMoleFractions(x1); + m_thermo->restoreState(nsp+2, state2); + double p2 = m_thermo->pressure(); + double t2 = state2[0]; + m_thermo->getMoleFractions(x2); - m_thermo->restoreState(nsp+2, state2); - double p2 = m_thermo->pressure(); - double t2 = state2[0]; - m_thermo->getMoleFractions(x2); + // + double p = 0.5*(p1 + p2); + double t = 0.5*(state1[0] + state2[0]); - // - double p = 0.5*(p1 + p2); - double t = 0.5*(state1[0] + state2[0]); - - for (n = 0; n < nsp; n++) { - x3[n] = 0.5*(x1[n] + x2[n]); - } - m_thermo->setState_TPX(t, p, x3); - m_thermo->getMoleFractions(DATA_PTR(m_molefracs)); + for (n = 0; n < nsp; n++) { + x3[n] = 0.5*(x1[n] + x2[n]); + } + m_thermo->setState_TPX(t, p, x3); + m_thermo->getMoleFractions(DATA_PTR(m_molefracs)); - // update the binary diffusion coefficients if necessary - updateDiff_T(); + // update the binary diffusion coefficients if necessary + updateDiff_T(); - doublereal sum; - int i, j; + doublereal sum; + int i, j; - // If there is a temperature gadient, then get the - // thermal diffusion coefficients + // If there is a temperature gadient, then get the + // thermal diffusion coefficients - bool addThermalDiffusion = false; - if (state1[0] != state2[0]) { - addThermalDiffusion = true; - getThermalDiffCoeffs(DATA_PTR(m_spwork)); - } + bool addThermalDiffusion = false; + if (state1[0] != state2[0]) { + addThermalDiffusion = true; + getThermalDiffCoeffs(DATA_PTR(m_spwork)); + } - const doublereal* y = m_thermo->massFractions(); - doublereal rho = m_thermo->density(); + const doublereal* y = m_thermo->massFractions(); + doublereal rho = m_thermo->density(); - for (i = 0; i < m_nsp; i++) { - sum = 0.0; - for (j = 0; j < m_nsp; j++) { - m_aa(i,j) = m_molefracs[j]*m_molefracs[i]/m_bdiff(i,j); - sum += m_aa(i,j); - } - m_aa(i,i) -= sum; - } + for (i = 0; i < m_nsp; i++) { + sum = 0.0; + for (j = 0; j < m_nsp; j++) { + m_aa(i,j) = m_molefracs[j]*m_molefracs[i]/m_bdiff(i,j); + sum += m_aa(i,j); + } + m_aa(i,i) -= sum; + } - // enforce the condition \sum Y_k V_k = 0. This is done by - // replacing the flux equation with the largest gradx - // component with the flux balance condition. - int jmax = 0; - doublereal gradmax = -1.0; - for (j = 0; j < m_nsp; j++) { - if (fabs(x2[j] - x1[j]) > gradmax) { - gradmax = fabs(x1[j] - x2[j]); - jmax = j; - } - } + // enforce the condition \sum Y_k V_k = 0. This is done by + // replacing the flux equation with the largest gradx + // component with the flux balance condition. + int jmax = 0; + doublereal gradmax = -1.0; + for (j = 0; j < m_nsp; j++) { + if (fabs(x2[j] - x1[j]) > gradmax) { + gradmax = fabs(x1[j] - x2[j]); + jmax = j; + } + } - // set the matrix elements in this row to the mass fractions, - // and set the entry in gradx to zero + // set the matrix elements in this row to the mass fractions, + // and set the entry in gradx to zero - for (j = 0; j < m_nsp; j++) { - m_aa(jmax,j) = y[j]; - fluxes[j] = x2[j] - x1[j]; - } - fluxes[jmax] = 0.0; + for (j = 0; j < m_nsp; j++) { + m_aa(jmax,j) = y[j]; + fluxes[j] = x2[j] - x1[j]; + } + fluxes[jmax] = 0.0; - // use LAPACK to solve the equations - int info=0; - int nr = m_aa.nRows(); - int nc = m_aa.nColumns(); + // use LAPACK to solve the equations + int info=0; + int nr = m_aa.nRows(); + int nc = m_aa.nColumns(); - ct_dgetrf(nr, nc, m_aa.ptrColumn(0), nr, &m_aa.ipiv()[0], info); - if (info == 0) { - int ndim = 1; - ct_dgetrs(ctlapack::NoTranspose, nr, ndim, + ct_dgetrf(nr, nc, m_aa.ptrColumn(0), nr, &m_aa.ipiv()[0], info); + if (info == 0) { + int ndim = 1; + ct_dgetrs(ctlapack::NoTranspose, nr, ndim, m_aa.ptrColumn(0), nr, &m_aa.ipiv()[0], fluxes, nr, info); - if (info != 0) - throw CanteraError("MultiTransport::getMassFluxes", - "Error in DGETRS. Info = "+int2str(info)); - } - else - throw CanteraError("MultiTransport::getMassFluxes", - "Error in DGETRF. Info = "+int2str(info)); + if (info != 0) + throw CanteraError("MultiTransport::getMassFluxes", + "Error in DGETRS. Info = "+int2str(info)); + } + else + throw CanteraError("MultiTransport::getMassFluxes", + "Error in DGETRF. Info = "+int2str(info)); - doublereal pp = pressure_ig(); + doublereal pp = pressure_ig(); - // multiply diffusion velocities by rho * Y_k to create - // mass fluxes, and divide by pressure - for (i = 0; i < m_nsp; i++) { - fluxes[i] *= rho * y[i] / pp; - } - - // thermal diffusion - if (addThermalDiffusion) { - doublereal grad_logt = (t2 - t1)/m_temp; - for (i = 0; i < m_nsp; i++) { - fluxes[i] -= m_spwork[i]*grad_logt; - } - } + // multiply diffusion velocities by rho * Y_k to create + // mass fluxes, and divide by pressure + for (i = 0; i < m_nsp; i++) { + fluxes[i] *= rho * y[i] / pp; } - void MultiTransport::getMolarFluxes(const doublereal* state1, - const doublereal* state2, doublereal delta, - doublereal* fluxes) { - getMassFluxes(state1, state2, delta, fluxes); - int k, nsp = m_thermo->nSpecies(); - for (k = 0; k < nsp; k++) { - fluxes[k] /= m_mw[k]; - } + // thermal diffusion + if (addThermalDiffusion) { + doublereal grad_logt = (t2 - t1)/m_temp; + for (i = 0; i < m_nsp; i++) { + fluxes[i] -= m_spwork[i]*grad_logt; + } } + } + //==================================================================================================================== + void MultiTransport::getMolarFluxes(const doublereal* const state1, + const doublereal * const state2, + const doublereal delta, + doublereal * const fluxes) { + getMassFluxes(state1, state2, delta, fluxes); + int k, nsp = m_thermo->nSpecies(); + for (k = 0; k < nsp; k++) { + fluxes[k] /= m_mw[k]; + } + } + //==================================================================================================================== + // Set the solution method for inverting the L matrix + /* + * @param method enum TRANSOLVE_TYPE Either use direct or TRANSOLVE_GMRES + */ + void MultiTransport::setSolutionMethod(TRANSOLVE_TYPE method) { + if (method == TRANSOLVE_GMRES) m_gmres = true; + else m_gmres = false; + } + //==================================================================================================================== + void MultiTransport::setOptions_GMRES(int m, doublereal eps) { + if (m > 0) m_mgmres = m; + if (eps > 0.0) m_eps_gmres = eps; + } + //==================================================================================================================== + void MultiTransport::getMultiDiffCoeffs(const int ld, doublereal* const d) { + int i,j; - void MultiTransport::getMultiDiffCoeffs(const int ld, doublereal* const d) { - int i,j; + doublereal p = pressure_ig(); - doublereal p = pressure_ig(); + // update the mole fractions + updateTransport_C(); - // update the mole fractions - updateTransport_C(); + // update the binary diffusion coefficients + updateDiff_T(); - // update the binary diffusion coefficients - updateDiff_T(); - - // evaluate L0000 if the temperature or concentrations have - // changed since it was last evaluated. - if (!m_l0000_ok) eval_L0000(DATA_PTR(m_molefracs)); + // evaluate L0000 if the temperature or concentrations have + // changed since it was last evaluated. + if (!m_l0000_ok) eval_L0000(DATA_PTR(m_molefracs)); - // invert L00,00 - int ierr = invert(m_Lmatrix, m_nsp); - if (ierr != 0) { - throw CanteraError("MultiTransport::getMultiDiffCoeffs", - string(" invert returned ierr = ")+int2str(ierr)); - } - m_l0000_ok = false; // matrix is overwritten by inverse - - //doublereal pres = m_thermo->pressure(); - doublereal prefactor = 16.0 * m_temp - * m_thermo->meanMolecularWeight()/(25.0 * p); - doublereal c; - - for (i = 0; i < m_nsp; i++) { - for (j = 0; j < m_nsp; j++) { - c = prefactor/m_mw[j]; - d[ld*j + i] = c*m_molefracs[i]* - (m_Lmatrix(i,j) - m_Lmatrix(i,i)); - } - } + // invert L00,00 + int ierr = invert(m_Lmatrix, m_nsp); + if (ierr != 0) { + throw CanteraError("MultiTransport::getMultiDiffCoeffs", + string(" invert returned ierr = ")+int2str(ierr)); } + m_l0000_ok = false; // matrix is overwritten by inverse + //doublereal pres = m_thermo->pressure(); + doublereal prefactor = 16.0 * m_temp + * m_thermo->meanMolecularWeight()/(25.0 * p); + doublereal c; - void MultiTransport::getMixDiffCoeffs(doublereal* const d) { + for (i = 0; i < m_nsp; i++) { + for (j = 0; j < m_nsp; j++) { + c = prefactor/m_mw[j]; + d[ld*j + i] = c*m_molefracs[i]* + (m_Lmatrix(i,j) - m_Lmatrix(i,i)); + } + } + } + //==================================================================================================================== - // update the mole fractions - updateTransport_C(); + void MultiTransport::getMixDiffCoeffs(doublereal* const d) { - // update the binary diffusion coefficients if necessary - updateDiff_T(); + // update the mole fractions + updateTransport_C(); - int k, j; - doublereal mmw = m_thermo->meanMolecularWeight(); - doublereal sumxw = 0.0, sum2; - doublereal p = pressure_ig(); - if (m_nsp == 1) { - d[0] = m_bdiff(0,0) / p; - } else { - for (k = 0; k < m_nsp; k++) sumxw += m_molefracs[k] * m_mw[k]; - for (k = 0; k < m_nsp; k++) { - sum2 = 0.0; - for (j = 0; j < m_nsp; j++) { - if (j != k) { - sum2 += m_molefracs[j] / m_bdiff(j,k); - } - } - if (sum2 <= 0.0) { - d[k] = m_bdiff(k,k) / p; - } else { - d[k] = (sumxw - m_molefracs[k] * m_mw[k])/(p * mmw * sum2); - } + // update the binary diffusion coefficients if necessary + updateDiff_T(); + + int k, j; + doublereal mmw = m_thermo->meanMolecularWeight(); + doublereal sumxw = 0.0, sum2; + doublereal p = pressure_ig(); + if (m_nsp == 1) { + d[0] = m_bdiff(0,0) / p; + } else { + for (k = 0; k < m_nsp; k++) sumxw += m_molefracs[k] * m_mw[k]; + for (k = 0; k < m_nsp; k++) { + sum2 = 0.0; + for (j = 0; j < m_nsp; j++) { + if (j != k) { + sum2 += m_molefracs[j] / m_bdiff(j,k); } } + if (sum2 <= 0.0) { + d[k] = m_bdiff(k,k) / p; + } else { + d[k] = (sumxw - m_molefracs[k] * m_mw[k])/(p * mmw * sum2); + } + } } + } - void MultiTransport::updateTransport_T() { - //m_thermo->update_T(m_update_transport_T); - _update_transport_T(); - } + void MultiTransport::updateTransport_T() { + //m_thermo->update_T(m_update_transport_T); + _update_transport_T(); + } - void MultiTransport::updateTransport_C() { - // {m_thermo->update_C(m_update_transport_C); - _update_transport_C(); - } + void MultiTransport::updateTransport_C() { + // {m_thermo->update_C(m_update_transport_C); + _update_transport_C(); + } - /** - * Update temperature-dependent quantities. This method is called - * by the temperature property updater. - */ - void MultiTransport::_update_transport_T() - { - if (m_temp == m_thermo->temperature()) return; + /** + * Update temperature-dependent quantities. This method is called + * by the temperature property updater. + */ + void MultiTransport::_update_transport_T() + { + if (m_temp == m_thermo->temperature()) return; - m_temp = m_thermo->temperature(); - m_logt = log(m_temp); - m_kbt = Boltzmann * m_temp; - m_sqrt_t = sqrt(m_temp); - m_t14 = sqrt(m_sqrt_t); - m_t32 = m_temp * m_sqrt_t; - m_sqrt_kbt = sqrt(Boltzmann*m_temp); + m_temp = m_thermo->temperature(); + m_logt = log(m_temp); + m_kbt = Boltzmann * m_temp; + m_sqrt_t = sqrt(m_temp); + m_t14 = sqrt(m_sqrt_t); + m_t32 = m_temp * m_sqrt_t; + m_sqrt_kbt = sqrt(Boltzmann*m_temp); - // compute powers of log(T) - m_polytempvec[0] = 1.0; - m_polytempvec[1] = m_logt; - m_polytempvec[2] = m_logt*m_logt; - m_polytempvec[3] = m_logt*m_logt*m_logt; - m_polytempvec[4] = m_logt*m_logt*m_logt*m_logt; + // compute powers of log(T) + m_polytempvec[0] = 1.0; + m_polytempvec[1] = m_logt; + m_polytempvec[2] = m_logt*m_logt; + m_polytempvec[3] = m_logt*m_logt*m_logt; + m_polytempvec[4] = m_logt*m_logt*m_logt*m_logt; - // temperature has changed, so polynomial fits will need to be - // redone, and the L matrix reevaluated. - m_visc_ok = false; - m_spvisc_ok = false; - m_diff_ok = false; - m_abc_ok = false; - m_lmatrix_soln_ok = false; - m_l0000_ok = false; - } + // temperature has changed, so polynomial fits will need to be + // redone, and the L matrix reevaluated. + m_visc_ok = false; + m_spvisc_ok = false; + m_diff_ok = false; + m_abc_ok = false; + m_lmatrix_soln_ok = false; + m_l0000_ok = false; + } - /** - * This is called the first time any transport property - * is requested from ThermoSubstance after the concentrations - * have changed. - */ - void MultiTransport::_update_transport_C() - { - // signal that concentration-dependent quantities will need to - // be recomputed before use, and update the local mole - // fraction array. - m_l0000_ok = false; - m_lmatrix_soln_ok = false; - m_thermo->getMoleFractions(DATA_PTR(m_molefracs)); + /** + * This is called the first time any transport property + * is requested from ThermoSubstance after the concentrations + * have changed. + */ + void MultiTransport::_update_transport_C() + { + // signal that concentration-dependent quantities will need to + // be recomputed before use, and update the local mole + // fraction array. + m_l0000_ok = false; + m_lmatrix_soln_ok = false; + m_thermo->getMoleFractions(DATA_PTR(m_molefracs)); - // add an offset to avoid a pure species condition - // (check - this may be unnecessary) - int k; - for (k = 0; k < m_nsp; k++) { - m_molefracs[k] = fmaxx(MIN_X, m_molefracs[k]); - } + // add an offset to avoid a pure species condition + // (check - this may be unnecessary) + int k; + for (k = 0; k < m_nsp; k++) { + m_molefracs[k] = fmaxx(MIN_X, m_molefracs[k]); } + } - /************************************************************************* - * - * methods to update temperature-dependent properties - * - *************************************************************************/ + /************************************************************************* + * + * methods to update temperature-dependent properties + * + *************************************************************************/ - /** - * @internal - * Update the binary diffusion coefficients. These are evaluated - * from the polynomial fits at unit pressure (1 Pa). - */ - void MultiTransport::updateDiff_T() { - if (m_diff_tlast == m_thermo->temperature()) return; - _update_diff_T(); - m_diff_tlast = m_thermo->temperature(); - //m_thermo->update_T(m_update_diff_T); - } + /** + * @internal + * Update the binary diffusion coefficients. These are evaluated + * from the polynomial fits at unit pressure (1 Pa). + */ + void MultiTransport::updateDiff_T() { + if (m_diff_tlast == m_thermo->temperature()) return; + _update_diff_T(); + m_diff_tlast = m_thermo->temperature(); + //m_thermo->update_T(m_update_diff_T); + } - void MultiTransport::_update_diff_T() { + void MultiTransport::_update_diff_T() { - updateTransport_T(); + updateTransport_T(); - // evaluate binary diffusion coefficients at unit pressure - int i,j; - int ic = 0; - if (m_mode == CK_Mode) { - for (i = 0; i < m_nsp; i++) { - for (j = i; j < m_nsp; j++) { - m_bdiff(i,j) = exp(dot4(m_polytempvec, m_diffcoeffs[ic])); - m_bdiff(j,i) = m_bdiff(i,j); - ic++; - } - } - } - else { - for (i = 0; i < m_nsp; i++) { - for (j = i; j < m_nsp; j++) { - m_bdiff(i,j) = m_temp * m_sqrt_t*dot5(m_polytempvec, - m_diffcoeffs[ic]); - m_bdiff(j,i) = m_bdiff(i,j); - ic++; - } - } - } - m_diff_ok = true; - } - - - /** - * @internal - * Update the temperature-dependent viscosity terms. - * Updates the array of pure species viscosities, and the - * weighting functions in the viscosity mixture rule. - * The flag m_visc_ok is set to true. - */ - void MultiTransport::updateSpeciesViscosities_T() { - if (m_spvisc_tlast == m_thermo->temperature()) return; - _update_species_visc_T(); - //m_thermo->update_T(m_update_spvisc_T); - m_spvisc_tlast = m_thermo->temperature(); - } - - - void MultiTransport::_update_species_visc_T() { - - updateTransport_T(); - - int k; - if (m_mode == CK_Mode) { - for (k = 0; k < m_nsp; k++) { - m_visc[k] = exp(dot4(m_polytempvec, m_visccoeffs[k])); - m_sqvisc[k] = sqrt(m_visc[k]); - } - } - else { - for (k = 0; k < m_nsp; k++) { - //m_visc[k] = m_sqrt_t*dot5(m_polytempvec, m_visccoeffs[k]); - // the polynomial fit is done for sqrt(visc/sqrt(T)) - m_sqvisc[k] = m_t14*dot5(m_polytempvec, m_visccoeffs[k]); - m_visc[k] = (m_sqvisc[k]*m_sqvisc[k]); - } - } - m_spvisc_ok = true; - } - - /** - * @internal - */ - void MultiTransport::updateViscosity_T() { - if (m_visc_tlast == m_thermo->temperature()) return; - _update_visc_T(); - m_visc_tlast = m_thermo->temperature(); - } - - void MultiTransport::_update_visc_T() { - doublereal vratiokj, wratiojk, factor1; - - updateSpeciesViscosities_T(); - - // see Eq. (9-5.15) of Reid, Prausnitz, and Poling - int j, k; - for (j = 0; j < m_nsp; j++) { - for (k = j; k < m_nsp; k++) { - vratiokj = m_visc[k]/m_visc[j]; - wratiojk = m_mw[j]/m_mw[k]; - //rootwjk = sqrt(wratiojk); - //factor1 = 1.0 + sqrt(vratiokj * rootwjk); - //m_phi(k,j) = factor1*factor1 / - // (SqrtEight * sqrt(1.0 + m_mw[k]/m_mw[j])); - //m_phi(j,k) = m_phi(k,j)/(vratiokj * wratiojk); - - // Note that m_wratjk(k,j) holds the square root of - // m_wratjk(j,k)! - factor1 = 1.0 + (m_sqvisc[k]/m_sqvisc[j]) * m_wratjk(k,j); - m_phi(k,j) = factor1*factor1 / - (SqrtEight * m_wratkj1(j,k)); - m_phi(j,k) = m_phi(k,j)/(vratiokj * wratiojk); - } - } - m_visc_ok = true; - } - - - /** - * @internal - * Update the temperature-dependent terms needed to compute the - * thermal conductivity and thermal diffusion coefficients. - */ - void MultiTransport::updateThermal_T() { - if (m_thermal_tlast == m_thermo->temperature()) return; - _update_thermal_T(); - // m_thermo->update_T(m_update_thermal_T); - m_thermal_tlast = m_thermo->temperature(); - } - - void MultiTransport::_update_thermal_T() { - - // we need species viscosities and binary diffusion - // coefficients - updateSpeciesViscosities_T(); - updateDiff_T(); - - // evaluate polynomial fits for A*, B*, C* - doublereal z; - int ipoly; - int i, j; - for (i = 0; i < m_nsp; i++) { - for (j = i; j < m_nsp; j++) { - z = m_logt - m_log_eps_k(i,j); - ipoly = m_poly[i][j]; - if (m_mode == CK_Mode) { - m_om22(i,j) = poly6(z, DATA_PTR(m_om22_poly[ipoly])); - m_astar(i,j) = poly6(z, DATA_PTR(m_astar_poly[ipoly])); - m_bstar(i,j) = poly6(z, DATA_PTR(m_bstar_poly[ipoly])); - m_cstar(i,j) = poly6(z, DATA_PTR(m_cstar_poly[ipoly])); - } - else { - m_om22(i,j) = poly8(z, DATA_PTR(m_om22_poly[ipoly])); - m_astar(i,j) = poly8(z, DATA_PTR(m_astar_poly[ipoly])); - m_bstar(i,j) = poly8(z, DATA_PTR(m_bstar_poly[ipoly])); - m_cstar(i,j) = poly8(z, DATA_PTR(m_cstar_poly[ipoly])); - } - m_om22(j,i) = m_om22(i,j); - m_astar(j,i) = m_astar(i,j); - m_bstar(j,i) = m_bstar(i,j); - m_cstar(j,i) = m_cstar(i,j); - } - } - m_abc_ok = true; - - // evaluate the temperature-dependent rotational relaxation - // rate - - int k; - doublereal tr, sqtr; - for (k = 0; k < m_nsp; k++) { - tr = m_eps[k]/ m_kbt; - sqtr = m_sqrt_eps_k[k] / m_sqrt_t; - m_rotrelax[k] = fmaxx(1.0,m_zrot[k]) * m_frot_298[k]/Frot(tr, sqtr); - } - - doublereal d; - doublereal c = 1.2*GasConstant*m_temp; - for (k = 0; k < m_nsp; k++) { - d = c * m_visc[k] * m_astar(k,k)/m_mw[k]; - m_bdiff(k,k) = d; - } - - // internal heat capacities - const array_fp& cp = ((IdealGasPhase*)m_thermo)->cp_R_ref(); - for (k = 0; k < m_nsp; k++) m_cinternal[k] = cp[k] - 2.5; - } - - /** - * This function returns a Transport data object for a given species. - * - */ - struct GasTransportData MultiTransport:: - getGasTransportData(int kSpecies) - { - struct GasTransportData td; - td.speciesName = m_thermo->speciesName(kSpecies); - - td.geometry = 2; - if (m_crot[kSpecies] == 0.0) { - td.geometry = 0; - } else if (m_crot[kSpecies] == 1.0) { - td.geometry = 1; + // evaluate binary diffusion coefficients at unit pressure + int i,j; + int ic = 0; + if (m_mode == CK_Mode) { + for (i = 0; i < m_nsp; i++) { + for (j = i; j < m_nsp; j++) { + m_bdiff(i,j) = exp(dot4(m_polytempvec, m_diffcoeffs[ic])); + m_bdiff(j,i) = m_bdiff(i,j); + ic++; + } } - td.wellDepth = m_eps[kSpecies] / Boltzmann; - td.dipoleMoment = m_dipoleDiag[kSpecies] * 1.0E25 / SqrtTen; - td.diameter = m_diam(kSpecies, kSpecies) * 1.0E10; - td.polarizability = m_alpha[kSpecies] * 1.0E30; - td.rotRelaxNumber = m_zrot[kSpecies]; + } + else { + for (i = 0; i < m_nsp; i++) { + for (j = i; j < m_nsp; j++) { + m_bdiff(i,j) = m_temp * m_sqrt_t*dot5(m_polytempvec, + m_diffcoeffs[ic]); + m_bdiff(j,i) = m_bdiff(i,j); + ic++; + } + } + } + m_diff_ok = true; + } - return td; + + /** + * @internal + * Update the temperature-dependent viscosity terms. + * Updates the array of pure species viscosities, and the + * weighting functions in the viscosity mixture rule. + * The flag m_visc_ok is set to true. + */ + void MultiTransport::updateSpeciesViscosities_T() { + if (m_spvisc_tlast == m_thermo->temperature()) return; + _update_species_visc_T(); + //m_thermo->update_T(m_update_spvisc_T); + m_spvisc_tlast = m_thermo->temperature(); + } + + + void MultiTransport::_update_species_visc_T() { + + updateTransport_T(); + + int k; + if (m_mode == CK_Mode) { + for (k = 0; k < m_nsp; k++) { + m_visc[k] = exp(dot4(m_polytempvec, m_visccoeffs[k])); + m_sqvisc[k] = sqrt(m_visc[k]); + } + } + else { + for (k = 0; k < m_nsp; k++) { + //m_visc[k] = m_sqrt_t*dot5(m_polytempvec, m_visccoeffs[k]); + // the polynomial fit is done for sqrt(visc/sqrt(T)) + m_sqvisc[k] = m_t14*dot5(m_polytempvec, m_visccoeffs[k]); + m_visc[k] = (m_sqvisc[k]*m_sqvisc[k]); + } + } + m_spvisc_ok = true; + } + + /** + * @internal + */ + void MultiTransport::updateViscosity_T() { + if (m_visc_tlast == m_thermo->temperature()) return; + _update_visc_T(); + m_visc_tlast = m_thermo->temperature(); + } + + void MultiTransport::_update_visc_T() { + doublereal vratiokj, wratiojk, factor1; + + updateSpeciesViscosities_T(); + + // see Eq. (9-5.15) of Reid, Prausnitz, and Poling + int j, k; + for (j = 0; j < m_nsp; j++) { + for (k = j; k < m_nsp; k++) { + vratiokj = m_visc[k]/m_visc[j]; + wratiojk = m_mw[j]/m_mw[k]; + //rootwjk = sqrt(wratiojk); + //factor1 = 1.0 + sqrt(vratiokj * rootwjk); + //m_phi(k,j) = factor1*factor1 / + // (SqrtEight * sqrt(1.0 + m_mw[k]/m_mw[j])); + //m_phi(j,k) = m_phi(k,j)/(vratiokj * wratiojk); + + // Note that m_wratjk(k,j) holds the square root of + // m_wratjk(j,k)! + factor1 = 1.0 + (m_sqvisc[k]/m_sqvisc[j]) * m_wratjk(k,j); + m_phi(k,j) = factor1*factor1 / + (SqrtEight * m_wratkj1(j,k)); + m_phi(j,k) = m_phi(k,j)/(vratiokj * wratiojk); + } + } + m_visc_ok = true; + } + + + /** + * @internal + * Update the temperature-dependent terms needed to compute the + * thermal conductivity and thermal diffusion coefficients. + */ + void MultiTransport::updateThermal_T() { + if (m_thermal_tlast == m_thermo->temperature()) return; + _update_thermal_T(); + // m_thermo->update_T(m_update_thermal_T); + m_thermal_tlast = m_thermo->temperature(); + } + + void MultiTransport::_update_thermal_T() { + + // we need species viscosities and binary diffusion + // coefficients + updateSpeciesViscosities_T(); + updateDiff_T(); + + // evaluate polynomial fits for A*, B*, C* + doublereal z; + int ipoly; + int i, j; + for (i = 0; i < m_nsp; i++) { + for (j = i; j < m_nsp; j++) { + z = m_logt - m_log_eps_k(i,j); + ipoly = m_poly[i][j]; + if (m_mode == CK_Mode) { + m_om22(i,j) = poly6(z, DATA_PTR(m_om22_poly[ipoly])); + m_astar(i,j) = poly6(z, DATA_PTR(m_astar_poly[ipoly])); + m_bstar(i,j) = poly6(z, DATA_PTR(m_bstar_poly[ipoly])); + m_cstar(i,j) = poly6(z, DATA_PTR(m_cstar_poly[ipoly])); + } + else { + m_om22(i,j) = poly8(z, DATA_PTR(m_om22_poly[ipoly])); + m_astar(i,j) = poly8(z, DATA_PTR(m_astar_poly[ipoly])); + m_bstar(i,j) = poly8(z, DATA_PTR(m_bstar_poly[ipoly])); + m_cstar(i,j) = poly8(z, DATA_PTR(m_cstar_poly[ipoly])); + } + m_om22(j,i) = m_om22(i,j); + m_astar(j,i) = m_astar(i,j); + m_bstar(j,i) = m_bstar(i,j); + m_cstar(j,i) = m_cstar(i,j); + } + } + m_abc_ok = true; + + // evaluate the temperature-dependent rotational relaxation + // rate + + int k; + doublereal tr, sqtr; + for (k = 0; k < m_nsp; k++) { + tr = m_eps[k]/ m_kbt; + sqtr = m_sqrt_eps_k[k] / m_sqrt_t; + m_rotrelax[k] = fmaxx(1.0,m_zrot[k]) * m_frot_298[k]/Frot(tr, sqtr); } + doublereal d; + doublereal c = 1.2*GasConstant*m_temp; + for (k = 0; k < m_nsp; k++) { + d = c * m_visc[k] * m_astar(k,k)/m_mw[k]; + m_bdiff(k,k) = d; + } + + // Calculate the internal heat capacities by subtracting off the translational contributions + /* + * HKM Exploratory comment: + * The translational component is 1.5 + * The rotational component is 1.0 for a linear molecule and 1.5 for a nonlinear molecule + * and zero for a monotomic. + * Chemkin has traditionally subtracted 1.5 here (SAND86-8246). + * The original Dixon-Lewis paper subtracted 1.5 here. + */ + const array_fp& cp = ((IdealGasPhase*)m_thermo)->cp_R_ref(); + for (k = 0; k < m_nsp; k++) { + m_cinternal[k] = cp[k] - 2.5; + } + } + //==================================================================================================================== + /* + * This function returns a Transport data object for a given species. + * + */ + struct GasTransportData MultiTransport:: + getGasTransportData(int kSpecies) + { + struct GasTransportData td; + td.speciesName = m_thermo->speciesName(kSpecies); + + td.geometry = 2; + if (m_crot[kSpecies] == 0.0) { + td.geometry = 0; + } else if (m_crot[kSpecies] == 1.0) { + td.geometry = 1; + } + td.wellDepth = m_eps[kSpecies] / Boltzmann; + td.dipoleMoment = m_dipoleDiag[kSpecies] * 1.0E25 / SqrtTen; + td.diameter = m_diam(kSpecies, kSpecies) * 1.0E10; + td.polarizability = m_alpha[kSpecies] * 1.0E30; + td.rotRelaxNumber = m_zrot[kSpecies]; + + return td; + } + //==================================================================================================================== } diff --git a/Cantera/src/transport/MultiTransport.h b/Cantera/src/transport/MultiTransport.h index 5979b8ce9..792099292 100644 --- a/Cantera/src/transport/MultiTransport.h +++ b/Cantera/src/transport/MultiTransport.h @@ -1,5 +1,4 @@ /** - * * @file MultiTransport.h * Interface for class MultiTransport * @@ -31,7 +30,7 @@ namespace Cantera { - + //==================================================================================================================== //! Transport solve options enum TRANSOLVE_TYPE { //! Solve the dense matrix via a gmres iteration @@ -39,14 +38,12 @@ namespace Cantera { //! Solve the dense matrix via an LU gauss elimination TRANSOLVE_LU }; - + //==================================================================================================================== class GasTransportParams; - - ///////////////////////////////////////////////////////////// - - /** - * Class L_Matrix is used to represent the "L" matrix. This class - * is used instead of DenseMatrix so that a version of mult can be + //==================================================================================================================== + //! Class L_Matrix is used to represent the "L" matrix. + /*! + * This class is used instead of DenseMatrix so that a version of mult can be * used that knows about the structure of the L matrix, * specifically that the upper-right and lower-left blocks are * zero. @@ -54,34 +51,54 @@ namespace Cantera { */ class L_Matrix : public DenseMatrix { public: + + //! default constructor L_Matrix() {} + + //! destructor virtual ~L_Matrix(){} - /** + //! Conduct a multiply with the Dense matrix + /*! * This method is used by GMRES to multiply the L matrix by a * vector b. The L matrix has a 3x3 block structure, where each * block is a K x K matrix. The elements of the upper-right and * lower-left blocks are all zero. This method is defined so * that the multiplication only involves the seven non-zero * blocks. + * + * @param b + * @param prod */ virtual void mult(const doublereal* b, doublereal* prod) const; }; - - /** - * Class MultiTransport implements multicomponent transport - * properties for ideal gas mixtures. The implementation generally + //==================================================================================================================== + //! Class MultiTransport implements multicomponent transport + //! properties for ideal gas mixtures. + /*! + * + * The implementation generally * follows the procedure outlined in Kee, Coltrin, and Glarborg, * "Theoretical and Practical Aspects of Chemically Reacting Flow - * Modeling," Wiley Interscience. @ingroup transportProps + * Modeling," Wiley Interscience. + * + * @ingroup transportProps */ class MultiTransport : public Transport { + protected: + + //! default constructor + /*! + * @param thermo Optional parameter for the pointer to the ThermoPhase object + */ + MultiTransport(thermo_t* thermo=0); + public: - + //! Destructor virtual ~MultiTransport(); // overloaded base class methods @@ -97,7 +114,18 @@ namespace Cantera { virtual void getSpeciesViscosities(doublereal* const visc) { updateViscosity_T(); std::copy(m_visc.begin(), m_visc.end(), visc); } + + //! Return the thermal diffusion coefficients (kg/m/s) + /*! + * Eqn. (12.126) displays how they are calculated. The reference work is from + * Dixon-Lewis. + * + * Eqns. (12.168) shows how they are used in an expression for the species flux. + * + * @param dt Vector of thermal diffusion coefficients. Units = kg/m/s + */ virtual void getThermalDiffCoeffs(doublereal* const dt); + virtual doublereal thermalConductivity(); virtual void getBinaryDiffCoeffs(const int ld, doublereal* const d); @@ -112,57 +140,88 @@ namespace Cantera { */ virtual void getMixDiffCoeffs(doublereal* const d); - //! Get the species diffusive mass fluxes wrt to - //! the mass averaged velocity, + //! Get the species diffusive mass fluxes wrt to the mass averaged velocity, //! given the gradients in mole fraction and temperature /*! * Units for the returned fluxes are kg m-2 s-1. * - * @param ndim Number of dimensions in the flux expressions - * @param grad_T Gradient of the temperature - * (length = ndim) - * @param ldx Leading dimension of the grad_X array - * (usually equal to m_nsp but not always) - * @param grad_X Gradients of the mole fraction - * Flat vector with the m_nsp in the inner loop. - * length = ldx * ndim - * @param ldf Leading dimension of the fluxes array - * (usually equal to m_nsp but not always) - * @param fluxes Output of the diffusive mass fluxes - * Flat vector with the m_nsp in the inner loop. - * length = ldx * ndim + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - virtual void getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, - const doublereal* grad_X, - int ldf, - doublereal* fluxes); + virtual void getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes); - virtual void getMolarFluxes(const doublereal* state1, - const doublereal* state2, doublereal delta, - doublereal* fluxes); + //! Get the molar diffusional fluxes [kmol/m^2/s] of the species, given the thermodynamic + //! state at two nearby points. + /*! + * The molar diffusional fluxes are calculated with reference to the mass averaged + * velocity. This is a one-dimensional vector + * + * @param state1 Array of temperature, density, and mass + * fractions for state 1. + * @param state2 Array of temperature, density, and mass + * fractions for state 2. + * @param delta Distance from state 1 to state 2 (m). + * @param fluxes Output molar fluxes of the species. + * (length = m_nsp) + */ + virtual void getMolarFluxes(const doublereal* const state1, + const doublereal* const state2, + const doublereal delta, + doublereal* const fluxes); + //! Get the mass diffusional fluxes [kg/m^2/s] of the species, given the thermodynamic + //! state at two nearby points. + /*! + * The specific diffusional fluxes are calculated with reference to the mass averaged + * velocity. This is a one-dimensional vector + * + * @param state1 Array of temperature, density, and mass + * fractions for state 1. + * @param state2 Array of temperature, density, and mass + * fractions for state 2. + * @param delta Distance from state 1 to state 2 (m). + * @param fluxes Output mass fluxes of the species. + * (length = m_nsp) + */ virtual void getMassFluxes(const doublereal* state1, const doublereal* state2, doublereal delta, doublereal* fluxes); - virtual void setSolutionMethod(TRANSOLVE_TYPE method) { - if (method == TRANSOLVE_GMRES) m_gmres = true; - else m_gmres = false; - } + //! Set the solution method for inverting the L matrix + /*! + * @param method enum TRANSOLVE_TYPE Either use direct or TRANSOLVE_GMRES + */ + virtual void setSolutionMethod(TRANSOLVE_TYPE method); - virtual void setOptions_GMRES(int m, doublereal eps) { - if (m > 0) m_mgmres = m; - if (eps > 0.0) m_eps_gmres = eps; - } - - void save(std::string outfile); + //! Set the options for the GMRES solution + /*! + * @param m set the mgmres param + * @param eps Set the eps parameter + */ + virtual void setOptions_GMRES(int m, doublereal eps); /** * @internal */ - virtual bool initGas( GasTransportParams& tr ); + + //! Initialize the transport operator with parameters from GasTransportParams object + /*! + * @param tr input GasTransportParams object + */ + virtual bool initGas(GasTransportParams& tr); /** @@ -194,35 +253,25 @@ namespace Cantera { friend class TransportFactory; - /** - * Return a structure containing all of the pertinent parameters - * about a species that was used to construct the Transport - * properties in this object. - * - * @param k Species number to obtain the properties from. + + //! Return a structure containing all of the pertinent parameters + //! about a species that was used to construct the Transport properties in this object + /*! + * @param k Species index */ - struct GasTransportData getGasTransportData(int); - - - protected: - /// default constructor - MultiTransport(thermo_t* thermo=0); + struct GasTransportData getGasTransportData(int k); private: - // int m_update_transport_T; - // int m_update_transport_C; - // int m_update_spvisc_T; - // int m_update_visc_T; - // int m_update_diff_T; - // int m_update_thermal_T; + doublereal m_diff_tlast; + doublereal m_spvisc_tlast; + doublereal m_visc_tlast; + doublereal m_thermal_tlast; - doublereal m_diff_tlast, m_spvisc_tlast, m_visc_tlast, - m_thermal_tlast; - - // mixture attributes + //! Number of species in the phase int m_nsp; - doublereal m_tmin, m_tmax; + doublereal m_tmin; + doublereal m_tmax; vector_fp m_mw; // polynomial fits @@ -239,13 +288,21 @@ namespace Cantera { std::vector > m_poly; - std::vector m_astar_poly; - std::vector m_bstar_poly; - std::vector m_cstar_poly; - std::vector m_om22_poly; + std::vector m_astar_poly; + std::vector m_bstar_poly; + std::vector m_cstar_poly; + std::vector m_om22_poly; + + //! Dense matrix for astar DenseMatrix m_astar; + + //! Dense matrix for bstar DenseMatrix m_bstar; + + //! Dense matrix for cstar DenseMatrix m_cstar; + + //! Dense matrix for omega22 DenseMatrix m_om22; DenseMatrix m_phi; // viscosity weighting functions @@ -283,6 +340,8 @@ namespace Cantera { vector_fp m_spwork, m_spwork1, m_spwork2, m_spwork3; void correctBinDiffCoeffs(); + + //! Boolean indicating viscosity is up to date bool m_visc_ok; bool m_spvisc_ok; bool m_diff_ok; @@ -291,9 +350,25 @@ namespace Cantera { bool m_lmatrix_soln_ok; int m_mode; - void eval_L0000(const doublereal* x); - void eval_L0010(const doublereal* x); + //! Evalulate the L0000 matrices + /*! + * Evaluate the upper-left block of the L matrix. + * @param x vector of species mole fractions + */ + void eval_L0000(const doublereal* const x); + + //! Evalulate the L0010 matrices + /*! + * @param x vector of species mole fractions + */ + void eval_L0010(const doublereal* const x); + + //! Evalulate the L1000 matrices + /*! + * + */ void eval_L1000(); + void eval_L0100(); void eval_L0001(); void eval_L1010(const doublereal* x); diff --git a/Cantera/src/transport/SimpleTransport.cpp b/Cantera/src/transport/SimpleTransport.cpp index 569f6a2ab..817b6527d 100644 --- a/Cantera/src/transport/SimpleTransport.cpp +++ b/Cantera/src/transport/SimpleTransport.cpp @@ -3,8 +3,8 @@ * Simple mostly constant transport properties */ /* - * $Revision: 1.10 $ - * $Date: 2009/03/24 20:44:30 $ + * $Revision$ + * $Date$ */ #include "ThermoPhase.h" @@ -26,6 +26,12 @@ using namespace std; #define MIN_X 1.e-14 +#ifndef SAFE_DELETE +//! \cond +#define SAFE_DELETE(x) if (x) { delete (x); x = 0; } +//! \endcond +#endif + namespace Cantera { //================================================================================================ SimpleTransport::SimpleTransport(thermo_t* thermo, int ndim) : @@ -83,7 +89,7 @@ namespace Cantera { } //================================================================================================ SimpleTransport& SimpleTransport::operator=(const SimpleTransport& right) { - if (&right != this) { + if (&right == this) { return *this; } Transport::operator=(right); @@ -97,10 +103,34 @@ namespace Cantera { m_tmax = right.m_tmax; m_mw = right.m_mw; - m_coeffVisc_Ns = right.m_coeffVisc_Ns; - m_coeffLambda_Ns = right.m_coeffLambda_Ns; - m_coeffDiff_Ns = right.m_coeffDiff_Ns; - + m_coeffVisc_Ns = right.m_coeffVisc_Ns; + for (size_t k = 0; k duplMyselfAsLTPspecies(); + } + } + + m_coeffLambda_Ns = right.m_coeffLambda_Ns; + for (size_t k = 0; k < right.m_coeffLambda_Ns.size(); k++) { + if (right.m_coeffLambda_Ns[k]) { + m_coeffLambda_Ns[k] = (right.m_coeffLambda_Ns[k])->duplMyselfAsLTPspecies(); + } + } + + m_coeffDiff_Ns = right.m_coeffDiff_Ns; + for (size_t k = 0; k < right.m_coeffDiff_Ns.size(); k++) { + if (right.m_coeffDiff_Ns[k]) { + m_coeffDiff_Ns[k] = (right.m_coeffDiff_Ns[k])->duplMyselfAsLTPspecies(); + } + } + + m_coeffHydroRadius_Ns = right.m_coeffHydroRadius_Ns; + for (size_t k = 0; k < right.m_coeffHydroRadius_Ns.size(); k++) { + if (right.m_coeffHydroRadius_Ns[k]) { + m_coeffHydroRadius_Ns[k] = (right.m_coeffHydroRadius_Ns[k])->duplMyselfAsLTPspecies(); + } + } + m_Grad_X = right.m_Grad_X; m_Grad_T = right.m_Grad_T; m_Grad_P = right.m_Grad_P; @@ -132,13 +162,27 @@ namespace Cantera { return *this; } - //================================================================================================ Transport *SimpleTransport::duplMyselfAsTransport() const { SimpleTransport* tr = new SimpleTransport(*this); return (dynamic_cast(tr)); } //================================================================================================ + SimpleTransport::~SimpleTransport() { + for (size_t k = 0; k < m_coeffVisc_Ns.size() ; k++) { + SAFE_DELETE(m_coeffVisc_Ns[k]); + } + for (size_t k = 0; k < m_coeffLambda_Ns.size(); k++) { + SAFE_DELETE(m_coeffLambda_Ns[k]); + } + for (size_t k = 0; k < m_coeffDiff_Ns.size(); k++) { + SAFE_DELETE(m_coeffDiff_Ns[k]); + } + for (size_t k = 0; k < m_coeffHydroRadius_Ns.size(); k++) { + SAFE_DELETE(m_coeffHydroRadius_Ns[k]); + } + } + //================================================================================================ // Initialize the object /* * This is where we dimension everything. @@ -166,8 +210,8 @@ namespace Cantera { * */ std::string modelName = ""; - if (getOptionalModel(transportNode, "compositionDependence", - modelName)) { + if (ctml::getOptionalModel(transportNode, "compositionDependence", + modelName)) { modelName = lowercase(modelName); if (modelName == "solvent_only") { compositionDepType_ = 0; @@ -196,10 +240,11 @@ namespace Cantera { m_coeffVisc_Ns.clear(); m_coeffVisc_Ns.resize(m_nsp); - Cantera::LiquidTransportData <d0 = tr.LTData[0]; + //Cantera::LiquidTransportData <d0 = tr.LTData[0]; + std::string spName = m_thermo->speciesName(0); + /* LiquidTR_Model vm0 = ltd0.model_viscosity; std::string spName0 = m_thermo->speciesName(0); - std::string spName = m_thermo->speciesName(0); if (vm0 == LTR_MODEL_CONSTANT) { tempDepType_ = 0; } else if (vm0 == LTR_MODEL_ARRHENIUS) { @@ -211,12 +256,14 @@ namespace Cantera { throw CanteraError("SimpleTransport::initLiquid", "Viscosity Model for species " + spName0 + " is not handled by this object"); } + */ for (k = 0; k < m_nsp; k++) { spName = m_thermo->speciesName(k); Cantera::LiquidTransportData <d = tr.LTData[k]; - LiquidTR_Model vm = ltd.model_viscosity; - vector_fp &kentry = m_coeffVisc_Ns[k]; + //LiquidTR_Model vm = ltd.model_viscosity; + //vector_fp &kentry = m_coeffVisc_Ns[k]; + /* if (vm != vm0) { if (compositionDepType_ != 0) { throw CanteraError(" SimpleTransport::initLiquid", @@ -225,7 +272,9 @@ namespace Cantera { kentry = m_coeffVisc_Ns[0]; } } - kentry = ltd.viscCoeffs; + */ + m_coeffVisc_Ns[k] = ltd.viscosity; + ltd.viscosity = 0; } /* @@ -234,17 +283,18 @@ namespace Cantera { m_condSpecies.resize(m_nsp); m_coeffLambda_Ns.clear(); m_coeffLambda_Ns.resize(m_nsp); - LiquidTR_Model cm0 = ltd0.model_thermalCond; - if (cm0 != vm0) { - throw CanteraError("SimpleTransport::initLiquid", - "Conductivity model is not the same as the viscosity model for species " + spName0); - } + //LiquidTR_Model cm0 = ltd0.model_thermalCond; + //if (cm0 != vm0) { + // throw CanteraError("SimpleTransport::initLiquid", + // "Conductivity model is not the same as the viscosity model for species " + spName0); + // } for (k = 0; k < m_nsp; k++) { spName = m_thermo->speciesName(k); Cantera::LiquidTransportData <d = tr.LTData[k]; - LiquidTR_Model cm = ltd.model_thermalCond; - vector_fp &kentry = m_coeffLambda_Ns[k]; + //LiquidTR_Model cm = ltd.model_thermalCond; + //vector_fp &kentry = m_coeffLambda_Ns[k]; + /* if (cm != cm0) { if (compositionDepType_ != 0) { throw CanteraError(" SimpleTransport::initLiquid", @@ -253,7 +303,9 @@ namespace Cantera { kentry = m_coeffLambda_Ns[0]; } } - kentry = ltd.thermalCondCoeffs; + */ + m_coeffLambda_Ns[k] = ltd.thermalCond; + ltd.thermalCond = 0; } /* @@ -264,7 +316,8 @@ namespace Cantera { m_diffSpecies.resize(m_nsp); m_coeffDiff_Ns.clear(); m_coeffDiff_Ns.resize(m_nsp); - LiquidTR_Model dm0 = ltd0.model_speciesDiffusivity; + //LiquidTR_Model dm0 = ltd0.model_speciesDiffusivity; + /* if (dm0 != vm0) { if (dm0 == LTR_MODEL_NOTSET) { LiquidTR_Model rm0 = ltd0.model_hydroradius; @@ -276,10 +329,12 @@ namespace Cantera { } } } + */ for (k = 0; k < m_nsp; k++) { spName = m_thermo->speciesName(k); Cantera::LiquidTransportData <d = tr.LTData[k]; + /* LiquidTR_Model dm = ltd.model_speciesDiffusivity; if (dm == LTR_MODEL_NOTSET) { LiquidTR_Model rm = ltd.model_hydroradius; @@ -296,17 +351,31 @@ namespace Cantera { "hydroradius model is not constant for species " + spName0); } vector_fp &kentry = m_coeffHydroRadius_Ns[k]; - kentry.push_back(ltd.hydroradius); + kentry = ltd.hydroradius; } else { if (dm != dm0) { throw CanteraError(" SimpleTransport::initLiquid", "different diffusivity models for species " + spName + " and " + spName0 ); } vector_fp &kentry = m_coeffDiff_Ns[k]; - kentry = ltd.speciesDiffusivityCoeffs; + kentry = ltd.speciesDiffusivity; + } + */ + + m_coeffDiff_Ns[k] = ltd.speciesDiffusivity; + ltd.speciesDiffusivity = 0; + + if (!(m_coeffDiff_Ns[k])) { + if (ltd.hydroRadius) { + m_coeffHydroRadius_Ns[k] = (ltd.hydroRadius)->duplMyselfAsLTPspecies(); + } + if (!(m_coeffHydroRadius_Ns[k])) { + throw CanteraError("SimpleTransport::initLiquid", + "Neither diffusivity nor hydroradius is set for species " + spName); + } } } - + @@ -325,8 +394,6 @@ namespace Cantera { m_Grad_P.resize(m_nDim, 0.0); m_Grad_V.resize(m_nDim, 0.0); - - // set all flags to false m_visc_mix_ok = false; m_visc_temp_ok = false; @@ -531,21 +598,137 @@ namespace Cantera { dt[k] = 0.0; } } -//================================================================================================ - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from + + //==================================================================================================================== + //! Get the species diffusive velocities wrt to the averaged velocity, + //! given the gradients in mole fraction and temperature + /*! + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. * - * \f[ - * \vec{j}_k = -n M_k D_k \nabla X_k. - * \f] + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param Vdiff Output of the diffusive velocities. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - void SimpleTransport::getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, const doublereal* grad_X, - int ldf, doublereal* fluxes) { + void SimpleTransport::getSpeciesVdiff(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + doublereal* Vdiff) { + set_Grad_T(grad_T); + set_Grad_X(grad_X); + const doublereal* y = m_thermo->massFractions(); + const doublereal rho = m_thermo->density(); + + getSpeciesFluxesExt(m_nsp, DATA_PTR(Vdiff)); + + for (int n = 0; n < m_nDim; n++) { + for (int k = 0; k < m_nsp; k++) { + if (y[k] > 1.0E-200) { + Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]); + } else { + Vdiff[n * m_nsp + k] = 0.0; + } + } + } + } + //================================================================================================ + // Get the species diffusive velocities wrt to the averaged velocity, + // given the gradients in mole fraction, temperature and electrostatic potential. + /* + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. + * + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * (length = ndim) + * @param Vdiff Output of the species diffusion velocities + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + void SimpleTransport::getSpeciesVdiffES(int ndim, const doublereal* grad_T, + int ldx, const doublereal* grad_X, + int ldf, const doublereal* grad_Phi, + doublereal* Vdiff) { + set_Grad_T(grad_T); + set_Grad_X(grad_X); + set_Grad_V(grad_Phi); + const doublereal* y = m_thermo->massFractions(); + const doublereal rho = m_thermo->density(); + + getSpeciesFluxesExt(m_nsp, DATA_PTR(Vdiff)); + + for (int n = 0; n < m_nDim; n++) { + for (int k = 0; k < m_nsp; k++) { + if (y[k] > 1.0E-200) { + Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]); + } else { + Vdiff[n * m_nsp + k] = 0.0; + } + } + } + } + //================================================================================================ + // Get the species diffusive mass fluxes wrt to the specified solution averaged velocity, + // given the gradients in mole fraction and temperature + /* + * units = kg/m2/s + * + * The diffusive mass flux of species \e k is computed from the following + * formula + * + * Usually the specified solution average velocity is the mass averaged velocity. + * This is changed in some subclasses, however. + * + * \f[ + * j_k = - \rho M_k D_k \nabla X_k - Y_k V_c + * \f] + * + * where V_c is the correction velocity + * + * \f[ + * V_c = - \sum_j {\rho M_j D_j \nabla X_j} + * \f] + * + * + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * @param ldx Leading dimension of the grad_X array. + * @param grad_X Gradient of the mole fractions(length nsp * num dimensions); + * @param ldf Leading dimension of the fluxes array. + * @param fluxes Output fluxes of species. + */ + void SimpleTransport::getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes) { set_Grad_T(grad_T); set_Grad_X(grad_X); getSpeciesFluxesExt(ldf, fluxes); @@ -588,34 +771,73 @@ namespace Cantera { const array_fp& mw = m_thermo->molecularWeights(); const doublereal* y = m_thermo->massFractions(); - doublereal conc = m_thermo->molarDensity(); + + doublereal concTotal = m_thermo->molarDensity(); + // Unroll wrt ndim - vector_fp sum(m_nDim, 0.0); - + if (doMigration_) { double FRT = ElectronCharge / (Boltzmann * m_temp); for (n = 0; n < m_nDim; n++) { + rhoVc[n] = 0.0; for (k = 0; k < m_nsp; k++) { - fluxes[n*ldf + k] = -conc * mw[k] * m_spwork[k] * + fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] * ( m_Grad_X[n*m_nsp + k] + FRT * m_molefracs[k] * m_chargeSpecies[k] * m_Grad_V[n]); - sum[n] += fluxes[n*ldf + k]; + rhoVc[n] += fluxes[n*ldf + k]; } } } else { for (n = 0; n < m_nDim; n++) { + rhoVc[n] = 0.0; for (k = 0; k < m_nsp; k++) { - fluxes[n*ldf + k] = -conc * mw[k] * m_spwork[k] * m_Grad_X[n*m_nsp + k]; - sum[n] += fluxes[n*ldf + k]; + fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] * m_Grad_X[n*m_nsp + k]; + rhoVc[n] += fluxes[n*ldf + k]; } } } - // add correction flux to enforce sum to zero - for (n = 0; n < m_nDim; n++) { - for (k = 0; k < m_nsp; k++) { - fluxes[n*ldf + k] -= y[k]*sum[n]; + if (m_velocityBasis == VB_MASSAVG) { + for (n = 0; n < m_nDim; n++) { + rhoVc[n] = 0.0; + for (k = 0; k < m_nsp; k++) { + rhoVc[n] += fluxes[n*ldf + k]; + } } + for (n = 0; n < m_nDim; n++) { + for (k = 0; k < m_nsp; k++) { + fluxes[n*ldf + k] -= y[k] * rhoVc[n]; + } + } + } else if (m_velocityBasis == VB_MOLEAVG) { + for (n = 0; n < m_nDim; n++) { + rhoVc[n] = 0.0; + for (k = 0; k < m_nsp; k++) { + rhoVc[n] += fluxes[n*ldf + k] / mw[k]; + } + } + for (n = 0; n < m_nDim; n++) { + for (k = 0; k < m_nsp; k++) { + fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k]; + } + } + } else if (m_velocityBasis >= 0) { + for (n = 0; n < m_nDim; n++) { + rhoVc[n] = - fluxes[n*ldf + m_velocityBasis] / mw[m_velocityBasis]; + for (k = 0; k < m_nsp; k++) { + rhoVc[n] += fluxes[n*ldf + k] / mw[k]; + } + } + for (n = 0; n < m_nDim; n++) { + for (k = 0; k < m_nsp; k++) { + fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k]; + } + fluxes[n*ldf + m_velocityBasis] = 0.0; + } + + } else { + throw CanteraError("SimpleTransport::getSpeciesFluxesExt()", + "unknown velocity basis"); } } //================================================================================================ @@ -689,16 +911,11 @@ namespace Cantera { * thermal conductivity. */ void SimpleTransport::updateCond_T() { - int k; - if (tempDepType_ == 0) { - for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffLambda_Ns[k]; - m_condSpecies[k] = coeff[0]; - } - } else if (tempDepType_ == 1) { - for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffLambda_Ns[k]; - m_condSpecies[k] = coeff[0] * pow(m_temp,coeff[1]) * exp(-coeff[2]/m_temp); + if (compositionDepType_ == 0) { + m_condSpecies[0] = m_coeffLambda_Ns[0]->getSpeciesTransProp(); + } else { + for (int k = 0; k < m_nsp; k++) { + m_condSpecies[k] = m_coeffLambda_Ns[k]->getSpeciesTransProp(); } } m_cond_temp_ok = true; @@ -714,24 +931,14 @@ namespace Cantera { double visc = viscosity(); double RT = GasConstant * m_temp; for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffHydroRadius_Ns[k]; - double rad = coeff[0]; + double rad = m_coeffHydroRadius_Ns[k]->getSpeciesTransProp() ; m_diffSpecies[k] = RT / (6.0 * Pi * visc * rad); } } else { - if (tempDepType_ == 0) { - for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffDiff_Ns[k]; - m_diffSpecies[k] = coeff[0]; - } - } else if (tempDepType_ == 1) { - for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffDiff_Ns[k]; - m_diffSpecies[k] = coeff[0] * pow(m_temp,coeff[1]) * exp(-coeff[2]/m_temp); - } + for (k = 0; k < m_nsp; k++) { + m_diffSpecies[k] = m_coeffDiff_Ns[k]->getSpeciesTransProp(); } } - m_diff_temp_ok = true; m_diff_mix_ok = false; } @@ -750,16 +957,11 @@ namespace Cantera { * The flag m_visc_ok is set to true. */ void SimpleTransport::updateViscosity_T() { - int k; - if (tempDepType_ == 0) { - for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffVisc_Ns[k]; - m_viscSpecies[k] = coeff[0]; - } - } else if (tempDepType_ == 1) { - for (k = 0; k < m_nsp; k++) { - Coeff_T_ &coeff = m_coeffVisc_Ns[k]; - m_viscSpecies[k] = coeff[0] * pow(m_temp,coeff[1]) * exp(-coeff[2]/m_temp); + if (compositionDepType_ == 0) { + m_viscSpecies[0] = m_coeffVisc_Ns[0]->getSpeciesTransProp(); + } else { + for (int k = 0; k < m_nsp; k++) { + m_viscSpecies[k] = m_coeffVisc_Ns[k]->getSpeciesTransProp(); } } m_visc_temp_ok = true; @@ -793,7 +995,7 @@ namespace Cantera { return true; } //================================================================================================ - /** + /* * Throw an exception if this method is invoked. * This probably indicates something is not yet implemented. */ @@ -805,7 +1007,7 @@ namespace Cantera { return 0.0; } - //================================================================================================ + //=================================================================================================================== } -//================================================================================================ +//====================================================================================================================== diff --git a/Cantera/src/transport/SimpleTransport.h b/Cantera/src/transport/SimpleTransport.h index 35eb9560f..3c60f1b90 100644 --- a/Cantera/src/transport/SimpleTransport.h +++ b/Cantera/src/transport/SimpleTransport.h @@ -1,11 +1,12 @@ /** - * * @file SimpleTransport.h - * Header file defining class SimpleTransport + * Header file for the class SimpleTransport which provides simple + * transport properties for liquids and solids + * (see \ref tranprops and \link Cantera::SimpleTransport SimpleTransport \endlink) . */ /* - * $Revision: 1.9 $ - * $Date: 2009/03/27 18:24:39 $ + * $Revision$ + * $Date$ */ #ifndef CT_SIMPLETRAN_H @@ -20,8 +21,6 @@ #include #include -using namespace std; - // Cantera includes #include "TransportBase.h" #include "DenseMatrix.h" @@ -30,13 +29,10 @@ using namespace std; namespace Cantera { - - - class LiquidTransportParams; - //! Class LiquidTransport implements mixture-averaged transport + //! Class SimpleTransport implements mixture-averaged transport //! properties for liquid phases. /*! * The model is based on that @@ -120,18 +116,100 @@ namespace Cantera { * * The viscosity calculation may be broken down into two parts. * In the first part, the viscosity of the pure species are calculated - * In the second part, a mixing rule is applied, based on the - * Wilkes correlation, to yield the mixture viscosity. - * + * In the second part, a mixing rule is applied. There are two mixing rules. + * Solvent-only and mixture-averaged. * + * For the solvent-only mixing rule, we use the pure species viscosity calculated for + * the solvent as the viscosity of the entire mixture. For the mixture averaged rule + * we do a mole fraction based average of the pure species viscosities: + * + * Solvent-only: + * \f[ + * \mu = \mu_0 + * \f] + * Mixture-average: + * \f[ + * \mu = \sum_k {\mu_k X_k} + * \f] + * + * + *

Calculate of the Binary Diffusion Coefficients

+ * + * The binary diffusion coefficients are obtained from the pure species diffusion coefficients + * using an additive process + * + * \f[ + * D_{i,j} = \frac{1}{2} \left( D^0_i(T) + D^0_j(T) \right) + * \f] + * + * + * + * + *

Electrical Mobilities

+ * + * The mobility \f$ \mu^e_k \f$ is calculated from the diffusion coefficient using the Einstein relation. + * + * \f[ + * \mu^e_k = \frac{F D_k}{R T} + * \f] + * + * The diffusion coefficients, \f$ D_k \f$ , is calculated from a call to the mixture diffusion + * coefficient routine. + * + *

Species Diffusive Fluxes

+ * + * The diffusive mass flux of species \e k is computed from the following + * formula + * + * Usually the specified solution average velocity is the mass averaged velocity. + * This is changed in some subclasses, however. + * + * \f[ + * j_k = - c^T M_k D_k \nabla X_k - \rho Y_k V_c + * \f] + * + * where V_c is the correction velocity + * + * \f[ + * \rho V_c = - \sum_j {c^T M_j D_j \nabla X_j} + * \f] + * + * In the above equation, \f$ D_k \f$ is the mixture diffusivity for species k calculated for the current + * conditions, which may depend on T, P, and X_k. \f$ C^T \f$ is the total concentration of the phase. + * + * When this is electrical migration, the formulas above are enhanced to + * + * \f[ + * j_k = - C^T M_k D_k \nabla X_k + F C^T M_k \frac{D_k}{ R T } X_k z_k \nabla V - \rho Y_k V_c + * \f] + * + * where V_c is the correction velocity + * + * \f[ + * \rho V_c = - \sum_j {c^T M_j D_j \nabla X_j} + \sum_j F C^T M_j \frac{D_j}{ R T } X_j z_j \nabla V + * \f] + * + * + *

Species Diffusional Velocities

+ * + * Species diffusional velocities are calculated from the species diffusional fluxes, within this object, + * using the following formula for the diffusional velocity of the kth species, \f$ V_k^d \f$ + * + * \f[ + * j_k = \rho Y_k V_k^d + * \f] + * + * + * TODO + * This object has to be made compatible with different types of reference velocities. Right now, elements + * of the formulas are only compatible with the mass-averaged velocity. + * + * @ingroup tranprops * */ class SimpleTransport : public Transport { public: - - typedef vector_fp Coeff_T_; - //! Default constructor. /*! * This requires call to initLiquid(LiquidTransportParams& tr) @@ -173,7 +251,7 @@ namespace Cantera { //! virtual destructor - virtual ~SimpleTransport() {} + virtual ~SimpleTransport(); //! Initialize the transport object /*! @@ -185,15 +263,11 @@ namespace Cantera { */ virtual bool initLiquid(LiquidTransportParams& tr); - friend class TransportFactory; - - //! Return the model id for this transport parameterization virtual int model() const { return cSimpleTransport; } - //! overloaded base class methods //! Returns the mixture viscosity of the solution /*! @@ -211,6 +285,8 @@ namespace Cantera { * * Here \f$ \mu_k \f$ is the viscosity of pure species \e k. * + * units are Pa s or kg/m/s + * * @see updateViscosity_T(); */ virtual doublereal viscosity(); @@ -218,7 +294,12 @@ namespace Cantera { //! Returns the pure species viscosities /*! * The pure species viscosities are to be given in an Arrhenius - * form in accordance with activated-jump-process dominated transport. + * form in accordance with activated-jump-process dominated transport. + * + * units are Pa s or kg/m/s + * + * @param visc Return the species viscosities as a vector of + * length m_nsp */ virtual void getSpeciesViscosities(doublereal* const visc); @@ -310,40 +391,121 @@ namespace Cantera { */ virtual void getFluidMobilities(doublereal* const mobil_f); - //! Specify the valpdaue of the gradient of the voltage + //! Specify the value of the gradient of the voltage /*! * * @param grad_V Gradient of the voltage (length num dimensions); */ - virtual void set_Grad_V(const doublereal* const grad_V); + virtual void set_Grad_V(const doublereal * const grad_V); //! Specify the value of the gradient of the temperature /*! - * - * @param grad_V Gradient of the temperature (length num dimensions); + * @param grad_T Gradient of the temperature (length num dimensions); */ - virtual void set_Grad_T(const doublereal* const grad_T); + virtual void set_Grad_T(const doublereal * const grad_T); //! Specify the value of the gradient of the MoleFractions /*! * * @param grad_X Gradient of the mole fractions(length nsp * num dimensions); */ - virtual void set_Grad_X(const doublereal* const grad_X); + virtual void set_Grad_X(const doublereal * const grad_X); - - /** - * @param ndim The number of spatial dimensions (1, 2, or 3). - * @param grad_T The temperature gradient (ignored in this model). - * @param ldx Leading dimension of the grad_X array. - * The diffusive mass flux of species \e k is computed from - * + //! Get the species diffusive velocities wrt to the averaged velocity, + //! given the gradients in mole fraction and temperature + /*! + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. * + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param Vdiff Output of the diffusive velocities. + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - virtual void getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, const doublereal* grad_X, - int ldf, doublereal* fluxes); + virtual void getSpeciesVdiff(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + doublereal* Vdiff); + + //! Get the species diffusive velocities wrt to the averaged velocity, + //! given the gradients in mole fraction, temperature and electrostatic potential. + /*! + * The average velocity can be computed on a mole-weighted + * or mass-weighted basis, or the diffusion velocities may + * be specified as relative to a specific species (i.e. a + * solvent) all according to the velocityBasis input parameter. + * + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * (length = ndim) + * @param Vdiff Output of the species diffusion velocities + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + */ + virtual void getSpeciesVdiffES(int ndim, const doublereal* grad_T, + int ldx, const doublereal* grad_X, + int ldf, const doublereal* grad_Phi, + doublereal* Vdiff); + + + //! Get the species diffusive mass fluxes wrt to the specified solution averaged velocity, + //! given the gradients in mole fraction and temperature + /*! + * units = kg/m2/s + * + * The diffusive mass flux of species \e k is computed from the following + * formula + * + * Usually the specified solution average velocity is the mass averaged velocity. + * This is changed in some subclasses, however. + * + * \f[ + * j_k = - \rho M_k D_k \nabla X_k - Y_k V_c + * \f] + * + * where V_c is the correction velocity + * + * \f[ + * V_c = - \sum_j {\rho M_j D_j \nabla X_j} + * \f] + * + * + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * @param ldx Leading dimension of the grad_X array. + * @param grad_X Gradient of the mole fractions(length nsp * num dimensions); + * @param ldf Leading dimension of the fluxes array. + * @param fluxes Output fluxes of species. + */ + virtual void getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes); //! Return the species diffusive mass fluxes wrt to //! the mass averaged velocity, @@ -450,7 +612,7 @@ namespace Cantera { * Types of temperature dependencies: * 0 - Independent of temperature (only one implemented so far) * 1 - extended arrhenius form - * 2 - power law form + * 2 - polynomial in temperature form */ int tempDepType_; @@ -468,6 +630,11 @@ namespace Cantera { */ int compositionDepType_; + //! Boolean indicating whether to use the hydrodynamic radius formulation + /*! + * If true, then the diffusion coefficient is calculated from the + * hydrodynamic radius. + */ bool useHydroRadius_; //! Boolean indicating whether electro-migration term should be @@ -490,20 +657,21 @@ namespace Cantera { vector_fp m_mw; //! Pure species viscosities in Arrhenius temperature-dependent form. - std::vector m_coeffVisc_Ns; + std::vector m_coeffVisc_Ns; //! Pure species thermal conductivities in Arrhenius temperature-dependent form. /*! * */ - std::vector m_coeffLambda_Ns; + std::vector m_coeffLambda_Ns; //! Pure species viscosities in Arrhenius temperature-dependent form. - std::vector m_coeffDiff_Ns; + std::vector m_coeffDiff_Ns; - std::vector m_coeffHydroRadius_Ns; + //! Hydrodynamic radius in LTPspecies form + std::vector m_coeffHydroRadius_Ns; //! Internal value of the gradient of the mole fraction vector @@ -665,6 +833,8 @@ namespace Cantera { */ vector_fp m_spwork; + vector_fp m_fluxes; + private: @@ -697,13 +867,16 @@ namespace Cantera { */ int m_nDim; + //! Temporary variable that stores the rho Vc value + double rhoVc[3]; + private: //! Throw an exception if this method is invoked. /*! * This probably indicates something is not yet implemented. * - * @pram msg Indicates the member function which is not implemented + * @param msg Indicates the member function which is not implemented */ doublereal err(std::string msg) const; diff --git a/Cantera/src/transport/SolidTransport.cpp b/Cantera/src/transport/SolidTransport.cpp index 6401d7f45..4f27ed757 100644 --- a/Cantera/src/transport/SolidTransport.cpp +++ b/Cantera/src/transport/SolidTransport.cpp @@ -1,14 +1,15 @@ /** - * * @file SolidTransport.cpp + * Definition file for the class SolidTransport, which handles transport + * of ions within solid phases + * (see \ref tranprops and \link Cantera::SolidTransport SolidTransport \endlink). */ - /* $Author$ * $Revision$ * $Date$ */ -// copyright 2008 California Institute of Technology +// Copyright 2008 California Institute of Technology // turn off warnings under Windows @@ -27,91 +28,151 @@ using namespace std; namespace Cantera { - SolidTransport::SolidTransport() {} + //==================================================================================================================== + SolidTransport::SolidTransport() : + Transport() , + m_nmobile(0), + m_Adiff(0), + m_Ndiff(0), + m_Ediff(0), + m_sp(0), + m_Alam(0), + m_Nlam(0), + m_Elam(0) + { + } + //==================================================================================================================== + SolidTransport::~SolidTransport() + { + } + //==================================================================================================================== + SolidTransport::SolidTransport(const SolidTransport &right) : + Transport(), + m_nmobile(0), + m_Adiff(0), + m_Ndiff(0), + m_Ediff(0), + m_sp(0), + m_Alam(0), + m_Nlam(0), + m_Elam(0) + { + /* + * Use the assignment operator to do the brunt + * of the work for the copy construtor. + */ + *this = right; + } + //==================================================================================================================== + SolidTransport& SolidTransport::operator=(const SolidTransport& b) + { + if (&b != this) { + return *this; + } + Transport::operator=(b); - void SolidTransport::setParameters(const int n, const int k, const double* const p) { - switch (n) { + m_nmobile = b.m_nmobile; + m_Adiff = b.m_Adiff; + m_Ndiff = b.m_Ndiff; + m_Ediff = b.m_Ediff; + m_sp = b.m_sp; + m_Alam = b.m_Alam; + m_Nlam = b.m_Nlam; + m_Elam = b.m_Elam; + + return *this; + } + //==================================================================================================================== + Transport *SolidTransport::duplMyselfAsTransport() const + { + SolidTransport* tr = new SolidTransport(*this); + return (dynamic_cast(tr)); + } + //==================================================================================================================== + void SolidTransport::setParameters(const int n, const int k, const doublereal * const p) { + switch (n) { - case 0: - // set the Arrhenius parameters for the diffusion coefficient - // of species k. - m_sp.push_back(k); - m_Adiff.push_back(p[0]); - m_Ndiff.push_back(p[1]); - m_Ediff.push_back(p[2]); - m_nmobile = m_sp.size(); - break; + case 0: + // set the Arrhenius parameters for the diffusion coefficient + // of species k. + m_sp.push_back(k); + m_Adiff.push_back(p[0]); + m_Ndiff.push_back(p[1]); + m_Ediff.push_back(p[2]); + m_nmobile = m_sp.size(); + break; - case 1: - // set the thermal conductivity Arrhenius parameters. - m_Alam = p[0]; - m_Nlam = p[2]; - m_Elam = p[2]; - break; + case 1: + // set the thermal conductivity Arrhenius parameters. + m_Alam = p[0]; + m_Nlam = p[2]; + m_Elam = p[2]; + break; - default: - ; - } + default: + ; } - - /** - * Compute the mobilities of the species from the diffusion coefficients, - * using the Einstein relation. - */ - void SolidTransport::getMobilities(doublereal* const mobil) { - int k; - getMixDiffCoeffs(mobil); - doublereal t = m_thermo->temperature(); - int nsp = m_thermo->nSpecies(); - doublereal c1 = ElectronCharge / (Boltzmann * t); - for (k = 0; k < nsp; k++) { - mobil[k] *= c1 * fabs(m_thermo->charge(k)); - } - } - - /** - * Thermal Conductivity. - * \f[ - * \lambda = A T^n \exp(-E/RT) - */ - doublereal SolidTransport::thermalConductivity() { - doublereal t = m_thermo->temperature(); - return m_Alam *pow(t, m_Nlam) * exp(-m_Elam/t); + m_work.resize(m_thermo->nSpecies()); + } + //==================================================================================================================== + /* + * Compute the mobilities of the species from the diffusion coefficients, + * using the Einstein relation. + */ + void SolidTransport::getMobilities(doublereal* const mobil) { + int k; + getMixDiffCoeffs(mobil); + doublereal t = m_thermo->temperature(); + int nsp = m_thermo->nSpecies(); + doublereal c1 = ElectronCharge / (Boltzmann * t); + for (k = 0; k < nsp; k++) { + mobil[k] *= c1; } - - - /** - * The diffusion coefficients are computed from - * - * \f[ - * D_k = A_k T^{n_k} \exp(-E_k/RT). - * \f] - * - * The diffusion coefficients are only non-zero for species for - * which parameters have been specified using method - * setParameters. - */ - void SolidTransport::getMixDiffCoeffs(doublereal* const d) { - doublereal temp = m_thermo->temperature(); - int nsp = m_thermo->nSpecies(); - int k; - for (k = 0; k < nsp; k++) d[k] = 0.0; - for (k = 0; k < m_nmobile; k++) { - d[m_sp[k]] = - m_Adiff[k] * pow(temp, m_Ndiff[k]) * exp(-m_Ediff[k]/temp); - } + } + //==================================================================================================================== + /* + * Thermal Conductivity. + * \f[ + * \lambda = A T^n \exp(-E/RT) + * \f] + */ + doublereal SolidTransport::thermalConductivity() { + doublereal t = m_thermo->temperature(); + return m_Alam * pow(t, m_Nlam) * exp(-m_Elam/t); + } + //==================================================================================================================== + /* + * The diffusion coefficients are computed from + * + * \f[ + * D_k = A_k T^{n_k} \exp(-E_k/RT). + * \f] + * + * The diffusion coefficients are only non-zero for species for + * which parameters have been specified using method + * setParameters. + */ + void SolidTransport::getMixDiffCoeffs(doublereal* const d) { + doublereal temp = m_thermo->temperature(); + int nsp = m_thermo->nSpecies(); + int k; + for (k = 0; k < nsp; k++) d[k] = 0.0; + for (k = 0; k < m_nmobile; k++) { + d[m_sp[k]] = + m_Adiff[k] * pow(temp, m_Ndiff[k]) * exp(-m_Ediff[k]/temp); } - -// void SolidTransport::electricalConductivity() { -// getMobilities(m_work.begin()); -// int nsp = m_thermo->nSpecies(); -// int k; -// doublereal sum = 0.0; -// for (k = 0; k < nsp; n++) { -// sum += m_thermo->charge(k)*m_thermo->moleFraction(k)*m_work[k]; -// } -// return sum * m_thermo->molarDensity(); -// } - + } + //==================================================================================================================== + doublereal SolidTransport::electricalConductivity() + { + getMobilities(&m_work[0]); + int nsp = m_thermo->nSpecies(); + doublereal sum = 0.0; + for (int k = 0; k < nsp; k++) { + sum += m_thermo->charge(k) * m_thermo->moleFraction(k) * m_work[k]; + } + return sum * m_thermo->molarDensity(); + } + //==================================================================================================================== } diff --git a/Cantera/src/transport/SolidTransport.h b/Cantera/src/transport/SolidTransport.h index 31e5fe0a1..3d2833f79 100644 --- a/Cantera/src/transport/SolidTransport.h +++ b/Cantera/src/transport/SolidTransport.h @@ -1,10 +1,11 @@ /** - * * @file SolidTransport.h - * Header file defining class SolidTransport + * Header file for defining the class SolidTransport, which handles transport + * of ions within solid phases + * (see \ref tranprops and \link Cantera::SolidTransport SolidTransport \endlink). */ -/* $Author$ +/* * $Revision$ * $Date$ */ @@ -37,40 +38,136 @@ namespace Cantera { - /** - * Class SolidTransport implements transport - * properties for solids. + + //! Class SolidTransport implements transport properties for solids. + /*! + * + * + * + */ + class SolidTransport : public Transport { + + public: + + //! Default constructor + SolidTransport(); + + //! Copy Constructor + /*! + * @param right Object to be copied */ - class SolidTransport : public Transport { + SolidTransport(const SolidTransport &right); - public: -virtual ~SolidTransport() {} + //! Destructor + virtual ~SolidTransport(); - virtual int model() const { return cSolidTransport; } + //! Assignment operator + /*! + * This is NOT a virtual function. + * + * @param right Reference to Transport object to be copied into the + * current one. + */ + SolidTransport& operator=(const SolidTransport& right); - virtual doublereal thermalConductivity(); - virtual void getMixDiffCoeffs(doublereal* const d); - virtual void getMobilities(doublereal* const mobil); - virtual void setParameters(const int n, const int k, const doublereal* const p); + //! Duplication routine for objects which inherit from + //! %Transport + /*! + * This virtual routine can be used to duplicate %Transport objects + * inherited from %Transport even if the application only has + * a pointer to %Transport to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + */ + virtual Transport *duplMyselfAsTransport() const; - friend class TransportFactory; - protected: + virtual int model() const { return cSolidTransport; } - /// default constructor - SolidTransport(); + virtual doublereal thermalConductivity(); + virtual void getMixDiffCoeffs(doublereal* const d); - private: + //! Compute the electrical mobilities of the species from the diffusion coefficients, + //! using the Einstein relation. + /*! + * Frequently, but not always, the mobility is calculated from the + * diffusion coefficient using the Einstein relation + * + * \f[ + * \mu^e_k = \frac{F D_k}{R T} + * \f] + * + * units (m^2/V/s). + * @param mobil Returns the mobilities of + * the species in array \c mobil_e. The array must be + * dimensioned at least as large as the number of species. + */ + virtual void getMobilities(doublereal* const mobil); - int m_nmobile; // number of mobile species - vector_fp m_Adiff; - vector_fp m_Ndiff; - vector_fp m_Ediff; - vector_int m_sp; - doublereal m_Alam; - doublereal m_Nlam; - doublereal m_Elam; - }; + virtual void setParameters(const int n, const int k, const doublereal* const p); + + friend class TransportFactory; + + /** + * The electrical conductivity (Siemens/m). + */ + virtual doublereal electricalConductivity(); + + + private: + + //! number of mobile species + /*! + * This is equal to the + */ + int m_nmobile; + + //! Coefficient for the diffusivity of species within a solid + /*! + * This is with respect to the lattice + * units = m**2 / s + * vector of length m_nmobile + */ + vector_fp m_Adiff; + + //! Temperature power coefficient for the diffusivity of species in a solid + /*! + * vector of length m_nmobile + */ + vector_fp m_Ndiff; + + //! Arrhenius factor for the species diffusivities of a solid + /*! + * units = temperature + * vector of length m_nmobile + */ + vector_fp m_Ediff; + + //! Index of mobile species to global species + /*! + * vector of length m_nmobile + */ + vector_int m_sp; + + //! Coefficient for the thermal conductivity of a solid + /*! + * units = kg m / s3 /K = W/m/K + */ + doublereal m_Alam; + + //! Temperature power coefficient for the thermal conductivity of a solid + doublereal m_Nlam; + + //! Arrhenius factor for the thermal conductivity of a solid + /*! + * units = temperature + */ + doublereal m_Elam; + + //! extra fp array of length nSpecies() + vector_fp m_work; + }; } #endif diff --git a/Cantera/src/transport/Tortuosity.h b/Cantera/src/transport/Tortuosity.h new file mode 100644 index 000000000..2fa72717c --- /dev/null +++ b/Cantera/src/transport/Tortuosity.h @@ -0,0 +1,192 @@ +/** + * @file TortuosityBruggeman.h + * Class to compute the increase in diffusive path length in porous media + * assuming the Bruggeman exponent relation + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ +#ifndef CT_TORTUOSITY_H +#define CT_TORTUOSITY_H + + +namespace Cantera { + + //! Specific Class to handle tortuosity corrections for diffusive transport + //! in porous media using the Bruggeman exponent + /*! + * Class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + * This base class implementation relates tortuosity to volume fraction + * through a power-law relationship that goes back to Bruggemann. The + * exponent is referred to as the Bruggemann exponent. + * + * Note that the total diffusional flux is generally written as + * + * \f[ + * \frac{ \phi C_T D_i \nabla X_i }{ \tau^2 } + * \f] + * + * where \f$ \phi \f$ is the volume fraction of the transported phase, + * \f$ \tau \f$ is referred to as the tortuosity. (Other variables are + * \f$ C_T \f$, the total concentration, \f$ D_i \f$, the diffusion + * coefficient, and \f$ X_i \f$, the mole fraction with Fickian + * transport assumed.) + * + * The tortuosity comes into play in conjunction the the + */ + class Tortuosity { + + public: + //! Default constructor uses Bruggemann exponent of 1.5 + Tortuosity(double setPower = 1.5 ) : expBrug_(setPower) { + } + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /** + * This method returns \f$ 1/\tau^2 \f$ in the description of the + * flux \f$ \phi C_T D_i \nabla X_i / \tau^2 \f$. + */ + virtual double toruosityFactor( double porosity ) { + return pow( porosity, expBrug_ - 1.0 ); + } + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /** + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + virtual double McMillan( double porosity ) { + return pow( porosity, expBrug_ ); + } + + protected: + //! Bruggemann exponent: power to which the tortuosity depends on the volume fraction + double expBrug_ ; + + }; + + + + /** This class implements transport coefficient corrections + * appropriate for porous media where percollation theory applies. + * It is derived from the Tortuosity class. + */ + class TortuosityPercolation : public Tortuosity { + + public: + //! Default constructor uses Bruggemann exponent of 1.5 + TortuosityPercolation( double percolationThreshold = 0.4, double conductivityExponent = 2.0 ) : percolationThreshold_(percolationThreshold), conductivityExponent_(conductivityExponent) { + } + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /** + * This method returns \f$ 1/\tau^2 \f$ in the description of the + * flux \f$ \phi C_T D_i \nabla X_i / \tau^2 \f$. + */ + double toruosityFactor( double porosity ) { + return McMillan( porosity ) / porosity; + } + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /** + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + double McMillan( double porosity ) { + return pow( ( porosity - percolationThreshold_ ) + / ( 1.0 - percolationThreshold_ ), + conductivityExponent_ ); + } + + protected: + //! Critical volume fraction / site density for percolation + double percolationThreshold_; + //! Conductivity exponent + /** + * The McMillan number (ratio of effective conductivity + * to non-porous conductivity) is + * \f[ \kappa/\kappa_0 = ( \phi - \phi_c )^\mu \f] + * where \f$ \mu \f$ is the conductivity exponent (typical + * values range from 1.6 to 2.0) and \f$ \phi_c \f$ + * is the percolation threshold. + */ + double conductivityExponent_; + }; + + + + /** This class implements transport coefficient corrections + * appropriate for porous media with a dispersed phase. + * This model goes back to Maxwell. The formula for the + * conductivity is expressed in terms of the volume fraction + * of the continuous phase, \f$ \phi \f$, and the relative + * conductivities of the dispersed and continuous phases, + * \f$ r = \kappa_d / \kappa_0 \f$. For dilute particle + * suspensions the effective conductivity is + * \f[ + * \kappa / \kappa_0 = 1 + 3 ( 1 - \phi ) ( r - 1 ) / ( r + 2 ) + * + O(\phi^2) + * \f] + * The class is derived from the Tortuosity class. + */ + class TortuosityMaxwell : public Tortuosity { + + public: + //! Default constructor uses Bruggemann exponent of 1.5 + TortuosityMaxwell( double relativeConductivites = 0.0 ) : relativeConductivites_(relativeConductivites) { + } + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /** + * This method returns \f$ 1/\tau^2 \f$ in the description of the + * flux \f$ \phi C_T D_i \nabla X_i / \tau^2 \f$. + */ + double toruosityFactor( double porosity ) { + return McMillan( porosity ) / porosity; + } + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /** + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + double McMillan( double porosity ) { + return 1 + 3 * ( 1.0 - porosity ) * ( relativeConductivites_ - 1.0 ) / ( relativeConductivites_ + 2 ); + } + + protected: + //! Relative conductivities of the dispersed and continuous phases, + //! \code{relativeConductivites_}\f$ = \kappa_d / \kappa_0 \f$. + double relativeConductivites_; + + }; + +} +#endif diff --git a/Cantera/src/transport/TortuosityBase.cpp b/Cantera/src/transport/TortuosityBase.cpp new file mode 100644 index 000000000..4fe734dbb --- /dev/null +++ b/Cantera/src/transport/TortuosityBase.cpp @@ -0,0 +1,96 @@ +/** + * @file TortuosityBase.cpp + * Base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ + +#include "TortuosityBase.h" +#include "ctexceptions.h" + +#include + +namespace Cantera { + //==================================================================================================================== + static void err(const std::string r) { + throw Cantera::CanteraError("TortuosityBase", "Error calling base class " + r); + } + //==================================================================================================================== + // Default constructor + TortuosityBase::TortuosityBase() + { + } + //==================================================================================================================== + // Copy Constructor + /* + * @param right Object to be copied + */ + TortuosityBase::TortuosityBase(const TortuosityBase &right) + { + *this = right; + } + //==================================================================================================================== + // Default destructor for TortuosityBase + TortuosityBase::~TortuosityBase() { + + } + //==================================================================================================================== + // Assignment operator + /* + * @param right Object to be copied + */ + TortuosityBase & TortuosityBase::operator=(const TortuosityBase &right) { + if (&right == this) { + return *this; + } + return *this; + } + //==================================================================================================================== + // Duplication operator + /* + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + TortuosityBase * TortuosityBase::duplMyselfAsTortuosityBase() const { + TortuosityBase * tb = new TortuosityBase(*this); + return tb; + } + //==================================================================================================================== + // The tortuosity factor models the effective increase in the diffusive transport length. + /* + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + * + */ + doublereal TortuosityBase::tortuosityFactor(doublereal porosity) { + err("tortuosityFactor"); + return 0.0; + } + //==================================================================================================================== + // The McMillan number is the ratio of the flux-like variable to the value it would have without porous flow. + /* + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + doublereal TortuosityBase::McMillanFactor(doublereal porosity) { + err("McMillanFactor"); + return 0.0; + } + //==================================================================================================================== +} diff --git a/Cantera/src/transport/TortuosityBase.h b/Cantera/src/transport/TortuosityBase.h new file mode 100644 index 000000000..5b4c2dacc --- /dev/null +++ b/Cantera/src/transport/TortuosityBase.h @@ -0,0 +1,108 @@ +/** + * @file TortuosityBase.h + * Virtual base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ +#ifndef CT_TORTUOSITYBASE_H +#define CT_TORTUOSITYBASE_H + +#include "ct_defs.h" + + +namespace Cantera { + + //! Base case to handle tortuosity corrections for diffusive transport + //! in porous media + /*! + * Class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + * This base class implementation relates tortuosity to volume fraction + * through a power-law relationship that goes back to Bruggemann. The + * exponent is referred to as the Bruggemann exponent. + * + * Note that the total diffusional flux is generally written as + * + * \f[ + * \frac{ \phi C_T D_i \nabla X_i }{ \tau^2 } + * \f] + * + * where \f$ \phi \f$ is the volume fraction of the transported phase, + * \f$ \tau \f$ is referred to as the tortuosity. (Other variables are + * \f$ C_T \f$, the total concentration, \f$ D_i \f$, the diffusion + * coefficient, and \f$ X_i \f$, the mole fraction with Fickian + * transport assumed.) + * + * The tortuosity comes into play in conjunction the the + */ + class TortuosityBase { + + public: + //! Default constructor uses Bruggemann exponent of 1.5 + TortuosityBase(); + + //! Copy Constructor + /*! + * @param right Object to be copied + */ + TortuosityBase(const TortuosityBase &right); + + //! Default destructor for TortuosityBase + virtual ~TortuosityBase(); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + TortuosityBase & operator=(const TortuosityBase &right); + + //! Duplication operator + /*! + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + virtual TortuosityBase * duplMyselfAsTortuosityBase() const; + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /*! + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + * + */ + virtual doublereal tortuosityFactor(doublereal porosity); + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /** + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + virtual doublereal McMillanFactor(doublereal porosity); + + protected: + + }; + + + +} + +#endif + diff --git a/Cantera/src/transport/TortuosityBruggeman.cpp b/Cantera/src/transport/TortuosityBruggeman.cpp new file mode 100644 index 000000000..ca88e38cf --- /dev/null +++ b/Cantera/src/transport/TortuosityBruggeman.cpp @@ -0,0 +1,99 @@ +/** + * @file TortuosityBase.cpp + * Base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ + +#include "TortuosityBruggeman.h" +#include "ctexceptions.h" + +#include + +namespace Cantera { + + //==================================================================================================================== + // Default constructor + TortuosityBruggeman::TortuosityBruggeman(doublereal setPower) : + TortuosityBase(), + expBrug_(setPower) + { + } + //==================================================================================================================== + // Copy Constructor + /* + * @param right Object to be copied + */ + TortuosityBruggeman::TortuosityBruggeman(const TortuosityBruggeman &right) : + TortuosityBase(), + expBrug_(right.expBrug_) + { + *this = right; + } + //==================================================================================================================== + // Default destructor for TortuosityBruggeman + TortuosityBruggeman::~TortuosityBruggeman() { + + } + //==================================================================================================================== + // Assignment operator + /* + * @param right Object to be copied + */ + TortuosityBruggeman & TortuosityBruggeman::operator=(const TortuosityBruggeman &right) { + if (&right == this) { + return *this; + } + TortuosityBase::operator=(right); + + expBrug_ = right.expBrug_; + + return *this; + } + //==================================================================================================================== + // Duplication operator + /* + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + TortuosityBase * TortuosityBruggeman::duplMyselfAsTortuosityBase() const { + TortuosityBruggeman * tb = new TortuosityBruggeman(*this); + return dynamic_cast(tb); + } + //==================================================================================================================== + // The tortuosity factor models the effective increase in the diffusive transport length. + /* + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + * + */ + doublereal TortuosityBruggeman::tortuosityFactor(doublereal porosity) { + return pow(porosity, expBrug_ - 1.0); + } + //==================================================================================================================== + // The McMillan number is the ratio of the flux-like variable to the value it would have without porous flow. + /* + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + doublereal TortuosityBruggeman::McMillanFactor(doublereal porosity) { + return pow(porosity, expBrug_); + } + //==================================================================================================================== +} diff --git a/Cantera/src/transport/TortuosityBruggeman.h b/Cantera/src/transport/TortuosityBruggeman.h new file mode 100644 index 000000000..d20e10665 --- /dev/null +++ b/Cantera/src/transport/TortuosityBruggeman.h @@ -0,0 +1,114 @@ +/** + * @file TortuosityBase.h + * Virtual base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ +#ifndef CT_TORTUOSITYBRUGGEMAN_H +#define CT_TORTUOSITYBRUGGEMAN_H + +#include "TortuosityBase.h" + + +namespace Cantera { + + //! Base case to handle tortuosity corrections for diffusive transport + //! in porous media using the Bruggeman exponential approximation + /*! + * Class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + * This base class implementation relates tortuosity to volume fraction + * through a power-law relationship that goes back to Bruggemann. The + * exponent is referred to as the Bruggemann exponent. + * + * Note that the total diffusional flux is generally written as + * + * \f[ + * \frac{ \phi C_T D_i \nabla X_i }{ \tau^2 } + * \f] + * + * where \f$ \phi \f$ is the volume fraction of the transported phase, + * \f$ \tau \f$ is referred to as the tortuosity. (Other variables are + * \f$ C_T \f$, the total concentration, \f$ D_i \f$, the diffusion + * coefficient, and \f$ X_i \f$, the mole fraction with Fickian + * transport assumed.) + * + * The tortuosity comes into play in conjunction the the + */ + class TortuosityBruggeman : public TortuosityBase { + + public: + //! Default constructor uses Bruggemann exponent of 1.5 + /*! + * @param setPower Exponent in the Bruggeman factor. The default is 1.5 + */ + TortuosityBruggeman(doublereal setPower = 1.5); + + //! Copy Constructor + /*! + * @param right Object to be copied + */ + TortuosityBruggeman(const TortuosityBruggeman &right); + + //! Default destructor for TortuosityBruggeman + virtual ~TortuosityBruggeman(); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + TortuosityBruggeman & operator=(const TortuosityBruggeman &right); + + //! Duplication operator + /*! + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + virtual TortuosityBase * duplMyselfAsTortuosityBase() const; + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /*! + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + * + */ + virtual doublereal tortuosityFactor(doublereal porosity); + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /** + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + virtual doublereal McMillanFactor(doublereal porosity); + + + protected: + //! Bruggemann exponent: power to which the tortuosity depends on the volume fraction + doublereal expBrug_; + + }; + + + +} + +#endif + diff --git a/Cantera/src/transport/TortuosityMaxwell.cpp b/Cantera/src/transport/TortuosityMaxwell.cpp new file mode 100644 index 000000000..782567202 --- /dev/null +++ b/Cantera/src/transport/TortuosityMaxwell.cpp @@ -0,0 +1,99 @@ +/** + * @file TortuosityBase.cpp + * Base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ + +#include "TortuosityMaxwell.h" +#include "ctexceptions.h" + +#include + +namespace Cantera { + + //==================================================================================================================== + // Default constructor + TortuosityMaxwell::TortuosityMaxwell(doublereal relativeConductivities) : + TortuosityBase(), + relativeConductivities_(relativeConductivities) + { + } + //==================================================================================================================== + // Copy Constructor + /* + * @param right Object to be copied + */ + TortuosityMaxwell::TortuosityMaxwell(const TortuosityMaxwell &right) : + TortuosityBase(), + relativeConductivities_(right.relativeConductivities_) + { + *this = right; + } + //==================================================================================================================== + // Default destructor for TortuosityMaxwell + TortuosityMaxwell::~TortuosityMaxwell() { + + } + //==================================================================================================================== + // Assignment operator + /* + * @param right Object to be copied + */ + TortuosityMaxwell & TortuosityMaxwell::operator=(const TortuosityMaxwell &right) { + if (&right == this) { + return *this; + } + TortuosityBase::operator=(right); + + relativeConductivities_ = right.relativeConductivities_; + + return *this; + } + //==================================================================================================================== + // Duplication operator + /* + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + TortuosityBase * TortuosityMaxwell::duplMyselfAsTortuosityBase() const { + TortuosityMaxwell * tb = new TortuosityMaxwell(*this); + return dynamic_cast(tb); + } + //==================================================================================================================== + // The tortuosity factor models the effective increase in the diffusive transport length. + /* + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + */ + doublereal TortuosityMaxwell::tortuosityFactor(doublereal porosity) { + return McMillanFactor(porosity) / porosity; + } + //==================================================================================================================== + // The McMillan number is the ratio of the flux-like variable to the value it would have without porous flow. + /* + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + doublereal TortuosityMaxwell::McMillanFactor(doublereal porosity) { + doublereal tmp = 1 + 3 * ( 1.0 - porosity ) * ( relativeConductivities_ - 1.0 ) / ( relativeConductivities_ + 2 ); + return tmp; + } + //==================================================================================================================== +} diff --git a/Cantera/src/transport/TortuosityMaxwell.h b/Cantera/src/transport/TortuosityMaxwell.h new file mode 100644 index 000000000..861145fad --- /dev/null +++ b/Cantera/src/transport/TortuosityMaxwell.h @@ -0,0 +1,118 @@ +/** + * @file TortuosityBase.h + * Virtual base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ +#ifndef CT_TORTUOSITYBRUGGEMAN_H +#define CT_TORTUOSITYBRUGGEMAN_H + +#include "TortuosityBase.h" + + +namespace Cantera { + + //! Maxwell model for tortuosity + /*! + * + * This class implements transport coefficient corrections + * appropriate for porous media with a dispersed phase. + * This model goes back to Maxwell. The formula for the + * conductivity is expressed in terms of the volume fraction + * of the continuous phase, \f$ \phi \f$, and the relative + * conductivities of the dispersed and continuous phases, + * \f$ r = \kappa_d / \kappa_0 \f$. For dilute particle + * suspensions the effective conductivity is + * + * \f[ + * \kappa / \kappa_0 = 1 + 3 ( 1 - \phi ) ( r - 1 ) / ( r + 2 ) + * + O(\phi^2) + * \f] + * + * The class is derived from the TortuosityBase class. + * + */ + class TortuosityMaxwell : public TortuosityBase { + + public: + //! Default constructor uses Maxwelln exponent of 1.5 + /*! + * @param setPower Exponent in the Maxwell factor. The default is 1.5 + */ + TortuosityMaxwell(double relativeConductivites = 0.0); + + //! Copy Constructor + /*! + * @param right Object to be copied + */ + TortuosityMaxwell(const TortuosityMaxwell &right); + + //! Default destructor for TortuosityMaxwell + virtual ~TortuosityMaxwell(); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + TortuosityMaxwell & operator=(const TortuosityMaxwell &right); + + //! Duplication operator + /*! + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + virtual TortuosityBase * duplMyselfAsTortuosityBase() const; + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /*! + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + * + */ + virtual doublereal tortuosityFactor(doublereal porosity); + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /** + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + virtual doublereal McMillanFactor(doublereal porosity); + + + protected: + + //! Relative conductivities of the dispersed and continuous phases, + /*! + * + * \f[ + * \code{relativeConductivites_} = \kappa_d / \kappa_0 + * \f] + */ + doublereal relativeConductivities_; + + }; + + + +} + +#endif + diff --git a/Cantera/src/transport/TortuosityPercolation.cpp b/Cantera/src/transport/TortuosityPercolation.cpp new file mode 100644 index 000000000..49f0f4724 --- /dev/null +++ b/Cantera/src/transport/TortuosityPercolation.cpp @@ -0,0 +1,105 @@ +/** + * @file TortuosityPercolation.cpp + * Base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ + +#include "TortuosityPercolation.h" +#include "ctexceptions.h" + +#include + +namespace Cantera { + + //==================================================================================================================== + // Default constructor + TortuosityPercolation::TortuosityPercolation(double percolationThreshold, double conductivityExponent) : + TortuosityBase(), + percolationThreshold_(percolationThreshold), + conductivityExponent_(conductivityExponent) + { + + } + //==================================================================================================================== + // Copy Constructor + /* + * @param right Object to be copied + */ + TortuosityPercolation::TortuosityPercolation(const TortuosityPercolation &right) : + TortuosityBase(), + percolationThreshold_(right.percolationThreshold_), + conductivityExponent_(right.conductivityExponent_) + { + *this = right; + } + //==================================================================================================================== + // Default destructor for TortuosityPercolation + TortuosityPercolation::~TortuosityPercolation() { + + } + //==================================================================================================================== + // Assignment operator + /* + * @param right Object to be copied + */ + TortuosityPercolation & TortuosityPercolation::operator=(const TortuosityPercolation &right) { + if (&right == this) { + return *this; + } + TortuosityBase::operator=(right); + + percolationThreshold_ = right.percolationThreshold_; + conductivityExponent_ = right.conductivityExponent_; + + return *this; + } + //==================================================================================================================== + // Duplication operator + /* + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + TortuosityBase * TortuosityPercolation::duplMyselfAsTortuosityBase() const { + TortuosityPercolation * tb = new TortuosityPercolation(*this); + return dynamic_cast(tb); + } + //==================================================================================================================== + // The tortuosity factor models the effective increase in the diffusive transport length. + /* + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + */ + doublereal TortuosityPercolation::tortuosityFactor(doublereal porosity) { + return McMillanFactor(porosity) / porosity; + } + //==================================================================================================================== + // The McMillan number is the ratio of the flux-like variable to the value it would have without porous flow. + /* + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + doublereal TortuosityPercolation::McMillanFactor(doublereal porosity) { + doublereal tmp = pow(((porosity - percolationThreshold_) + / ( 1.0 - percolationThreshold_ )) , + conductivityExponent_); + return tmp; + } + //==================================================================================================================== +} diff --git a/Cantera/src/transport/TortuosityPercolation.h b/Cantera/src/transport/TortuosityPercolation.h new file mode 100644 index 000000000..fd11f9ec2 --- /dev/null +++ b/Cantera/src/transport/TortuosityPercolation.h @@ -0,0 +1,108 @@ +/** + * @file TortuosityBase.h + * Virtual base class to compute the increase in diffusive path length associated with + * tortuous path diffusion through, for example, porous media. + */ + +/* + * 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. + */ + +/* + * $Revision: 572 $ + * $Date: 2010-08-13 20:21:57 -0600 (Fri, 13 Aug 2010) $ + */ +#ifndef CT_TORTUOSITYPERCOLATION_H +#define CT_TORTUOSITYPERCOLATION_H + +#include "TortuosityBase.h" + + +namespace Cantera { + + //! This class implements transport coefficient corrections + //! appropriate for porous media where percollation theory applies. + /*! + * + * + */ + class TortuosityPercolation : public TortuosityBase { + + public: + //! Default constructor uses Percolationn exponent of 1.5 + /*! + * @param setPower Exponent in the Percolation factor. The default is 1.5 + */ + TortuosityPercolation(double percolationThreshold = 0.4, double conductivityExponent = 2.0); + + //! Copy Constructor + /*! + * @param right Object to be copied + */ + TortuosityPercolation(const TortuosityPercolation &right); + + //! Default destructor for TortuosityPercolation + virtual ~TortuosityPercolation(); + + //! Assignment operator + /*! + * @param right Object to be copied + */ + TortuosityPercolation & operator=(const TortuosityPercolation &right); + + //! Duplication operator + /*! + * @return Returns a pointer to a duplicate of the current object given a + * base class pointer + */ + virtual TortuosityBase * duplMyselfAsTortuosityBase() const; + + //! The tortuosity factor models the effective increase in the + //! diffusive transport length. + /*! + * This method returns \f$ 1/\tau^2 \f$ in the description of the flux + * + * \f$ C_T D_i \nabla X_i / \tau^2 \f$. + * + * + */ + virtual doublereal tortuosityFactor(doublereal porosity); + + //! The McMillan number is the ratio of the flux-like + //! variable to the value it would have without porous flow. + /*! + * The McMillan number combines the effect of toruosity + * and volume fraction of the transported phase. The net flux + * observed is then the product of the McMillan number and the + * non-porous transport rate. For a conductivity in a non-porous + * media, \f$ \kappa_0 \f$, the conductivity in the porous media + * would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$. + */ + virtual doublereal McMillanFactor(doublereal porosity); + + + protected: + + //! Critical volume fraction / site density for percolation + double percolationThreshold_; + + //! Conductivity exponent + /*! + * The McMillan number (ratio of effective conductivity to non-porous conductivity) is + * \f[ \kappa/\kappa_0 = ( \phi - \phi_c )^\mu \f] + * where \f$ \mu \f$ is the conductivity exponent (typical values range from 1.6 to 2.0) and \f$ \phi_c \f$ + * is the percolation threshold. + */ + double conductivityExponent_; + + + }; + + + +} + +#endif + diff --git a/Cantera/src/transport/TransportBase.cpp b/Cantera/src/transport/TransportBase.cpp index f0c881907..f7a9a6fed 100644 --- a/Cantera/src/transport/TransportBase.cpp +++ b/Cantera/src/transport/TransportBase.cpp @@ -38,7 +38,8 @@ namespace Cantera { m_ready(false), m_nmin(0), m_index(-1), - m_nDim(ndim) + m_nDim(ndim), + m_velocityBasis(VB_MASSAVG) { } @@ -49,6 +50,7 @@ namespace Cantera { m_nmin = right.m_nmin; m_index = right.m_index; m_nDim = right.m_nDim; + m_velocityBasis = right.m_velocityBasis; } @@ -61,6 +63,7 @@ namespace Cantera { m_nmin = right.m_nmin; m_index = right.m_index; m_nDim = right.m_nDim; + m_velocityBasis = right.m_velocityBasis; return *this; } @@ -81,17 +84,15 @@ namespace Cantera { return m_index; } - /* - * Set an integer index number. This is for internal use of + /* Set an integer index number. This is for internal use of * Cantera, and may be removed in the future. */ void Transport::setIndex(int i) { m_index = i; } - //! Set the number of dimensions to be expected in flux expressions - /*! - * Internal memory will be set with this value + // Set the number of dimensions to be expected in flux expressions + /* Internal memory will be set with this value */ void Transport::setNDim(const int ndim) { m_nDim = ndim; @@ -100,8 +101,7 @@ namespace Cantera { - /* - * Set transport model parameters. This method may be + /* Set transport model parameters. This method may be * overloaded in subclasses to set model-specific parameters. */ void Transport::setParameters(const int type, const int k, @@ -142,4 +142,11 @@ namespace Cantera { "finalize has already been called."); } + //==================================================================================================================== + void Transport::getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes) { + err("getSpeciesFluxes"); + } + //==================================================================================================================== } diff --git a/Cantera/src/transport/TransportBase.h b/Cantera/src/transport/TransportBase.h index 46328c4e0..e605836ed 100644 --- a/Cantera/src/transport/TransportBase.h +++ b/Cantera/src/transport/TransportBase.h @@ -1,5 +1,10 @@ /** * @file TransportBase.h + * Headers for the Transport object, which is the virtual base class + * for all transport property evaluators and also includes the + * tranprops group definition + * (see \ref tranprops and \link Cantera::Transport Transport \endlink) . + * * Provides class Transport. */ @@ -12,7 +17,7 @@ /** - * @defgroup tranprops Transport Properties + * @defgroup tranprops Transport Properties for Species in Phases * * @ingroup phases * @@ -23,7 +28,7 @@ #define CT_TRANSPORTBASE_H #include "ThermoPhase.h" - +#include "DenseMatrix.h" namespace Cantera { @@ -31,6 +36,11 @@ namespace Cantera { class GasTransportParams; class LiquidTransportParams; + /*! + * \addtogroup tranprops + */ + //! \cond + const int CK_Mode = 10; // types of transport models that can be constructed @@ -48,26 +58,135 @@ namespace Cantera { const int cSimpleTransport = 770; const int cRadiativeTransport = 800; const int cWaterTransport = 721; + //! \endcond // forward reference class XML_Writer; + //! The diffusion fluxes must be referenced to a particular reference + //! fluid velocity. + /*! + * Most typical is to reference the diffusion fluxes to the mass averaged velocity, but + * referencing to the mole averaged velocity is suitable for some + * liquid flows, and referencing to a single species is suitable for + * solid phase transport within a lattice. Currently, the identity of the reference + * velocity is coded into each transport object as a typedef named VelocityBasis, which + * is equated to an integer. Negative values of this variable refer to mass or mole-averaged + * velocities. Zero or positive quantities refers to the reference + * velocity being referenced to a particular species. Below are the predefined constants + * for its value. + * + * - VB_MASSAVG Diffusion velocities are based on the mass averaged velocity + * - VB_MOLEAVG Diffusion velocities are based on the mole averaged velocities + * - VB_SPECIES_0 Diffusion velocities are based on the relative motion wrt species 0 + * - ... + * - VB_SPECIES_3 Diffusion velocities are based on the relative motion wrt species 3 + * + * @ingroup tranprops + */ + typedef int VelocityBasis; - /** - * Base class for transport property managers. All classes that - * compute transport properties derive from this class. Class - * Transport is meant to be used as a base class only. It is - * possible to instantiate it, but its methods throw exceptions if - * called. + /*! + * \addtogroup tranprops + */ + //@{ + //! Diffusion velocities are based on the mass averaged velocity + const VelocityBasis VB_MASSAVG = -1; + //! Diffusion velocities are based on the mole averaged velocities + const VelocityBasis VB_MOLEAVG = -2; + //! Diffusion velocities are based on the relative motion wrt species 0 + const VelocityBasis VB_SPECIES_0 = 0; + //! Diffusion velocities are based on the relative motion wrt species 1 + const VelocityBasis VB_SPECIES_1 = 1; + //! Diffusion velocities are based on the relative motion wrt species 2 + const VelocityBasis VB_SPECIES_2 = 2; + //! Diffusion velocities are based on the relative motion wrt species 3 + const VelocityBasis VB_SPECIES_3 = 3; + //@} + + //! Base class for transport property managers. + /*! + * All classes that compute transport properties for a single phase + * derive from this class. Class + * %Transport is meant to be used as a base class only. It is + * possible to instantiate it, but its methods throw exceptions if + * called. + * + * Note, transport properties for multiphase situations have yet to be + * fully developed within Cantera. + * + * All member functions are virtual, unless otherwise stated. + * + *
+ *

Relationship of the %Transport class to the %ThermoPhase Class

+ *
+ * + * This section describes how calculations are carried out within + * the %Transport class. The %Transport class and derived classes of the + * the %Transport class necessarily use the %ThermoPhase class to obtain + * the list of species and the thermodynamic state of the phase. + * + * No state information is storred within %Transport classes. + * Queries to the underlying ThermoPhase object must be made to obtain + * the state of the system. + * + * An exception to this however is the state information concerning the + * the gradients of variables. This information is not storred within + * the ThermoPhase objects. It may be collected within the Transport objects. + * In fact, the meaning of const operations within the Transport class + * refers to calculations which do not change the state of the + * system nor the state of the first order gradients of the system. + * + * When a const operation is evoked within the Transport class, it is + * also implicitly assumed that the underlying state within the ThermoPhase + * object has not changed its values. + * + * + *
+ *

Diffusion Fluxes and their Relationship to Reference Velocities

+ *
+ * + * The diffusion fluxes must be referenced to a particular reference + * fluid velocity. + * Most typical is to reference the diffusion fluxes to the mass averaged velocity, but + * referencing to the mole averaged velocity is suitable for some + * liquid flows, and referencing to a single species is suitable for + * solid phase transport within a lattice. Currently, the identity of the reference + * velocity is coded into each transport object as a typedef named VelocityBasis, which + * is equated to an integer. Negative values of this variable refer to mass or mole-averaged + * velocities. Zero or positive quantities refers to the reference + * velocity being referenced to a particular species. Below are the predefined constants + * for its value. + * + * - VB_MASSAVG Diffusion velocities are based on the mass averaged velocity + * - VB_MOLEAVG Diffusion velocities are based on the mole averaged velocities + * - VB_SPECIES_0 Diffusion velocities are based on the relative motion wrt species 0 + * - ... + * - VB_SPECIES_3 Diffusion velocities are based on the relative motion wrt species 3 + * + * All transport managers specify a default reference velocity in their default constructors. + * All gas phase transport managers by default specify the mass-averaged velocity as their + * reference velocities. + * + * + * @todo Provide a general mechanism to store the gradients of state variables + * within the system. + * + * @ingroup tranprops */ class Transport { public: - - /** - * Constructor. New transport managers should be created using + //! Constructor. + /*! + * New transport managers should be created using * TransportFactory, not by calling the constructor directly. + * + * @param thermo Pointer to the ThermoPhase class representing + * this phase. + * @param ndim Dimension of the flux vector used in the calculation. + * * @see TransportFactory */ Transport(thermo_t* thermo=0, int ndim = 1); @@ -103,14 +222,16 @@ namespace Cantera { // Note ->need working copy constructors and operator=() functions for all first virtual Transport *duplMyselfAsTransport() const; - - /** - * Transport model. The transport model is the set of - * equations used to compute the transport properties. This + + //! Transport model. + /*! + * The transport model is the set of equations used to compute the transport properties. This * virtual method returns an integer flag that identifies the * transport model implemented. The base class returns 0. */ - virtual int model() const {return 0;} + virtual int model() const { + return 0; + } /** * Phase object. Every transport manager is designed to compute @@ -119,7 +240,9 @@ namespace Cantera { * returns a reference to the object representing the phase * itself. */ - thermo_t& thermo() { return *m_thermo; } + thermo_t& thermo() { + return *m_thermo; + } /** @@ -127,26 +250,44 @@ namespace Cantera { */ bool ready(); - /** - * Returns an integer index number. This is for internal use - * of Cantera, and may be removed in the future. + + //! Returns an integer index number. + /*! + * This is for internal use + * of Cantera, and may be removed in the future. + * + * @return Returns the index number + * + * @deprecated */ int index() const ; - /** - * Set an integer index number. This is for internal use of - * Cantera, and may be removed in the future. + //! Set an integer index number. + /*! + * This is for internal use of + * Cantera, and may be removed in the future. + * + * @param i index value + * + * @deprecated */ void setIndex(int i); //! Set the number of dimensions to be expected in flux expressions /*! - * Internal memory will be set with this value + * Internal memory will be set with this value. + * + * @param ndim Number of dimensions in flux expressions */ void setNDim(const int ndim); - //! return the number of dimensions - int nDim() const { return m_nDim; } + //! Return the number of dimensions in flux expressions + /*! + * @return Returns the number of dimensions + */ + int nDim() const { + return m_nDim; + } /** * @name Transport Properties @@ -178,6 +319,93 @@ namespace Cantera { virtual doublereal bulkViscosity() { return err("bulkViscosity"); } + /** + * The ionic conducitivity in 1/ohm/m. + */ + virtual doublereal ionConductivity() + { return err("ionConductivity"); } + + //! Returns the pure species ionic conducitivity + /*! + * The units are 1/ohm/m and the length is the number of species + * + * @param ionCond Vector of ionic conductivities + */ + virtual void getSpeciesIonConductivity(doublereal* const ionCond) + { err("getSpeciesIonConductivity"); } + + + //! Returns the pointer to the mobility ratios of the species in the phase + /*! + * + * @param mobRat Returns a matrix of mobility ratios for the current problem. + * The mobility ratio mobRat(i,j) is defined as the ratio of the + * mobility of species i to species j. + * + * mobRat(i,j) = mu_i / mu_j + * + * It is returned in fortran-ordering format. ie. it is returned as mobRat[k], where + * + * k = j * nsp + i + * + * The size of mobRat must be at least equal to nsp*nsp + * + * @deprecated This doesn't seem to be the essential input; it should just be the mobility. + */ + virtual void mobilityRatio(double* mobRat) + { err("mobilityRatio"); } + + //! Returns the pure species limit of the mobility ratios + /*! + * The value is dimensionless and the length is the number of species + * + * @param mobRat Vector of mobility ratios + */ + virtual void getSpeciesMobilityRatio(double** mobRat) + { err("getSpeciesMobilityRatio"); } + + //! Returns the self diffusion coefficients of the species in the phase + /*! + * The self diffusion coefficient is the diffusion coefficient of a tracer species + * at the current temperature and composition of the species. Therefore, + * the dilute limit of transport is assumed for the tracer species. + * The effective formula may be calculated from the stefan-maxwell formulation by + * adding another row for the tracer species, assigning all D's to be equal + * to the respective species D's, and then taking the limit as the + * tracer species mole fraction goes to zero. The corresponding flux equation + * for the tracer species k in units of kmol m-2 s-1 is. + * + * \f[ + * J_k = - D^{sd}_k \frac{C_k}{R T} \nabla \mu_k + * \f] + * + * The derivative is taken at constant T and P. + * + * The self diffusion calculation is handled by subclasses of + * LiquidTranInteraction as specified in the input file. + * These in turn employ subclasses of LTPspecies to + * determine the individual species self diffusion coeffs. + * + * @param selfDiff Vector of self-diffusion coefficients + * Length = number of species in phase + * units = m**2 s-1 + */ + virtual void selfDiffusion(doublereal * const selfDiff) + { err("selfDiffusion"); } + + + //! Returns the pure species self diffusion in solution of each species + /*! + * The pure species molar volumes are evaluated using the + * appropriate subclasses of LTPspecies as specified in the + * input file. + * + * @param selfDiff array of length "number of species" + * to hold returned self diffusion coeffs. + */ + virtual void getSpeciesSelfDiffusion(double** selfDiff) + { err("getSpeciesSelfDiffusion"); } + //! Returns the mixture thermal conductivity in W/m/K. /*! * Units are in W / m K or equivalently kg m / s3 K @@ -237,36 +465,80 @@ namespace Cantera { //@} + + //! Compute the mixture electrical conductivity (S m-1) at the current + //! conditions of the phase (Siemens m-1) + /*! + * The electrical conductivity, \f$ \sigma \f$, relates the electric + * current density, J, to the electric field, E. + * + * \f[ + * \vec{J} = \sigma \vec{E} + * \f] + * + * We assume here that the mixture electrical conductivity is an + * isotropic quantity, at this stage. Tensors may be included at a + * later time. + * + * The conductivity is the reciprocal of the resistivity. + * + * The units are Siemens m-1, where 1 S = 1 A / volt = 1 s^3 A^2 /kg /m^2 + */ + virtual doublereal getElectricConduct() + { + err("getElectricConduct"); return 0.0; + } + //! Compute the electric current density in A/m^2 + /*! + * Calculates the electric current density as a vector, given + * the gradients of the field variables. + * + * @param ndim The number of spatial dimensions (1, 2, or 3). + * @param grad_T The temperature gradient (ignored in this model). + * @param ldx Leading dimension of the grad_X array. + * @param grad_X The gradient of the mole fraction + * @param ldf Leading dimension of the grad_V and current vectors. + * @param grad_V The electrostatic potential gradient. + * @param current The electric current in A/m^2. This is a vector of length ndim + */ + virtual void getElectricCurrent(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_V, + doublereal* current) + { + err("getElectricCurrent"); + } - //! Get the species diffusive mass fluxes wrt to - //! the mass averaged velocity, + + //! Get the species diffusive mass fluxes wrt to the specified solution averaged velocity, //! given the gradients in mole fraction and temperature /*! * Units for the returned fluxes are kg m-2 s-1. + * + * Usually the specified solution average velocity is the mass averaged velocity. + * This is changed in some subclasses, however. * - * @param ndim Number of dimensions in the flux expressions - * @param grad_T Gradient of the temperature - * (length = ndim) - * @param ldx Leading dimension of the grad_X array - * (usually equal to m_nsp but not always) - * @param grad_X Gradients of the mole fraction - * Flat vector with the m_nsp in the inner loop. - * length = ldx * ndim - * @param ldf Leading dimension of the fluxes array - * (usually equal to m_nsp but not always) - * @param fluxes Output of the diffusive mass fluxes - * Flat vector with the m_nsp in the inner loop. - * length = ldx * ndim + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param fluxes Output of the diffusive mass fluxes + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim */ - virtual void getSpeciesFluxes(int ndim, - const doublereal* grad_T, - int ldx, - const doublereal* grad_X, - int ldf, - doublereal* fluxes) { - err("getSpeciesFluxes"); - } + virtual void getSpeciesFluxes(int ndim, const doublereal * const grad_T, + int ldx, const doublereal * const grad_X, + int ldf, doublereal * const fluxes); //! Get the species diffusive mass fluxes wrt to //! the mass averaged velocity, @@ -301,87 +573,217 @@ namespace Cantera { getSpeciesFluxes( ndim, grad_T, ldx, grad_X, ldf, fluxes ); } - /** - * Get the molar fluxes [kmol/m^2/s], given the thermodynamic - * state at two nearby points. - * @param state1 Array of temperature, density, and mass - * fractions for state 1. - * @param state2 Array of temperature, density, and mass - * fractions for state 2. - * @param delta Distance from state 1 to state 2 (m). - */ - virtual void getMolarFluxes(const doublereal* state1, - const doublereal* state2, doublereal delta, - doublereal* fluxes) { err("getMolarFluxes"); } + + //! Get the species diffusive velocities wrt to + //! the mass averaged velocity, + //! given the gradients in mole fraction and temperature + /*! + * Units for the returned velocities are m s-1 + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param Vdiff Output of the diffusive velocities wrt the mass-averaged + * velocity + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * units are m / s. + */ + virtual void getSpeciesVdiff(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + doublereal* Vdiff) { + err("getSpeciesVdiff"); + } - /** - * Get the mass fluxes [kg/m^2/s], given the thermodynamic - * state at two nearby points. + //! Get the species diffusive velocities wrt to the mass averaged velocity, + //! given the gradients in mole fraction, temperature, + //! and electrostatic potential. + /*! + * Units for the returned velocities are m s-1. + * + * @param ndim Number of dimensions in the flux expressions + * @param grad_T Gradient of the temperature + * (length = ndim) + * @param ldx Leading dimension of the grad_X array + * (usually equal to m_nsp but not always) + * @param grad_X Gradients of the mole fraction + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * @param ldf Leading dimension of the fluxes array + * (usually equal to m_nsp but not always) + * @param grad_Phi Gradients of the electrostatic potential + * (length = ndim) + * @param Vdiff Output of the diffusive velocities wrt the mass-averaged velocity + * Flat vector with the m_nsp in the inner loop. + * length = ldx * ndim + * units are m / s. + */ + virtual void getSpeciesVdiffES(int ndim, + const doublereal* grad_T, + int ldx, + const doublereal* grad_X, + int ldf, + const doublereal* grad_Phi, + doublereal* Vdiff) { + getSpeciesVdiff( ndim, grad_T, ldx, grad_X, ldf, Vdiff ); + } + + + //! Get the molar fluxes [kmol/m^2/s], given the thermodynamic + //! state at two nearby points. + /*! + * @param state1 Array of temperature, density, and mass + * fractions for state 1. + * @param state2 Array of temperature, density, and mass + * fractions for state 2. + * @param delta Distance from state 1 to state 2 (m). + * @param cfluxes Output array containing the diffusive molar fluxes of species + * from state1 to state2. This is a flat vector with the + * m_nsp in the inner loop. + * length = ldx * ndim. + * Units are [kmol/m^2/s]. + */ + virtual void getMolarFluxes(const doublereal * const state1, + const doublereal * const state2, const doublereal delta, + doublereal * const cfluxes) { + err("getMolarFluxes"); + } + + + //! Get the mass fluxes [kg/m^2/s], given the thermodynamic + //! state at two nearby points. + /*! * @param state1 Array of temperature, density, and mass * fractions for state 1. * @param state2 Array of temperature, density, and mass * fractions for state 2. * @param delta Distance from state 1 to state 2 (m). + * @param mfluxes Output array containing the diffusive mass fluxes of species + * from state1 to state2. This is a flat vector with the + * m_nsp in the inner loop. + * length = ldx * ndim. + * Units are [kg/m^2/s]. */ virtual void getMassFluxes(const doublereal* state1, const doublereal* state2, doublereal delta, - doublereal* fluxes) { err("getMassFluxes"); } - - /** - * Thermal diffusion coefficients [kg/m/sec]. + doublereal* mfluxes) { + err("getMassFluxes"); + } + + //! Return a vector of Thermal diffusion coefficients [kg/m/sec]. + /*! * The thermal diffusion coefficient \f$ D^T_k \f$ is defined - * so that the diffusive mass flux of species k induced by the - * local temperature gradient is \f[ M_k J_k = -D^T_k \nabla - * \ln T. \f]. The thermal diffusion coefficient can be either - * positive or negative. + * so that the diffusive mass flux of species k induced by the + * local temperature gradient is given by the following formula + * + * \f[ + * M_k J_k = -D^T_k \nabla \ln T. + * \f] + * + * The thermal diffusion coefficient can be either positive or negative. * - * @param dt on return, dt will contain the species thermal - * diffusion coefficients. Dimension dt at least as large as - * the number of species. + * @param dt On return, dt will contain the species thermal + * diffusion coefficients. Dimension dt at least as large as + * the number of species. Units are kg/m/s. */ - virtual void getThermalDiffCoeffs(doublereal* const dt) - { err("getThermalDiffCoeffs"); } + virtual void getThermalDiffCoeffs(doublereal* const dt) { + err("getThermalDiffCoeffs"); + } - //! Returns the matrix of binary diffusion coefficients [m^2/s]. + //! Returns the matrix of binary diffusion coefficients [m^2/s]. /*! * @param ld Inner stride for writing the two dimension diffusion * coefficients into a one dimensional vector * @param d Diffusion coefficient matrix (must be at least m_k * m_k * in length. */ - virtual void getBinaryDiffCoeffs(const int ld, doublereal* const d) - { err("getBinaryDiffCoeffs"); } + virtual void getBinaryDiffCoeffs(const int ld, doublereal* const d) { + err("getBinaryDiffCoeffs"); + } - - /** - * Multicomponent diffusion coefficients. Units: [m^2/s]. If - * the transport manager implements a multicomponent diffusion + + //! Return the Multicomponent diffusion coefficients. Units: [m^2/s]. + /*! + * If the transport manager implements a multicomponent diffusion * model, then this method returns the array of multicomponent * diffusion coefficients. Otherwise it throws an exception. + * + * @param ld The dimension of the inner loop of d (usually equal to m_nsp) + * @param d flat vector of diffusion coefficients, fortran ordering. + * d[ld*j+i] is the D_ij diffusion coefficient (the diffusion + * coefficient for species i due to species j). */ virtual void getMultiDiffCoeffs(const int ld, doublereal* const d) { err("getMultiDiffCoeffs"); } + //! Returns a vector of mixture averaged diffusion coefficients /** * Mixture-averaged diffusion coefficients [m^2/s]. If the + * * transport manager implements a mixture-averaged diffusion * model, then this method returns the array of * mixture-averaged diffusion coefficients. Otherwise it * throws an exception. + * + * @param d Return vector of mixture averaged diffusion coefficients + * Units = m2/s. Length = n_sp */ virtual void getMixDiffCoeffs(doublereal* const d) { err("getMixDiffCoeffs"); } - /** - * Set transport model parameters. This method may be - * overloaded in subclasses to set model-specific parameters. + //! Set model parameters for derived classes + /*! + * This method may be derived in subclasses to set model-specific parameters. + * The primary use of this class is to set parameters while in the middle of a calculation + * without actually having to dynamically cast the base Transport pointer. + * + * @param type Specifies the type of parameters to set + * 0 : Diffusion coefficient + * 1 : Thermal Conductivity + * The rest are currently unused. + * @param k Species index to set the parameters on + * @param p Vector of parameters. The length of the vector + * varies with the parameterization */ - virtual void setParameters(const int type, const int k, - const doublereal* const p); + virtual void setParameters(const int type, const int k, const doublereal* const p); + //! Sets the velocity basis + /*! + * What the transport object does with this parameter is up to the + * individual operator. Currently, this is not functional for most + * transport operators including all of the gas-phase operators. + * + * @param ivb Species the velocity basis + */ + void setVelocityBasis(VelocityBasis ivb) + { + m_velocityBasis = ivb; + } + + //! Gets the velocity basis + /*! + * What the transport object does with this parameter is up to the + * individual operator. Currently, this is not functional for most + * transport operators including all of the gas-phase operators. + * + * @return Returns the velocity basis + */ + VelocityBasis getVelocityBasis( ) const { + return m_velocityBasis; + } friend class TransportFactory; @@ -400,29 +802,46 @@ namespace Cantera { //virtual bool init(TransportParams& tr) //{ err("init"); return false; } - /** - * Called by TransportFactory to set parameters. + + //! Called by TransportFactory to set parameters. + /*! + * This is called by classes that use the gas phase parameter + * list to initialize themselves. + * + * @param tr Reference to the parameter list that will be used + * to initialize the class */ - virtual bool initGas( GasTransportParams& tr ) - { err("initGas"); return false; } + virtual bool initGas(GasTransportParams& tr) + { + err("initGas"); + return false; + } - /** - * Called by TransportFactory to set parameters. - */ - virtual bool initLiquid( LiquidTransportParams& tr ) - { err("initLiquid"); return false; } - - - - - /** - * Set the phase object. + //! Called by TransportFactory to set parameters. + /*! + * This is called by classes that use the liquid phase parameter + * list to initialize themselves. + * + * @param tr Reference to the parameter list that will be used + * to initialize the class */ + virtual bool initLiquid(LiquidTransportParams& tr) + { + err("initLiquid"); + return false; + } + + //! Specifies the %ThermPhase object. + /*! + * @param thermo Reference to the ThermoPhase object that + * the transport object will use + */ void setThermo(thermo_t& thermo); - - /** - * Enable for use. Once finalize() has been called, the + + //! Enable the transport object for use. + /*! + * Once finalize() has been called, the * transport manager should be ready to compute any supported * transport property, and no further modifications to the * model parameters should be made. @@ -431,19 +850,32 @@ namespace Cantera { //@} + //! pointer to the object representing the phase + thermo_t* m_thermo; - thermo_t* m_thermo; ///< pointer to the object representing the phase - bool m_ready; ///< true if finalize has been called - size_t m_nmin; ///< number of species + //! true if finalize has been called + bool m_ready; + + //! Number of species + size_t m_nmin; + + //! Value of the internal index + /*! + * @deprecated + */ int m_index; //! Number of dimensions used in flux expresions int m_nDim; + //! Velocity basis from which diffusion velocities are computed. + //! Defaults to the mass averaged basis = -2 + int m_velocityBasis; private: - /** + //! Error routine + /*! * Throw an exception if a method of this class is * invoked. This probably indicates that a transport manager * is being used that does not implement all virtual methods, @@ -454,11 +886,19 @@ namespace Cantera { * meaningless. If the application invokes the viscosity() * method, the base class method will be called, resulting in * an exception being thrown. + * + * @param msg Descriptive message string to add to the error report + * + * @return returns a double, though we will never get there */ doublereal err(std::string msg) const; }; + //! General definition for the transport class + /*! + * \ingroup tranprops + */ typedef Transport transport_t; } diff --git a/Cantera/src/transport/TransportFactory.cpp b/Cantera/src/transport/TransportFactory.cpp index 3fce58ea3..0b82466a8 100644 --- a/Cantera/src/transport/TransportFactory.cpp +++ b/Cantera/src/transport/TransportFactory.cpp @@ -6,6 +6,10 @@ * * */ +/* + * $Revision$ + * $Date$ + */ // turn off warnings under Windows #ifdef WIN32 @@ -37,86 +41,63 @@ #include "XML_Writer.h" #include "TransportParams.h" #include "LiquidTransportParams.h" +#include "LiquidTranInteraction.h" #include "global.h" #include "IdealGasPhase.h" #include "ctml.h" #include +#include using namespace std; -/** - * polynomial degree used for fitting collision integrals - * except in CK mode, where the degree is 6. - */ + +//! polynomial degree used for fitting collision integrals +//! except in CK mode, where the degree is 6. #define COLL_INT_POLY_DEGREE 8 - namespace Cantera { + /////////////////////////// constants ////////////////////////// + //@ \cond + const doublereal ThreeSixteenths = 3.0/16.0; + const doublereal TwoOverPi = 2.0/Pi; + const doublereal FiveThirds = 5.0/3.0; + //@ \endcond + + //==================================================================================================================== TransportFactory* TransportFactory::s_factory = 0; + #if defined(THREAD_SAFE_CANTERA) + // declaration of static storage for the mutex boost::mutex TransportFactory::transport_mutex; #endif ////////////////////////// exceptions ///////////////////////// - /** - * Exception thrown if an error is encountered while reading the - * transport database. - */ + //==================================================================================================================== + //! Exception thrown if an error is encountered while reading the transport database class TransportDBError : public CanteraError { public: - TransportDBError(int linenum, string msg) - : CanteraError("getTransportData", - "error reading transport data: " - + msg + "\n") {} - }; - - - class NotImplemented : public CanteraError { - public: - NotImplemented(string method) : CanteraError("Transport", - "\n\n\n**** Method "+method+" not implemented. ****\n" - "(Did you forget to specify a transport model?)\n\n\n") {} - }; - - - /////////////////////////// constants ////////////////////////// - - const doublereal ThreeSixteenths = 3.0/16.0; - const doublereal TwoOverPi = 2.0/Pi; - const doublereal FiveThirds = 5.0/3.0; - - - TransportParams::~TransportParams(){ -#ifdef DEBUG_MODE - delete xml; -#endif - }; - - - /** - * getArrhenius() parses the xml element called Arrhenius. - * The Arrhenius expression is - * \f[ k = A T^(b) exp (-E_a / RT). \f] - */ - static void getArrhenius(const XML_Node& node, - doublereal& A, doublereal& b, doublereal& E) { - /* parse the children for the A, b, and E conponents. + //! Default constructor + /*! + * @param linenum inputs the line number + * @param msg String message to be sent to the user */ - A = getFloat(node, "A", "toSI"); - b = getFloat(node, "b"); - E = getFloat(node, "E", "actEnergy"); - E /= GasConstant; - } + TransportDBError(int linenum, std::string msg) : + CanteraError("getTransportData", "error reading transport data: " + msg + "\n") + { + } + }; + //==================================================================================================================== //////////////////// class TransportFactory methods ////////////// - - /** - * Calculate second-order corrections to binary diffusion + //==================================================================================================================== + // Second-order correction to the binary diffusion coefficients + /* + * Calculate second-order corrections to binary diffusion * coefficient pair (dkj, djk). At first order, the binary * diffusion coefficients are independent of composition, and * d(k,j) = d(j,k). But at second order, there is a weak @@ -126,17 +107,17 @@ namespace Cantera { * to produce the value correct to second order. The expressions * here are taken from Marerro and Mason, * J. Phys. Chem. Ref. Data, vol. 1, p. 3 (1972). - * - * @param t Temperature (K) - * @param tr Transport parameters - * @param k index of first species - * @param j index of second species - * @param xmk mole fraction of species k - * @param xmj mole fraction of species j - * @param fkj multiplier for d(k,j) - * @param fjk multiplier for d(j,k) - * - * @note This method is not used currently. + * + * @param t Temperature (K) + * @param tr Transport parameters + * @param k index of first species + * @param j index of second species + * @param xmk mole fraction of species k + * @param xmj mole fraction of species j + * @param fkj multiplier for d(k,j) + * @param fjk multiplier for d(j,k) + * + * @note This method is not used currently. */ void TransportFactory::getBinDiffCorrection(doublereal t, const GasTransportParams& tr, int k, int j, doublereal xk, doublereal xj, @@ -202,13 +183,19 @@ namespace Cantera { (p2*xk*xk + p1*xj*xj + p12*xk*xj)/ (q2*xk*xk + q1*xj*xj + q12*xk*xj); } - - - /** + //============================================================================================================================= + // Corrections for polar-nonpolar binary diffusion coefficients + /* * Calculate corrections to the well depth parameter and the - * diamter for use in computing the binary diffusion coefficient + * diameter for use in computing the binary diffusion coefficient * of polar-nonpolar pairs. For more information about this * correction, see Dixon-Lewis, Proc. Royal Society (1968). + * + * @param i Species one - this is a bimolecular correction routine + * @param j species two - this is a bimolecular correction routine + * @param tr Database of species properties read in from the input xml file. + * @param f_eps Multiplicative correction factor to be applied to epsilon(i,j) + * @param f_sigma Multiplicative correction factor to be applied to diam(i,j) */ void TransportFactory::makePolarCorrections(int i, int j, const GasTransportParams& tr, doublereal& f_eps, doublereal& f_sigma) { @@ -234,18 +221,17 @@ namespace Cantera { f_sigma = pow(xi, -1.0/6.0); f_eps = xi*xi; } - - /** - * TransportFactory(): default constructor - * - * The default constructor for this class sets up - * m_models[], a mapping between the string name - * for a transport model and the integer name. - */ + //============================================================================================================================= + /* + TransportFactory(): default constructor + + The default constructor for this class sets up + m_models[], a mapping between the string name + for a transport model and the integer name. + */ TransportFactory::TransportFactory() : m_verbose(false), m_integrals(0) - { m_models["Mix"] = cMixtureAveraged; m_models["Multi"] = cMulticomponent; @@ -260,17 +246,41 @@ namespace Cantera { m_models["None"] = None; //m_models["Radiative"] = cRadiative; + m_tranPropMap["viscostiy"] = TP_VISCOSITY; + m_tranPropMap["ionConductivity"] = TP_IONCONDUCTIVITY; + m_tranPropMap["mobilityRatio"] = TP_MOBILITYRATIO; + m_tranPropMap["selfDiffusion"] = TP_SELFDIFFUSION; + m_tranPropMap["thermalConductivity"] = TP_THERMALCOND; + m_tranPropMap["speciesDiffusivity"] = TP_DIFFUSIVITY; + m_tranPropMap["hydrodynamicRadius"] = TP_HYDRORADIUS; + m_tranPropMap["electricalConductivity"] = TP_ELECTCOND; + + m_LTRmodelMap[""] = LTP_TD_CONSTANT; + m_LTRmodelMap["constant"] = LTP_TD_CONSTANT; + m_LTRmodelMap["arrhenius"] = LTP_TD_ARRHENIUS; + m_LTRmodelMap["coeffs"] = LTP_TD_POLY; + m_LTRmodelMap["exptemp"] = LTP_TD_EXPT; + + m_LTImodelMap[""] = LTI_MODEL_NOTSET; + m_LTImodelMap["none"] = LTI_MODEL_NONE; + m_LTImodelMap["solvent"] = LTI_MODEL_SOLVENT; + m_LTImodelMap["moleFractions"] = LTI_MODEL_MOLEFRACS; + m_LTImodelMap["massFractions"] = LTI_MODEL_MASSFRACS; + m_LTImodelMap["logMoleFractions"] = LTI_MODEL_LOG_MOLEFRACS; + m_LTImodelMap["pairwiseInteraction"] = LTI_MODEL_PAIRWISE_INTERACTION; + m_LTImodelMap["stefanMaxwell_PPN"] = LTI_MODEL_STEFANMAXWELL_PPN; + m_LTImodelMap["moleFractionsExpT"] = LTI_MODEL_MOLEFRACS_EXPT; } - /** - * Destructor - * - * We do not delete statically created single instance of this - * class here, because it would create an infinite loop if - * destructor is called for that single instance. However, we do - * have a pointer to m_integrals that does need to be - * explicitly deleted. - */ + /* + Destructor + + We do not delete statically created single instance of this + class here, because it would create an infinite loop if + destructor is called for that single instance. However, we do + have a pointer to m_integrals that does need to be + explicitly deleted. + */ TransportFactory::~TransportFactory() { if (m_integrals) { delete m_integrals; @@ -278,9 +288,7 @@ namespace Cantera { } } - /** - * This static function deletes the statically allocated instance. - */ + // This static function deletes the statically allocated instance. void TransportFactory::deleteFactory() { #if defined(THREAD_SAFE_CANTERA) boost::mutex::scoped_lock lock(transport_mutex) ; @@ -291,10 +299,100 @@ namespace Cantera { } } - /** - * make one of several transport models, and return a base class - * pointer to it. - */ + /* + make one of several transport models, and return a base class + pointer to it. This method operates at the level of a + single transport property as a function of temperature + and possibly composition. + */ + LTPspecies* TransportFactory::newLTP(const XML_Node &trNode, std::string &name, + TransportPropertyType tp_ind, thermo_t* thermo) + { + LTPspecies* ltps = 0; + std::string model = lowercase(trNode["model"]); + switch (m_LTRmodelMap[model]) { + case LTP_TD_CONSTANT: + ltps = new LTPspecies_Const(trNode, name, tp_ind, thermo); + break; + case LTP_TD_ARRHENIUS: + ltps = new LTPspecies_Arrhenius(trNode, name, tp_ind, thermo); + break; + case LTP_TD_POLY: + ltps = new LTPspecies_Poly(trNode, name, tp_ind, thermo); + break; + case LTP_TD_EXPT: + ltps = new LTPspecies_ExpT(trNode, name, tp_ind, thermo); + break; + default: + throw CanteraError("newLTP","unknown transport model: " + model); + ltps = new LTPspecies(&trNode, name, tp_ind, thermo); + } + return ltps; + } + + /* + make one of several transport models, and return a base class + pointer to it. This method operates at the level of a + single mixture transport property. Individual species + transport properties are addressed by the LTPspecies + returned by newLTP + */ + LiquidTranInteraction* TransportFactory::newLTI(const XML_Node &trNode, + TransportPropertyType tp_ind, + LiquidTransportParams& trParam) { + LiquidTranInteraction* lti = 0; + + thermo_t* thermo = trParam.thermo; + + std::string model = trNode["model"]; + switch (m_LTImodelMap[model] ) { + case LTI_MODEL_SOLVENT: + lti = new LTI_Solvent(tp_ind); + lti->init(trNode, thermo ); + break; + case LTI_MODEL_MOLEFRACS: + lti = new LTI_MoleFracs(tp_ind ); + lti->init(trNode, thermo ); + break; + case LTI_MODEL_MASSFRACS: + lti = new LTI_MassFracs(tp_ind ); + lti->init(trNode, thermo ); + break; + case LTI_MODEL_LOG_MOLEFRACS: + lti = new LTI_Log_MoleFracs(tp_ind ); + lti->init(trNode, thermo ); + break; + case LTI_MODEL_PAIRWISE_INTERACTION: + lti = new LTI_Pairwise_Interaction(tp_ind ); + lti->init(trNode, thermo ); + lti->setParameters(trParam ); + break; + case LTI_MODEL_STEFANMAXWELL_PPN: + lti = new LTI_StefanMaxwell_PPN(tp_ind ); + lti->init(trNode, thermo ); + lti->setParameters(trParam ); + break; + case LTI_MODEL_STOKES_EINSTEIN: + lti = new LTI_StokesEinstein(tp_ind ); + lti->init(trNode, thermo ); + lti->setParameters(trParam ); + break; + case LTI_MODEL_MOLEFRACS_EXPT: + lti = new LTI_MoleFracs_ExpT(tp_ind ); + lti->init(trNode, thermo ); + break; + default: + // throw CanteraError("newLTI","unknown transport model: " + model ); + lti = new LiquidTranInteraction(tp_ind ); + lti->init(trNode, thermo ); + } + return lti; + } + + /* + make one of several transport models, and return a base class + pointer to it. + */ Transport* TransportFactory::newTransport(std::string transportModel, thermo_t* phase, int log_level) { @@ -362,10 +460,10 @@ namespace Cantera { return tr; } - /** - * make one of several transport models, and return a base class - * pointer to it. - */ + /* + make one of several transport models, and return a base class + pointer to it. + */ Transport* TransportFactory::newTransport(thermo_t* phase, int log_level) { XML_Node &phaseNode=phase->xml(); /* @@ -376,7 +474,7 @@ namespace Cantera { "no transport XML node"); } XML_Node& transportNode = phaseNode.child("transport"); - string transportModel = transportNode.attrib("model"); + std::string transportModel = transportNode.attrib("model"); if (transportModel == "") { throw CanteraError("TransportFactory::newTransport", "transport XML node doesn't have a model string"); @@ -384,14 +482,23 @@ namespace Cantera { return newTransport(transportModel, phase,log_level); } - - /** - * Prepare to build a new kinetic-theory-based transport manager - * for low-density gases. Uses polynomial fits to Monchick & Mason - * collision integrals. + //==================================================================================================================== + // Prepare to build a new kinetic-theory-based transport manager for low-density gases + /* + * This class fills up the GastransportParams structure for the current phase + * + * Uses polynomial fits to Monchick & Mason collision integrals. store then in tr + * + * @param flog Reference to the ostream for writing log info + * @param transport_database Reference to a vector of pointers containing the + * transport database for each species + * @param thermo Pointer to the %ThermoPhase object + * @param mode Mode -> Either it's CK_Mode, chemkin compatibility mode, or it is not + * We usually run with chemkin compatibility mode turned off. + * @param log_level log level + * @param tr GasTransportParams structure to be filled up with information */ - void TransportFactory::setupMM(std::ostream &flog, - const std::vector &transport_database, + void TransportFactory::setupMM(std::ostream &flog, const std::vector &transport_database, thermo_t* thermo, int mode, int log_level, GasTransportParams& tr) { // constant mixture attributes @@ -404,8 +511,7 @@ namespace Cantera { tr.mw.resize(nsp); tr.log_level = log_level; - copy(tr.thermo->molecularWeights().begin(), - tr.thermo->molecularWeights().end(), tr.mw.begin()); + copy(tr.thermo->molecularWeights().begin(), tr.thermo->molecularWeights().end(), tr.mw.begin()); tr.mode_ = mode; tr.epsilon.resize(nsp, nsp, 0.0); @@ -422,8 +528,7 @@ namespace Cantera { tr.eps.resize(nsp); XML_Node root, log; - getTransportData(transport_database, log, - tr.thermo->speciesNames(), tr); + getTransportData(transport_database, log, tr.thermo->speciesNames(), tr); int i, j; for (i = 0; i < nsp; i++) tr.poly[i].resize(nsp); @@ -434,47 +539,44 @@ namespace Cantera { DenseMatrix& diam = tr.diam; DenseMatrix& epsilon = tr.epsilon; - for (i = 0; i < nsp; i++) - { - for (j = i; j < nsp; j++) - { - // the reduced mass - tr.reducedMass(i,j) = - tr.mw[i] * tr.mw[j] / (Avogadro * (tr.mw[i] + tr.mw[j])); + for (i = 0; i < nsp; i++) { + for (j = i; j < nsp; j++) { + // the reduced mass + tr.reducedMass(i,j) = tr.mw[i] * tr.mw[j] / (Avogadro * (tr.mw[i] + tr.mw[j])); - // hard-sphere diameter for (i,j) collisions - diam(i,j) = 0.5*(tr.sigma[i] + tr.sigma[j]); + // hard-sphere diameter for (i,j) collisions + diam(i,j) = 0.5*(tr.sigma[i] + tr.sigma[j]); - // the effective well depth for (i,j) collisions - epsilon(i,j) = sqrt(tr.eps[i]*tr.eps[j]); + // the effective well depth for (i,j) collisions + epsilon(i,j) = sqrt(tr.eps[i]*tr.eps[j]); - // The polynomial fits of collision integrals vs. T* - // will be done for the T* from tstar_min to tstar_max - ts1 = Boltzmann * tr.tmin/epsilon(i,j); - ts2 = Boltzmann * tr.tmax/epsilon(i,j); - if (ts1 < tstar_min) tstar_min = ts1; - if (ts2 > tstar_max) tstar_max = ts2; + // The polynomial fits of collision integrals vs. T* + // will be done for the T* from tstar_min to tstar_max + ts1 = Boltzmann * tr.tmin/epsilon(i,j); + ts2 = Boltzmann * tr.tmax/epsilon(i,j); + if (ts1 < tstar_min) tstar_min = ts1; + if (ts2 > tstar_max) tstar_max = ts2; - // the effective dipole moment for (i,j) collisions - tr.dipole(i,j) = sqrt(tr.dipole(i,i)*tr.dipole(j,j)); + // the effective dipole moment for (i,j) collisions + tr.dipole(i,j) = sqrt(tr.dipole(i,i)*tr.dipole(j,j)); - // reduced dipole moment delta* (nondimensional) - doublereal d = diam(i,j); - tr.delta(i,j) = 0.5 * tr.dipole(i,j)*tr.dipole(i,j) - / (epsilon(i,j) * d * d * d); + // reduced dipole moment delta* (nondimensional) + doublereal d = diam(i,j); + tr.delta(i,j) = 0.5 * tr.dipole(i,j)*tr.dipole(i,j) + / (epsilon(i,j) * d * d * d); - makePolarCorrections(i, j, tr, f_eps, f_sigma); - tr.diam(i,j) *= f_sigma; - epsilon(i,j) *= f_eps; + makePolarCorrections(i, j, tr, f_eps, f_sigma); + tr.diam(i,j) *= f_sigma; + epsilon(i,j) *= f_eps; - // properties are symmetric - tr.reducedMass(j,i) = tr.reducedMass(i,j); - diam(j,i) = diam(i,j); - epsilon(j,i) = epsilon(i,j); - tr.dipole(j,i) = tr.dipole(i,j); - tr.delta(j,i) = tr.delta(i,j); - } + // properties are symmetric + tr.reducedMass(j,i) = tr.reducedMass(i,j); + diam(j,i) = diam(i,j); + epsilon(j,i) = epsilon(i,j); + tr.dipole(j,i) = tr.dipole(i,j); + tr.delta(j,i) = tr.delta(i,j); } + } // Chemkin fits the entire T* range in the Monchick and Mason tables, // so modify tstar_min and tstar_max if in Chemkin compatibility mode @@ -514,16 +616,21 @@ namespace Cantera { #endif } - - - /** - * Prepare to build a new transport manager for liquids assuming that - * viscosity transport data is provided in Arhennius form. + //==================================================================================================================== + // Prepare to build a new transport manager for liquids assuming that + // viscosity transport data is provided in Arhennius form. + /* + * @param flog Reference to the ostream for writing log info + * @param thermo Pointer to the %ThermoPhase object + * @param log_level log level + * @param trParam LiquidTransportParams structure to be filled up with information */ - void TransportFactory::setupLiquidTransport(std::ostream &flog, - const std::vector &transport_database, - thermo_t* thermo, int log_level, LiquidTransportParams& trParam) { + void TransportFactory::setupLiquidTransport(std::ostream &flog, thermo_t* thermo, int log_level, + LiquidTransportParams& trParam) { + const std::vector & species_database = thermo->speciesData(); + const XML_Node* phase_database = &thermo->xml(); + // constant mixture attributes trParam.thermo = thermo; trParam.nsp_ = trParam.thermo->nSpecies(); @@ -539,25 +646,44 @@ namespace Cantera { trParam.thermo->molecularWeights().end(), trParam.mw.begin()); // Resize all other vectors in trParam - trParam.visc_A.resize(nsp, 0.0); - trParam.visc_n.resize(nsp, 0.0); - trParam.visc_Tact.resize(nsp, 0.0); - trParam.thermCond_A.resize(nsp, 0.0); - trParam.thermCond_n.resize(nsp, 0.0); - trParam.thermCond_Tact.resize(nsp, 0.0); - trParam.visc_Eij.resize(nsp, nsp, 0.0); - trParam.visc_Sij.resize(nsp, nsp, 0.0); - trParam.hydroRadius.resize(nsp, 0.0); - trParam.A_k_cond.resize(nsp, 0.0); - trParam.B_k_cond.resize(nsp, 0.0); trParam.LTData.resize(nsp); + // Need to identify a method to obtain interaction matrices. + // This will fill LiquidTransportParams members visc_Eij, visc_Sij + // trParam.visc_Eij.resize(nsp,nsp); + // trParam.visc_Sij.resize(nsp,nsp); + trParam.thermalCond_Aij.resize(nsp,nsp); + trParam.diff_Dij.resize(nsp,nsp); + trParam.radius_Aij.resize(nsp,nsp); + XML_Node root, log; - getLiquidTransportData(transport_database, log, - trParam.thermo->speciesNames(), trParam); + // Note that getLiquidSpeciesTransportData just populates the pure species transport data. + getLiquidSpeciesTransportData(species_database, log, trParam.thermo->speciesNames(), trParam); + + // getLiquidInteractionsTransportData() populates the + // species-species interaction models parameters + // like visc_Eij + if (phase_database->hasChild("transport")) { + XML_Node& transportNode = phase_database->child("transport"); + getLiquidInteractionsTransportData(transportNode, log, trParam.thermo->speciesNames(), trParam); + } } - - + //==================================================================================================================== + // Initialize an existing transport manager + /* + * This routine sets up an existing gas-phase transport manager. + * It calculates the collision integrals and calls the initGas() function to + * populate the species-dependent data structure. + * + * @param tr Pointer to the Transport manager + * @param thermo Pointer to the ThermoPhase object + * @param mode Chemkin compatible mode or not. This alters the specification of the + * collision integrals. defaults to no. + * @param log_level Defaults to zero, no logging + * + * In DEBUG_MODE, this routine will create the file transport_log.xml + * and write informative information to it. + */ void TransportFactory::initTransport(Transport* tran, thermo_t* thermo, int mode, int log_level) { @@ -565,6 +691,9 @@ namespace Cantera { GasTransportParams trParam; #ifdef DEBUG_MODE + if (log_level == 0) { + m_verbose = 0; + } ofstream flog("transport_log.xml"); trParam.xml = new XML_Writer(flog); if (m_verbose) { @@ -587,17 +716,15 @@ namespace Cantera { #endif return; } + //==================================================================================================================== - - /** Similar to initTransport except uses LiquidTransportParams - * class and calls setupLiquidTransport(). - */ + /* Similar to initTransport except uses LiquidTransportParams + class and calls setupLiquidTransport(). + */ void TransportFactory::initLiquidTransport(Transport* tran, thermo_t* thermo, int log_level) { - const std::vector & transport_database = thermo->speciesData(); - LiquidTransportParams trParam; #ifdef DEBUG_MODE ofstream flog("transport_log.xml"); @@ -609,7 +736,7 @@ namespace Cantera { // create the object, but don't associate it with a file std::ostream &flog(std::cout); #endif - setupLiquidTransport(flog, transport_database, thermo, log_level, trParam); + setupLiquidTransport(flog, thermo, log_level, trParam); // do model-specific initialization tran->initLiquid(trParam); #ifdef DEBUG_MODE @@ -622,18 +749,14 @@ namespace Cantera { return; } - - - - /******************************************************** - * - * Collision Integral Fits - * - ********************************************************/ - - - void TransportFactory::fitCollisionIntegrals(ostream& logfile, - GasTransportParams& tr) { + //==================================================================================================================== + // Generate polynomial fits to collision integrals + /* + * @param logfile Reference to an ostream that will contain log information when in + * DEBUG_MODE + * @param tr Reference to the GasTransportParams object that will contain the results. + */ + void TransportFactory::fitCollisionIntegrals(ostream& logfile, GasTransportParams& tr) { vector_fp::iterator dptr; doublereal dstar; @@ -652,54 +775,52 @@ namespace Cantera { tr.xml->XML_comment(logfile, "*** polynomial coefficients not printed (log_level < 3) ***"); } #endif - for (i = 0; i < nsp; i++) - { - for (j = i; j < nsp; j++) - { - // Chemkin fits only delta* = 0 - if (mode != CK_Mode) - dstar = tr.delta(i,j); - else - dstar = 0.0; + for (i = 0; i < nsp; i++) { + for (j = i; j < nsp; j++) { + // Chemkin fits only delta* = 0 + if (mode != CK_Mode) { + dstar = tr.delta(i,j); + } else { + dstar = 0.0; + } - // if a fit has already been generated for - // delta* = tr.delta(i,j), then use it. Otherwise, - // make a new fit, and add tr.delta(i,j) to the list - // of delta* values for which fits have been done. + // if a fit has already been generated for + // delta* = tr.delta(i,j), then use it. Otherwise, + // make a new fit, and add tr.delta(i,j) to the list + // of delta* values for which fits have been done. - // 'find' returns a pointer to end() if not found - if (dptr = find(tr.fitlist.begin(), tr.fitlist.end(), - dstar), dptr == tr.fitlist.end()) - { - vector_fp ca(degree+1), cb(degree+1), cc(degree+1); - vector_fp co22(degree+1); - m_integrals->fit(logfile, degree, dstar, - DATA_PTR(ca), DATA_PTR(cb), DATA_PTR(cc)); - m_integrals->fit_omega22(logfile, degree, dstar, - DATA_PTR(co22)); - tr.omega22_poly.push_back(co22); - tr.astar_poly.push_back(ca); - tr.bstar_poly.push_back(cb); - tr.cstar_poly.push_back(cc); - tr.poly[i][j] = static_cast(tr.astar_poly.size()) - 1; - tr.fitlist.push_back(dstar); - } + // 'find' returns a pointer to end() if not found + dptr = find(tr.fitlist.begin(), tr.fitlist.end(), dstar); + if (dptr == tr.fitlist.end()) { + vector_fp ca(degree+1), cb(degree+1), cc(degree+1); + vector_fp co22(degree+1); + m_integrals->fit(logfile, degree, dstar, + DATA_PTR(ca), DATA_PTR(cb), DATA_PTR(cc)); + m_integrals->fit_omega22(logfile, degree, dstar, + DATA_PTR(co22)); + tr.omega22_poly.push_back(co22); + tr.astar_poly.push_back(ca); + tr.bstar_poly.push_back(cb); + tr.cstar_poly.push_back(cc); + tr.poly[i][j] = static_cast(tr.astar_poly.size()) - 1; + tr.fitlist.push_back(dstar); + } - // delta* found in fitlist, so just point to this - // polynomial - else { - tr.poly[i][j] = static_cast((dptr - tr.fitlist.begin())); - } - tr.poly[j][i] = tr.poly[i][j]; - } - } + // delta* found in fitlist, so just point to this + // polynomial + else { + tr.poly[i][j] = static_cast((dptr - tr.fitlist.begin())); + } + tr.poly[j][i] = tr.poly[i][j]; + } + } #ifdef DEBUG_MODE if (m_verbose) { tr.xml->XML_close(logfile, "tstar_fits"); } #endif } - + //==================================================================================================================== @@ -709,17 +830,17 @@ namespace Cantera { * *********************************************************/ - /** - * Read transport property data from a file for a list of species. - * Given the name of a file containing transport property - * parameters and a list of species names, this method returns an - * instance of TransportParams containing the transport data for - * these species read from the file. - */ + /* + Read transport property data from a file for a list of species. + Given the name of a file containing transport property + parameters and a list of species names, this method returns an + instance of TransportParams containing the transport data for + these species read from the file. + */ void TransportFactory::getTransportData(const std::vector &xspecies, XML_Node& log, const std::vector &names, GasTransportParams& tr) { - string name; + std::string name; int geom; std::map datatable; doublereal welldepth, diam, dipole, polar, rot; @@ -730,8 +851,8 @@ namespace Cantera { // errors. Note that this procedure validates all entries, not // only those for the species listed in 'names'. - string val, type; - map gindx; + std::string val, type; + map gindx; gindx["atom"] = 100; gindx["linear"] = 101; gindx["nonlinear"] = 102; @@ -740,21 +861,21 @@ namespace Cantera { for (i = 0; i < nsp; i++) { const XML_Node& sp = *xspecies[i]; name = sp["name"]; - // std::cout << "Processing node for " << name << std::endl; + // std::cout << "Processing node for " << name << std::endl; // put in a try block so that species with no 'transport' // child are skipped, instead of throwing an exception. try { XML_Node& tr = sp.child("transport"); - getString(tr, "geometry", val, type); + ctml::getString(tr, "geometry", val, type); geom = gindx[val] - 100; - map fv; + map fv; - welldepth = getFloat(tr, "LJ_welldepth"); - diam = getFloat(tr, "LJ_diameter"); - dipole = getFloat(tr, "dipoleMoment"); - polar = getFloat(tr, "polarizability"); - rot = getFloat(tr, "rotRelax"); + welldepth = ctml::getFloat(tr, "LJ_welldepth"); + diam = ctml::getFloat(tr, "LJ_diameter"); + dipole = ctml::getFloat(tr, "dipoleMoment"); + polar = ctml::getFloat(tr, "polarizability"); + rot = ctml::getFloat(tr, "rotRelax"); GasTransportData data; data.speciesName = name; @@ -780,14 +901,14 @@ namespace Cantera { "negative rotation relaxation number"); datatable[name] = data; - } - catch(CanteraError) { + } catch(CanteraError) { ; } } for (i = 0; i < tr.nsp_; i++) { + GasTransportData& trdat = datatable[names[i]]; // 'datatable' returns a default TransportData object if @@ -831,44 +952,41 @@ namespace Cantera { } } - /** - * Read transport property data from a file for a list of species. - * Given the name of a file containing transport property - * parameters and a list of species names, this method returns an - * instance of TransportParams containing the transport data for - * these species read from the file. - */ - void TransportFactory::getLiquidTransportData( const std::vector &xspecies, - XML_Node& log, - const std::vector &names, - LiquidTransportParams& trParam) + /* + Read transport property data from a file for a list of species. + Given the name of a file containing transport property + parameters and a list of species names, this method returns an + instance of TransportParams containing the transport data for + these species read from the file. + */ + void TransportFactory::getLiquidSpeciesTransportData(const std::vector &xspecies, + XML_Node& log, + const std::vector &names, + LiquidTransportParams& trParam) { std::string name; /* - * Create a map of species names versus liquid transport data parameters - */ + Create a map of species names versus liquid transport data parameters + */ std::map datatable; - doublereal A_visc, n_visc, Tact_visc, hydrodynamic_radius; - doublereal A_thcond, n_thcond, Tact_thcond; - doublereal A_spdiff, n_spdiff, Tact_spdiff; + std::map::iterator it; - int nsp = static_cast(xspecies.size()); - std::cout << "Size of xspecies " << nsp << std::endl; + // Store the number of species in the phase + int nsp = trParam.nsp_; + + // Store the number of off-diagonal symmetric interactions between species in the phase + int nBinInt = nsp*(nsp-1)/2; // read all entries in database into 'datatable' and check for // errors. Note that this procedure validates all entries, not // only those for the species listed in 'names'. - - int linenum = 0; - int i; - for (i = 0; i < nsp; i++) { + for (int i = 0; i < nsp; i++) { const XML_Node& sp = *xspecies[i]; name = sp["name"]; vector_fp vCoeff; - // std::cout << "Processing node for " << name << std::endl; - // put in a try block so that species with no 'transport' - // child are skipped, instead of throwing an exception. + // Species with no 'transport' child are skipped. However, if that species is in the list, + // it will throw an exception below. try { if (sp.hasChild("transport")) { XML_Node& trNode = sp.child("transport"); @@ -877,222 +995,230 @@ namespace Cantera { // and then insertion into LiquidTransportData objects below. LiquidTransportData data; data.speciesName = name; + data.mobilityRatio.resize(nsp*nsp,0); + data.selfDiffusion.resize(nsp,0); + ThermoPhase *temp_thermo = trParam.thermo; - /* - * hydrodynamic radius - * - * format: - * 3.0 - * 3.0 - */ - if (trNode.hasChild("hydrodynamic_radius")) { - XML_Node& hnode = trNode.child("hydrodynamic_radius"); - std::string model = lowercase(hnode["model"]); - if (model == "" || model == "constant") { - hydrodynamic_radius = hnode.fp_value(); - if (hydrodynamic_radius > 0.0) data.hydroradius = hydrodynamic_radius; - else throw TransportDBError(linenum, - "negative or zero hydrodynamic radius"); - data.model_hydroradius = LTR_MODEL_CONSTANT; - } else { - throw CanteraError(" TransportFactory::getLiquidTransportData", - "Unknown model for hydrodynamic_radius:" + model); + int num = trNode.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + XML_Node &xmlChild = trNode.child(iChild); + std::string nodeName = xmlChild.name(); + + switch (m_tranPropMap[nodeName]) { + case TP_VISCOSITY: + data.viscosity = newLTP(xmlChild, name, m_tranPropMap[nodeName], temp_thermo); + break; + case TP_IONCONDUCTIVITY: + data.ionConductivity = newLTP(xmlChild, name, m_tranPropMap[nodeName], temp_thermo); + break; + case TP_MOBILITYRATIO: + { + for (int iSpec = 0; iSpec< nBinInt; iSpec++){ + XML_Node &propSpecNode = xmlChild.child(iSpec); + std::string specName = propSpecNode.name(); + size_t loc = specName.find(":"); + std::string firstSpec = specName.substr(0,loc); + std::string secondSpec = specName.substr(loc+1); + int index = temp_thermo->speciesIndex(firstSpec.c_str())+nsp*temp_thermo->speciesIndex(secondSpec.c_str()); + data.mobilityRatio[index] = newLTP(propSpecNode, name, m_tranPropMap[nodeName], temp_thermo); + }; + }; + break; + case TP_SELFDIFFUSION: + { + for (int iSpec = 0; iSpec< nsp; iSpec++){ + XML_Node &propSpecNode = xmlChild.child(iSpec); + std::string specName = propSpecNode.name(); + int index = temp_thermo->speciesIndex(specName.c_str()); + data.selfDiffusion[index] = newLTP(propSpecNode, name, m_tranPropMap[nodeName], temp_thermo); + }; + }; + break; + case TP_THERMALCOND: + data.thermalCond = newLTP(xmlChild, + name, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_DIFFUSIVITY: + data.speciesDiffusivity = newLTP(xmlChild, + name, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_HYDRORADIUS: + data.hydroRadius = newLTP(xmlChild, + name, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_ELECTCOND: + data.electCond = newLTP(xmlChild, + name, + m_tranPropMap[nodeName], + temp_thermo); + + break; + default: + throw CanteraError("getLiquidSpeciesTransportData","unknown transport property: " + nodeName); } - } - /* - * viscosity - * - * format: - * 3.0 - * 3.0 - * - * 1.0 - * 2.0 - * 3.0 - * - * - * - * 0.0. 1.0, 2.0, 3.0, 4.0 - * - * - */ - if (trNode.hasChild("viscosity")) { - XML_Node& vnode = trNode.child("viscosity"); - std::string model = lowercase(vnode["model"]); - if (model == "" || model == "constant") { - A_visc = ctml::getFloatCurrent(vnode, "toSI"); - if (A_visc > 0.0) (data.viscCoeffs).push_back(A_visc); - else throw TransportDBError(linenum, - "negative or zero viscosity"); - data.model_viscosity = LTR_MODEL_CONSTANT; - } else if (model == "arrhenius") { - getArrhenius(vnode, A_visc, n_visc, Tact_visc); - if (A_visc <= 0.0) { - throw TransportDBError(linenum, "negative or zero viscosity"); - } - (data.viscCoeffs).push_back(A_visc); - (data.viscCoeffs).push_back(n_visc); - (data.viscCoeffs).push_back(Tact_visc); - data.model_viscosity = LTR_MODEL_ARRHENIUS; - } else if (model == "coeff") { - getFloatArray(vnode, vCoeff, true); - data.viscCoeffs = vCoeff; - vCoeff.clear(); - data.model_viscosity = LTR_MODEL_COEFF; - } else { - throw CanteraError(" TransportFactory::getLiquidTransportData", - "Unknown model for viscosity:" + vnode["model"]); - } } - - /* - * thermalConductivity - * - * format: - * 3.0 - * 3.0 - * - * 1.0 - * 2.0 - * 3.0 - * - * - * - * 0.0. 1.0, 2.0, 3.0, 4.0 - * - * - */ - if (trNode.hasChild("thermalConductivity")) { - XML_Node& tnode = trNode.child("thermalConductivity"); - std::string model = lowercase(tnode["model"]); - if (model == "" || model == "constant") { - A_thcond = ctml::getFloatCurrent(tnode, "toSI"); - if (A_thcond > 0.0) (data.thermalCondCoeffs).push_back(A_thcond); - else throw TransportDBError(linenum, - "negative or zero thermalConductivity"); - data.model_thermalCond = LTR_MODEL_CONSTANT; - } else if (model == "arrhenius") { - getArrhenius(tnode, A_thcond, n_thcond, Tact_thcond); - if (A_thcond <= 0.0) { - throw TransportDBError(linenum, "negative or zero thermalConductivity"); - } - (data.thermalCondCoeffs).push_back(A_thcond); - (data.thermalCondCoeffs).push_back(n_thcond); - (data.thermalCondCoeffs).push_back(Tact_thcond); - data.model_thermalCond = LTR_MODEL_ARRHENIUS; - } else if (model == "coeff") { - getFloatArray(tnode, vCoeff, true); - data.thermalCondCoeffs = vCoeff; - vCoeff.clear(); - data.model_thermalCond = LTR_MODEL_COEFF; - } else { - throw CanteraError(" TransportFactory::getLiquidTransportData", - "Unknown model for thermalConductivity:" + tnode["model"]); - } - } - - - /* - * speciesDiffusivity - * - * format: - * 3.0 - * 3.0 - * - * 1.0 - * 2.0 - * 3.0 - * - * - * - * 0.0. 1.0, 2.0, 3.0, 4.0 - * - * - */ - if (trNode.hasChild("speciesDiffusivity")) { - XML_Node& dnode = trNode.child("speciesDiffusivity"); - std::string model = lowercase(dnode["model"]); - if (model == "" || model == "constant") { - A_spdiff = ctml::getFloatCurrent(dnode, "toSI"); - if (A_spdiff > 0.0) (data.speciesDiffusivityCoeffs).push_back(A_spdiff); - else throw TransportDBError(linenum, - "negative or zero speciesDiffusivity"); - data.model_speciesDiffusivity = LTR_MODEL_CONSTANT; - } else if (model == "arrhenius") { - getArrhenius(dnode, A_spdiff, n_spdiff, Tact_spdiff); - if (A_spdiff <= 0.0) { - throw TransportDBError(linenum, "negative or zero speciesDiffusivity"); - } - (data.speciesDiffusivityCoeffs).push_back(A_spdiff); - (data.speciesDiffusivityCoeffs).push_back(n_spdiff); - (data.speciesDiffusivityCoeffs).push_back(Tact_spdiff); - data.model_speciesDiffusivity = LTR_MODEL_ARRHENIUS; - } else if (model == "coeff") { - getFloatArray(dnode, vCoeff, true); - data.speciesDiffusivityCoeffs = vCoeff; - data.model_speciesDiffusivity = LTR_MODEL_COEFF; - } else { - throw CanteraError(" TransportFactory::getLiquidTransportData", - "Unknown model for speciesDiffusivity:" + dnode["model"]); - } - } - - datatable[name] = data; + datatable.insert(pair(name,data)); } } - catch(CanteraError) { - ; + catch (CanteraError yy) { + throw yy; } } trParam.LTData.clear(); - for (i = 0; i < trParam.nsp_; i++) { - - LiquidTransportData& trdat = datatable[names[i]]; - - // 'datatable' returns a default TransportData object if - // the species name is not one in the transport database. - // This can be detected by examining 'geometry'. - if (trdat.viscCoeffs[0] < 0) { - throw TransportDBError(0,"no transport data found for species " - + names[i]); - } - - // parameters should be converted to SI units before storing - if (trdat.viscCoeffs.size() > 0) { - trParam.visc_A[i] = trdat.viscCoeffs[0] ; - } - if (trdat.viscCoeffs.size() > 2) { - trParam.visc_n[i] = trdat.viscCoeffs[1] ; - trParam.visc_Tact[i] = trdat.viscCoeffs[2] ; - } - - if (trdat.thermalCondCoeffs.size() > 0) { - trParam.thermCond_A[i] = trdat.thermalCondCoeffs[0] ; - } - if (trdat.thermalCondCoeffs.size() > 2) { - trParam.thermCond_n[i] = trdat.thermalCondCoeffs[1] ; - trParam.thermCond_Tact[i] = trdat.thermalCondCoeffs[2] ; - } - - // Angstroms -> meters - trParam.hydroRadius[i] = 1.e-10 * trdat.hydroradius; - + for (int i = 0; i < trParam.nsp_; i++) { /* - * this is a much more general way to handle the transfer - * -> calling the default copy constructor for LiquidTransportData - */ + Check to see that we have a LiquidTransportData object for all of the + species in the phase. If not, throw an error. + */ + it = datatable.find(names[i]); + if (it == datatable.end()) { + throw TransportDBError(0,"No transport data found for species " + names[i]); + } + LiquidTransportData& trdat = it->second; + + /* + Now, transfer these objects into LTData in the correct phase index order by + calling the default copy constructor for LiquidTransportData. + */ trParam.LTData.push_back(trdat); } - - // Need to identify a method to obtain interaction matrices. - // This will fill LiquidTransportParams members visc_Eij, visc_Sij - trParam.visc_Eij.resize(trParam.nsp_,trParam.nsp_); - //cout << "No support for species viscosity interactions in TransportFactory.cpp" << endl; } + /* + Read transport property data from a file for interactions + between species in a liquid. + Given the name of a file containing transport property + parameters and a list of species names, this method returns an + instance of TransportParams containing the transport data for + these species read from the file. + */ + void TransportFactory::getLiquidInteractionsTransportData(const XML_Node &transportNode, + XML_Node& log, + const std::vector &names, + LiquidTransportParams& trParam) + { + try { + + int nsp = trParam.nsp_; + int nBinInt = nsp*(nsp-1)/2; + + int num = transportNode.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + //tranTypeNode is a type of transport property like viscosity + XML_Node &tranTypeNode = transportNode.child(iChild); + std::string nodeName = tranTypeNode.name(); + + trParam.mobilityRatio.resize(nsp*nsp,0); + trParam.selfDiffusion.resize(nsp,0); + ThermoPhase *temp_thermo = trParam.thermo; + + if (tranTypeNode.hasChild("compositionDependence")) { + //compDepNode contains the interaction model + XML_Node &compDepNode = tranTypeNode.child("compositionDependence"); + switch (m_tranPropMap[nodeName]) { + break; + case TP_VISCOSITY: + trParam.viscosity = newLTI(compDepNode, m_tranPropMap[nodeName], trParam); + break; + case TP_IONCONDUCTIVITY: + trParam.ionConductivity = newLTI(compDepNode, + m_tranPropMap[nodeName], + trParam); + break; + case TP_MOBILITYRATIO: + { + for (int iSpec = 0; iSpec< nBinInt; iSpec++){ + XML_Node &propSpecNode = compDepNode.child(iSpec); + string specName = propSpecNode.name(); + size_t loc = specName.find(":"); + string firstSpec = specName.substr(0,loc); + string secondSpec = specName.substr(loc+1); + int index = temp_thermo->speciesIndex(firstSpec.c_str())+nsp*temp_thermo->speciesIndex(secondSpec.c_str()); + trParam.mobilityRatio[index] = newLTI(propSpecNode, + m_tranPropMap[nodeName], + trParam); + }; + }; + break; + case TP_SELFDIFFUSION: + { + for (int iSpec = 0; iSpec< nsp; iSpec++){ + XML_Node &propSpecNode = compDepNode.child(iSpec); + string specName = propSpecNode.name(); + int index = temp_thermo->speciesIndex(specName.c_str()); + trParam.selfDiffusion[index] = newLTI(propSpecNode, + m_tranPropMap[nodeName], + trParam); + }; + }; + break; + case TP_THERMALCOND: + trParam.thermalCond = newLTI(compDepNode, + m_tranPropMap[nodeName], + trParam); + break; + case TP_DIFFUSIVITY: + trParam.speciesDiffusivity = newLTI(compDepNode, + m_tranPropMap[nodeName], + trParam); + break; + case TP_HYDRORADIUS: + trParam.hydroRadius = newLTI(compDepNode, + m_tranPropMap[nodeName], + trParam); + break; + case TP_ELECTCOND: + trParam.electCond = newLTI(compDepNode, + m_tranPropMap[nodeName], + trParam); + break; + default: + throw CanteraError("getLiquidInteractionsTransportData","unknown transport property: " + nodeName); + + } + } + /* Allow a switch between mass-averaged, mole-averaged + * and solvent specified reference velocities. + * XML code within the transportProperty node + * (i.e. within ) should read as follows + * + * + * + */ + if (tranTypeNode.hasChild("velocityBasis")) { + std::string velocityBasis = + tranTypeNode.child("velocityBasis").attrib("basis"); + if (velocityBasis == "mass") + trParam.velocityBasis_ = VB_MASSAVG; + else if (velocityBasis == "mole") + trParam.velocityBasis_ = VB_MOLEAVG; + else if (trParam.thermo->speciesIndex(velocityBasis) > 0) + trParam.velocityBasis_ = trParam.thermo->speciesIndex(velocityBasis) ; + else { + int linenum = __LINE__; + throw TransportDBError(linenum, "Unknown attribute \"" + velocityBasis + "\" for node. "); + } + } + } + } + catch (CanteraError) { + showErrors(std::cout); + } + //catch(CanteraError) { + // ; + //} + return; + } + /********************************************************* * * Polynomial fitting @@ -1100,29 +1226,33 @@ namespace Cantera { *********************************************************/ - - /***************** fitProperties ***************/ - - /** - * Generate polynomial fits for the pure-species viscosities and - * for the binary diffusion coefficients. If - * CK_mode, then the fits are of the - * form \f[ - * \log(\eta(i)) = \sum_{n = 0}^3 a_n(i) (\log T)^n - * \f] - * and \f[ - * \log(D(i,j)) = \sum_{n = 0}^3 a_n(i,j) (\log T)^n - * \f] - * Otherwise the fits are of the form - * \f[ - * \eta(i)/sqrt(k_BT) = \sum_{n = 0}^4 a_n(i) (\log T)^n - * \f] - * and \f[ - * D(i,j)/sqrt(k_BT)) = \sum_{n = 0}^4 a_n(i,j) (\log T)^n - * \f] + //==================================================================================================================== + // Generate polynomial fits to the viscosity, conductivity, and + // the binary diffusion coefficients + /* + * If CK_mode, then the fits are of the form + * \f[ + * \log(\eta(i)) = \sum_{n = 0}^3 a_n(i) (\log T)^n + * \f] + * and + * \f[ + * \log(D(i,j)) = \sum_{n = 0}^3 a_n(i,j) (\log T)^n + * \f] + * Otherwise the fits are of the form + * \f[ + * \eta(i)/sqrt(k_BT) = \sum_{n = 0}^4 a_n(i) (\log T)^n + * \f] + * and + * \f[ + * D(i,j)/sqrt(k_BT)) = \sum_{n = 0}^4 a_n(i,j) (\log T)^n + * \f] + * + * @param tr Reference to the GasTransportParams object that will contain the results. + * @param logfile Reference to an ostream that will contain log information when in + * DEBUG_MODE */ - void TransportFactory::fitProperties(GasTransportParams& tr, - ostream& logfile) { + void TransportFactory::fitProperties(GasTransportParams& tr, std::ostream& logfile) { + doublereal tstar; int k, j, n, ndeg = 0; #ifdef DEBUG_MODE @@ -1199,7 +1329,7 @@ namespace Cantera { // self-diffusion coefficient, without polar // corrections diffcoeff = ThreeSixteenths * - sqrt( 2.0 * Pi/tr.reducedMass(k,k) ) * + sqrt(2.0 * Pi/tr.reducedMass(k,k)) * pow((Boltzmann * t), 1.5)/ (Pi * tr.sigma[k] * tr.sigma[k] * om11); @@ -1348,71 +1478,69 @@ namespace Cantera { mxerr = 0.0, mxrelerr = 0.0; vector_fp diff(np + 1); doublereal eps, sigma; - for (k = 0; k < tr.nsp_; k++) - { - for (j = k; j < tr.nsp_; j++) { + for (k = 0; k < tr.nsp_; k++) { + for (j = k; j < tr.nsp_; j++) { - ipoly = tr.poly[k][j]; - for (n = 0; n < np; n++) { + ipoly = tr.poly[k][j]; + for (n = 0; n < np; n++) { - t = tr.tmin + dt*n; + t = tr.tmin + dt*n; - eps = tr.epsilon(j,k); - tstar = Boltzmann * t/eps; - sigma = tr.diam(j,k); - om11 = m_integrals->omega11(tstar, tr.delta(j,k)); + eps = tr.epsilon(j,k); + tstar = Boltzmann * t/eps; + sigma = tr.diam(j,k); + om11 = m_integrals->omega11(tstar, tr.delta(j,k)); - diffcoeff = ThreeSixteenths * - sqrt( 2.0 * Pi/tr.reducedMass(k,j) ) * - pow((Boltzmann * t), 1.5)/ - (Pi * sigma * sigma * om11); + diffcoeff = ThreeSixteenths * + sqrt(2.0 * Pi/tr.reducedMass(k,j)) * + pow((Boltzmann * t), 1.5)/ + (Pi * sigma * sigma * om11); - // 2nd order correction - // NOTE: THIS CORRECTION IS NOT APPLIED - doublereal fkj, fjk; - getBinDiffCorrection(t, tr, k, j, 1.0, 1.0, fkj, fjk); - //diffcoeff *= fkj; + // 2nd order correction + // NOTE: THIS CORRECTION IS NOT APPLIED + doublereal fkj, fjk; + getBinDiffCorrection(t, tr, k, j, 1.0, 1.0, fkj, fjk); + //diffcoeff *= fkj; - if (mode == CK_Mode) { - diff[n] = log(diffcoeff); - w[n] = -1.0; - } - else { - diff[n] = diffcoeff/pow(t, 1.5); - w[n] = 1.0/(diff[n]*diff[n]); - } + if (mode == CK_Mode) { + diff[n] = log(diffcoeff); + w[n] = -1.0; } - polyfit(np, DATA_PTR(tlog), DATA_PTR(diff), - DATA_PTR(w), degree, ndeg, 0.0, DATA_PTR(c)); - - doublereal pre; - for (n = 0; n < np; n++) { - if (mode == CK_Mode) { - val = exp(diff[n]); - fit = exp(poly3(tlog[n], DATA_PTR(c))); - } - else { - t = exp(tlog[n]); - pre = pow(t, 1.5); - val = pre * diff[n]; - fit = pre * poly4(tlog[n], DATA_PTR(c)); - } - err = fit - val; - relerr = err/val; - if (fabs(err) > mxerr) mxerr = fabs(err); - if (fabs(relerr) > mxrelerr) mxrelerr = fabs(relerr); + else { + diff[n] = diffcoeff/pow(t, 1.5); + w[n] = 1.0/(diff[n]*diff[n]); } - tr.diffcoeffs.push_back(c); -#ifdef DEBUG_MODE - if (tr.log_level >= 2 && m_verbose) { - tr.xml->XML_writeVector(logfile, " ", tr.thermo->speciesName(k) - + "__"+tr.thermo->speciesName(j), c.size(), DATA_PTR(c)); - } -#endif } + polyfit(np, DATA_PTR(tlog), DATA_PTR(diff), + DATA_PTR(w), degree, ndeg, 0.0, DATA_PTR(c)); + + doublereal pre; + for (n = 0; n < np; n++) { + if (mode == CK_Mode) { + val = exp(diff[n]); + fit = exp(poly3(tlog[n], DATA_PTR(c))); + } else { + t = exp(tlog[n]); + pre = pow(t, 1.5); + val = pre * diff[n]; + fit = pre * poly4(tlog[n], DATA_PTR(c)); + } + err = fit - val; + relerr = err/val; + if (fabs(err) > mxerr) mxerr = fabs(err); + if (fabs(relerr) > mxrelerr) mxrelerr = fabs(relerr); + } + tr.diffcoeffs.push_back(c); +#ifdef DEBUG_MODE + if (tr.log_level >= 2 && m_verbose) { + tr.xml->XML_writeVector(logfile, " ", tr.thermo->speciesName(k) + + "__"+tr.thermo->speciesName(j), c.size(), DATA_PTR(c)); + } +#endif } + } #ifdef DEBUG_MODE if (m_verbose) { sprintf(s,"Maximum binary diffusion coefficient absolute error:" @@ -1425,5 +1553,53 @@ namespace Cantera { } #endif } + //==================================================================================================================== + // Create a new transport manager instance. + /* + * @param transportModel String identifying the transport model to be instantiated, defaults to the empty string + * @param thermo ThermoPhase object associated with the phase, defaults to null pointer + * @param loglevel int containing the Loglevel, defaults to zero + * @param f ptr to the TransportFactory object if it's been malloced. + * + * @ingroup transportProps + */ + Transport* newTransportMgr(std::string transportModel, thermo_t* thermo, int loglevel, TransportFactory* f) + { + if (f == 0) { + f = TransportFactory::factory(); + } + Transport* ptr = f->newTransport(transportModel, thermo, loglevel); + /* + * Note: We delete the static s_factory instance here, instead of in + * appdelete() in misc.cpp, to avoid linking problems involving + * the need for multiple cantera and transport library statements + * for applications that don't have transport in them. + */ + return ptr; + } + //==================================================================================================================== + // Create a new transport manager instance. + /* + * @param thermo ThermoPhase object associated with the phase, defaults to null pointer + * @param loglevel int containing the Loglevel, defaults to zero + * @param f ptr to the TransportFactory object if it's been malloced. + * + * @ingroup transportProps + */ + Transport* newDefaultTransportMgr(thermo_t* thermo, int loglevel, TransportFactory* f) + { + if (f == 0) { + f = TransportFactory::factory(); + } + Transport* ptr = f->newTransport(thermo, loglevel); + /* + * Note: We delete the static s_factory instance here, instead of in + * appdelete() in misc.cpp, to avoid linking problems involving + * the need for multiple cantera and transport library statements + * for applications that don't have transport in them. + */ + return ptr; + } + //==================================================================================================================== } diff --git a/Cantera/src/transport/TransportFactory.h b/Cantera/src/transport/TransportFactory.h index e3fe35dd2..d69e9519a 100644 --- a/Cantera/src/transport/TransportFactory.h +++ b/Cantera/src/transport/TransportFactory.h @@ -12,8 +12,8 @@ * */ -#ifndef CT_TRANFACTORY_H -#define CT_TRANFACTORY_H +#ifndef CT_TRANSPORTFACTORY_H +#define CT_TRANSPORTFACTORY_H // turn off warnings under Windows @@ -34,61 +34,95 @@ #include "ct_defs.h" #include "TransportBase.h" #include "FactoryBase.h" -#include "LiquidTransportData.h" +//#include "LiquidTransportData.h" +#include "LiquidTransportParams.h" #if defined(THREAD_SAFE_CANTERA) #include #endif - +//====================================================================================================================== namespace Cantera { - - /** - * Struct to hold data read from a transport property database file. - */ + //==================================================================================================================== + //! Struct to hold data read from a transport property database file for gas-phase species struct GasTransportData { - GasTransportData() : speciesName("-"), - geometry(-1), wellDepth(-1.0), - diameter(-1.0), - dipoleMoment(-1.0), - polarizability(-1.0), - rotRelaxNumber(-1.0) {} + //! Default constructor + GasTransportData() : + speciesName("-"), + geometry(-1), + wellDepth(-1.0), + diameter(-1.0), + dipoleMoment(-1.0), + polarizability(-1.0), + rotRelaxNumber(-1.0) + { + } + //! gas phase species name std::string speciesName; + //! Geometry of the molecule + /*! + * 0 - single atom + * 1 - linear atom + * 2 - non-linear geom + */ int geometry; + + //! well-depth parameter + /*! + * units - temperature (CHECK) + */ doublereal wellDepth; + + //! Lennard-Jones diameter of the molecule + /*! + * units - Angstroms + */ doublereal diameter; + + //! dipole Moment of the molecule + /*! + * units = Debye (a debye is 10-18 cm3/2 erg1/2) + */ doublereal dipoleMoment; + + //! Polarizability of the molecule + /*! + * units = A**3 + */ doublereal polarizability; + + //! Rotational relaxation number + /*! + * Number of collisions it takes to equilibrate the rotational dofs with the temperature + */ doublereal rotRelaxNumber; }; - + //==================================================================================================================== // forward references class MMCollisionInt; class GasTransportParams; class LiquidTransportParams; class XML_Node; - - //! The purpose of TransportFactory is to create new instances of + //==================================================================================================================== + //! The purpose of the TransportFactory class is to create new instances of //! 'transport managers', which are classes that provide transport - //! properties and are derived from base class Transport. + //! properties and which are derived from the base class, %Transport. /*! - * TransportFactory handles all initialization - * required, including evaluation of collision integrals and - * generating polynomial fits. Transport managers can also be - * created in other ways. + * TransportFactory handles all initialization required, including evaluation of collision integrals and + * generating polynomial fits. Transport managers can also be created in other ways. * * @ingroup transportgroup * @ingroup transportProps */ - class TransportFactory : FactoryBase { + class TransportFactory : public FactoryBase { public: - - /** - * Return a pointer to a TransportFactory - * instance. TransportFactory is implemented as a 'singleton', + + //! Return a pointer to a TransportFactory instance. + /*! + * TransportFactory is implemented as a 'singleton', * which means that at most one instance may be created. The * constructor is private. When a TransportFactory instance is * required, call static method factory() to return a pointer @@ -110,33 +144,62 @@ namespace Cantera { } - /** - * Deletes the statically malloced instance. - */ + //! Deletes the statically malloced instance. virtual void deleteFactory(); - /** + /*! * Destructor * - * We do not delete statically - * created single instance of this class here, because it would - * create an infinite loop if destructor is called for that - * single instance. + * We do not delete statically created single instance of this + * class here, because it would create an infinite loop if + * destructor is called for that single instance. However, we do + * have a pointer to m_integrals that does need to be + * explicitly deleted. */ virtual ~TransportFactory(); + + //! Make one of several transport models, and return a base class pointer to it. + /*! + * This method operates at the level of a single transport property as a function of temperature + * and possibly composition. It's a factory for LTPspecies classes. + * + * @param trNode XML node + * @param name reference to the name + * @param tp_ind TransportPropertyType class + * @param thermo Pointer to the %ThermoPhase class + */ + virtual LTPspecies* newLTP(const XML_Node &trNode, std::string &name, + TransportPropertyType tp_ind, thermo_t* thermo); + + + //! Factory function for the construction of new LiquidTranInteraction + //! objects, which are transport models. + /*! + * This method operates at the level of a single mixture transport property. Individual species + * transport properties are addressed by the LTPspecies returned by newLTP. + * + * @param trNode XML_Node containing the information for the interaction + * @param tp_ind TransportPropertyType object + * @param trParam reference to the LiquidTransportParams object + */ + virtual LiquidTranInteraction* newLTI(const XML_Node &trNode, + TransportPropertyType tp_ind, + LiquidTransportParams& trParam); + + //! Build a new transport manager using a transport manager //! that may not be the same as in the phase description + //! and return a base class pointer to it /*! * @param model String name for the transport manager * @param thermo ThermoPhase object * @param log_level log level */ - virtual Transport* - newTransport(std::string model, thermo_t* thermo, int log_level=0); + virtual Transport* newTransport(std::string model, thermo_t* thermo, int log_level=0); //! Build a new transport manager using the default transport manager - //! in the phase description + //! in the phase description and return a base class pointer to it /*! * @param thermo ThermoPhase object * @param log_level log level @@ -144,22 +207,49 @@ namespace Cantera { virtual Transport* newTransport(thermo_t* thermo, int log_level=0); - /// Initialize an existing transport manager - virtual void initTransport(Transport* tr, - thermo_t* thermo, int mode=0, int log_level=0); + //! Initialize an existing transport manager + /*! + * This routine sets up an existing gas-phase transport manager. + * It calculates the collision integrals and calls the initGas() function to + * populate the species-dependent data structure. + * + * @param tr Pointer to the Transport manager + * @param thermo Pointer to the ThermoPhase object + * @param mode Chemkin compatible mode or not. This alters the specification of the + * collision integrals. defaults to no. + * @param log_level Defaults to zero, no logging + * + * In DEBUG_MODE, this routine will create the file transport_log.xml + * and write informative information to it. + * + */ + virtual void initTransport(Transport* tr, thermo_t* thermo, int mode=0, int log_level=0); + + //! Initialize an existing transport manager for liquid phase + /*! + * This routine sets up an existing liquid-phase transport manager. + * It is similar to initTransport except that it uses the LiquidTransportParams + * class and calls setupLiquidTransport(). + * + * @param tr Pointer to the Transport manager + * @param thermo Pointer to the ThermoPhase object + * @param log_level Defaults to zero, no logging + * + * In DEBUG_MODE, this routine will create the file transport_log.xml + * and write informative information to it. + */ + virtual void initLiquidTransport(Transport* tr, thermo_t* thermo, int log_level=0); - /// Initialize an existing transport manager for liquid phase - virtual void initLiquidTransport(Transport* tr, - thermo_t* thermo, - int log_level=0); private: //! Static instance of the factor -> This is the only instance of this //! object allowed static TransportFactory* s_factory; + #if defined(THREAD_SAFE_CANTERA) - static boost::mutex transport_mutex ; + //! Static instance of the mutex used to ensure the proper reading of the transport database + static boost::mutex transport_mutex; #endif //! The constructor is private; use static method factory() to @@ -172,51 +262,171 @@ namespace Cantera { */ TransportFactory(); - void getTransportData(const std::vector &db, - XML_Node& log, const std::vector& names, - GasTransportParams& tr); - - - //! Read transport property data from a file for a list of species. + //! Read the transport database /*! - * - * Given the name of a file containing transport property + * Read transport property data from a file for a list of species. + * Given the name of a file containing transport property * parameters and a list of species names, this method returns an * instance of TransportParams containing the transport data for * these species read from the file. * + * @param xspecies Vector of pointers to species XML_Node databases. + * @param log reference to an XML_Node that will contain the log (unused) + * @param names vector of species names that must be filled in with valid transport parameters + * @param tr Output object containing the transport parameters + * for the species listed in names (in the order of their listing + * in names). */ - void getLiquidTransportData(const std::vector &db, - XML_Node& log, const std::vector& names, - LiquidTransportParams& tr); + void getTransportData(const std::vector &xspecies, + XML_Node& log, const std::vector& names, + GasTransportParams& tr); - /** Generate polynomial fits to viscosity, conductivity, and - * binary diffusion coefficients */ - void fitProperties(GasTransportParams& tr, std::ostream & logfile); - /// Generate polynomial fits to collision integrals - void fitCollisionIntegrals(std::ostream & logfile, - GasTransportParams& tr); + //! Read transport property data from a file for a list of species that comprise + //! the phase. + /*! + * Given a vector of pointers to species XML data bases + * and a list of species names, this method constructs the LiquidTransport + * Params object containing the transport data for these species. + * + * It is an error to not find a "transport" XML element within each of the species + * XML elements listed in the names vector. + * + * @param db Reference to a vector of XML_Node pointers containing the species XML + * nodes. + * @param log Reference to an XML log file. (currently unused) + * @param names Vector of names of species. On output, tr will contain transport data + * for each of of these names in the order determined by this vector. + * @param tr Reference to the LiquidTransportParams object that will contain the results. + */ + void getLiquidSpeciesTransportData(const std::vector &db, + XML_Node& log, const std::vector& names, + LiquidTransportParams& tr); - + //! Read transport property data from a file for interactions between species. + /*! + * Given the XML_Node database for transport interactions defined within the current phase + * and a list of species names within the phase, this method returns an + * instance of TransportParams containing the transport data for + * these species read from the file. + * + * This routine reads interaction parameters between species within the phase. + * + * @param phaseTran_db Reference to the transport XML field for the phase + * @param log Reference to an XML log file. (currently unused) + * @param names Vector of names of species. On output, tr will contain transport data + * for each of of these names in the order determined by this vector. + * @param tr Reference to the LiquidTransportParams object that will contain the results. + */ + void getLiquidInteractionsTransportData(const XML_Node &phaseTran_db, XML_Node& log, + const std::vector& names, LiquidTransportParams& tr); + //! Generate polynomial fits to the viscosity, conductivity, and + //! the binary diffusion coefficients + /*! + * If CK_mode, then the fits are of the form + * \f[ + * \log(\eta(i)) = \sum_{n = 0}^3 a_n(i) (\log T)^n + * \f] + * and + * \f[ + * \log(D(i,j)) = \sum_{n = 0}^3 a_n(i,j) (\log T)^n + * \f] + * Otherwise the fits are of the form + * \f[ + * \eta(i)/sqrt(k_BT) = \sum_{n = 0}^4 a_n(i) (\log T)^n + * \f] + * and + * \f[ + * D(i,j)/sqrt(k_BT)) = \sum_{n = 0}^4 a_n(i,j) (\log T)^n + * \f] + * + * @param tr Reference to the GasTransportParams object that will contain the results. + * @param logfile Reference to an ostream that will contain log information when in + * DEBUG_MODE + * + */ + void fitProperties(GasTransportParams& tr, std::ostream &logfile); + + //! Generate polynomial fits to collision integrals + /*! + * @param logfile Reference to an ostream that will contain log information when in + * DEBUG_MODE + * @param tr Reference to the GasTransportParams object that will contain the results. + */ + void fitCollisionIntegrals(std::ostream & logfile, GasTransportParams& tr); + + + //! Prepare to build a new kinetic-theory-based transport manager for low-density gases + /*! + * This class fills up the GastransportParams structure for the current phase + * + * Uses polynomial fits to Monchick & Mason collision integrals. store then in tr + * + * @param flog Reference to the ostream for writing log info + * @param transport_database Reference to a vector of pointers containing the + * transport database for each species + * @param thermo Pointer to the %ThermoPhase object + * @param mode Mode -> Either it's CK_Mode, chemkin compatibility mode, or it is not + * We usually run with chemkin compatibility mode turned off. + * @param log_level log level + * @param tr GasTransportParams structure to be filled up with information + */ void setupMM(std::ostream &flog, const std::vector &transport_database, - thermo_t* thermo, int mode, int log_level, - GasTransportParams& tr); + thermo_t* thermo, int mode, int log_level, GasTransportParams& tr); - void setupLiquidTransport(std::ostream &flog, const std::vector &transport_database, - thermo_t* thermo, int log_level, - LiquidTransportParams& tr); + //! Prepare to build a new transport manager for liquids assuming that + //! viscosity transport data is provided in Arhennius form. + /*! + * @param flog Reference to the ostream for writing log info + * @param thermo Pointer to the %ThermoPhase object + * @param log_level log level + * @param trParam LiquidTransportParams structure to be filled up with information + */ + void setupLiquidTransport(std::ostream &flog, thermo_t* thermo, int log_level, LiquidTransportParams& trParam); - /// Second-order correction to the binary diffusion coefficients - void getBinDiffCorrection(doublereal t, - const GasTransportParams& tr, int k, int j, + //! Second-order correction to the binary diffusion coefficients + /*! + * Calculate second-order corrections to binary diffusion + * coefficient pair (dkj, djk). At first order, the binary + * diffusion coefficients are independent of composition, and + * d(k,j) = d(j,k). But at second order, there is a weak + * dependence on composition, with the result that d(k,j) != + * d(j,k). This method computes the multiplier by which the + * first-order binary diffusion coefficient should be multiplied + * to produce the value correct to second order. The expressions + * here are taken from Marerro and Mason, J. Phys. Chem. Ref. Data, vol. 1, p. 3 (1972). + * + * @param t Temperature (K) + * @param tr Transport parameters + * @param k index of first species + * @param j index of second species + * @param xk Mole fraction of species k + * @param xj Mole fraction of species j + * @param fkj multiplier for d(k,j) + * @param fjk multiplier for d(j,k) + * + * @note This method is not used currently. + */ + void getBinDiffCorrection(doublereal t, const GasTransportParams& tr, int k, int j, doublereal xk, doublereal xj, doublereal& fkj, doublereal& fjk); - /// Corrections for polar-nonpolar binary diffusion coefficients + //! Corrections for polar-nonpolar binary diffusion coefficients + /*! + * Calculate corrections to the well depth parameter and the + * diameter for use in computing the binary diffusion coefficient + * of polar-nonpolar pairs. For more information about this + * correction, see Dixon-Lewis, Proc. Royal Society (1968). + * + * @param i Species one - this is a bimolecular correction routine + * @param j species two - this is a bimolecular correction routine + * @param tr Database of species properties read in from the input xml file. + * @param f_eps Multiplicative correction factor to be applied to epsilon(i,j) + * @param f_sigma Multiplicative correction factor to be applied to diam(i,j) + */ void makePolarCorrections(int i, int j, const GasTransportParams& tr, doublereal& f_eps, doublereal& f_sigma); @@ -231,48 +441,46 @@ namespace Cantera { //! Mapping between between the string name //! for a transport model and the integer name. std::map m_models; + + //! Mapping between between the string name + //! for a transport property and the integer name. + std::map m_tranPropMap; + + //! Mapping between between the string name for a + //! species-specific transport property model and the integer name. + std::map m_LTRmodelMap; + + //! Mapping between between the string name for a + //! liquid mixture transport property model and the integer name. + std::map m_LTImodelMap; }; - - /** - * Create a new transport manager instance. + //==================================================================================================================== + //! Create a new transport manager instance. + /*! + * @param transportModel String identifying the transport model to be instantiated, defaults to the empty string + * @param thermo ThermoPhase object associated with the phase, defaults to null pointer + * @param loglevel int containing the Loglevel, defaults to zero + * @param f ptr to the TransportFactory object if it's been malloced. + * * @ingroup transportProps */ - inline Transport* newTransportMgr(std::string transportModel = "", - thermo_t* thermo = 0, int loglevel=0, - TransportFactory* f=0) { - if (f == 0) { - f = TransportFactory::factory(); - } - Transport* ptr = f->newTransport(transportModel, thermo, loglevel); - /* - * Note: We delete the static s_factory instance here, instead of in - * appdelete() in misc.cpp, to avoid linking problems involving - * the need for multiple cantera and transport library statements - * for applications that don't have transport in them. - */ - return ptr; - } - - /** - * Create a new transport manager instance. + Transport* newTransportMgr(std::string transportModel = "", thermo_t* thermo = 0, int loglevel = 0, + TransportFactory* f = 0); + //==================================================================================================================== + //! Create a new transport manager instance. + /*! + * @param thermo ThermoPhase object associated with the phase, defaults to null pointer + * @param loglevel int containing the Loglevel, defaults to zero + * @param f ptr to the TransportFactory object if it's been malloced. + * + * @return Returns a transport manager for the phase + * * @ingroup transportProps */ - inline Transport* newDefaultTransportMgr(thermo_t* thermo, int loglevel=0, - TransportFactory* f=0) { - if (f == 0) { - f = TransportFactory::factory(); - } - Transport* ptr = f->newTransport(thermo, loglevel); - /* - * Note: We delete the static s_factory instance here, instead of in - * appdelete() in misc.cpp, to avoid linking problems involving - * the need for multiple cantera and transport library statements - * for applications that don't have transport in them. - */ - return ptr; - } + Transport* newDefaultTransportMgr(thermo_t* thermo, int loglevel = 0, TransportFactory* f = 0); - -} + //==================================================================================================================== +} // End of namespace Cantera +//====================================================================================================================== #endif diff --git a/Cantera/src/transport/TransportParams.cpp b/Cantera/src/transport/TransportParams.cpp new file mode 100644 index 000000000..a3e57b86d --- /dev/null +++ b/Cantera/src/transport/TransportParams.cpp @@ -0,0 +1,85 @@ +/** + * @file TransportParams.h + * Class that holds the data that is read in from the xml file, and which is used for + * processing of the transport object + * (see \ref tranprops and \link Cantera::TransportParams TransportParams \endlink). + */ +/* + * Latest Checkin: + * $Author$ + * $Date$ + * $Revision$ + */ + +#include "TransportParams.h" + +#ifdef DEBUG_MODE +#include "XML_Writer.h" +#endif +using namespace std; + + +namespace Cantera { + //==================================================================================================================== + NotImplemented::NotImplemented(std::string method) : + CanteraError("Transport", + "\n\n**** Method " + method + " not implemented. ****\n" + "(Did you forget to specify a transport model?)\n\n") + { + } + //==================================================================================================================== + TransportParams::TransportParams() : + nsp_(0), + thermo(0), + mw(0), + velocityBasis_(VB_MASSAVG), + tmax(1000000.), + tmin(10.), + mode_(0), + xml(0), + log_level(-1) + { + } + //==================================================================================================================== + // Destructor + TransportParams::~TransportParams() + { +#ifdef DEBUG_MODE + delete xml; +#endif + } + //==================================================================================================================== + // Constructor + GasTransportParams::GasTransportParams() : + TransportParams(), + visccoeffs(0), + condcoeffs(0), + diffcoeffs(0), + poly(0), + omega22_poly(0), + astar_poly(0), + bstar_poly(0), + cstar_poly(0), + zrot(0), + crot(0), + polar(0), + alpha(0), + fitlist(0), + eps(0), + sigma(0), + reducedMass(0, 0), + diam(0, 0), + epsilon(0, 0), + dipole(0, 0), + delta(0, 0) + { + } + //==================================================================================================================== + GasTransportParams:: ~GasTransportParams() + { + } + + + //==================================================================================================================== +} // End of namespace Cantera +//====================================================================================================================== diff --git a/Cantera/src/transport/TransportParams.h b/Cantera/src/transport/TransportParams.h old mode 100755 new mode 100644 index 24eeaa1cd..24a81ada5 --- a/Cantera/src/transport/TransportParams.h +++ b/Cantera/src/transport/TransportParams.h @@ -1,84 +1,284 @@ +/** + * @file TransportParams.h + * Class that holds the data that is read in from the xml file, and which is used for + * processing of the transport object + * (see \ref tranprops and \link Cantera::TransportParams TransportParams \endlink). + */ +/* + * Latest Checkin: + * $Date$ + * $Revision$ + */ + #ifndef CT_TRANSPORTPARAMS_H #define CT_TRANSPORTPARAMS_H #include #include "ct_defs.h" +#include "DenseMatrix.h" #include "TransportBase.h" -#include "xml.h" -#include "XML_Writer.h" namespace Cantera { - /** - * Base class to hold transport model parameters. - * Used by TransportFactory. + class XML_Writer; + + + //==================================================================================================================== + //! Error class to indicate an unimplemented method + /*! + * This class is used by transport objects + */ + class NotImplemented : public CanteraError { + public: + + //! Constructor for error class + /*! + * @param method Single string indicating a method that is not implemented */ - class TransportParams { + NotImplemented(std::string method); + }; + //==================================================================================================================== + //! Base structure to hold transport model parameters. + /*! + * This structure is used by TransportFactory. + */ + class TransportParams { - public: + public: - TransportParams() : thermo(0), xml(0) {} - virtual ~TransportParams(); - int nsp_; + //! Default Constructor + TransportParams(); - // phase_t* mix; - thermo_t* thermo; - vector_fp mw; + //! Destructor + virtual ~TransportParams(); - // polynomial fits - //temperature-fit viscosity - std::vector visccoeffs; - //temperature-fit heat conduction - std::vector condcoeffs; - //temperature-fit diffusivity - std::vector diffcoeffs; - vector_fp polytempvec; + //! Local storage of the number of species + int nsp_; - //minimum and maximum temperatures for parameter fits - doublereal tmax, tmin; - int mode_; - XML_Writer* xml; - int log_level; + //! Pointer to the ThermoPhase object + thermo_t* thermo; - }; - - - /** - * Holds transport model parameters relevant to transport in ideal - * gases with a kinetic theory of gases derived transport model. - * Used by TransportFactory. + //! Local storage of the molecular weights of the species + /*! + * Length is nsp_ and units are kg kmol-1. */ - class GasTransportParams : public TransportParams { + vector_fp mw; - public: + //! A basis for the average velocity can be specified. + /*! + * Valid bases include "mole", "mass", and "species" names. + */ + VelocityBasis velocityBasis_; - GasTransportParams() {} - ~GasTransportParams() {} + //! Maximum temperatures for parameter fits + doublereal tmax; + //! Minimum temperatures for parameter fits + doublereal tmin; - std::vector > poly; - std::vector omega22_poly; - std::vector astar_poly; - std::vector bstar_poly; - std::vector cstar_poly; + //! Mode parameter + int mode_; - vector_fp zrot; - vector_fp crot; + //! Pointer to the xml tree describing the implementation of transport for this object + XML_Writer* xml; - std::vector polar; - vector_fp alpha; - vector_fp fitlist; - vector_fp eps; - vector_fp sigma; - DenseMatrix reducedMass; - DenseMatrix diam; - DenseMatrix epsilon; - DenseMatrix dipole; - DenseMatrix delta; + //! Log level + int log_level; + }; - }; + //==================================================================================================================== + //! This structure holds transport model parameters relevant to transport in ideal + //! gases with a kinetic theory of gases derived transport model. + /*! + * This structure is used by TransportFactory object. + */ + class GasTransportParams : public TransportParams { -} + public: + + //! Constructor + GasTransportParams(); + + //! Destructor + virtual ~GasTransportParams(); + + // polynomial fits + + //! temperature-fit of the viscosity + /*! + * The outer loop the number of species, nsp + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector visccoeffs; + + //! temperature-fits of the heat conduction + /*! + * The outer loop the number of species, nsp + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector condcoeffs; + + //! temperature-fits of the diffusivity + /*! + * The outer loop the number of species, nsp + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector diffcoeffs; + + //! This is vector of vectors containing the integer lookup value for the (i,j) interaction + /*! + * The outer loop is over a flat (i,j) index that is parameterized on the tr.delta(i,j) value. + * Unique values of delta get their own spot in the array. The values of delta are storred in + * the fitlist vector. + * + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector > poly; + + //! This is vector of vectors containing the astar fit. + /*! + * The outer loop is over a flat (i,j) index that is parameterized on the tr.delta(i,j) value. + * Unique values of delta get their own spot in the array. The values of delta are storred in + * the fitlist vector. + * + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector omega22_poly; + + //! This is vector of vectors containing the astar fit. + /*! + * The outer loop is over a flat (i,j) index that is parameterized on the tr.delta(i,j) value. + * Unique values of delta get their own spot in the array. The values of delta are storred in + * the fitlist vector. + * + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector astar_poly; + + //! This is vector of vectors containing the astar fit. + /*! + * The outer loop is over a flat (i,j) index that is parameterized on the tr.delta(i,j) value. + * Unique values of delta get their own spot in the array. The values of delta are storred in + * the fitlist vector. + * + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector bstar_poly; + + //! This is vector of vectors containing the astar fit. + /*! + * The outer loop is over a flat (i,j) index that is parameterized on the tr.delta(i,j) value. + * Unique values of delta get their own spot in the array. The values of delta are storred in + * the fitlist vector. + * + * The inner loop is over degree + 1, which is the polynomial order of the collision integral fit. + */ + std::vector cstar_poly; + + //! Rotational relaxation number for the species in the current phase + /*! + * length is the number of species in the phase + * units are dimensionless + */ + vector_fp zrot; + + //! Dimensionless rotational heat capacity of the species in the current phase + /*! + * These values are 0, 1 and 1.5 for single-molecule, linear, and nonlinear species respectively + * length is the number of species in the pahse + * units are dimensionless (Cr / R) + */ + vector_fp crot; + + //! Vector of booleans indicating whether a species is a polar molecule + /*! + * Length is nsp + */ + std::vector polar; + + //! Polarizability of each species in the phase + /*! + * Length = nsp + * Units = m^3 + */ + vector_fp alpha; + + //! This is vector containing the values of delta(i,j) that are used in the collision integral fits. + /*! + * This is used in astar_poly, bstar_poly, cstar_poly, and omega22_poly. + * The outer loop is over a flat (i,j) index that is parameterized on the tr.delta(i,j) value. + * Unique values of delta get their own spot in the array. The values of delta are storred in + * the fitlist vector. + * + */ + vector_fp fitlist; + + //! Lennard-Jones well-depth of the species in the current phase + /*! + * length is the number of species in the phase + * Units are Joules (Note this is not Joules/kmol) (note, no kmol -> this is a per molecule amount) + */ + vector_fp eps; + + //! Lennard-Jones diameter of the species in the current phase + /*! + * length is the number of species in the phase + * units are in meters. + */ + vector_fp sigma; + + //! This is the reduced mass of the interaction between species i and j + /*! + * tr.reducedMass(i,j) = tr.mw[i] * tr.mw[j] / (Avogadro * (tr.mw[i] + tr.mw[j])); + * + * Units are kg (note, no kmol -> this is a per molecule amount) + * + * Length nsp * nsp. This is a symmetric matrix + */ + DenseMatrix reducedMass; + + //! hard-sphere diameter for (i,j) collision + /*! + * diam(i,j) = 0.5*(tr.sigma[i] + tr.sigma[j]); + * Units are m (note, no kmol -> this is a per molecule amount) + * + * Length nsp * nsp. This is a symmetric matrix. + */ + DenseMatrix diam; + + //! The effective well depth for (i,j) collisions + /*! + * epsilon(i,j) = sqrt(tr.eps[i]*tr.eps[j]); + * Units are Joules (note, no kmol -> this is a per molecule amount) + * + * Length nsp * nsp. This is a symmetric matrix. + */ + DenseMatrix epsilon; + + //! The effective dipole moment for (i,j) collisions + /*! + * tr.dipoleMoment has units of Debye's. A Debye is 10-18 cm3/2 erg1/2 + * + * tr.dipole(i,i) = 1.e-25 * SqrtTen * trdat.dipoleMoment; + * tr.dipole(i,j) = sqrt(tr.dipole(i,i)*tr.dipole(j,j)); + * Units are in Debye (note, no kmol -> this is a per molecule amount) + * + * Length nsp * nsp. This is a symmetric matrix. + */ + DenseMatrix dipole; + + //! Matrix containing the reduced dipole moment of the interaction between two species + /*! + * This is the reduced dipole moment of the interaction between two species + * 0.5 * tr.dipole(i,j)*tr.dipole(i,j) (epsilon(i,j) * d * d * d); + * + * Length nsp * nsp .This is a symmetric matrix + */ + DenseMatrix delta; + }; + //==================================================================================================================== +} // End of namespace Cantera +//====================================================================================================================== #endif //CT_TRANSPORTPARAMS_H diff --git a/Cantera/src/transport/WaterTransport.h b/Cantera/src/transport/WaterTransport.h index 31d89966a..f4e626bbe 100644 --- a/Cantera/src/transport/WaterTransport.h +++ b/Cantera/src/transport/WaterTransport.h @@ -1,11 +1,10 @@ /** - * - * @file LiquidTransport.h + * @file WaterTransport.h * Header file defining class LiquidTransport */ /* - * $Revision: 1.9 $ - * $Date: 2009/03/27 18:24:39 $ + * $Revision$ + * $Date$ */ #ifndef CT_WATERTRAN_H @@ -20,7 +19,6 @@ #include #include -using namespace std; // Cantera includes #include "TransportBase.h" @@ -28,7 +26,7 @@ using namespace std; #include "LiquidTransportParams.h" namespace Cantera { - + //! @{ const int LVISC_CONSTANT = 0; const int LVISC_WILKES = 1; const int LVISC_MIXTUREAVG = 2; @@ -36,18 +34,28 @@ namespace Cantera { const int LDIFF_MIXDIFF_UNCORRECTED = 0; const int LDIFF_MIXDIFF_FLUXCORRECTED = 1; const int LDIFF_MULTICOMP_STEFANMAXWELL = 2; - + //! @} class TransportParams; class WaterProps; class PDSS_Water; - + //! Transport Parameters for pure water + /*! + * + */ class WaterTransport : public Transport { public: //! default constructor + /*! + * @param thermo ThermoPhase object that represents the phase. + * Defaults to zero + * + * @param ndim Number of dimensions of the flux expressions. + * Defaults to a value of one. + */ WaterTransport(thermo_t* thermo = 0, int ndim = 1); //!Copy Constructor for the %LiquidThermo object. diff --git a/Cantera/src/zeroD/FlowDevice.cpp b/Cantera/src/zeroD/FlowDevice.cpp index 60d9fdeef..85a39aa70 100644 --- a/Cantera/src/zeroD/FlowDevice.cpp +++ b/Cantera/src/zeroD/FlowDevice.cpp @@ -4,6 +4,7 @@ #include "Func1.h" using namespace std; +using namespace Cantera; namespace CanteraZeroD { diff --git a/Cantera/src/zeroD/FlowDevice.h b/Cantera/src/zeroD/FlowDevice.h index 3273f5c5e..efd59b13d 100644 --- a/Cantera/src/zeroD/FlowDevice.h +++ b/Cantera/src/zeroD/FlowDevice.h @@ -23,7 +23,6 @@ namespace Cantera { class Func1; } -using namespace Cantera; namespace CanteraZeroD { @@ -166,7 +165,7 @@ namespace CanteraZeroD { doublereal m_mdot; Cantera::Func1* m_func; - vector_fp m_coeffs; + Cantera::vector_fp m_coeffs; int m_type; private: @@ -174,10 +173,10 @@ namespace CanteraZeroD { int m_nspin, m_nspout; ReactorBase* m_in; ReactorBase* m_out; - vector_int m_in2out, m_out2in; + Cantera::vector_int m_in2out, m_out2in; void warn(std::string meth) { - writelog(std::string("Warning: method ") + meth + " of base class " + Cantera::writelog(std::string("Warning: method ") + meth + " of base class " + " FlowDevice called. Nothing done.\n"); } }; diff --git a/Cantera/src/zeroD/Reactor.h b/Cantera/src/zeroD/Reactor.h index aca2506ce..510844405 100644 --- a/Cantera/src/zeroD/Reactor.h +++ b/Cantera/src/zeroD/Reactor.h @@ -59,10 +59,8 @@ namespace CanteraZeroD { public: - /** - * Default constructor. - */ - Reactor(); + //! Default constructor. + Reactor(); /** * Destructor. Deletes the integrator. @@ -82,7 +80,7 @@ namespace CanteraZeroD { setKineticsMgr(contents); } - void setKineticsMgr(Kinetics& kin) { + void setKineticsMgr(Cantera::Kinetics& kin) { m_kin = &kin; if (m_kin->nReactions() == 0) disableChemistry(); } @@ -121,26 +119,27 @@ namespace CanteraZeroD { virtual int componentIndex(std::string nm) const; protected: - - Kinetics* m_kin; - - doublereal m_temp_atol; // tolerance on T - doublereal m_maxstep; // max step size - doublereal m_vdot, m_Q; - vector_fp m_atol; - doublereal m_rtol; - vector_fp m_work; - vector_fp m_sdot; // surface production rates - bool m_chem; - bool m_energy; - int m_nv; - - int m_nsens; - vector_int m_pnum; - std::vector m_pname; - vector_int m_nsens_wall; - vector_fp m_mult_save; + //! Pointer to the homogeneous Kinetics object that handles the reactions + Cantera::Kinetics* m_kin; + //! Tolerance on the temperature + doublereal m_temp_atol; + doublereal m_maxstep; // max step size + doublereal m_vdot, m_Q; + Cantera::vector_fp m_atol; + doublereal m_rtol; + Cantera::vector_fp m_work; + Cantera::vector_fp m_sdot; // surface production rates + bool m_chem; + bool m_energy; + int m_nv; + + int m_nsens; + Cantera::vector_int m_pnum; + std::vector m_pname; + Cantera::vector_int m_nsens_wall; + Cantera::vector_fp m_mult_save; + private: }; } diff --git a/Cantera/src/zeroD/ReactorBase.cpp b/Cantera/src/zeroD/ReactorBase.cpp index 9348e6d66..dc7693a31 100644 --- a/Cantera/src/zeroD/ReactorBase.cpp +++ b/Cantera/src/zeroD/ReactorBase.cpp @@ -19,6 +19,8 @@ #include "Wall.h" using namespace std; +using namespace Cantera; + namespace CanteraZeroD { ReactorBase::ReactorBase(string name) : m_nsp(0), diff --git a/Cantera/src/zeroD/ReactorBase.h b/Cantera/src/zeroD/ReactorBase.h index 047265478..4f0bc5a11 100644 --- a/Cantera/src/zeroD/ReactorBase.h +++ b/Cantera/src/zeroD/ReactorBase.h @@ -20,8 +20,6 @@ #include "ThermoPhase.h" -using namespace Cantera; - /// Namespace for classes implementing zero-dimensional reactor networks. namespace CanteraZeroD { @@ -82,7 +80,7 @@ namespace CanteraZeroD { * a pointer to this substance is stored, and as the integration * proceeds, the state of the substance is modified. */ - void setThermoMgr(thermo_t& thermo); + void setThermoMgr(Cantera::thermo_t& thermo); void addInlet(FlowDevice& inlet); void addOutlet(FlowDevice& outlet); @@ -118,9 +116,9 @@ namespace CanteraZeroD { void resetState(); /// return a reference to the contents. - thermo_t& contents() { return *m_thermo; } + Cantera::thermo_t& contents() { return *m_thermo; } - const thermo_t& contents() const { return *m_thermo; } + const Cantera::thermo_t& contents() const { return *m_thermo; } doublereal residenceTime(); @@ -135,7 +133,14 @@ namespace CanteraZeroD { /// the current time (s). doublereal time() const { return m_time; } - doublereal volume() const { return m_vol; } + + //! Returns the current volume of the reactor + /*! + * @return Return the volume in m**3 + */ + doublereal volume() const { + return m_vol; + } doublereal density() const { return m_state[1]; } doublereal temperature() const { return m_state[0]; } doublereal enthalpy_mass() const { return m_enthalpy; } @@ -148,14 +153,16 @@ namespace CanteraZeroD { //@} int error(std::string msg) const { - writelog("Error: "+msg); + Cantera::writelog("Error: "+msg); return 1; } protected: - int m_nsp; - thermo_t* m_thermo; + //! Number of homogeneous species in the mixture + int m_nsp; + + Cantera::thermo_t* m_thermo; doublereal m_time; doublereal m_vol, m_vol0; bool m_init; @@ -164,10 +171,10 @@ namespace CanteraZeroD { doublereal m_enthalpy; doublereal m_intEnergy; doublereal m_pressure; - vector_fp m_state; + Cantera::vector_fp m_state; std::vector m_inlet, m_outlet; std::vector m_wall; - vector_int m_lr; + Cantera::vector_int m_lr; int m_nwalls; std::string m_name; double m_rho0; @@ -175,7 +182,7 @@ namespace CanteraZeroD { private: void tilt(std::string method="") const { - throw CanteraError("ReactorBase::"+method, + throw Cantera::CanteraError("ReactorBase::"+method, "ReactorBase method called!"); } }; } diff --git a/Cantera/src/zeroD/ReactorFactory.cpp b/Cantera/src/zeroD/ReactorFactory.cpp index 3a07c12fa..541e5d0ad 100644 --- a/Cantera/src/zeroD/ReactorFactory.cpp +++ b/Cantera/src/zeroD/ReactorFactory.cpp @@ -64,7 +64,7 @@ namespace CanteraZeroD { case ConstPressureReactorType: return new ConstPressureReactor(); default: - throw CanteraError("ReactorFactory::newReactor", + throw Cantera::CanteraError("ReactorFactory::newReactor", "unknown reactor type!"); } return 0; diff --git a/Cantera/src/zeroD/ReactorFactory.h b/Cantera/src/zeroD/ReactorFactory.h index d1da8024f..e54d07380 100644 --- a/Cantera/src/zeroD/ReactorFactory.h +++ b/Cantera/src/zeroD/ReactorFactory.h @@ -24,7 +24,7 @@ namespace CanteraZeroD { - class ReactorFactory : FactoryBase { + class ReactorFactory : Cantera::FactoryBase { public: diff --git a/Cantera/src/zeroD/ReactorNet.cpp b/Cantera/src/zeroD/ReactorNet.cpp index 48a02776b..e1a9d3693 100644 --- a/Cantera/src/zeroD/ReactorNet.cpp +++ b/Cantera/src/zeroD/ReactorNet.cpp @@ -4,6 +4,7 @@ #include "Wall.h" using namespace std; +using namespace Cantera; namespace CanteraZeroD { diff --git a/Cantera/src/zeroD/ReactorNet.h b/Cantera/src/zeroD/ReactorNet.h index 021610a23..b4d33b847 100644 --- a/Cantera/src/zeroD/ReactorNet.h +++ b/Cantera/src/zeroD/ReactorNet.h @@ -101,7 +101,7 @@ namespace CanteraZeroD { void setVerbose(bool v = true) { m_verbose = v; } /// Return a reference to the integrator. - Integrator& integrator() { return *m_integ; } + Cantera::Integrator& integrator() { return *m_integ; } void updateState(doublereal* y); @@ -115,7 +115,7 @@ namespace CanteraZeroD { } void evalJacobian(doublereal t, doublereal* y, - doublereal* ydot, doublereal* p, Array2D* j); + doublereal* ydot, doublereal* p, Cantera::Array2D* j); //----------------------------------------------------- @@ -144,20 +144,20 @@ namespace CanteraZeroD { std::vector m_reactors; int m_nr; int m_nreactors; - Integrator* m_integ; + Cantera::Integrator* m_integ; doublereal m_time; bool m_init; int m_nv; - vector_int m_size; - vector_fp m_atol; + Cantera::vector_int m_size; + Cantera::vector_fp m_atol; doublereal m_rtol, m_rtolsens; doublereal m_atols, m_atolsens; doublereal m_maxstep; bool m_verbose; int m_ntotpar; - vector_int m_nparams; - vector_int m_connect; - vector_fp m_ydot; + Cantera::vector_int m_nparams; + Cantera::vector_int m_connect; + Cantera::vector_fp m_ydot; std::vector m_iown; diff --git a/Cantera/src/zeroD/Reservoir.h b/Cantera/src/zeroD/Reservoir.h index d60539df3..e7ec546fa 100644 --- a/Cantera/src/zeroD/Reservoir.h +++ b/Cantera/src/zeroD/Reservoir.h @@ -33,8 +33,8 @@ namespace CanteraZeroD { virtual void initialize(doublereal t0 = 0.0) {} virtual void advance(doublereal time) {m_time = time;} - void insert(ThermoPhase& contents) { - setThermoMgr(contents); + void insert(Cantera::ThermoPhase& contents) { + setThermoMgr(contents); } private: diff --git a/Cantera/src/zeroD/Wall.cpp b/Cantera/src/zeroD/Wall.cpp index 2cfd91e46..30cbf5bf4 100644 --- a/Cantera/src/zeroD/Wall.cpp +++ b/Cantera/src/zeroD/Wall.cpp @@ -9,6 +9,7 @@ using Cantera::Func1; using Cantera::Kinetics; using namespace std; +using namespace Cantera; namespace CanteraZeroD { diff --git a/Cantera/src/zeroD/Wall.h b/Cantera/src/zeroD/Wall.h index 4afeb4b3f..8a9c7e351 100644 --- a/Cantera/src/zeroD/Wall.h +++ b/Cantera/src/zeroD/Wall.h @@ -28,7 +28,6 @@ namespace Cantera { class Func1; class SurfPhase; } -//using namespace Cantera; namespace CanteraZeroD { diff --git a/Cantera/user/Makefile.in b/Cantera/user/Makefile.in index 2160a2aa5..42548c761 100644 --- a/Cantera/user/Makefile.in +++ b/Cantera/user/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh ############################################################### -# $Author: hkmoffa $ -# $Date: 2008/01/01 19:19:50 $ -# $Revision: 1.7 $ +# $Author$ +# $Date$ +# $Revision$ # # Copyright 2002 California Institute of Technology # diff --git a/License.rtf b/License.rtf index 1adaa3d95..9142e3da8 100755 --- a/License.rtf +++ b/License.rtf @@ -43,7 +43,7 @@ \par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12135870 Copyright (c) 2001-2009}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid2033138\charrsid602915 , California Institute of Technology}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid602915 . }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid2033138\charrsid602915 All rights reserved.}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid2033138 \par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid602915 -\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid12135870 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12135870 Copyright (c) 2009, Sandia Corporation. Under the terms of +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid12135870 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12135870 Copyright (c) 2009, 2011, Sandia Corporation. Under the terms of Contract AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights to certain parts of this software. \par All rights reserved. \par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12135870\charrsid602915 @@ -173,4 +173,4 @@ ffffffffffffffffffffffffffffffff52006f006f007400200045006e0074007200790000000000 98404912ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file +0000000000000000000000000000000000000000000000000105000000000000}} diff --git a/License.txt b/License.txt index 9c39fa167..215387e61 100755 --- a/License.txt +++ b/License.txt @@ -2,7 +2,7 @@ Copyright (c) 2001-2009, California Institute of Technology All rights reserved. -Copyright (c) 2009, Sandia Corporation. Under the terms of +Copyright (c) 2009, 2011, Sandia Corporation. Under the terms of Contract AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights to certain parts of this software. All rights reserved. diff --git a/Makefile.in b/Makefile.in index 0d63a6f12..b672a59d6 100755 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,6 @@ #!/bin/sh # -# $Id: Makefile.in,v 1.96 2009/03/25 01:11:48 hkmoffa Exp $ +# $Id$ # export_dir = $(HOME)/sfdist version = @ctversion@ @@ -81,6 +81,7 @@ kernel-install: ( for ilib in @buildlib@/*.a ; do \ @INSTALL@ -c -m 644 $${ilib} @ct_libdir@ ; \ done ) + @INSTALL@ -d @ct_libdir@/apps ifeq ($(do_ranlib),1) @RANLIB@ @ct_libdir@/*.a endif @@ -116,7 +117,7 @@ hdr-install: @INSTALL@ -d @ct_incdir@ cp -r -f build/include/cantera @ct_incroot@ @(if test -f @ct_incroot@/cantera/Cantera_bt.mak ; then rm -f @ct_incroot@/cantera/Cantera_bt.mak ; fi ) - + @INSTALL@ -d @ct_incroot@/apps f90-modules-install: ifeq ($(build_f90),1) @@ -192,8 +193,14 @@ endif finish-install: @INSTALL@ -d @ct_docdir@ @INSTALL@ -d @ct_bindir@ + @INSTALL@ -d @ct_dir@/apps + @INSTALL@ -d @ct_dir@/apps/include + @INSTALL@ -d @ct_dir@/apps/bin + @INSTALL@ -d @ct_dir@/apps/lib + -( cd @ct_dir@/apps ; -$(RMDIRTREE) lib/* include/* bin/* ) -( cd bin ; @INSTALL@ -c exp3to2.sh "@ct_bindir@" ) -( cd bin ; @INSTALL@ -c csvdiff "@ct_bindir@" ) + -( cd bin ; @INSTALL@ -c install_tsc "@ct_bindir@" ) ifeq ($(os_is_win),0) # Commands to be executed for non-win systems cp -f License.rtf "@ct_bindir@" @@ -242,6 +249,7 @@ uninstall: -$(RMDIRTREE) @ct_demodir@ -$(RMDIRTREE) @ct_docdir@ -$(RMDIRTREE) @ct_tutdir@ + -$(RMDIRTREE) @ct_dir@/apps -$(RMDIRTREE) @prefix@/matlab/toolbox/cantera cd tools; @MAKE@ uninstall @@ -249,20 +257,18 @@ clean: -$(RMDIRTREE) *.*~ @buildlib@/*.* build/include/cantera/config.h svn*~ -cd Cantera; @MAKE@ clean -cd tools; @MAKE@ clean + -cd docs; @MAKE@ clean -cd ext; @MAKE@ clean -cd test_problems; @MAKE@ clean -$(RM) mt.mod docs: - cd tools/doxygen/Cantera; doxygen Cantera.cfg + cd docs; doxygen Cantera.cfg depends: cd Cantera; @MAKE@ depends cd tools; @MAKE@ depends cd ext; @MAKE@ depends -ifeq ($(build_particles),1) - cd Cantera/cads; @MAKE@ depends -endif ChangeLog: CVS/Entries tools/bin/cvs2cl.pl --prune diff --git a/apps/bvp/BoundaryValueProblem.h b/apps/bvp/BoundaryValueProblem.h index 106aabc4b..dc000fb91 100644 --- a/apps/bvp/BoundaryValueProblem.h +++ b/apps/bvp/BoundaryValueProblem.h @@ -7,8 +7,6 @@ #include #include -using namespace Cantera; -using namespace std; /// Namespace for the boundary value problem package. namespace BVP { diff --git a/apps/bvp/stagnation.cpp b/apps/bvp/stagnation.cpp index ac885ae38..e0357b63c 100644 --- a/apps/bvp/stagnation.cpp +++ b/apps/bvp/stagnation.cpp @@ -3,9 +3,9 @@ */ /* - * $Author: dggoodwin $ - * $Revision: 1.1 $ - * $Date: 2007/11/06 21:13:09 $ + * $Author$ + * $Revision$ + * $Date$ */ // Copyright 2002 California Institute of Technology diff --git a/config.h.in b/config.h.in index 52d4f7eb0..c13ec878b 100755 --- a/config.h.in +++ b/config.h.in @@ -9,12 +9,21 @@ // refering to branch number within svn #undef CANTERA_VERSION +//---------------------------- Version Flags ------------------// +// +// Cantera version -> this will be a double-quoted string value +// refering to branch number within svn +#undef CANTERA_VERSION +// // Integer for major number of Cantera #define CANTERA_VERSION_MAJORNUMBER 18 // Flag indicating it's part of major version 18 #define CANTERA_VERSION_18 1 // Flag indicating it's a development version #define CANTERA_VERSION_18_XXX 1 +// Flag indictaing that its part of 1.8_LiquidTransportDevelop branch +#define CANTERA_VERSION_18_LTD 1 +// //------------------------ Development flags ------------------// // @@ -75,9 +84,6 @@ typedef int ftnlen; // Fortran hidden string length type #undef DARWIN #undef HAS_SSTREAM -// Cantera version -#undef CANTERA_VERSION - // Identify whether the operating system is cygwin's overlay of // windows, with gcc being used as the compiler. #undef CYGWIN @@ -177,12 +183,19 @@ typedef int ftnlen; // Fortran hidden string length type // models for electrolyte solutions. #undef WITH_ELECTROLYTES +// Enable Real Gasses +#undef WITH_REAL_GASSES + #undef WITH_PRIME // Enable the VCS NonIdeal equilibrium solver. This is // accessed by specifying the solver=2 option #undef WITH_VCSNONIDEAL +// Enable intermediate zeroed phases to be included in the +// interfacial kinetics operator +#undef KINETICS_WITH_INTERMEDIATE_ZEROED_PHASES + //-------------- Optional Cantera Capabilities ---------------------- // Enable sensitivity analysis via changing H298 directly diff --git a/configure b/configure index 5f3a58df0..d85b60181 100755 --- a/configure +++ b/configure @@ -1,81 +1,423 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.59 for Cantera 1.7.0. +# Generated by GNU Autoconf 2.68 for Cantera 1.7.0. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# # -# Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' -elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then - set -o posix -fi -DUALCASE=1; export DUALCASE # for MKS sh - -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset + setopt NO_GLOB_SUBST else - as_unset=false + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac fi -# Work around bugs in pre-3.0 UWIN ksh. -$as_unset ENV MAIL MAILPATH +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. -for as_var in \ - LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ - LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ - LC_TELEPHONE LC_TIME -do - if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then - eval $as_var=C; export $as_var - else - $as_unset $as_var - fi -done +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE -# Required to use basename. -if expr a : '\(a\)' >/dev/null 2>&1; then +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi -if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. -as_me=`$as_basename "$0" || +as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)$' \| \ - . : '\(.\)' 2>/dev/null || -echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } - /^X\/\(\/\/\)$/{ s//\1/; q; } - /^X\/\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` - -# PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -83,146 +425,107 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x$as_lineno_3" = "x$as_lineno_2" || { - # Find who we are. Look in the path if we contain no path at all - # relative or not. - case $0 in - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done - - ;; - esac - # We did not find ourselves, most probably we were run as `sh COMMAND' - # in which case we are not to be found in the path. - if test "x$as_myself" = x; then - as_myself=$0 - fi - if test ! -f "$as_myself"; then - { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 - { (exit 1); exit 1; }; } - fi - case $CONFIG_SHELL in - '') - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for as_base in sh bash ksh sh5; do - case $as_dir in - /*) - if ("$as_dir/$as_base" -c ' - as_lineno_1=$LINENO - as_lineno_2=$LINENO - as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then - $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } - $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } - CONFIG_SHELL=$as_dir/$as_base - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$0" ${1+"$@"} - fi;; - esac - done -done -;; - esac - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line before each line; the second 'sed' does the real - # work. The second script uses 'N' to pair each line-number line - # with the numbered line, and appends trailing '-' during - # substitution so that $LINENO is not a special case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) - sed '=' <$as_myself | + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno N - s,$,-, - : loop - s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop - s,-$,, - s,^['$as_cr_digits']*\n,, + s/-\n.*// ' >$as_me.lineno && - chmod +x $as_me.lineno || - { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensible to this). - . ./$as_me.lineno + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" # Exit status is that of the last command. exit } - -case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in - *c*,-n*) ECHO_N= ECHO_C=' -' ECHO_T=' ' ;; - *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; - *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1; then - as_expr=expr -else - as_expr=false -fi - rm -f conf$$ conf$$.exe conf$$.file -echo >conf$$.file -if ln -s conf$$.file conf$$ 2>/dev/null; then - # We could just check for DJGPP; but this test a) works b) is more generic - # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). - if test -f conf$$.exe; then - # Don't use ln at all; we don't have any links - as_ln_s='cp -p' - else +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' fi -elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln else as_ln_s='cp -p' fi -rm -f conf$$ conf$$.exe conf$$.file +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi -as_executable_p="test -f" +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -231,38 +534,25 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" -# IFS -# We need space, tab and new line, in precisely that order. -as_nl=' -' -IFS=" $as_nl" - -# CDPATH. -$as_unset CDPATH - +test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` -exec 6>&1 - # # Initializations. # ac_default_prefix=/usr/local +ac_clean_files= ac_config_libobj_dir=. +LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} - -# Maximum number of lines to put in a shell here document. -# This variable seems obsolete. It should probably be removed, and -# only ac_max_sed_lines should be used. -: ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='Cantera' @@ -270,50 +560,264 @@ PACKAGE_TARNAME='cantera' PACKAGE_VERSION='1.7.0' PACKAGE_STRING='Cantera 1.7.0' PACKAGE_BUGREPORT='' +PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include -#if HAVE_SYS_TYPES_H +#ifdef HAVE_SYS_TYPES_H # include #endif -#if HAVE_SYS_STAT_H +#ifdef HAVE_SYS_STAT_H # include #endif -#if STDC_HEADERS +#ifdef STDC_HEADERS # include # include #else -# if HAVE_STDLIB_H +# ifdef HAVE_STDLIB_H # include # endif #endif -#if HAVE_STRING_H -# if !STDC_HEADERS && HAVE_MEMORY_H +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif -#if HAVE_STRINGS_H +#ifdef HAVE_STRINGS_H # include #endif -#if HAVE_INTTYPES_H +#ifdef HAVE_INTTYPES_H # include -#else -# if HAVE_STDINT_H -# include -# endif #endif -#if HAVE_UNISTD_H +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS BITCOMPILE BITHARDWARE BITCHANGE ldemulationarg CVF_LIBDIR USE_CLIB_DLL local_inst local_python_inst python_prefix python_win_prefix ctversion homedir ct_libdir ct_bindir ct_incdir ct_incroot ct_datadir ct_demodir ct_templdir ct_tutdir ct_docdir ct_dir ct_mandir build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os username ctroot buildinc buildlib buildbin MAKE GRAPHVIZDIR ARCHIVE DO_RANLIB RANLIB CXX_DEPENDS USERDIR INCL_USER_CODE CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT use_sundials CVODE_LIBS IDA_LIBS sundials_include sundials_lib_dir sundials_lib sundials_lib_dep CANTERA_DEBUG_MODE COMPILE_PURE_FLUIDS phase_object_files phase_header_files COMPILE_IDEAL_SOLUTIONS COMPILE_ELECTROLYTES NEED_CATHERMO COMPILE_KINETICS COMPILE_HETEROKIN COMPILE_RXNPATH WITH_REACTORS KERNEL KERNEL_OBJ BUILD_CK LIB_DIR COMPILE_VCSNONIDEAL COMPILE_H298MODIFY_CAPABILITY BOOST_INCLUDE BOOST_LIB PURIFY build_lapack build_blas BLAS_LAPACK_LIBS BLAS_LAPACK_LINK BLAS_LAPACK_DIR build_with_f2c build_f2c_lib F2C_SYSTEMLIB BOOST_LIB_DIR LOCAL_LIB_DIRS LOCAL_LIBS LOCAL_LIBS_DEP INSTALL_LIBS_DEP RAW_LIBS_DEP CANTERA_CORE_LIBS CANTERA_CORE_LIBS_DEP CT_SHARED_LIB PYTHON_CMD BUILD_PYTHON NUMPY_INC_DIR NUMPY_HOME NUMARRAY_INC_DIR NUMARRAY_HOME CANTERA_PYTHON_HOME CVSTAG MATLAB_CMD BUILD_MATLAB BUILD_CLIB export_name PIC INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CC CFLAGS ac_ct_CC CXXCPP EGREP SOEXT SHARED CXX_INCLUDES LCXX_FLAGS LCXX_END_LIBS HAVE_STRIPSYMBOLS F77 FFLAGS ac_ct_F77 FLIBS F90 BUILD_F90 F90FLAGS F90BUILDFLAGS F90LIBS LCXX_FLIBS precompile_headers OS_IS_DARWIN OS_IS_WIN OS_IS_CYGWIN SHARED_CTLIB mex_ext F77_EXT CXX_EXT OBJ_EXT EXE_EXT math_libs SO LDSHARED EXTRA_LINK TSCOMPARE_abs INSTALL_abs INSTALL_VERBOSE LIBOBJS LTLIBOBJS' +ac_subst_vars='LTLIBOBJS +LIBOBJS +INSTALL_VERBOSE +INSTALL_abs +TSCOMPARE_abs +EXTRA_LINK +LDSHARED +SO +math_libs +EXE_EXT +OBJ_EXT +CXX_EXT +F77_EXT +mex_ext +SHARED_CTLIB +OS_IS_CYGWIN +OS_IS_WIN +OS_IS_DARWIN +precompile_headers +LCXX_FLIBS +F90LIBS +F90BUILDFLAGS +F90FLAGS +BUILD_F90 +F90 +FLIBS +ac_ct_F77 +FFLAGS +F77 +HAVE_STRIPSYMBOLS +LCXX_END_LIBS +LCXX_FLAGS +CXX_INCLUDES +SHARED +SOEXT +EGREP +GREP +CXXCPP +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +PIC +export_name +BUILD_CLIB +BUILD_MATLAB +MATLAB_CMD +CVSTAG +CANTERA_PYTHON_HOME +NUMARRAY_HOME +NUMARRAY_INC_DIR +NUMPY_HOME +NUMPY_INC_DIR +BUILD_PYTHON +PYTHON_CMD +CT_SHARED_LIB +CANTERA_CORE_LIBS_DEP +CANTERA_CORE_LIBS +RAW_LIBS_DEP +INSTALL_LIBS_DEP +LOCAL_LIBS_DEP +LOCAL_LIBS +LOCAL_LIB_DIRS +BOOST_LIB_DIR +F2C_SYSTEMLIB +build_f2c_lib +build_with_f2c +BLAS_LAPACK_DIR +BLAS_LAPACK_LINK +BLAS_LAPACK_LIBS +build_blas +build_lapack +PURIFY +BOOST_LIB +BOOST_INCLUDE +COMPILE_INTERMEDIATE_ZEROED_KINETICS +COMPILE_H298MODIFY_CAPABILITY +COMPILE_VCSNONIDEAL +LIB_DIR +BUILD_CK +KERNEL_OBJ +KERNEL +WITH_REACTORS +COMPILE_RXNPATH +COMPILE_HETEROKIN +COMPILE_KINETICS +NEED_CATHERMO +COMPILE_ELECTROLYTES +COMPILE_IDEAL_SOLUTIONS +phase_header_files +phase_object_files +COMPILE_PURE_FLUIDS +CANTERA_DEBUG_MODE +sundials_lib_dep +sundials_lib +sundials_lib_dir +sundials_include +IDA_LIBS +CVODE_LIBS +use_sundials +INCL_USER_CODE +USERDIR +CXX_DEPENDS +RANLIB +DO_RANLIB +ARCHIVE +GRAPHVIZDIR +MAKE +buildbin +buildlib +buildinc +ctroot +username +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +ct_mandir +ct_dir +ct_docdir +ct_tutdir +ct_templdir +ct_demodir +ct_datadir +ct_incroot +ct_incdir +ct_bindir +ct_libdir +homedir +ctversion +python_win_prefix +python_prefix +local_python_inst +local_inst +USE_CLIB_DLL +CVF_LIBDIR +ldemulationarg +ac_ct_CC +CFLAGS +CC +OBJEXT +EXEEXT +ac_ct_CXX +CPPFLAGS +LDFLAGS +CXXFLAGS +CXX +BITCHANGE +BITHARDWARE +BITCOMPILE +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' ac_subst_files='' +ac_user_opts=' +enable_option_checking +' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CC +CFLAGS +CXXCPP +F77 +FFLAGS' + # Initialize some variables set by options. ac_init_help= ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null @@ -336,34 +840,49 @@ x_libraries=NONE # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' -datadir='${prefix}/share' +datarootdir='${prefix}/share' +datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' -infodir='${prefix}/info' -mandir='${prefix}/man' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' ac_prev= +ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then - eval "$ac_prev=\$ac_option" + eval $ac_prev=\$ac_option ac_prev= continue fi - ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_option in + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; @@ -385,33 +904,59 @@ do --config-cache | -C) cache_file=config.cache ;; - -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ - | --da=*) + -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + -disable-* | --disable-*) - ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid feature name: $ac_feature" >&2 - { (exit 1); exit 1; }; } - ac_feature=`echo $ac_feature | sed 's/-/_/g'` - eval "enable_$ac_feature=no" ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; -enable-* | --enable-*) - ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid feature name: $ac_feature" >&2 - { (exit 1); exit 1; }; } - ac_feature=`echo $ac_feature | sed 's/-/_/g'` - case $ac_option in - *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; - *) ac_optarg=yes ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; esac - eval "enable_$ac_feature='$ac_optarg'" ;; + eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ @@ -438,6 +983,12 @@ do -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; @@ -462,13 +1013,16 @@ do | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst \ - | --locals | --local | --loca | --loc | --lo) + | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* \ - | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) @@ -533,6 +1087,16 @@ do | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; @@ -583,26 +1147,36 @@ do ac_init_version=: ;; -with-* | --with-*) - ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid package name: $ac_package" >&2 - { (exit 1); exit 1; }; } - ac_package=`echo $ac_package| sed 's/-/_/g'` - case $ac_option in - *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; - *) ac_optarg=yes ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; esac - eval "with_$ac_package='$ac_optarg'" ;; + eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) - ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid package name: $ac_package" >&2 - { (exit 1); exit 1; }; } - ac_package=`echo $ac_package | sed 's/-/_/g'` - eval "with_$ac_package=no" ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. @@ -622,27 +1196,26 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) { echo "$as_me: error: unrecognized option: $ac_option -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. - expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 - { (exit 1); exit 1; }; } - ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` - eval "$ac_envvar='$ac_optarg'" + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. - echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -650,31 +1223,36 @@ done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - { echo "$as_me: error: missing argument to $ac_option" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "missing argument to $ac_option" fi -# Be sure to have absolute paths. -for ac_var in exec_prefix prefix -do - eval ac_val=$`echo $ac_var` - case $ac_val in - [\\/$]* | ?:[\\/]* | NONE | '' ) ;; - *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 - { (exit 1); exit 1; }; };; +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac -done +fi -# Be sure to have absolute paths. -for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ - localstatedir libdir includedir oldincludedir infodir mandir +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir do - eval ac_val=$`echo $ac_var` + eval ac_val=\$$ac_var + # Remove trailing slashes. case $ac_val in - [\\/$]* | ?:[\\/]* ) ;; - *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 - { (exit 1); exit 1; }; };; + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -688,8 +1266,8 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -701,90 +1279,72 @@ test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes - # Try the directory containing this script, then its parent. - ac_confdir=`(dirname "$0") 2>/dev/null || -$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$0" : 'X\(//\)[^/]' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || -echo X"$0" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } - /^X\(\/\/\)[^/].*/{ s//\1/; q; } - /^X\(\/\/\)$/{ s//\1/; q; } - /^X\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` srcdir=$ac_confdir - if test ! -r $srcdir/$ac_unique_file; then + if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi -if test ! -r $srcdir/$ac_unique_file; then - if test "$ac_srcdir_defaulted" = yes; then - { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 - { (exit 1); exit 1; }; } - else - { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 - { (exit 1); exit 1; }; } - fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || - { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 - { (exit 1); exit 1; }; } -srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` -ac_env_build_alias_set=${build_alias+set} -ac_env_build_alias_value=$build_alias -ac_cv_env_build_alias_set=${build_alias+set} -ac_cv_env_build_alias_value=$build_alias -ac_env_host_alias_set=${host_alias+set} -ac_env_host_alias_value=$host_alias -ac_cv_env_host_alias_set=${host_alias+set} -ac_cv_env_host_alias_value=$host_alias -ac_env_target_alias_set=${target_alias+set} -ac_env_target_alias_value=$target_alias -ac_cv_env_target_alias_set=${target_alias+set} -ac_cv_env_target_alias_value=$target_alias -ac_env_CXX_set=${CXX+set} -ac_env_CXX_value=$CXX -ac_cv_env_CXX_set=${CXX+set} -ac_cv_env_CXX_value=$CXX -ac_env_CXXFLAGS_set=${CXXFLAGS+set} -ac_env_CXXFLAGS_value=$CXXFLAGS -ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} -ac_cv_env_CXXFLAGS_value=$CXXFLAGS -ac_env_LDFLAGS_set=${LDFLAGS+set} -ac_env_LDFLAGS_value=$LDFLAGS -ac_cv_env_LDFLAGS_set=${LDFLAGS+set} -ac_cv_env_LDFLAGS_value=$LDFLAGS -ac_env_CPPFLAGS_set=${CPPFLAGS+set} -ac_env_CPPFLAGS_value=$CPPFLAGS -ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} -ac_cv_env_CPPFLAGS_value=$CPPFLAGS -ac_env_CC_set=${CC+set} -ac_env_CC_value=$CC -ac_cv_env_CC_set=${CC+set} -ac_cv_env_CC_value=$CC -ac_env_CFLAGS_set=${CFLAGS+set} -ac_env_CFLAGS_value=$CFLAGS -ac_cv_env_CFLAGS_set=${CFLAGS+set} -ac_cv_env_CFLAGS_value=$CFLAGS -ac_env_CXXCPP_set=${CXXCPP+set} -ac_env_CXXCPP_value=$CXXCPP -ac_cv_env_CXXCPP_set=${CXXCPP+set} -ac_cv_env_CXXCPP_value=$CXXCPP -ac_env_F77_set=${F77+set} -ac_env_F77_value=$F77 -ac_cv_env_F77_set=${F77+set} -ac_cv_env_F77_value=$F77 -ac_env_FFLAGS_set=${FFLAGS+set} -ac_env_FFLAGS_value=$FFLAGS -ac_cv_env_FFLAGS_set=${FFLAGS+set} -ac_cv_env_FFLAGS_value=$FFLAGS +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done # # Report the --help message. @@ -807,20 +1367,17 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] -_ACEOF - - cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] + [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] + [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify @@ -830,18 +1387,25 @@ for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --datadir=DIR read-only architecture-independent data [PREFIX/share] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --infodir=DIR info documentation [PREFIX/info] - --mandir=DIR man documentation [PREFIX/man] + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/cantera] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF @@ -864,8 +1428,9 @@ Some influential environment variables: CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory - CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have - headers in a nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory CC C compiler command CFLAGS C compiler flags CXXCPP C++ preprocessor @@ -875,121 +1440,541 @@ Some influential environment variables: Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. +Report bugs to the package provider. _ACEOF +ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. - ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d $ac_dir || continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue ac_builddir=. -if test "$ac_dir" != .; then - ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` - # A "../" for each directory in $ac_dir_suffix. - ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` -else - ac_dir_suffix= ac_top_builddir= -fi +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix case $srcdir in - .) # No --srcdir option. We are building in place. + .) # We are building in place. ac_srcdir=. - if test -z "$ac_top_builddir"; then - ac_top_srcdir=. - else - ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` - fi ;; - [\\/]* | ?:[\\/]* ) # Absolute path. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir ;; - *) # Relative path. - ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_builddir$srcdir ;; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix -# Do not use `cd foo && pwd` to compute absolute paths, because -# the directories may not exist. -case `pwd` in -.) ac_abs_builddir="$ac_dir";; -*) - case "$ac_dir" in - .) ac_abs_builddir=`pwd`;; - [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; - *) ac_abs_builddir=`pwd`/"$ac_dir";; - esac;; -esac -case $ac_abs_builddir in -.) ac_abs_top_builddir=${ac_top_builddir}.;; -*) - case ${ac_top_builddir}. in - .) ac_abs_top_builddir=$ac_abs_builddir;; - [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; - *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; - esac;; -esac -case $ac_abs_builddir in -.) ac_abs_srcdir=$ac_srcdir;; -*) - case $ac_srcdir in - .) ac_abs_srcdir=$ac_abs_builddir;; - [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; - *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; - esac;; -esac -case $ac_abs_builddir in -.) ac_abs_top_srcdir=$ac_top_srcdir;; -*) - case $ac_top_srcdir in - .) ac_abs_top_srcdir=$ac_abs_builddir;; - [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; - *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; - esac;; -esac - - cd $ac_dir - # Check for guested configure; otherwise get Cygnus style configure. - if test -f $ac_srcdir/configure.gnu; then - echo - $SHELL $ac_srcdir/configure.gnu --help=recursive - elif test -f $ac_srcdir/configure; then - echo - $SHELL $ac_srcdir/configure --help=recursive - elif test -f $ac_srcdir/configure.ac || - test -f $ac_srcdir/configure.in; then - echo - $ac_configure --help + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive else - echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi - cd $ac_popdir + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } done fi -test -n "$ac_init_help" && exit 0 +test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Cantera configure 1.7.0 -generated by GNU Autoconf 2.59 +generated by GNU Autoconf 2.68 -Copyright (C) 2003 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF - exit 0 + exit fi -exec 5>config.log -cat >&5 <<_ACEOF + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_cxx_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_cxx_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_run + +# ac_fn_cxx_compute_int LINENO EXPR VAR INCLUDES +# ---------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_cxx_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES +# --------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_cxx_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_compile + +# ac_fn_f77_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_f77_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_f77_try_compile +cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Cantera $as_me 1.7.0, which was -generated by GNU Autoconf 2.59. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ _ACEOF +exec 5>>config.log { cat <<_ASUNAME ## --------- ## @@ -1008,7 +1993,7 @@ uname -v = `(uname -v) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` @@ -1020,8 +2005,9 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - echo "PATH: $as_dir" -done + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS } >&5 @@ -1043,7 +2029,6 @@ _ACEOF ac_configure_args= ac_configure_args0= ac_configure_args1= -ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do @@ -1054,13 +2039,13 @@ do -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) - ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in - 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) - ac_configure_args1="$ac_configure_args1 '$ac_arg'" + as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else @@ -1076,104 +2061,115 @@ do -* ) ac_must_keep_next=true ;; esac fi - ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" - # Get rid of the leading space. - ac_sep=" " + as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done -$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } -$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. -# WARNING: Be sure not to use single quotes in there, as some shells, -# such as our DU 5.0 friend, will then `close' the trap. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, -{ +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done (set) 2>&1 | - case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in - *ac_space=\ *) + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) sed -n \ - "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" - ;; + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( *) - sed -n \ - "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; - esac; -} + esac | + sort +) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do - eval ac_val=$`echo $ac_var` - echo "$ac_var='"'"'$ac_val'"'"'" + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------- ## -## Output files. ## -## ------------- ## -_ASBOX + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" echo for ac_var in $ac_subst_files do - eval ac_val=$`echo $ac_var` - echo "$ac_var='"'"'$ac_val'"'"'" + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo - sed "/^$/d" confdefs.h | sort + cat confdefs.h echo fi test "$ac_signal" != 0 && - echo "$as_me: caught signal $ac_signal" - echo "$as_me: exit $exit_status" + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" } >&5 - rm -f core *.core && - rm -rf conftest* confdefs* conf$$* $ac_clean_files && + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status - ' 0 +' 0 for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -rf conftest* confdefs.h -# AIX cpp loses on an empty file, so make sure it contains at least a newline. -echo >confdefs.h +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. @@ -1181,42 +2177,57 @@ cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + # Let the site file select an alternate cache file if it wants to. -# Prefer explicitly selected file to automatically selected ones. -if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" - fi +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site fi -for ac_site_file in $CONFIG_SITE; do - if test -r "$ac_site_file"; then - { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 -echo "$as_me: loading site script $ac_site_file" >&6;} +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } fi done @@ -1224,53 +2235,63 @@ done # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false -for ac_var in `(set) 2>&1 | - sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do +for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val="\$ac_cv_env_${ac_var}_value" - eval ac_new_val="\$ac_env_${ac_var}_value" + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 -echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then - { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 -echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 -echo "$as_me: former value: $ac_old_val" >&2;} - { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 -echo "$as_me: current value: $ac_new_val" >&2;} - ac_cache_corrupted=: + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) - ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then - { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 -echo "$as_me: error: changes in the environment can compromise the build" >&2;} - { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 -echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} - { (exit 1); exit 1; }; } + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -1280,58 +2301,38 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - - - - - - - - - - - - - - - - - - - - ac_config_headers="$ac_config_headers config.h" +ac_config_headers="$ac_config_headers config.h" # AC_CONFIG_AUX_DIR(.) # AC_CONFIG_SRCDIR(./License.txt) ac_aux_dir= -for ac_dir in config $srcdir/config; do - if test -f $ac_dir/install-sh; then +for ac_dir in config "$srcdir"/config; do + if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break - elif test -f $ac_dir/install.sh; then + elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break - elif test -f $ac_dir/shtool; then + elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then - { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in config $srcdir/config" >&5 -echo "$as_me: error: cannot find install-sh or install.sh in config $srcdir/config" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5 fi -ac_config_guess="$SHELL $ac_aux_dir/config.guess" -ac_config_sub="$SHELL $ac_aux_dir/config.sub" -ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + if test -z $CANTERA_VERSION ; then @@ -1356,9 +2357,7 @@ echo " " echo "--------------------------------------------------------------" echo " " -cat >>confdefs.h <<\_ACEOF -#define NDEBUG 1 -_ACEOF +$as_echo "#define NDEBUG 1" >>confdefs.h ac_sys_system=`uname -s` @@ -1409,6 +2408,1095 @@ fi +# +#----------------------------------------------------------------------- +# C++ and C Compilation - INITIAL SECTION +#----------------------------------------------------------------------- +# +# CFLAGS: flags that get attached to the C compiler +# statement. AFLAGS are base flags that +# get added to compilers and loaders. +# FFLAGS: flags that get attached to the Fortran compiler +# statement. AFLAGS are base flags that +# get added to compilers and loaders. +# +# CXXFLAGS: Flags that get attached to the CXX compiler +# statement. AFLAGS are base flags that +# get added to compilers and loaders. +# +if test -z "$AFLAGS" ; then + AFLAGS=" " +fi +if test -z "$CXXFLAGS" ; then + CXXFLAGS="$AFLAGS" +else + CXXFLAGS="$CXXFLAGS"" ""$AFLAGS" +fi +if test -z "$CFLAGS" ; then + CFLAGS="$AFLAGS" +else + CFLAGS="$CFLAGS"" ""$AFLAGS" +fi +if test -z "$FFLAGS" ; then + FFLAGS="$AFLAGS" +else + FFLAGS="$FFLAGS"" ""$AFLAGS" +fi +export CXXFLAGS +export AFLAGS +export CFLAGS +export FFLAGS +# +# Note these should not be within if blocks +# +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 +$as_echo_n "checking whether the C++ compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C++ compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 +$as_echo_n "checking for C++ compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + SHARED_CTLIB=0 @@ -1558,79 +3646,107 @@ ct_mandir=${prefix} # Make sure we can run config.sub. -$ac_config_sub sun4 >/dev/null 2>&1 || - { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 -echo "$as_me: error: cannot run $ac_config_sub" >&2;} - { (exit 1); exit 1; }; } +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -echo "$as_me:$LINENO: checking build system type" >&5 -echo $ECHO_N "checking build system type... $ECHO_C" >&6 -if test "${ac_cv_build+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 else - ac_cv_build_alias=$build_alias -test -z "$ac_cv_build_alias" && - ac_cv_build_alias=`$ac_config_guess` -test -z "$ac_cv_build_alias" && - { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 -echo "$as_me: error: cannot guess build type; you must specify one" >&2;} - { (exit 1); exit 1; }; } -ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || - { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 -echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} - { (exit 1); exit 1; }; } + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi -echo "$as_me:$LINENO: result: $ac_cv_build" >&5 -echo "${ECHO_T}$ac_cv_build" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; +esac build=$ac_cv_build -build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -echo "$as_me:$LINENO: checking host system type" >&5 -echo $ECHO_N "checking host system type... $ECHO_C" >&6 -if test "${ac_cv_host+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 else - ac_cv_host_alias=$host_alias -test -z "$ac_cv_host_alias" && - ac_cv_host_alias=$ac_cv_build_alias -ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || - { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 -echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} - { (exit 1); exit 1; }; } + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi fi -echo "$as_me:$LINENO: result: $ac_cv_host" >&5 -echo "${ECHO_T}$ac_cv_host" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; +esac host=$ac_cv_host -host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -echo "$as_me:$LINENO: checking target system type" >&5 -echo $ECHO_N "checking target system type... $ECHO_C" >&6 -if test "${ac_cv_target+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 else - ac_cv_target_alias=$target_alias -test "x$ac_cv_target_alias" = "x" && - ac_cv_target_alias=$ac_cv_host_alias -ac_cv_target=`$ac_config_sub $ac_cv_target_alias` || - { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5 -echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;} - { (exit 1); exit 1; }; } + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi fi -echo "$as_me:$LINENO: result: $ac_cv_target" >&5 -echo "${ECHO_T}$ac_cv_target" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5 ;; +esac target=$ac_cv_target -target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. @@ -1639,6 +3755,7 @@ test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- + # the root of the source tree ctroot=`(pwd)` builddir=$target @@ -1738,16 +3855,19 @@ fi #---------------------------------------- -######################################################## +######################################################### # User Code ######################################################### USERDIR="" INCL_USER_CODE=0 -if test -n "$USER_SRC_DIR"; then USERDIR=$USER_SRC_DIR; INCL_USER_CODE=1; fi +if test -n "$USER_SRC_DIR"; then + USERDIR=$USER_SRC_DIR + INCL_USER_CODE=1 +fi -ac_ext=cc +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -1760,11 +3880,11 @@ CVODE_LIBS='-lcvode' IDA_LIBS='' if test "x$SUNDIALS_HOME" = "x"; then -SUNDIALS_LIB_DIR=/usr/local/lib -SUNDIALS_INC_DIR=/usr/local/include + SUNDIALS_LIB_DIR=/usr/local/lib + SUNDIALS_INC_DIR=/usr/local/include else -SUNDIALS_LIB_DIR="$SUNDIALS_HOME/lib" -SUNDIALS_INC_DIR="$SUNDIALS_HOME/include" + SUNDIALS_LIB_DIR="$SUNDIALS_HOME/lib" + SUNDIALS_INC_DIR="$SUNDIALS_HOME/include" fi if test "$USE_SUNDIALS" = "default"; then @@ -1773,629 +3893,44 @@ if test "$USE_SUNDIALS" = "default"; then # SUNDIALS_LIB_DIR had a space in it, despite use of double quotes everywhere #ldsave="$LDFLAGS" #LDFLAGS='-L'"$SUNDIALS_LIB_DIR"' '"$ldsave" -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -n "$ac_tool_prefix"; then - for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - echo "$as_me:$LINENO: result: $CXX" >&5 -echo "${ECHO_T}$CXX" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 -echo "${ECHO_T}$ac_ct_CXX" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$ac_ct_CXX" && break -done -test -n "$ac_ct_CXX" || ac_ct_CXX="g++" - - CXX=$ac_ct_CXX -fi - - -# Provide some information about the compiler. -echo "$as_me:$LINENO:" \ - "checking for C++ compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 -echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6 -ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` -if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 - (eval $ac_link_default) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # Find the output, starting from the most likely. This scheme is -# not robust to junk in `.', hence go to wildcards (a.*) only as a last -# resort. - -# Be careful to initialize this variable, since it used to be cached. -# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. -ac_cv_exeext= -# b.out is created by i960 compilers. -for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) - ;; - conftest.$ac_ext ) - # This is the source file. - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - # FIXME: I believe we export ac_cv_exeext for Libtool, - # but it would be cool to find out if it's true. Does anybody - # maintain Libtool? --akim. - export ac_cv_exeext - break;; - * ) - break;; - esac -done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables -See \`config.log' for more details." >&5 -echo "$as_me: error: C++ compiler cannot create executables -See \`config.log' for more details." >&2;} - { (exit 77); exit 77; }; } -fi - -ac_exeext=$ac_cv_exeext -echo "$as_me:$LINENO: result: $ac_file" >&5 -echo "${ECHO_T}$ac_file" >&6 - -# Check the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 -echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6 -# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run C++ compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - fi - fi -fi -echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 - -rm -f a.out a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -# Check the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 -echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 -echo "$as_me:$LINENO: result: $cross_compiling" >&5 -echo "${ECHO_T}$cross_compiling" >&6 - -echo "$as_me:$LINENO: checking for suffix of executables" >&5 -echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - export ac_cv_exeext - break;; - * ) break;; - esac -done -else - { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -rm -f conftest$ac_cv_exeext -echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 -echo "${ECHO_T}$ac_cv_exeext" >&6 - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -echo "$as_me:$LINENO: checking for suffix of object files" >&5 -echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 -if test "${ac_cv_objext+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 -echo "${ECHO_T}$ac_cv_objext" >&6 -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 -if test "${ac_cv_cxx_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_compiler_gnu=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 -GXX=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -CXXFLAGS="-g" -echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 -echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 -if test "${ac_cv_prog_cxx_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cxx_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cxx_g=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -for ac_declaration in \ - '' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -#include -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -continue -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -rm -f conftest* -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - -echo "$as_me:$LINENO: checking for CVodeCreate in -lsundials_cvodes" >&5 -echo $ECHO_N "checking for CVodeCreate in -lsundials_cvodes... $ECHO_C" >&6 -if test "${ac_cv_lib_sundials_cvodes_CVodeCreate+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CVodeCreate in -lsundials_cvodes" >&5 +$as_echo_n "checking for CVodeCreate in -lsundials_cvodes... " >&6; } +if ${ac_cv_lib_sundials_cvodes_CVodeCreate+:} false; then : + $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lsundials_cvodes \ --lsundials_cvodes -lsundials_nvecserial -lm $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +LIBS="-lsundials_cvodes -lsundials_cvodes -lsundials_nvecserial -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -/* Override any gcc2 internal prototype to avoid an error. */ +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ char CVodeCreate (); int main () { -CVodeCreate (); +return CVodeCreate (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_sundials_cvodes_CVodeCreate=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_lib_sundials_cvodes_CVodeCreate=no + ac_cv_lib_sundials_cvodes_CVodeCreate=no fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_sundials_cvodes_CVodeCreate" >&5 -echo "${ECHO_T}$ac_cv_lib_sundials_cvodes_CVodeCreate" >&6 -if test $ac_cv_lib_sundials_cvodes_CVodeCreate = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sundials_cvodes_CVodeCreate" >&5 +$as_echo "$ac_cv_lib_sundials_cvodes_CVodeCreate" >&6; } +if test "x$ac_cv_lib_sundials_cvodes_CVodeCreate" = xyes; then : use_sundials=1 else use_sundials=0 @@ -2410,7 +3945,7 @@ if test ${use_sundials} = 0 ; then fi if test ${use_sundials} = 1 ; then - echo SUNDIALS: succeeded in finding a sundials installation + echo "SUNDIALS: succeeded in finding a sundials installation" else echo SUNDIALS: failed at finding a sundials installation fi @@ -2418,8 +3953,9 @@ fi fi if test "x$USE_SUNDIALS" = "xy"; then -use_sundials=1 + use_sundials=1 fi +echo "Out of Block" sundials_lib_dir= sundials_lib= sundials_lib_dep= @@ -2432,13 +3968,9 @@ CVODE_LIBS='-lsundials_cvodes -lsundials_nvecserial' IDA_LIBS='-lsundials_ida -lsundials_nvecserial' if test "$SUNDIALS_VERSION" = "2.2"; then - cat >>confdefs.h <<\_ACEOF -#define HAS_SUNDIALS 1 -_ACEOF + $as_echo "#define HAS_SUNDIALS 1" >>confdefs.h - cat >>confdefs.h <<\_ACEOF -#define SUNDIALS_VERSION_22 1 -_ACEOF + $as_echo "#define SUNDIALS_VERSION_22 1" >>confdefs.h sundials_include='-I'${SUNDIALS_HOME}'/include -I'${SUNDIALS_HOME}'/include/sundials -I'${SUNDIALS_HOME}'/include/cvodes -I'${SUNDIALS_HOME}'/include/ida' echo "sundials include directory: " ${sundials_include} @@ -2447,13 +3979,9 @@ _ACEOF sundials_lib="-L$SUNDIALS_LIB_DIR -lsundials_cvodes -lsundials_ida -lsundials_nvecserial" sundials_lib_dep="$SUNDIALS_LIB_DIR/libsundials_cvodes.a $SUNDIALS_LIB_DIR/libsundials_ida.a $SUNDIALS_LIB_DIR/libsundials_nvecserial.a" elif test "$SUNDIALS_VERSION" = "2.3"; then - cat >>confdefs.h <<\_ACEOF -#define HAS_SUNDIALS 1 -_ACEOF + $as_echo "#define HAS_SUNDIALS 1" >>confdefs.h - cat >>confdefs.h <<\_ACEOF -#define SUNDIALS_VERSION_23 1 -_ACEOF + $as_echo "#define SUNDIALS_VERSION_23 1" >>confdefs.h sundials_include='-I'${SUNDIALS_INC_DIR} echo "sundials include directory: " ${sundials_include} @@ -2463,13 +3991,9 @@ _ACEOF sundials_lib_dep="$SUNDIALS_LIB_DIR/libsundials_cvodes.a $SUNDIALS_LIB_DIR/libsundials_ida.a $SUNDIALS_LIB_DIR/libsundials_nvecserial.a" # python tools/src/sundials_version.py $SUNDIALS_HOME elif test "$SUNDIALS_VERSION" = "2.4"; then - cat >>confdefs.h <<\_ACEOF -#define HAS_SUNDIALS 1 -_ACEOF + $as_echo "#define HAS_SUNDIALS 1" >>confdefs.h - cat >>confdefs.h <<\_ACEOF -#define SUNDIALS_VERSION_24 1 -_ACEOF + $as_echo "#define SUNDIALS_VERSION_24 1" >>confdefs.h sundials_include='-I'${SUNDIALS_INC_DIR} echo "sundials include directory: " ${sundials_include} @@ -2511,9 +4035,7 @@ fi DEBUG_MODE=${DEBUG_MODE:="n"} CANTERA_DEBUG_MODE=0 if test "$DEBUG_MODE" = "y" -o "$DEBUG_MODE" = "Y" ; then - cat >>confdefs.h <<\_ACEOF -#define DEBUG_MODE 1 -_ACEOF + $as_echo "#define DEBUG_MODE 1" >>confdefs.h CANTERA_DEBUG_MODE="1" else @@ -2540,32 +4062,24 @@ NEED_ZEROD= #fi if test "$WITH_METAL" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_METAL 1 -_ACEOF + $as_echo "#define WITH_METAL 1" >>confdefs.h hdrs=$hdrs' MetalPhase.h' fi if test "$WITH_SEMICONDUCTOR" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_SEMICONDUCTOR 1 -_ACEOF + $as_echo "#define WITH_SEMICONDUCTOR 1" >>confdefs.h hdrs=$hdrs' SemiconductorPhase.h' objs=$objs' SemiconductorPhase.o' fi if test "$WITH_ADSORBATE" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_ADSORBATE 1 -_ACEOF + $as_echo "#define WITH_ADSORBATE 1" >>confdefs.h hdrs=$hdrs' AdsorbateThermo.h' fi if test "$WITH_STOICH_SUBSTANCE" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_STOICH_SUBSTANCE 1 -_ACEOF + $as_echo "#define WITH_STOICH_SUBSTANCE 1" >>confdefs.h hdrs=$hdrs' StoichSubstance.h' objs=$objs' StoichSubstance.o' @@ -2573,9 +4087,7 @@ fi COMPILE_PURE_FLUIDS= if test "$WITH_PURE_FLUIDS" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_PURE_FLUIDS 1 -_ACEOF + $as_echo "#define WITH_PURE_FLUIDS 1" >>confdefs.h COMPILE_PURE_FLUIDS=1 hdrs=$hdrs' PureFluidPhase.h' @@ -2583,10 +4095,16 @@ _ACEOF fi +if test "$WITH_REAL_GASSES" = "y"; then + $as_echo "#define WITH_REAL_GASSES 1" >>confdefs.h + + hdrs=$hdrs' RedlichKwongMFTP.h' + objs=$objs' RedlichKwongMFTP.o' +fi + + if test "$WITH_LATTICE_SOLID" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_LATTICE_SOLID 1 -_ACEOF + $as_echo "#define WITH_LATTICE_SOLID 1" >>confdefs.h hdrs=$hdrs' LatticeSolidPhase.h' objs=$objs' LatticeSolidPhase.o' @@ -2602,9 +4120,7 @@ phase_header_files=$hdrs NEED_CATHERMO= COMPILE_IDEAL_SOLUTIONS=0 if test "$WITH_IDEAL_SOLUTIONS" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_IDEAL_SOLUTIONS 1 -_ACEOF + $as_echo "#define WITH_IDEAL_SOLUTIONS 1" >>confdefs.h NEED_CATHERMO=1 COMPILE_IDEAL_SOLUTIONS=1 @@ -2613,9 +4129,7 @@ fi COMPILE_ELECTROLYTES=0 if test "$WITH_ELECTROLYTES" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_ELECTROLYTES 1 -_ACEOF + $as_echo "#define WITH_ELECTROLYTES 1" >>confdefs.h NEED_CATHERMO=1 COMPILE_ELECTROLYTES=1 @@ -2625,17 +4139,13 @@ fi if test "$WITH_PRIME" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_PRIME 1 -_ACEOF + $as_echo "#define WITH_PRIME 1" >>confdefs.h fi COMPILE_KINETICS=0 if test "$WITH_KINETICS" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_KINETICS 1 -_ACEOF + $as_echo "#define WITH_KINETICS 1" >>confdefs.h COMPILE_KINETICS=1 fi @@ -2644,9 +4154,7 @@ fi COMPILE_HETEROKIN=0 if test "$WITH_HETERO_KINETICS" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_HETEROKINETICS 1 -_ACEOF + $as_echo "#define WITH_HETEROKINETICS 1" >>confdefs.h COMPILE_HETEROKIN=1 fi @@ -2654,9 +4162,7 @@ fi COMPILE_RXNPATH=0 if test "$WITH_REACTION_PATHS" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_REACTIONPATHS 1 -_ACEOF + $as_echo "#define WITH_REACTIONPATHS 1" >>confdefs.h COMPILE_RXNPATH=1 fi @@ -2705,17 +4211,13 @@ fi if test "$ENABLE_TPX" = "y" ; then KERNEL=$KERNEL' 'tpx NEED_TPX=1 - cat >>confdefs.h <<\_ACEOF -#define INCL_PURE_FLUIDS 1 -_ACEOF + $as_echo "#define INCL_PURE_FLUIDS 1" >>confdefs.h fi NEED_SPECTRA=0 if test "$WITH_SPECTRA" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_SPECTRA 1 -_ACEOF + $as_echo "#define WITH_SPECTRA 1" >>confdefs.h KERNEL=$KERNEL' 'spectra NEED_SPECTRA=1 @@ -2728,9 +4230,7 @@ fi COMPILE_VCSNONIDEAL=0 if test "$WITH_VCSNONIDEAL" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_VCSNONIDEAL 1 -_ACEOF + $as_echo "#define WITH_VCSNONIDEAL 1" >>confdefs.h COMPILE_VCSNONIDEAL=1 fi @@ -2738,28 +4238,31 @@ fi COMPILE_H298MODIFY_CAPABILITY=0 if test "$WITH_H298MODIFY_CAPABILITY" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define H298MODIFY_CAPABILITY 1 -_ACEOF + $as_echo "#define H298MODIFY_CAPABILITY 1" >>confdefs.h COMPILE_H298MODIFY_CAPABILITY=1 fi +COMPILE_INTERMEDIATE_ZEROED_KINETICS=0 +if test "$KINETICS_WITH_INTERMEDIATE_ZEROED_KINETICS" = "y"; then + $as_echo "#define KINETICS_WITH_INTERMEDIATE_ZEROED_KINETICS 1" >>confdefs.h + + COMPILE_INTERMEDIATE_ZEROED_KINETICS=1 +fi + + + if test "$WITH_HTML_LOG_FILES" = "y"; then - cat >>confdefs.h <<\_ACEOF -#define WITH_HTML_LOGS 1 -_ACEOF + $as_echo "#define WITH_HTML_LOGS 1" >>confdefs.h fi BOOST_INCLUDE= BOOST_LIB= if test "$BUILD_THREAD_SAFE" = "y" ; then - cat >>confdefs.h <<\_ACEOF -#define THREAD_SAFE_CANTERA 1 -_ACEOF + $as_echo "#define THREAD_SAFE_CANTERA 1" >>confdefs.h BOOST_INCLUDE=-I$BOOST_INC_DIR BOOST_LIB=$BOOST_THREAD_LIB @@ -2899,9 +4402,7 @@ echo " " if test "x$PURIFY" != "x"; then - cat >>confdefs.h <<\_ACEOF -#define PURIFY_MODE 1 -_ACEOF + $as_echo "#define PURIFY_MODE 1" >>confdefs.h fi @@ -2979,7 +4480,7 @@ if test -n "$NEED_F2C" ; then build_f2c_lib=1 else case $ac_sys_system in - Linux) F2C_SYSTEMLIB="-lg2c" + Linux) F2C_SYSTEMLIB="" esac fi @@ -3119,7 +4620,7 @@ then RAW_LIBS_DEP=$RAW_LIBS_DEP' 'libctf2c.a else case $ac_sys_system in - Linux) LOCAL_LIBS=$LOCAL_LIBS' '-lg2c;; + Linux) LOCAL_LIBS=$LOCAL_LIBS;; esac fi # Darwin*) LOCAL_LIBS=$LOCAL_LIBS' '-lg2c;; @@ -3167,9 +4668,7 @@ fi # case $ac_sys_system in SunOS* ) - cat >>confdefs.h <<\_ACEOF -#define NEEDS_GENERIC_TEMPL_STATIC_DECL 1 -_ACEOF + $as_echo "#define NEEDS_GENERIC_TEMPL_STATIC_DECL 1" >>confdefs.h echo 'Turned on special handing of static definitions in templated classes' ;; @@ -3207,9 +4706,7 @@ else exit 1 fi if test $BUILD_PYTHON = 0 ; then -cat >>confdefs.h <<\_ACEOF -#define HAS_NO_PYTHON 1 -_ACEOF +$as_echo "#define HAS_NO_PYTHON 1" >>confdefs.h fi @@ -3219,10 +4716,10 @@ if test "$PYTHON_CMD" = "default" -o \ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_PYTHON_CMD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PYTHON_CMD+:} false; then : + $as_echo_n "(cached) " >&6 else case $PYTHON_CMD in [\\/]* | ?:[\\/]*) @@ -3234,28 +4731,29 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON_CMD="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done +IFS=$as_save_IFS ;; esac fi PYTHON_CMD=$ac_cv_path_PYTHON_CMD - if test -n "$PYTHON_CMD"; then - echo "$as_me:$LINENO: result: $PYTHON_CMD" >&5 -echo "${ECHO_T}$PYTHON_CMD" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_CMD" >&5 +$as_echo "$PYTHON_CMD" >&6; } else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi + test -n "$PYTHON_CMD" && break done test -n "$PYTHON_CMD" || PYTHON_CMD=""none"" @@ -3283,24 +4781,18 @@ USE_NUMARRAY='y' if test "$USE_NUMERIC" = "y"; then USE_NUMARRAY='n' USE_NUMPY='n' -cat >>confdefs.h <<\_ACEOF -#define HAS_NUMERIC 1 -_ACEOF +$as_echo "#define HAS_NUMERIC 1" >>confdefs.h fi if test "$USE_NUMPY" = "y"; then USE_NUMARRAY='n' -cat >>confdefs.h <<\_ACEOF -#define HAS_NUMPY 1 -_ACEOF +$as_echo "#define HAS_NUMPY 1" >>confdefs.h fi if test "$USE_NUMARRAY" = "y"; then -cat >>confdefs.h <<\_ACEOF -#define HAS_NUMARRAY 1 -_ACEOF +$as_echo "#define HAS_NUMARRAY 1" >>confdefs.h fi @@ -3432,10 +4924,10 @@ if test "$BUILD_MATLAB_TOOLBOX" != "n"; then "$MATLAB_CMD"x = "x"; then # Extract the first word of "matlab", so it can be a program name with args. set dummy matlab; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_MATLAB_CMD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_MATLAB_CMD+:} false; then : + $as_echo_n "(cached) " >&6 else case $MATLAB_CMD in [\\/]* | ?:[\\/]*) @@ -3447,29 +4939,30 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_MATLAB_CMD="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done +IFS=$as_save_IFS test -z "$ac_cv_path_MATLAB_CMD" && ac_cv_path_MATLAB_CMD=""none"" ;; esac fi MATLAB_CMD=$ac_cv_path_MATLAB_CMD - if test -n "$MATLAB_CMD"; then - echo "$as_me:$LINENO: result: $MATLAB_CMD" >&5 -echo "${ECHO_T}$MATLAB_CMD" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MATLAB_CMD" >&5 +$as_echo "$MATLAB_CMD" >&6; } else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi + if test "$MATLAB_CMD" = "none"; then MATLAB_CMD=`find /*/MATLAB*/bin/m* -name matlab` fi @@ -3488,8 +4981,8 @@ fi echo "Windows MATLAB command: ${MATLAB_CMD}" fi - echo "$as_me:$LINENO: checking MATLAB ($MATLAB_CMD)" >&5 -echo $ECHO_N "checking MATLAB ($MATLAB_CMD)... $ECHO_C" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking MATLAB ($MATLAB_CMD)" >&5 +$as_echo_n "checking MATLAB ($MATLAB_CMD)... " >&6; } rm -f diary cat >> testmat.m << EOF diary; @@ -3592,22 +5085,23 @@ echo 'checking for Position independent code command ... ' $PIC # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. -echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 -echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in - ./ | .// | /cC/* | \ + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. @@ -3615,7 +5109,7 @@ case $as_dir/ in # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. @@ -3625,30 +5119,43 @@ case $as_dir/ in # program-specific install script used by HP pwplus--don't use. : else - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi fi fi done done ;; esac -done + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else - # As a last resort, use the slow shell script. We don't cache a - # path for INSTALL within a source directory, because that will + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is - # removed, or if the path is relative. + # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi -echo "$as_me:$LINENO: result: $INSTALL" >&5 -echo "${ECHO_T}$INSTALL" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. @@ -3685,2246 +5192,33 @@ esac # precompile_headers still relevant? # precompile_headers=no -# -# CFLAGS: flags that get attached to the C compiler -# statement. AFLAGS are base flags that -# get added to compilers and loaders. -# FFLAGS: flags that get attached to the Fortran compiler -# statement. AFLAGS are base flags that -# get added to compilers and loaders. -# -# CXXFLAGS: Flags that get attached to the CXX compiler -# statement. AFLAGS are base flags that -# get added to compilers and loaders. -# -if test -z "$AFLAGS" ; then - AFLAGS=" " -fi -if test -z "$CXXFLAGS" ; then - CXXFLAGS="$AFLAGS" -else - CXXFLAGS="$CXXFLAGS"" ""$AFLAGS" -fi -if test -z "$CFLAGS" ; then - CFLAGS="$AFLAGS" -else - CFLAGS="$CFLAGS"" ""$AFLAGS" -fi -if test -z "$FFLAGS" ; then - FFLAGS="$AFLAGS" -else - FFLAGS="$FFLAGS"" ""$AFLAGS" -fi - -if test "x$OS_IS_WIN" = "x1"; then - #CXX=cl.exe - #CC=cl.exe - #export CXX - ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -n "$ac_tool_prefix"; then - for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - echo "$as_me:$LINENO: result: $CXX" >&5 -echo "${ECHO_T}$CXX" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 -echo "${ECHO_T}$ac_ct_CXX" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$ac_ct_CXX" && break -done -test -n "$ac_ct_CXX" || ac_ct_CXX="g++" - - CXX=$ac_ct_CXX -fi - - -# Provide some information about the compiler. -echo "$as_me:$LINENO:" \ - "checking for C++ compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 -if test "${ac_cv_cxx_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_compiler_gnu=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 -GXX=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -CXXFLAGS="-g" -echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 -echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 -if test "${ac_cv_prog_cxx_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cxx_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cxx_g=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -for ac_declaration in \ - '' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -#include -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -continue -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -rm -f conftest* -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - CC=$ac_ct_CC -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - CC=$ac_ct_CC -else - CC="$ac_cv_prog_CC" -fi - -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$ac_ct_CC" && break -done - - CC=$ac_ct_CC -fi - -fi - - -test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&5 -echo "$as_me: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - -# Provide some information about the compiler. -echo "$as_me:$LINENO:" \ - "checking for C compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 -if test "${ac_cv_c_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_compiler_gnu=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 -GCC=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -CFLAGS="-g" -echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 -echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cc_g=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 -echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_prog_cc_stdc=no -ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -#include -#include -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std1 is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std1. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -# Don't try gcc -ansi; that turns off useful extensions and -# breaks some systems' header files. -# AIX -qlanglvl=ansi -# Ultrix and OSF/1 -std1 -# HP-UX 10.20 and later -Ae -# HP-UX older versions -Aa -D_HPUX_SOURCE -# SVR4 -Xc -D__EXTENSIONS__ -for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_stdc=$ac_arg -break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext -done -rm -f conftest.$ac_ext conftest.$ac_objext -CC=$ac_save_CC - -fi - -case "x$ac_cv_prog_cc_stdc" in - x|xno) - echo "$as_me:$LINENO: result: none needed" >&5 -echo "${ECHO_T}none needed" >&6 ;; - *) - echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 - CC="$CC $ac_cv_prog_cc_stdc" ;; -esac - -# Some people use a C++ compiler to compile C. Since we use `exit', -# in C++ we need to declare it. In case someone uses the same compiler -# for both compiling C and C++ we need to have the C++ compiler decide -# the declaration of exit, since it's the most demanding environment. -cat >conftest.$ac_ext <<_ACEOF -#ifndef __cplusplus - choke me -#endif -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - for ac_declaration in \ - '' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -#include -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -continue -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -rm -f conftest* -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -else - -# -# Determines the CXX compiler to use -# -export CXX -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -n "$ac_tool_prefix"; then - for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - echo "$as_me:$LINENO: result: $CXX" >&5 -echo "${ECHO_T}$CXX" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 -echo "${ECHO_T}$ac_ct_CXX" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$ac_ct_CXX" && break -done -test -n "$ac_ct_CXX" || ac_ct_CXX="g++" - - CXX=$ac_ct_CXX -fi - - -# Provide some information about the compiler. -echo "$as_me:$LINENO:" \ - "checking for C++ compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 -if test "${ac_cv_cxx_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_compiler_gnu=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 -GXX=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -CXXFLAGS="-g" -echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 -echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 -if test "${ac_cv_prog_cxx_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cxx_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cxx_g=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -for ac_declaration in \ - '' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -#include -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -continue -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -rm -f conftest* -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - CC=$ac_ct_CC -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - CC=$ac_ct_CC -else - CC="$ac_cv_prog_CC" -fi - -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - test -n "$ac_ct_CC" && break -done - - CC=$ac_ct_CC -fi - -fi - - -test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&5 -echo "$as_me: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - -# Provide some information about the compiler. -echo "$as_me:$LINENO:" \ - "checking for C compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 -if test "${ac_cv_c_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_compiler_gnu=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 -GCC=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -CFLAGS="-g" -echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 -echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_cc_g=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 -echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_prog_cc_stdc=no -ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -#include -#include -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std1 is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std1. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -# Don't try gcc -ansi; that turns off useful extensions and -# breaks some systems' header files. -# AIX -qlanglvl=ansi -# Ultrix and OSF/1 -std1 -# HP-UX 10.20 and later -Ae -# HP-UX older versions -Aa -D_HPUX_SOURCE -# SVR4 -Xc -D__EXTENSIONS__ -for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_stdc=$ac_arg -break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext -done -rm -f conftest.$ac_ext conftest.$ac_objext -CC=$ac_save_CC - -fi - -case "x$ac_cv_prog_cc_stdc" in - x|xno) - echo "$as_me:$LINENO: result: none needed" >&5 -echo "${ECHO_T}none needed" >&6 ;; - *) - echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 - CC="$CC $ac_cv_prog_cc_stdc" ;; -esac - -# Some people use a C++ compiler to compile C. Since we use `exit', -# in C++ we need to declare it. In case someone uses the same compiler -# for both compiling C and C++ we need to have the C++ compiler decide -# the declaration of exit, since it's the most demanding environment. -cat >conftest.$ac_ext <<_ACEOF -#ifndef __cplusplus - choke me -#endif -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - for ac_declaration in \ - '' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -#include -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -continue -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_declaration -int -main () -{ -exit (42); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -rm -f conftest* -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -ac_ext=cc -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - -echo "$as_me:$LINENO: checking for ability to precompile headers" >&5 -echo $ECHO_N "checking for ability to precompile headers... $ECHO_C" >&6 - +if test "x$OS_IS_WIN" != "x1"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ability to precompile headers" >&5 +$as_echo_n "checking for ability to precompile headers... " >&6; } if test -n "$GCC"; then msg=`rm -f *h.gch; $CXX testpch.h &> /dev/null` if test -f testpch.h.gch; then precompile_headers=yes - cat >>confdefs.h <<\_ACEOF -#define USE_PCH 1 -_ACEOF + $as_echo "#define USE_PCH 1" >>confdefs.h fi fi -echo "$as_me:$LINENO: result: ${precompile_headers}" >&5 -echo "${ECHO_T}${precompile_headers}" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${precompile_headers}" >&5 +$as_echo "${precompile_headers}" >&6; } # End of the OS_IS_WIN section fi # Sizes of various common basic types -ac_ext=cc +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 -echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then - if test "${ac_cv_prog_CXXCPP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" @@ -5938,11 +5232,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -5951,78 +5241,34 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_cxx_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_cxx_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext - # OK, works on sane cases. Now check whether non-existent headers + # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_cxx_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then +if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : break fi @@ -6034,8 +5280,8 @@ fi else ac_cv_prog_CXXCPP=$CXXCPP fi -echo "$as_me:$LINENO: result: $CXXCPP" >&5 -echo "${ECHO_T}$CXXCPP" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do @@ -6045,11 +5291,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -6058,119 +5300,185 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_cxx_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_cxx_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext - # OK, works on sane cases. Now check whether non-existent headers + # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_cxx_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then +if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - : +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + else - { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details." >&5 -echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } fi -ac_ext=cc +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -echo "$as_me:$LINENO: checking for egrep" >&5 -echo $ECHO_N "checking for egrep... $ECHO_C" >&6 -if test "${ac_cv_prog_egrep+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 else - if echo a | (grep -E '(a|b)') >/dev/null 2>&1 - then ac_cv_prog_egrep='grep -E' - else ac_cv_prog_egrep='egrep' + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count fi -fi -echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 -echo "${ECHO_T}$ac_cv_prog_egrep" >&6 - EGREP=$ac_cv_prog_egrep + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac - -echo "$as_me:$LINENO: checking for ANSI C header files" >&5 -echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 -if test "${ac_cv_header_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -6185,51 +5493,23 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_header_stdc=no + ac_cv_header_stdc=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : + $EGREP "memchr" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -6239,18 +5519,14 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : + $EGREP "free" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -6260,16 +5536,13 @@ fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then + if test "$cross_compiling" = yes; then : : else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +#include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) @@ -6289,109 +5562,39 @@ main () for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) - exit(2); - exit (0); + return 2; + return 0; } _ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_cxx_try_run "$LINENO"; then : -( exit $ac_status ) -ac_cv_header_stdc=no +else + ac_cv_header_stdc=no fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + fi fi -fi -echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 -echo "${ECHO_T}$ac_cv_header_stdc" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF +$as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. - - - - - - - - - for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - eval "$as_ac_Header=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -eval "$as_ac_Header=no" -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 -if test `eval echo '${'$as_ac_Header'}'` = yes; then +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi @@ -6399,3313 +5602,265 @@ fi done -echo "$as_me:$LINENO: checking for int" >&5 -echo $ECHO_N "checking for int... $ECHO_C" >&6 -if test "${ac_cv_type_int+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +$as_echo_n "checking size of int... " >&6; } +if ${ac_cv_sizeof_int+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((int *) 0) - return 0; -if (sizeof (int)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_int=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : -ac_cv_type_int=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 -echo "${ECHO_T}$ac_cv_type_int" >&6 - -echo "$as_me:$LINENO: checking size of int" >&5 -echo $ECHO_N "checking size of int... $ECHO_C" >&6 -if test "${ac_cv_sizeof_int+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_int" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_int=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +$as_echo "$ac_cv_sizeof_int" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_int=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (int)); } -unsigned long ulongval () { return (long) (sizeof (int)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (int))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (int)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (int)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_int=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (int), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_int=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 -echo "${ECHO_T}$ac_cv_sizeof_int" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF -echo "$as_me:$LINENO: checking for long" >&5 -echo $ECHO_N "checking for long... $ECHO_C" >&6 -if test "${ac_cv_type_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if ${ac_cv_sizeof_long+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((long *) 0) - return 0; -if (sizeof (long)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_long=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : -ac_cv_type_long=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 -echo "${ECHO_T}$ac_cv_type_long" >&6 - -echo "$as_me:$LINENO: checking size of long" >&5 -echo $ECHO_N "checking size of long... $ECHO_C" >&6 -if test "${ac_cv_sizeof_long+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_long" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_long=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_long=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (long)); } -unsigned long ulongval () { return (long) (sizeof (long)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (long))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (long)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (long)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_long=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (long), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_long=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 -echo "${ECHO_T}$ac_cv_sizeof_long" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF -echo "$as_me:$LINENO: checking for void *" >&5 -echo $ECHO_N "checking for void *... $ECHO_C" >&6 -if test "${ac_cv_type_void_p+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +$as_echo_n "checking size of void *... " >&6; } +if ${ac_cv_sizeof_void_p+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((void * *) 0) - return 0; -if (sizeof (void *)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_void_p=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : -ac_cv_type_void_p=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_void_p" >&5 -echo "${ECHO_T}$ac_cv_type_void_p" >&6 - -echo "$as_me:$LINENO: checking size of void *" >&5 -echo $ECHO_N "checking size of void *... $ECHO_C" >&6 -if test "${ac_cv_sizeof_void_p+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_void_p" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_void_p=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +$as_echo "$ac_cv_sizeof_void_p" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (void *))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_void_p=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (void *)); } -unsigned long ulongval () { return (long) (sizeof (void *)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (void *))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (void *)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (void *)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_void_p=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (void *), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_void_p=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5 -echo "${ECHO_T}$ac_cv_sizeof_void_p" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_VOID_P $ac_cv_sizeof_void_p _ACEOF -echo "$as_me:$LINENO: checking for char" >&5 -echo $ECHO_N "checking for char... $ECHO_C" >&6 -if test "${ac_cv_type_char+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 +$as_echo_n "checking size of char... " >&6; } +if ${ac_cv_sizeof_char+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((char *) 0) - return 0; -if (sizeof (char)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_char=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : -ac_cv_type_char=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_char" >&5 -echo "${ECHO_T}$ac_cv_type_char" >&6 - -echo "$as_me:$LINENO: checking size of char" >&5 -echo $ECHO_N "checking size of char... $ECHO_C" >&6 -if test "${ac_cv_sizeof_char+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_char" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (char))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (char))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (char) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_char=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (char))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (char))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 +$as_echo "$ac_cv_sizeof_char" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (char))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_char=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (char), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (char), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (char)); } -unsigned long ulongval () { return (long) (sizeof (char)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (char))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (char)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (char)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_char=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (char), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (char), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_char=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_char" >&5 -echo "${ECHO_T}$ac_cv_sizeof_char" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_CHAR $ac_cv_sizeof_char _ACEOF -echo "$as_me:$LINENO: checking for short" >&5 -echo $ECHO_N "checking for short... $ECHO_C" >&6 -if test "${ac_cv_type_short+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +$as_echo_n "checking size of short... " >&6; } +if ${ac_cv_sizeof_short+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((short *) 0) - return 0; -if (sizeof (short)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_short=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : -ac_cv_type_short=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 -echo "${ECHO_T}$ac_cv_type_short" >&6 - -echo "$as_me:$LINENO: checking size of short" >&5 -echo $ECHO_N "checking size of short... $ECHO_C" >&6 -if test "${ac_cv_sizeof_short+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_short" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (short) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_short=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +$as_echo "$ac_cv_sizeof_short" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_short=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (short)); } -unsigned long ulongval () { return (long) (sizeof (short)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (short))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (short)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (short)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_short=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (short), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_short=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 -echo "${ECHO_T}$ac_cv_sizeof_short" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF -echo "$as_me:$LINENO: checking for float" >&5 -echo $ECHO_N "checking for float... $ECHO_C" >&6 -if test "${ac_cv_type_float+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 +$as_echo_n "checking size of float... " >&6; } +if ${ac_cv_sizeof_float+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((float *) 0) - return 0; -if (sizeof (float)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_float=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : -ac_cv_type_float=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_float" >&5 -echo "${ECHO_T}$ac_cv_type_float" >&6 - -echo "$as_me:$LINENO: checking size of float" >&5 -echo $ECHO_N "checking size of float... $ECHO_C" >&6 -if test "${ac_cv_sizeof_float+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_float" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (float))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (float))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (float) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_float=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (float))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (float))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_float" >&5 +$as_echo "$ac_cv_sizeof_float" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (float))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_float=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (float), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (float), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (float)); } -unsigned long ulongval () { return (long) (sizeof (float)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (float))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (float)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (float)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_float=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (float), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (float), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_float=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_float" >&5 -echo "${ECHO_T}$ac_cv_sizeof_float" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_FLOAT $ac_cv_sizeof_float _ACEOF -echo "$as_me:$LINENO: checking for double" >&5 -echo $ECHO_N "checking for double... $ECHO_C" >&6 -if test "${ac_cv_type_double+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 +$as_echo_n "checking size of double... " >&6; } +if ${ac_cv_sizeof_double+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((double *) 0) - return 0; -if (sizeof (double)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_double=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : -ac_cv_type_double=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_double" >&5 -echo "${ECHO_T}$ac_cv_type_double" >&6 - -echo "$as_me:$LINENO: checking size of double" >&5 -echo $ECHO_N "checking size of double... $ECHO_C" >&6 -if test "${ac_cv_sizeof_double+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_double" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (double))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (double))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (double) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_double=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (double))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (double))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 +$as_echo "$ac_cv_sizeof_double" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (double))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_double=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (double), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (double), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (double)); } -unsigned long ulongval () { return (long) (sizeof (double)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (double))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (double)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (double)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_double=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (double), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (double), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_double=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_double" >&5 -echo "${ECHO_T}$ac_cv_sizeof_double" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_DOUBLE $ac_cv_sizeof_double _ACEOF -echo "$as_me:$LINENO: checking for fpos_t" >&5 -echo $ECHO_N "checking for fpos_t... $ECHO_C" >&6 -if test "${ac_cv_type_fpos_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 +$as_echo_n "checking size of fpos_t... " >&6; } +if ${ac_cv_sizeof_fpos_t+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((fpos_t *) 0) - return 0; -if (sizeof (fpos_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_fpos_t=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : -ac_cv_type_fpos_t=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_fpos_t" >&5 -echo "${ECHO_T}$ac_cv_type_fpos_t" >&6 - -echo "$as_me:$LINENO: checking size of fpos_t" >&5 -echo $ECHO_N "checking size of fpos_t... $ECHO_C" >&6 -if test "${ac_cv_sizeof_fpos_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$ac_cv_type_fpos_t" = yes; then - # The cast to unsigned long works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (fpos_t))) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=0 ac_mid=0 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (fpos_t))) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_lo=`expr $ac_mid + 1` - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid + 1` + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (fpos_t) +See \`config.log' for more details" "$LINENO" 5 ; } + else + ac_cv_sizeof_fpos_t=0 + fi fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (fpos_t))) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=-1 ac_mid=-1 - while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (fpos_t))) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_lo=$ac_mid; break -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_hi=`expr '(' $ac_mid ')' - 1` - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - ac_mid=`expr 2 '*' $ac_mid` fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_fpos_t" >&5 +$as_echo "$ac_cv_sizeof_fpos_t" >&6; } -ac_lo= ac_hi= -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(((long) (sizeof (fpos_t))) <= $ac_mid)]; -test_array [0] = 0 - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_hi=$ac_mid -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 -ac_lo=`expr '(' $ac_mid ')' + 1` -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in -?*) ac_cv_sizeof_fpos_t=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (fpos_t), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (fpos_t), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } ;; -esac -else - if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -long longval () { return (long) (sizeof (fpos_t)); } -unsigned long ulongval () { return (long) (sizeof (fpos_t)); } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - exit (1); - if (((long) (sizeof (fpos_t))) < 0) - { - long i = longval (); - if (i != ((long) (sizeof (fpos_t)))) - exit (1); - fprintf (f, "%ld\n", i); - } - else - { - unsigned long i = ulongval (); - if (i != ((long) (sizeof (fpos_t)))) - exit (1); - fprintf (f, "%lu\n", i); - } - exit (ferror (f) || fclose (f) != 0); - - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_sizeof_fpos_t=`cat conftest.val` -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (fpos_t), 77 -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (fpos_t), 77 -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi -rm -f conftest.val -else - ac_cv_sizeof_fpos_t=0 -fi -fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_fpos_t" >&5 -echo "${ECHO_T}$ac_cv_sizeof_fpos_t" >&6 cat >>confdefs.h <<_ACEOF #define SIZEOF_FPOS_T $ac_cv_sizeof_fpos_t _ACEOF @@ -9738,80 +5893,46 @@ if test "$BUILD_WITH_F2C"="n"; then fi - -# -# Ending Libs for compiling static applications and -# dynamically loaded libraries -# (sunpro solaris needs a few for dynamic linking) -# # # Check to see if we have a -lm line # -echo "$as_me:$LINENO: checking for printf in -lm" >&5 -echo $ECHO_N "checking for printf in -lm... $ECHO_C" >&6 -if test "${ac_cv_lib_m_printf+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf in -lm" >&5 +$as_echo_n "checking for printf in -lm... " >&6; } +if ${ac_cv_lib_m_printf+:} false; then : + $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -/* Override any gcc2 internal prototype to avoid an error. */ +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ char printf (); int main () { -printf (); +return printf (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_m_printf=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_lib_m_printf=no + ac_cv_lib_m_printf=no fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_m_printf" >&5 -echo "${ECHO_T}$ac_cv_lib_m_printf" >&6 -if test $ac_cv_lib_m_printf = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_printf" >&5 +$as_echo "$ac_cv_lib_m_printf" >&6; } +if test "x$ac_cv_lib_m_printf" = xyes; then : add_stm=1 else add_stm=0 @@ -9821,78 +5942,54 @@ fi # # Check to see if we have a -lstdc++ line # -echo "$as_me:$LINENO: checking for printf in -lstdc++" >&5 -echo $ECHO_N "checking for printf in -lstdc++... $ECHO_C" >&6 -if test "${ac_cv_lib_stdcpp_printf+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf in -lstdc++" >&5 +$as_echo_n "checking for printf in -lstdc++... " >&6; } +if ${ac_cv_lib_stdcpp_printf+:} false; then : + $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lstdc++ $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -/* Override any gcc2 internal prototype to avoid an error. */ +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ char printf (); int main () { -printf (); +return printf (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_stdcpp_printf=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_lib_stdcpp_printf=no + ac_cv_lib_stdcpp_printf=no fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_stdcpp_printf" >&5 -echo "${ECHO_T}$ac_cv_lib_stdcpp_printf" >&6 -if test $ac_cv_lib_stdcpp_printf = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stdcpp_printf" >&5 +$as_echo "$ac_cv_lib_stdcpp_printf" >&6; } +if test "x$ac_cv_lib_stdcpp_printf" = xyes; then : add_stdc=1 else add_stdc=0 fi - +# +# Ending Libs for compiling static applications and +# dynamically loaded libraries +# (sunpro solaris needs a few for dynamic linking) +# if test -n "$NEED_F2C" ; then LCXX_END_LIBS="-lctf2c ""$LCXX_END_LIBS" fi @@ -9917,10 +6014,9 @@ fi - has_sstream=no -echo "$as_me:$LINENO: checking for sstream" >&5 -echo $ECHO_N "checking for sstream... $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sstream" >&5 +$as_echo_n "checking for sstream... " >&6; } cat >> testsstream.cpp << EOF #include main() {} @@ -9929,14 +6025,12 @@ EOF if test -f testsstream.o; then has_sstream=yes rm testsstream.o - cat >>confdefs.h <<\_ACEOF -#define HAS_SSTREAM 1 -_ACEOF + $as_echo "#define HAS_SSTREAM 1" >>confdefs.h fi rm -f testsstream.cpp -echo "$as_me:$LINENO: result: ${has_sstream}" >&5 -echo "${ECHO_T}${has_sstream}" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${has_sstream}" >&5 +$as_echo "${has_sstream}" >&6; } # # Determine if we have a command to strip symbols from an object file @@ -9955,20 +6049,24 @@ echo 'checking for a strip symbol command ... ' $HAVE_STRIPSYMBOLS # Fortran #--------------------------------------------------------------------------- -#if test x"$build_with_f2c" = "x0"; then +# +# This macro sets the substitution variable, @F77@ and @G77@ +# +echo " this is $F77" +echo "this is a test" ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu if test -n "$ac_tool_prefix"; then - for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran + for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_F77+:} false; then : + $as_echo_n "(cached) " >&6 else if test -n "$F77"; then ac_cv_prog_F77="$F77" # Let the user override the test. @@ -9978,39 +6076,41 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_F77="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done +IFS=$as_save_IFS fi fi F77=$ac_cv_prog_F77 if test -n "$F77"; then - echo "$as_me:$LINENO: result: $F77" >&5 -echo "${ECHO_T}$F77" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $F77" >&5 +$as_echo "$F77" >&6; } else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi + test -n "$F77" && break done fi if test -z "$F77"; then ac_ct_F77=$F77 - for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran + for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_prog_ac_ct_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_F77+:} false; then : + $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_F77"; then ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. @@ -10020,64 +6120,81 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_F77="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done +IFS=$as_save_IFS fi fi ac_ct_F77=$ac_cv_prog_ac_ct_F77 if test -n "$ac_ct_F77"; then - echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 -echo "${ECHO_T}$ac_ct_F77" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_F77" >&5 +$as_echo "$ac_ct_F77" >&6; } else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi + test -n "$ac_ct_F77" && break done - F77=$ac_ct_F77 + if test "x$ac_ct_F77" = x; then + F77="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + F77=$ac_ct_F77 + fi fi # Provide some information about the compiler. -echo "$as_me:10051:" \ - "checking for Fortran 77 compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 - (eval $ac_compiler --version &5) 2>&5 +$as_echo "$as_me:${as_lineno-$LINENO}: checking for Fortran 77 compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 - (eval $ac_compiler -v &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 - (eval $ac_compiler -V &5) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done rm -f a.out # If we don't use `.F' as extension, the preprocessor is not run on the # input file. (Note that this only needs to work for GNU compilers.) ac_save_ext=$ac_ext ac_ext=F -echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6 -if test "${ac_cv_f77_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Fortran 77 compiler" >&5 +$as_echo_n "checking whether we are using the GNU Fortran 77 compiler... " >&6; } +if ${ac_cv_f77_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF + cat > conftest.$ac_ext <<_ACEOF program main #ifndef __GNUC__ choke me @@ -10085,90 +6202,42 @@ else end _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_f77_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_f77_try_compile "$LINENO"; then : ac_compiler_gnu=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_compiler_gnu=no + ac_compiler_gnu=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_f77_compiler_gnu=$ac_compiler_gnu fi -echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_f77_compiler_gnu" >&5 +$as_echo "$ac_cv_f77_compiler_gnu" >&6; } ac_ext=$ac_save_ext ac_test_FFLAGS=${FFLAGS+set} ac_save_FFLAGS=$FFLAGS FFLAGS= -echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 -echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6 -if test "${ac_cv_prog_f77_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $F77 accepts -g" >&5 +$as_echo_n "checking whether $F77 accepts -g... " >&6; } +if ${ac_cv_prog_f77_g+:} false; then : + $as_echo_n "(cached) " >&6 else FFLAGS=-g -cat >conftest.$ac_ext <<_ACEOF +cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_f77_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_f77_try_compile "$LINENO"; then : ac_cv_prog_f77_g=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_prog_f77_g=no + ac_cv_prog_f77_g=no fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 -echo "${ECHO_T}$ac_cv_prog_f77_g" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_f77_g" >&5 +$as_echo "$ac_cv_prog_f77_g" >&6; } if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then @@ -10185,8 +6254,12 @@ else fi fi -G77=`test $ac_compiler_gnu = yes && echo yes` -ac_ext=cc +if test $ac_compiler_gnu = yes; then + G77=yes +else + G77= +fi +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -10202,48 +6275,27 @@ else FFLAGS=$FFLAGS' -fno-second-underscore' fi fi - +F77LDRCLIBS= ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu -echo "$as_me:$LINENO: checking how to get verbose linking output from $F77" >&5 -echo $ECHO_N "checking how to get verbose linking output from $F77... $ECHO_C" >&6 -if test "${ac_cv_prog_f77_v+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to get verbose linking output from $F77" >&5 +$as_echo_n "checking how to get verbose linking output from $F77... " >&6; } +if ${ac_cv_prog_f77_v+:} false; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF + cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_f77_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_f77_try_compile "$LINENO"; then : ac_cv_prog_f77_v= # Try some options frequently used verbose output for ac_verb in -v -verbose --verbose -V -\#\#\#; do - cat >conftest.$ac_ext <<_ACEOF + cat > conftest.$ac_ext <<_ACEOF program main end @@ -10255,20 +6307,29 @@ _ACEOF # flags. ac_save_FFLAGS=$FFLAGS FFLAGS="$FFLAGS $ac_verb" -(eval echo $as_me:10258: \"$ac_link\") >&5 -ac_f77_v_output=`eval $ac_link 5>&1 2>&1 | grep -v 'Driving:'` -echo "$ac_f77_v_output" >&5 +eval "set x $ac_link" +shift +$as_echo "$as_me:${as_lineno-$LINENO}: $*" >&5 +# gfortran 4.3 outputs lines setting COLLECT_GCC_OPTIONS, COMPILER_PATH, +# LIBRARY_PATH; skip all such settings. +ac_f77_v_output=`eval $ac_link 5>&1 2>&1 | + sed '/^Driving:/d; /^Configured with:/d; + '"/^[_$as_cr_Letters][_$as_cr_alnum]*=/d"` +$as_echo "$ac_f77_v_output" >&5 FFLAGS=$ac_save_FFLAGS -rm -f conftest* +rm -rf conftest* # On HP/UX there is a line like: "LPATH is: /foo:/bar:/baz" where # /foo, /bar, and /baz are search directories for the Fortran linker. # Here, we change these into -L/foo -L/bar -L/baz (and put it first): ac_f77_v_output="`echo $ac_f77_v_output | grep 'LPATH is:' | - sed 's,.*LPATH is\(: *[^ ]*\).*,\1,;s,: */, -L/,g'` $ac_f77_v_output" + sed 's|.*LPATH is\(: *[^ ]*\).*|\1|;s|: */| -L/|g'` $ac_f77_v_output" +# FIXME: we keep getting bitten by quoted arguments; a more general fix +# that detects unbalanced quotes in FLIBS should be implemented +# and (ugh) tested at some point. case $ac_f77_v_output in # If we are using xlf then replace all the commas with spaces. *xlfentry*) @@ -10277,51 +6338,55 @@ case $ac_f77_v_output in # With Intel ifc, ignore the quoted -mGLOB_options_string stuff (quoted # $LIBS confuse us, and the libraries appear later in the output anyway). *mGLOB_options_string*) - ac_f77_v_output=`echo $ac_f77_v_output | sed 's/\"-mGLOB[^\"]*\"/ /g'` ;; + ac_f77_v_output=`echo $ac_f77_v_output | sed 's/"-mGLOB[^"]*"/ /g'` ;; + + # Portland Group compiler has singly- or doubly-quoted -cmdline argument + # Singly-quoted arguments were reported for versions 5.2-4 and 6.0-4. + # Doubly-quoted arguments were reported for "PGF90/x86 Linux/x86 5.0-2". + *-cmdline\ * | *-ignore\ * | *-def\ *) + ac_f77_v_output=`echo $ac_f77_v_output | sed "\ + s/-cmdline *'[^']*'/ /g; s/-cmdline *\"[^\"]*\"/ /g + s/-ignore *'[^']*'/ /g; s/-ignore *\"[^\"]*\"/ /g + s/-def *'[^']*'/ /g; s/-def *\"[^\"]*\"/ /g"` ;; # If we are using Cray Fortran then delete quotes. - # Use "\"" instead of '"' for font-lock-mode. - # FIXME: a more general fix for quoted arguments with spaces? *cft90*) - ac_f77_v_output=`echo $ac_f77_v_output | sed "s/\"//g"` ;; + ac_f77_v_output=`echo $ac_f77_v_output | sed 's/"//g'` ;; esac # look for -l* and *.a constructs in the output for ac_arg in $ac_f77_v_output; do case $ac_arg in - [\\/]*.a | ?:[\\/]*.a | -[lLRu]*) - ac_cv_prog_f77_v=$ac_verb - break 2 ;; + [\\/]*.a | ?:[\\/]*.a | -[lLRu]*) + ac_cv_prog_f77_v=$ac_verb + break 2 ;; esac done done if test -z "$ac_cv_prog_f77_v"; then - { echo "$as_me:$LINENO: WARNING: cannot determine how to obtain linking information from $F77" >&5 -echo "$as_me: WARNING: cannot determine how to obtain linking information from $F77" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot determine how to obtain linking information from $F77" >&5 +$as_echo "$as_me: WARNING: cannot determine how to obtain linking information from $F77" >&2;} fi else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ echo "$as_me:$LINENO: WARNING: compilation failed" >&5 -echo "$as_me: WARNING: compilation failed" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: compilation failed" >&5 +$as_echo "$as_me: WARNING: compilation failed" >&2;} fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_prog_f77_v" >&5 -echo "${ECHO_T}$ac_cv_prog_f77_v" >&6 -echo "$as_me:$LINENO: checking for Fortran libraries of $F77" >&5 -echo $ECHO_N "checking for Fortran libraries of $F77... $ECHO_C" >&6 -if test "${ac_cv_f77_libs+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_f77_v" >&5 +$as_echo "$ac_cv_prog_f77_v" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Fortran 77 libraries of $F77" >&5 +$as_echo_n "checking for Fortran 77 libraries of $F77... " >&6; } +if ${ac_cv_f77_libs+:} false; then : + $as_echo_n "(cached) " >&6 else if test "x$FLIBS" != "x"; then ac_cv_f77_libs="$FLIBS" # Let the user override the test. else -cat >conftest.$ac_ext <<_ACEOF +cat > conftest.$ac_ext <<_ACEOF program main end @@ -10333,20 +6398,29 @@ _ACEOF # flags. ac_save_FFLAGS=$FFLAGS FFLAGS="$FFLAGS $ac_cv_prog_f77_v" -(eval echo $as_me:10336: \"$ac_link\") >&5 -ac_f77_v_output=`eval $ac_link 5>&1 2>&1 | grep -v 'Driving:'` -echo "$ac_f77_v_output" >&5 +eval "set x $ac_link" +shift +$as_echo "$as_me:${as_lineno-$LINENO}: $*" >&5 +# gfortran 4.3 outputs lines setting COLLECT_GCC_OPTIONS, COMPILER_PATH, +# LIBRARY_PATH; skip all such settings. +ac_f77_v_output=`eval $ac_link 5>&1 2>&1 | + sed '/^Driving:/d; /^Configured with:/d; + '"/^[_$as_cr_Letters][_$as_cr_alnum]*=/d"` +$as_echo "$ac_f77_v_output" >&5 FFLAGS=$ac_save_FFLAGS -rm -f conftest* +rm -rf conftest* # On HP/UX there is a line like: "LPATH is: /foo:/bar:/baz" where # /foo, /bar, and /baz are search directories for the Fortran linker. # Here, we change these into -L/foo -L/bar -L/baz (and put it first): ac_f77_v_output="`echo $ac_f77_v_output | grep 'LPATH is:' | - sed 's,.*LPATH is\(: *[^ ]*\).*,\1,;s,: */, -L/,g'` $ac_f77_v_output" + sed 's|.*LPATH is\(: *[^ ]*\).*|\1|;s|: */| -L/|g'` $ac_f77_v_output" +# FIXME: we keep getting bitten by quoted arguments; a more general fix +# that detects unbalanced quotes in FLIBS should be implemented +# and (ugh) tested at some point. case $ac_f77_v_output in # If we are using xlf then replace all the commas with spaces. *xlfentry*) @@ -10355,13 +6429,20 @@ case $ac_f77_v_output in # With Intel ifc, ignore the quoted -mGLOB_options_string stuff (quoted # $LIBS confuse us, and the libraries appear later in the output anyway). *mGLOB_options_string*) - ac_f77_v_output=`echo $ac_f77_v_output | sed 's/\"-mGLOB[^\"]*\"/ /g'` ;; + ac_f77_v_output=`echo $ac_f77_v_output | sed 's/"-mGLOB[^"]*"/ /g'` ;; + + # Portland Group compiler has singly- or doubly-quoted -cmdline argument + # Singly-quoted arguments were reported for versions 5.2-4 and 6.0-4. + # Doubly-quoted arguments were reported for "PGF90/x86 Linux/x86 5.0-2". + *-cmdline\ * | *-ignore\ * | *-def\ *) + ac_f77_v_output=`echo $ac_f77_v_output | sed "\ + s/-cmdline *'[^']*'/ /g; s/-cmdline *\"[^\"]*\"/ /g + s/-ignore *'[^']*'/ /g; s/-ignore *\"[^\"]*\"/ /g + s/-def *'[^']*'/ /g; s/-def *\"[^\"]*\"/ /g"` ;; # If we are using Cray Fortran then delete quotes. - # Use "\"" instead of '"' for font-lock-mode. - # FIXME: a more general fix for quoted arguments with spaces? *cft90*) - ac_f77_v_output=`echo $ac_f77_v_output | sed "s/\"//g"` ;; + ac_f77_v_output=`echo $ac_f77_v_output | sed 's/"//g'` ;; esac @@ -10376,8 +6457,8 @@ while test $# != 1; do shift ac_arg=$1 case $ac_arg in - [\\/]*.a | ?:[\\/]*.a) - ac_exists=false + [\\/]*.a | ?:[\\/]*.a) + ac_exists=false for ac_i in $ac_cv_f77_libs; do if test x"$ac_arg" = x"$ac_i"; then ac_exists=true @@ -10385,15 +6466,14 @@ while test $# != 1; do fi done - if test x"$ac_exists" = xtrue; then - : + if test x"$ac_exists" = xtrue; then : + else ac_cv_f77_libs="$ac_cv_f77_libs $ac_arg" fi - - ;; - -bI:*) - ac_exists=false + ;; + -bI:*) + ac_exists=false for ac_i in $ac_cv_f77_libs; do if test x"$ac_arg" = x"$ac_i"; then ac_exists=true @@ -10401,8 +6481,8 @@ fi fi done - if test x"$ac_exists" = xtrue; then - : + if test x"$ac_exists" = xtrue; then : + else if test "$ac_compiler_gnu" = yes; then for ac_link_opt in $ac_arg; do @@ -10412,18 +6492,18 @@ else ac_cv_f77_libs="$ac_cv_f77_libs $ac_arg" fi fi - - ;; - # Ignore these flags. - -lang* | -lcrt[01].o | -lcrtbegin.o | -lc | -lgcc | -libmil | -LANG:=*) - ;; - -lkernel32) - test x"$CYGWIN" != xyes && ac_cv_f77_libs="$ac_cv_f77_libs $ac_arg" - ;; - -[LRuY]) - # These flags, when seen by themselves, take an argument. - # We remove the space between option and argument and re-iterate - # unless we find an empty arg or a new option (starting with -) + ;; + # Ignore these flags. + -lang* | -lcrt*.o | -lc | -lgcc* | -lSystem | -libmil | -little \ + |-LANG:=* | -LIST:* | -LNO:* | -link) + ;; + -lkernel32) + test x"$CYGWIN" != xyes && ac_cv_f77_libs="$ac_cv_f77_libs $ac_arg" + ;; + -[LRuYz]) + # These flags, when seen by themselves, take an argument. + # We remove the space between option and argument and re-iterate + # unless we find an empty arg or a new option (starting with -) case $2 in "" | -*);; *) @@ -10432,10 +6512,10 @@ fi set X $ac_arg "$@" ;; esac - ;; - -YP,*) - for ac_j in `echo $ac_arg | sed -e 's/-YP,/-L/;s/:/ -L/g'`; do - ac_exists=false + ;; + -YP,*) + for ac_j in `$as_echo "$ac_arg" | sed -e 's/-YP,/-L/;s/:/ -L/g'`; do + ac_exists=false for ac_i in $ac_cv_f77_libs; do if test x"$ac_j" = x"$ac_i"; then ac_exists=true @@ -10443,17 +6523,16 @@ fi fi done - if test x"$ac_exists" = xtrue; then - : + if test x"$ac_exists" = xtrue; then : + else ac_arg="$ac_arg $ac_j" - ac_cv_f77_libs="$ac_cv_f77_libs $ac_j" + ac_cv_f77_libs="$ac_cv_f77_libs $ac_j" fi - - done - ;; - -[lLR]*) - ac_exists=false + done + ;; + -[lLR]*) + ac_exists=false for ac_i in $ac_cv_f77_libs; do if test x"$ac_arg" = x"$ac_i"; then ac_exists=true @@ -10461,14 +6540,16 @@ fi fi done - if test x"$ac_exists" = xtrue; then - : + if test x"$ac_exists" = xtrue; then : + else ac_cv_f77_libs="$ac_cv_f77_libs $ac_arg" fi - - ;; - # Ignore everything else. + ;; + -zallextract*| -zdefaultextract) + ac_cv_f77_libs="$ac_cv_f77_libs $ac_arg" + ;; + # Ignore everything else. esac done # restore positional arguments @@ -10479,10 +6560,10 @@ set X $ac_save_positional; shift # must begin with a "/"). case `(uname -sr) 2>/dev/null` in "SunOS 5"*) - ac_ld_run_path=`echo $ac_f77_v_output | - sed -n 's,^.*LD_RUN_PATH *= *\(/[^ ]*\).*$,-R\1,p'` + ac_ld_run_path=`$as_echo "$ac_f77_v_output" | + sed -n 's,^.*LD_RUN_PATH *= *\(/[^ ]*\).*$,-R\1,p'` test "x$ac_ld_run_path" != x && - if test "$ac_compiler_gnu" = yes; then + if test "$ac_compiler_gnu" = yes; then for ac_link_opt in $ac_ld_run_path; do ac_cv_f77_libs="$ac_cv_f77_libs -Xlinker $ac_link_opt" done @@ -10494,18 +6575,20 @@ esac fi # test "x$[]_AC_LANG_PREFIX[]LIBS" = "x" fi -echo "$as_me:$LINENO: result: $ac_cv_f77_libs" >&5 -echo "${ECHO_T}$ac_cv_f77_libs" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_f77_libs" >&5 +$as_echo "$ac_cv_f77_libs" >&6; } FLIBS="$ac_cv_f77_libs" -ac_ext=cc +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +echo " Macro returned with FLIBS defined as " $FLIBS + override_f77_libs=0; #case $ac_sys_system in @@ -10540,10 +6623,10 @@ if test "x${BUILD_F90}" != "x0"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_F90+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_F90+:} false; then : + $as_echo_n "(cached) " >&6 else case $F90 in [\\/]* | ?:[\\/]*) @@ -10555,28 +6638,29 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_F90="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done +IFS=$as_save_IFS ;; esac fi F90=$ac_cv_path_F90 - if test -n "$F90"; then - echo "$as_me:$LINENO: result: $F90" >&5 -echo "${ECHO_T}$F90" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $F90" >&5 +$as_echo "$F90" >&6; } else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi + test -n "$F90" && break done test -n "$F90" || F90=""none"" @@ -10597,8 +6681,8 @@ f90_module_dir='-I' f90_opts='' if test "x${BUILD_F90}" != "x0"; then - echo "$as_me:$LINENO: checking Fortran 90 compiler ($F90) type" >&5 -echo $ECHO_N "checking Fortran 90 compiler ($F90) type... $ECHO_C" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Fortran 90 compiler ($F90) type" >&5 +$as_echo_n "checking Fortran 90 compiler ($F90) type... " >&6; } cat >> testf90.f90 << EOF module mt double precision, parameter :: x = 2.3 @@ -10652,8 +6736,8 @@ F90LIBS= f90buildopts="-p. -s -YEXT_NAMES=LCS -YEXT_SFX=_ -YCFRL=1" fi rm -f testf90.f90 - echo "$as_me:$LINENO: result: ${f90type}" >&5 -echo "${ECHO_T}${f90type}" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${f90type}" >&5 +$as_echo "${f90type}" >&6; } if test "x${BUILD_F90}" != "x0"; then if test "x${has_f90}" = "xno"; then echo " -> cannot build the Fortran 90 interface" @@ -10684,13 +6768,12 @@ F90BUILDFLAGS=${f90buildopts}' '${savef90flags} - # filename extensions for Fortran 77 if test -z "$F77_EXT"; then F77_EXT=f; fi -ac_ext=cc +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -10715,27 +6798,19 @@ math_libs='-lcvode -lctmath' if test "$LAPACK_FTN_TRAILING_UNDERSCORE" = "y" then - cat >>confdefs.h <<\_ACEOF -#define LAPACK_FTN_TRAILING_UNDERSCORE 1 -_ACEOF + $as_echo "#define LAPACK_FTN_TRAILING_UNDERSCORE 1" >>confdefs.h - cat >>confdefs.h <<\_ACEOF -#define FTN_TRAILING_UNDERSCORE 1 -_ACEOF + $as_echo "#define FTN_TRAILING_UNDERSCORE 1" >>confdefs.h fi if test "$LAPACK_FTN_STRING_LEN_AT_END" = "y" -then cat >>confdefs.h <<\_ACEOF -#define LAPACK_FTN_STRING_LEN_AT_END 1 -_ACEOF +then $as_echo "#define LAPACK_FTN_STRING_LEN_AT_END 1" >>confdefs.h fi if test "$LAPACK_NAMES" = "lower" -then cat >>confdefs.h <<\_ACEOF -#define LAPACK_NAMES_LOWERCASE 1 -_ACEOF +then $as_echo "#define LAPACK_NAMES_LOWERCASE 1" >>confdefs.h fi @@ -10749,8 +6824,8 @@ fi # SO is the extension of shared libraries `(including the dot!) # -- usually .so, .sl on HP-UX, .dll on Cygwin -echo "$as_me:$LINENO: checking SO" >&5 -echo $ECHO_N "checking SO... $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SO" >&5 +$as_echo_n "checking SO... " >&6; } if test -z "$SO" then case $ac_sys_system in @@ -10760,12 +6835,12 @@ then *) SO=.so;; esac fi -echo "$as_me:$LINENO: result: $SO" >&5 -echo "${ECHO_T}$SO" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SO" >&5 +$as_echo "$SO" >&6; } -ac_ext=cc +ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -10840,39 +6915,27 @@ fi - ac_config_files="$ac_config_files Makefile Cantera/Makefile Cantera/src/Makefile Cantera/src/base/Makefile Cantera/src/zeroD/Makefile Cantera/src/oneD/Makefile Cantera/src/converters/Makefile Cantera/src/transport/Makefile Cantera/src/thermo/Makefile Cantera/src/kinetics/Makefile Cantera/src/numerics/Makefile Cantera/src/spectra/Makefile Cantera/src/equil/Makefile Cantera/clib/src/Makefile Cantera/fortran/src/Makefile Cantera/fortran/f77demos/f77demos.mak Cantera/fortran/f77demos/Makefile Cantera/matlab/Makefile Cantera/matlab/setup_matlab.py Cantera/python/Makefile Cantera/python/setup.py Cantera/cxx/Makefile Cantera/cxx/src/Makefile Cantera/cxx/demos/Makefile Cantera/cxx/demos/combustor/Makefile Cantera/cxx/demos/combustor/Makefile.install Cantera/cxx/demos/flamespeed/Makefile Cantera/cxx/demos/flamespeed/Makefile.install Cantera/cxx/demos/kinetics1/Makefile Cantera/cxx/demos/kinetics1/Makefile.install Cantera/cxx/demos/NASA_coeffs/Makefile Cantera/cxx/demos/NASA_coeffs/Makefile.install Cantera/cxx/demos/rankine/Makefile Cantera/cxx/demos/rankine/Makefile.install Cantera/cxx/include/Cantera.mak Cantera/cxx/include/Cantera_bt.mak Cantera/user/Makefile Cantera/python/src/Makefile Cantera/python/examples/Makefile Cantera/python/examples/equilibrium/Makefile Cantera/python/examples/equilibrium/adiabatic_flame/Makefile Cantera/python/examples/equilibrium/multiphase_plasma/Makefile Cantera/python/examples/equilibrium/simple_test/Makefile Cantera/python/examples/equilibrium/stoich_flame/Makefile Cantera/python/examples/gasdynamics/isentropic/Makefile Cantera/python/examples/gasdynamics/soundSpeed/Makefile Cantera/python/examples/flames/adiabatic_flame/Makefile Cantera/python/examples/flames/flame1/Makefile Cantera/python/examples/flames/flame2/Makefile Cantera/python/examples/flames/flame_fixed_T/Makefile Cantera/python/examples/flames/free_h2_air/Makefile Cantera/python/examples/flames/npflame1/Makefile Cantera/python/examples/flames/stflame1/Makefile Cantera/python/examples/fuel_cells/Makefile Cantera/python/examples/liquid_vapor/critProperties/Makefile Cantera/python/examples/liquid_vapor/rankine/Makefile Cantera/python/examples/kinetics/Makefile Cantera/python/examples/misc/Makefile Cantera/python/examples/reactors/combustor_sim/Makefile Cantera/python/examples/reactors/functors_sim/Makefile Cantera/python/examples/reactors/mix1_sim/Makefile Cantera/python/examples/reactors/mix2_sim/Makefile Cantera/python/examples/reactors/piston_sim/Makefile Cantera/python/examples/reactors/reactor1_sim/Makefile Cantera/python/examples/reactors/reactor2_sim/Makefile Cantera/python/examples/reactors/sensitivity_sim/Makefile Cantera/python/examples/reactors/surf_pfr_sim/Makefile Cantera/python/examples/surface_chemistry/diamond_cvd/Makefile Cantera/python/examples/surface_chemistry/catcomb_stagflow/Makefile Cantera/python/examples/transport/Makefile Cantera/python/examples/flames/Makefile Cantera/python/examples/gasdynamics/Makefile Cantera/python/examples/liquid_vapor/Makefile Cantera/python/examples/reactors/Makefile Cantera/python/examples/surface_chemistry/Makefile ext/lapack/Makefile ext/blas/Makefile ext/cvode/Makefile ext/math/Makefile ext/recipes/Makefile ext/tpx/Makefile ext/Makefile ext/f2c_libs/Makefile ext/f2c_blas/Makefile ext/f2c_lapack/Makefile ext/f2c_math/Makefile examples/Makefile examples/cxx/Makefile tools/Makefile tools/doc/Cantera.cfg tools/doc/Makefile tools/src/Makefile tools/src/sample.mak tools/src/finish_install.py tools/src/package4mac tools/templates/f77/demo.mak tools/templates/f90/demo.mak tools/templates/cxx/demo.mak tools/testtools/Makefile data/inputs/Makefile data/inputs/mkxml test_problems/Makefile test_problems/cxx_ex/Makefile test_problems/silane_equil/Makefile test_problems/surfkin/Makefile test_problems/spectroscopy/Makefile test_problems/surfSolverTest/Makefile test_problems/diamondSurf/Makefile test_problems/diamondSurf_dupl/Makefile test_problems/ChemEquil_gri_matrix/Makefile test_problems/ChemEquil_gri_pairs/Makefile test_problems/ChemEquil_ionizedGas/Makefile test_problems/ChemEquil_red1/Makefile test_problems/CpJump/Makefile test_problems/mixGasTransport/Makefile test_problems/multiGasTransport/Makefile test_problems/printUtilUnitTest/Makefile test_problems/fracCoeff/Makefile test_problems/negATest/Makefile test_problems/NASA9poly_test/Makefile test_problems/ck2cti_test/Makefile test_problems/ck2cti_test/runtest test_problems/nasa9_reader/Makefile test_problems/nasa9_reader/runtest test_problems/min_python/Makefile test_problems/min_python/minDiamond/Makefile test_problems/min_python/negATest/Makefile test_problems/pureFluidTest/Makefile test_problems/rankine_democxx/Makefile test_problems/python/Makefile test_problems/cathermo/Makefile test_problems/cathermo/issp/Makefile test_problems/cathermo/ims/Makefile test_problems/cathermo/stoichSubSSTP/Makefile test_problems/cathermo/testIAPWS/Makefile test_problems/cathermo/testIAPWSPres/Makefile test_problems/cathermo/testIAPWSTripP/Makefile test_problems/cathermo/testWaterPDSS/Makefile test_problems/cathermo/testWaterTP/Makefile test_problems/cathermo/HMW_test_1/Makefile test_problems/cathermo/HMW_test_3/Makefile test_problems/cathermo/HMW_graph_GvT/Makefile test_problems/cathermo/HMW_graph_GvI/Makefile test_problems/cathermo/HMW_graph_HvT/Makefile test_problems/cathermo/HMW_graph_CpvT/Makefile test_problems/cathermo/HMW_graph_VvT/Makefile test_problems/cathermo/DH_graph_1/Makefile test_problems/cathermo/DH_graph_acommon/Makefile test_problems/cathermo/DH_graph_NM/Makefile test_problems/cathermo/DH_graph_Pitzer/Makefile test_problems/cathermo/DH_graph_bdotak/Makefile test_problems/cathermo/HMW_dupl_test/Makefile test_problems/cathermo/VPissp/Makefile test_problems/cathermo/wtWater/Makefile test_problems/VCSnonideal/Makefile test_problems/VPsilane_test/Makefile test_problems/VPsilane_test/runtest test_problems/VCSnonideal/NaCl_equil/Makefile bin/install_tsc" +ac_config_files="$ac_config_files Makefile Cantera/Makefile Cantera/src/Makefile Cantera/src/base/Makefile Cantera/src/zeroD/Makefile Cantera/src/oneD/Makefile Cantera/src/converters/Makefile Cantera/src/transport/Makefile Cantera/src/thermo/Makefile Cantera/src/kinetics/Makefile Cantera/src/numerics/Makefile Cantera/src/spectra/Makefile Cantera/src/equil/Makefile Cantera/clib/src/Makefile Cantera/fortran/src/Makefile Cantera/fortran/f77demos/f77demos.mak Cantera/fortran/f77demos/Makefile Cantera/matlab/Makefile Cantera/matlab/setup_matlab.py Cantera/python/Makefile Cantera/python/setup.py Cantera/cxx/Makefile Cantera/cxx/src/Makefile Cantera/cxx/demos/Makefile Cantera/cxx/demos/combustor/Makefile Cantera/cxx/demos/combustor/Makefile.install Cantera/cxx/demos/flamespeed/Makefile Cantera/cxx/demos/flamespeed/Makefile.install Cantera/cxx/demos/kinetics1/Makefile Cantera/cxx/demos/kinetics1/Makefile.install Cantera/cxx/demos/NASA_coeffs/Makefile Cantera/cxx/demos/NASA_coeffs/Makefile.install Cantera/cxx/demos/rankine/Makefile Cantera/cxx/demos/rankine/Makefile.install Cantera/cxx/include/Cantera.mak Cantera/cxx/include/Cantera_bt.mak Cantera/user/Makefile Cantera/python/src/Makefile Cantera/python/examples/Makefile Cantera/python/examples/equilibrium/Makefile Cantera/python/examples/equilibrium/adiabatic_flame/Makefile Cantera/python/examples/equilibrium/multiphase_plasma/Makefile Cantera/python/examples/equilibrium/simple_test/Makefile Cantera/python/examples/equilibrium/stoich_flame/Makefile Cantera/python/examples/gasdynamics/isentropic/Makefile Cantera/python/examples/gasdynamics/soundSpeed/Makefile Cantera/python/examples/flames/adiabatic_flame/Makefile Cantera/python/examples/flames/flame1/Makefile Cantera/python/examples/flames/flame2/Makefile Cantera/python/examples/flames/flame_fixed_T/Makefile Cantera/python/examples/flames/free_h2_air/Makefile Cantera/python/examples/flames/npflame1/Makefile Cantera/python/examples/flames/stflame1/Makefile Cantera/python/examples/fuel_cells/Makefile Cantera/python/examples/liquid_vapor/critProperties/Makefile Cantera/python/examples/liquid_vapor/rankine/Makefile Cantera/python/examples/kinetics/Makefile Cantera/python/examples/misc/Makefile Cantera/python/examples/reactors/combustor_sim/Makefile Cantera/python/examples/reactors/functors_sim/Makefile Cantera/python/examples/reactors/mix1_sim/Makefile Cantera/python/examples/reactors/mix2_sim/Makefile Cantera/python/examples/reactors/piston_sim/Makefile Cantera/python/examples/reactors/reactor1_sim/Makefile Cantera/python/examples/reactors/reactor2_sim/Makefile Cantera/python/examples/reactors/sensitivity_sim/Makefile Cantera/python/examples/reactors/surf_pfr_sim/Makefile Cantera/python/examples/surface_chemistry/diamond_cvd/Makefile Cantera/python/examples/surface_chemistry/catcomb_stagflow/Makefile Cantera/python/examples/transport/Makefile Cantera/python/examples/flames/Makefile Cantera/python/examples/gasdynamics/Makefile Cantera/python/examples/liquid_vapor/Makefile Cantera/python/examples/reactors/Makefile Cantera/python/examples/surface_chemistry/Makefile ext/lapack/Makefile ext/blas/Makefile ext/cvode/Makefile ext/math/Makefile ext/recipes/Makefile ext/tpx/Makefile ext/Makefile ext/f2c_libs/Makefile ext/f2c_blas/Makefile ext/f2c_lapack/Makefile ext/f2c_math/Makefile examples/Makefile examples/cxx/Makefile docs/Makefile tools/Makefile docs/Cantera.cfg tools/src/Makefile tools/src/sample.mak tools/src/finish_install.py tools/src/package4mac tools/templates/f77/demo.mak tools/templates/f90/demo.mak tools/templates/cxx/demo.mak tools/testtools/Makefile data/inputs/Makefile data/inputs/mkxml test_problems/Makefile test_problems/cxx_ex/Makefile test_problems/silane_equil/Makefile test_problems/surfkin/Makefile test_problems/spectroscopy/Makefile test_problems/surfSolverTest/Makefile test_problems/diamondSurf/Makefile test_problems/diamondSurf_dupl/Makefile test_problems/ChemEquil_gri_matrix/Makefile test_problems/ChemEquil_gri_pairs/Makefile test_problems/ChemEquil_ionizedGas/Makefile test_problems/ChemEquil_red1/Makefile test_problems/CpJump/Makefile test_problems/mixGasTransport/Makefile test_problems/multiGasTransport/Makefile test_problems/printUtilUnitTest/Makefile test_problems/fracCoeff/Makefile test_problems/negATest/Makefile test_problems/NASA9poly_test/Makefile test_problems/ck2cti_test/Makefile test_problems/ck2cti_test/runtest test_problems/nasa9_reader/Makefile test_problems/nasa9_reader/runtest test_problems/min_python/Makefile test_problems/min_python/minDiamond/Makefile test_problems/min_python/negATest/Makefile test_problems/pureFluidTest/Makefile test_problems/rankine_democxx/Makefile test_problems/python/Makefile test_problems/cathermo/Makefile test_problems/cathermo/issp/Makefile test_problems/cathermo/ims/Makefile test_problems/cathermo/stoichSubSSTP/Makefile test_problems/cathermo/testIAPWS/Makefile test_problems/cathermo/testIAPWSPres/Makefile test_problems/cathermo/testIAPWSTripP/Makefile test_problems/cathermo/testWaterPDSS/Makefile test_problems/cathermo/testWaterTP/Makefile test_problems/cathermo/HMW_test_1/Makefile test_problems/cathermo/HMW_test_3/Makefile test_problems/cathermo/HMW_graph_GvT/Makefile test_problems/cathermo/HMW_graph_GvI/Makefile test_problems/cathermo/HMW_graph_HvT/Makefile test_problems/cathermo/HMW_graph_CpvT/Makefile test_problems/cathermo/HMW_graph_VvT/Makefile test_problems/cathermo/DH_graph_1/Makefile test_problems/cathermo/DH_graph_acommon/Makefile test_problems/cathermo/DH_graph_NM/Makefile test_problems/cathermo/DH_graph_Pitzer/Makefile test_problems/cathermo/DH_graph_bdotak/Makefile test_problems/cathermo/HMW_dupl_test/Makefile test_problems/cathermo/VPissp/Makefile test_problems/cathermo/wtWater/Makefile test_problems/VCSnonideal/Makefile test_problems/VPsilane_test/Makefile test_problems/VPsilane_test/runtest test_problems/VCSnonideal/NaCl_equil/Makefile bin/install_tsc" + test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/; -s/:*\${srcdir}:*/:/; -s/:*@srcdir@:*/:/; -s/^\([^=]*=[ ]*\):*/\1/; -s/:*$//; -s/^[^=]*=[ ]*$//; -}' -fi - DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. - ac_i=`echo "$ac_i" | - sed 's/\$U\././;s/\.o$//;s/\.obj$//'` - # 2. Add them. - ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" - ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs @@ -10880,12 +6943,14 @@ LTLIBOBJS=$ac_ltlibobjs -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 -echo "$as_me: creating $CONFIG_STATUS" >&6;} -cat >$CONFIG_STATUS <<_ACEOF +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. @@ -10895,81 +6960,253 @@ cat >$CONFIG_STATUS <<_ACEOF debug=false ac_cs_recheck=false ac_cs_silent=false + SHELL=\${CONFIG_SHELL-$SHELL} -_ACEOF +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## -cat >>$CONFIG_STATUS <<\_ACEOF -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## - -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' -elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then - set -o posix -fi -DUALCASE=1; export DUALCASE # for MKS sh - -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset + setopt NO_GLOB_SUBST else - as_unset=false + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac fi -# Work around bugs in pre-3.0 UWIN ksh. -$as_unset ENV MAIL MAILPATH +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. -for as_var in \ - LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ - LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ - LC_TELEPHONE LC_TIME -do - if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then - eval $as_var=C; export $as_var - else - $as_unset $as_var - fi -done +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE -# Required to use basename. -if expr a : '\(a\)' >/dev/null 2>&1; then +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi -if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. -as_me=`$as_basename "$0" || +as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)$' \| \ - . : '\(.\)' 2>/dev/null || -echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } - /^X\/\(\/\/\)$/{ s//\1/; q; } - /^X\/\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` - -# PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -10977,148 +7214,123 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x$as_lineno_3" = "x$as_lineno_2" || { - # Find who we are. Look in the path if we contain no path at all - # relative or not. - case $0 in - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done - - ;; - esac - # We did not find ourselves, most probably we were run as `sh COMMAND' - # in which case we are not to be found in the path. - if test "x$as_myself" = x; then - as_myself=$0 - fi - if test ! -f "$as_myself"; then - { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 -echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} - { (exit 1); exit 1; }; } - fi - case $CONFIG_SHELL in - '') - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for as_base in sh bash ksh sh5; do - case $as_dir in - /*) - if ("$as_dir/$as_base" -c ' - as_lineno_1=$LINENO - as_lineno_2=$LINENO - as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then - $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } - $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } - CONFIG_SHELL=$as_dir/$as_base - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$0" ${1+"$@"} - fi;; - esac - done -done -;; - esac - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line before each line; the second 'sed' does the real - # work. The second script uses 'N' to pair each line-number line - # with the numbered line, and appends trailing '-' during - # substitution so that $LINENO is not a special case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) - sed '=' <$as_myself | - sed ' - N - s,$,-, - : loop - s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, - t loop - s,-$,, - s,^['$as_cr_digits']*\n,, - ' >$as_me.lineno && - chmod +x $as_me.lineno || - { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 -echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} - { (exit 1); exit 1; }; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensible to this). - . ./$as_me.lineno - # Exit status is that of the last command. - exit -} - - -case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in - *c*,-n*) ECHO_N= ECHO_C=' -' ECHO_T=' ' ;; - *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; - *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1; then - as_expr=expr -else - as_expr=false -fi - rm -f conf$$ conf$$.exe conf$$.file -echo >conf$$.file -if ln -s conf$$.file conf$$ 2>/dev/null; then - # We could just check for DJGPP; but this test a) works b) is more generic - # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). - if test -f conf$$.exe; then - # Don't use ln at all; we don't have any links - as_ln_s='cp -p' - else +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' fi -elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln else as_ln_s='cp -p' fi -rm -f conf$$ conf$$.exe conf$$.file +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi -as_executable_p="test -f" +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -11127,31 +7339,20 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" -# IFS -# We need space, tab and new line, in precisely that order. -as_nl=' -' -IFS=" $as_nl" - -# CDPATH. -$as_unset CDPATH - exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 -# Open the log real soon, to keep \$[0] and so on meaningful, and to +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. Logging --version etc. is OK. -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX -} >&5 -cat >&5 <<_CSEOF - +# values after options handling. +ac_log=" This file was extended by Cantera $as_me 1.7.0, which was -generated by GNU Autoconf 2.59. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -11159,45 +7360,46 @@ generated by GNU Autoconf 2.59. Invocation command line was CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ -_CSEOF -echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 -echo >&5 +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + _ACEOF +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -if test -n "$ac_config_files"; then - echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS -fi +config_files="$ac_config_files" +config_headers="$ac_config_headers" -if test -n "$ac_config_headers"; then - echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS -fi - -if test -n "$ac_config_links"; then - echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS -fi - -if test -n "$ac_config_commands"; then - echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS -fi - -cat >>$CONFIG_STATUS <<\_ACEOF +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files from templates according to the -current configuration. +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. -Usage: $0 [OPTIONS] [FILE]... +Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit - -V, --version print version number, then exit - -q, --quiet do not print progress messages + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE Configuration files: $config_files @@ -11205,84 +7407,90 @@ $config_files Configuration headers: $config_headers -Report bugs to ." -_ACEOF +Report bugs to the package provider." -cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Cantera config.status 1.7.0 -configured by $0, generated by GNU Autoconf 2.59, - with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" +configured by $0, generated by GNU Autoconf 2.68, + with options \\"\$ac_cs_config\\" -Copyright (C) 2003 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." -srcdir=$srcdir -INSTALL="$INSTALL" + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -# If no file are specified by the user, then we need to provide default -# value. By we need to know if files were specified by the user. +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in - --*=*) - ac_option=`expr "x$1" : 'x\([^=]*\)='` - ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; - -*) + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; - *) # This is not an option, so the user has probably given explicit - # arguments. - ac_option=$1 - ac_need_defaults=false;; esac case $ac_option in # Handling of the options. -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; - --version | --vers* | -V ) - echo "$ac_cs_version"; exit 0 ;; - --he | --h) - # Conflict between --help and --header - { { echo "$as_me:$LINENO: error: ambiguous option: $1 -Try \`$0 --help' for more information." >&5 -echo "$as_me: error: ambiguous option: $1 -Try \`$0 --help' for more information." >&2;} - { (exit 1); exit 1; }; };; - --help | --hel | -h ) - echo "$ac_cs_usage"; exit 0 ;; - --debug | --d* | -d ) + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift - CONFIG_FILES="$CONFIG_FILES $ac_optarg" + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift - CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. - -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 -Try \`$0 --help' for more information." >&5 -echo "$as_me: error: unrecognized option: $1 -Try \`$0 --help' for more information." >&2;} - { (exit 1); exit 1; }; } ;; + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; - *) ac_config_targets="$ac_config_targets $1" ;; + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; esac shift @@ -11296,189 +7504,203 @@ if $ac_cs_silent; then fi _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 - exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" fi _ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - - -cat >>$CONFIG_STATUS <<\_ACEOF +# Handling of arguments. for ac_config_target in $ac_config_targets do - case "$ac_config_target" in - # Handling of arguments. - "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "Cantera/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/Makefile" ;; - "Cantera/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/Makefile" ;; - "Cantera/src/base/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/base/Makefile" ;; - "Cantera/src/zeroD/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/zeroD/Makefile" ;; - "Cantera/src/oneD/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/oneD/Makefile" ;; - "Cantera/src/converters/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/converters/Makefile" ;; - "Cantera/src/transport/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/transport/Makefile" ;; - "Cantera/src/thermo/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/thermo/Makefile" ;; - "Cantera/src/kinetics/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/kinetics/Makefile" ;; - "Cantera/src/numerics/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/numerics/Makefile" ;; - "Cantera/src/spectra/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/spectra/Makefile" ;; - "Cantera/src/equil/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/src/equil/Makefile" ;; - "Cantera/clib/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/clib/src/Makefile" ;; - "Cantera/fortran/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/fortran/src/Makefile" ;; - "Cantera/fortran/f77demos/f77demos.mak" ) CONFIG_FILES="$CONFIG_FILES Cantera/fortran/f77demos/f77demos.mak" ;; - "Cantera/fortran/f77demos/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/fortran/f77demos/Makefile" ;; - "Cantera/matlab/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/matlab/Makefile" ;; - "Cantera/matlab/setup_matlab.py" ) CONFIG_FILES="$CONFIG_FILES Cantera/matlab/setup_matlab.py" ;; - "Cantera/python/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/Makefile" ;; - "Cantera/python/setup.py" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/setup.py" ;; - "Cantera/cxx/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/Makefile" ;; - "Cantera/cxx/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/src/Makefile" ;; - "Cantera/cxx/demos/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/Makefile" ;; - "Cantera/cxx/demos/combustor/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/combustor/Makefile" ;; - "Cantera/cxx/demos/combustor/Makefile.install" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/combustor/Makefile.install" ;; - "Cantera/cxx/demos/flamespeed/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/flamespeed/Makefile" ;; - "Cantera/cxx/demos/flamespeed/Makefile.install" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/flamespeed/Makefile.install" ;; - "Cantera/cxx/demos/kinetics1/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/kinetics1/Makefile" ;; - "Cantera/cxx/demos/kinetics1/Makefile.install" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/kinetics1/Makefile.install" ;; - "Cantera/cxx/demos/NASA_coeffs/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/NASA_coeffs/Makefile" ;; - "Cantera/cxx/demos/NASA_coeffs/Makefile.install" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/NASA_coeffs/Makefile.install" ;; - "Cantera/cxx/demos/rankine/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/rankine/Makefile" ;; - "Cantera/cxx/demos/rankine/Makefile.install" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/rankine/Makefile.install" ;; - "Cantera/cxx/include/Cantera.mak" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/include/Cantera.mak" ;; - "Cantera/cxx/include/Cantera_bt.mak" ) CONFIG_FILES="$CONFIG_FILES Cantera/cxx/include/Cantera_bt.mak" ;; - "Cantera/user/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/user/Makefile" ;; - "Cantera/python/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/src/Makefile" ;; - "Cantera/python/examples/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/Makefile" ;; - "Cantera/python/examples/equilibrium/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/Makefile" ;; - "Cantera/python/examples/equilibrium/adiabatic_flame/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/adiabatic_flame/Makefile" ;; - "Cantera/python/examples/equilibrium/multiphase_plasma/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/multiphase_plasma/Makefile" ;; - "Cantera/python/examples/equilibrium/simple_test/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/simple_test/Makefile" ;; - "Cantera/python/examples/equilibrium/stoich_flame/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/stoich_flame/Makefile" ;; - "Cantera/python/examples/gasdynamics/isentropic/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/gasdynamics/isentropic/Makefile" ;; - "Cantera/python/examples/gasdynamics/soundSpeed/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/gasdynamics/soundSpeed/Makefile" ;; - "Cantera/python/examples/flames/adiabatic_flame/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/adiabatic_flame/Makefile" ;; - "Cantera/python/examples/flames/flame1/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/flame1/Makefile" ;; - "Cantera/python/examples/flames/flame2/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/flame2/Makefile" ;; - "Cantera/python/examples/flames/flame_fixed_T/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/flame_fixed_T/Makefile" ;; - "Cantera/python/examples/flames/free_h2_air/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/free_h2_air/Makefile" ;; - "Cantera/python/examples/flames/npflame1/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/npflame1/Makefile" ;; - "Cantera/python/examples/flames/stflame1/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/stflame1/Makefile" ;; - "Cantera/python/examples/fuel_cells/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/fuel_cells/Makefile" ;; - "Cantera/python/examples/liquid_vapor/critProperties/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/liquid_vapor/critProperties/Makefile" ;; - "Cantera/python/examples/liquid_vapor/rankine/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/liquid_vapor/rankine/Makefile" ;; - "Cantera/python/examples/kinetics/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/kinetics/Makefile" ;; - "Cantera/python/examples/misc/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/misc/Makefile" ;; - "Cantera/python/examples/reactors/combustor_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/combustor_sim/Makefile" ;; - "Cantera/python/examples/reactors/functors_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/functors_sim/Makefile" ;; - "Cantera/python/examples/reactors/mix1_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/mix1_sim/Makefile" ;; - "Cantera/python/examples/reactors/mix2_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/mix2_sim/Makefile" ;; - "Cantera/python/examples/reactors/piston_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/piston_sim/Makefile" ;; - "Cantera/python/examples/reactors/reactor1_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/reactor1_sim/Makefile" ;; - "Cantera/python/examples/reactors/reactor2_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/reactor2_sim/Makefile" ;; - "Cantera/python/examples/reactors/sensitivity_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/sensitivity_sim/Makefile" ;; - "Cantera/python/examples/reactors/surf_pfr_sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/surf_pfr_sim/Makefile" ;; - "Cantera/python/examples/surface_chemistry/diamond_cvd/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/surface_chemistry/diamond_cvd/Makefile" ;; - "Cantera/python/examples/surface_chemistry/catcomb_stagflow/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/surface_chemistry/catcomb_stagflow/Makefile" ;; - "Cantera/python/examples/transport/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/transport/Makefile" ;; - "Cantera/python/examples/flames/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/Makefile" ;; - "Cantera/python/examples/gasdynamics/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/gasdynamics/Makefile" ;; - "Cantera/python/examples/liquid_vapor/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/liquid_vapor/Makefile" ;; - "Cantera/python/examples/reactors/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/Makefile" ;; - "Cantera/python/examples/surface_chemistry/Makefile" ) CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/surface_chemistry/Makefile" ;; - "ext/lapack/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/lapack/Makefile" ;; - "ext/blas/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/blas/Makefile" ;; - "ext/cvode/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/cvode/Makefile" ;; - "ext/math/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/math/Makefile" ;; - "ext/recipes/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/recipes/Makefile" ;; - "ext/tpx/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/tpx/Makefile" ;; - "ext/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/Makefile" ;; - "ext/f2c_libs/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/f2c_libs/Makefile" ;; - "ext/f2c_blas/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/f2c_blas/Makefile" ;; - "ext/f2c_lapack/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/f2c_lapack/Makefile" ;; - "ext/f2c_math/Makefile" ) CONFIG_FILES="$CONFIG_FILES ext/f2c_math/Makefile" ;; - "examples/Makefile" ) CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; - "examples/cxx/Makefile" ) CONFIG_FILES="$CONFIG_FILES examples/cxx/Makefile" ;; - "tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; - "tools/doc/Cantera.cfg" ) CONFIG_FILES="$CONFIG_FILES tools/doc/Cantera.cfg" ;; - "tools/doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/doc/Makefile" ;; - "tools/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/src/Makefile" ;; - "tools/src/sample.mak" ) CONFIG_FILES="$CONFIG_FILES tools/src/sample.mak" ;; - "tools/src/finish_install.py" ) CONFIG_FILES="$CONFIG_FILES tools/src/finish_install.py" ;; - "tools/src/package4mac" ) CONFIG_FILES="$CONFIG_FILES tools/src/package4mac" ;; - "tools/templates/f77/demo.mak" ) CONFIG_FILES="$CONFIG_FILES tools/templates/f77/demo.mak" ;; - "tools/templates/f90/demo.mak" ) CONFIG_FILES="$CONFIG_FILES tools/templates/f90/demo.mak" ;; - "tools/templates/cxx/demo.mak" ) CONFIG_FILES="$CONFIG_FILES tools/templates/cxx/demo.mak" ;; - "tools/testtools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/testtools/Makefile" ;; - "data/inputs/Makefile" ) CONFIG_FILES="$CONFIG_FILES data/inputs/Makefile" ;; - "data/inputs/mkxml" ) CONFIG_FILES="$CONFIG_FILES data/inputs/mkxml" ;; - "test_problems/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/Makefile" ;; - "test_problems/cxx_ex/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cxx_ex/Makefile" ;; - "test_problems/silane_equil/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/silane_equil/Makefile" ;; - "test_problems/surfkin/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/surfkin/Makefile" ;; - "test_problems/spectroscopy/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/spectroscopy/Makefile" ;; - "test_problems/surfSolverTest/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/surfSolverTest/Makefile" ;; - "test_problems/diamondSurf/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/diamondSurf/Makefile" ;; - "test_problems/diamondSurf_dupl/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/diamondSurf_dupl/Makefile" ;; - "test_problems/ChemEquil_gri_matrix/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_gri_matrix/Makefile" ;; - "test_problems/ChemEquil_gri_pairs/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_gri_pairs/Makefile" ;; - "test_problems/ChemEquil_ionizedGas/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_ionizedGas/Makefile" ;; - "test_problems/ChemEquil_red1/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_red1/Makefile" ;; - "test_problems/CpJump/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/CpJump/Makefile" ;; - "test_problems/mixGasTransport/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/mixGasTransport/Makefile" ;; - "test_problems/multiGasTransport/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/multiGasTransport/Makefile" ;; - "test_problems/printUtilUnitTest/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/printUtilUnitTest/Makefile" ;; - "test_problems/fracCoeff/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/fracCoeff/Makefile" ;; - "test_problems/negATest/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/negATest/Makefile" ;; - "test_problems/NASA9poly_test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/NASA9poly_test/Makefile" ;; - "test_problems/ck2cti_test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/ck2cti_test/Makefile" ;; - "test_problems/ck2cti_test/runtest" ) CONFIG_FILES="$CONFIG_FILES test_problems/ck2cti_test/runtest" ;; - "test_problems/nasa9_reader/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/nasa9_reader/Makefile" ;; - "test_problems/nasa9_reader/runtest" ) CONFIG_FILES="$CONFIG_FILES test_problems/nasa9_reader/runtest" ;; - "test_problems/min_python/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/min_python/Makefile" ;; - "test_problems/min_python/minDiamond/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/min_python/minDiamond/Makefile" ;; - "test_problems/min_python/negATest/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/min_python/negATest/Makefile" ;; - "test_problems/pureFluidTest/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/pureFluidTest/Makefile" ;; - "test_problems/rankine_democxx/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/rankine_democxx/Makefile" ;; - "test_problems/python/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/python/Makefile" ;; - "test_problems/cathermo/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/Makefile" ;; - "test_problems/cathermo/issp/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/issp/Makefile" ;; - "test_problems/cathermo/ims/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/ims/Makefile" ;; - "test_problems/cathermo/stoichSubSSTP/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/stoichSubSSTP/Makefile" ;; - "test_problems/cathermo/testIAPWS/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testIAPWS/Makefile" ;; - "test_problems/cathermo/testIAPWSPres/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testIAPWSPres/Makefile" ;; - "test_problems/cathermo/testIAPWSTripP/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testIAPWSTripP/Makefile" ;; - "test_problems/cathermo/testWaterPDSS/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testWaterPDSS/Makefile" ;; - "test_problems/cathermo/testWaterTP/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testWaterTP/Makefile" ;; - "test_problems/cathermo/HMW_test_1/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_test_1/Makefile" ;; - "test_problems/cathermo/HMW_test_3/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_test_3/Makefile" ;; - "test_problems/cathermo/HMW_graph_GvT/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_GvT/Makefile" ;; - "test_problems/cathermo/HMW_graph_GvI/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_GvI/Makefile" ;; - "test_problems/cathermo/HMW_graph_HvT/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_HvT/Makefile" ;; - "test_problems/cathermo/HMW_graph_CpvT/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_CpvT/Makefile" ;; - "test_problems/cathermo/HMW_graph_VvT/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_VvT/Makefile" ;; - "test_problems/cathermo/DH_graph_1/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_1/Makefile" ;; - "test_problems/cathermo/DH_graph_acommon/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_acommon/Makefile" ;; - "test_problems/cathermo/DH_graph_NM/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_NM/Makefile" ;; - "test_problems/cathermo/DH_graph_Pitzer/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_Pitzer/Makefile" ;; - "test_problems/cathermo/DH_graph_bdotak/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_bdotak/Makefile" ;; - "test_problems/cathermo/HMW_dupl_test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_dupl_test/Makefile" ;; - "test_problems/cathermo/VPissp/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/VPissp/Makefile" ;; - "test_problems/cathermo/wtWater/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/wtWater/Makefile" ;; - "test_problems/VCSnonideal/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/VCSnonideal/Makefile" ;; - "test_problems/VPsilane_test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/VPsilane_test/Makefile" ;; - "test_problems/VPsilane_test/runtest" ) CONFIG_FILES="$CONFIG_FILES test_problems/VPsilane_test/runtest" ;; - "test_problems/VCSnonideal/NaCl_equil/Makefile" ) CONFIG_FILES="$CONFIG_FILES test_problems/VCSnonideal/NaCl_equil/Makefile" ;; - "bin/install_tsc" ) CONFIG_FILES="$CONFIG_FILES bin/install_tsc" ;; - "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 -echo "$as_me: error: invalid argument: $ac_config_target" >&2;} - { (exit 1); exit 1; }; };; + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "Cantera/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/Makefile" ;; + "Cantera/src/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/Makefile" ;; + "Cantera/src/base/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/base/Makefile" ;; + "Cantera/src/zeroD/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/zeroD/Makefile" ;; + "Cantera/src/oneD/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/oneD/Makefile" ;; + "Cantera/src/converters/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/converters/Makefile" ;; + "Cantera/src/transport/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/transport/Makefile" ;; + "Cantera/src/thermo/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/thermo/Makefile" ;; + "Cantera/src/kinetics/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/kinetics/Makefile" ;; + "Cantera/src/numerics/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/numerics/Makefile" ;; + "Cantera/src/spectra/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/spectra/Makefile" ;; + "Cantera/src/equil/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/src/equil/Makefile" ;; + "Cantera/clib/src/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/clib/src/Makefile" ;; + "Cantera/fortran/src/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/fortran/src/Makefile" ;; + "Cantera/fortran/f77demos/f77demos.mak") CONFIG_FILES="$CONFIG_FILES Cantera/fortran/f77demos/f77demos.mak" ;; + "Cantera/fortran/f77demos/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/fortran/f77demos/Makefile" ;; + "Cantera/matlab/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/matlab/Makefile" ;; + "Cantera/matlab/setup_matlab.py") CONFIG_FILES="$CONFIG_FILES Cantera/matlab/setup_matlab.py" ;; + "Cantera/python/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/Makefile" ;; + "Cantera/python/setup.py") CONFIG_FILES="$CONFIG_FILES Cantera/python/setup.py" ;; + "Cantera/cxx/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/Makefile" ;; + "Cantera/cxx/src/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/src/Makefile" ;; + "Cantera/cxx/demos/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/Makefile" ;; + "Cantera/cxx/demos/combustor/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/combustor/Makefile" ;; + "Cantera/cxx/demos/combustor/Makefile.install") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/combustor/Makefile.install" ;; + "Cantera/cxx/demos/flamespeed/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/flamespeed/Makefile" ;; + "Cantera/cxx/demos/flamespeed/Makefile.install") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/flamespeed/Makefile.install" ;; + "Cantera/cxx/demos/kinetics1/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/kinetics1/Makefile" ;; + "Cantera/cxx/demos/kinetics1/Makefile.install") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/kinetics1/Makefile.install" ;; + "Cantera/cxx/demos/NASA_coeffs/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/NASA_coeffs/Makefile" ;; + "Cantera/cxx/demos/NASA_coeffs/Makefile.install") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/NASA_coeffs/Makefile.install" ;; + "Cantera/cxx/demos/rankine/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/rankine/Makefile" ;; + "Cantera/cxx/demos/rankine/Makefile.install") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/demos/rankine/Makefile.install" ;; + "Cantera/cxx/include/Cantera.mak") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/include/Cantera.mak" ;; + "Cantera/cxx/include/Cantera_bt.mak") CONFIG_FILES="$CONFIG_FILES Cantera/cxx/include/Cantera_bt.mak" ;; + "Cantera/user/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/user/Makefile" ;; + "Cantera/python/src/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/src/Makefile" ;; + "Cantera/python/examples/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/Makefile" ;; + "Cantera/python/examples/equilibrium/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/Makefile" ;; + "Cantera/python/examples/equilibrium/adiabatic_flame/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/adiabatic_flame/Makefile" ;; + "Cantera/python/examples/equilibrium/multiphase_plasma/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/multiphase_plasma/Makefile" ;; + "Cantera/python/examples/equilibrium/simple_test/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/simple_test/Makefile" ;; + "Cantera/python/examples/equilibrium/stoich_flame/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/equilibrium/stoich_flame/Makefile" ;; + "Cantera/python/examples/gasdynamics/isentropic/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/gasdynamics/isentropic/Makefile" ;; + "Cantera/python/examples/gasdynamics/soundSpeed/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/gasdynamics/soundSpeed/Makefile" ;; + "Cantera/python/examples/flames/adiabatic_flame/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/adiabatic_flame/Makefile" ;; + "Cantera/python/examples/flames/flame1/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/flame1/Makefile" ;; + "Cantera/python/examples/flames/flame2/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/flame2/Makefile" ;; + "Cantera/python/examples/flames/flame_fixed_T/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/flame_fixed_T/Makefile" ;; + "Cantera/python/examples/flames/free_h2_air/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/free_h2_air/Makefile" ;; + "Cantera/python/examples/flames/npflame1/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/npflame1/Makefile" ;; + "Cantera/python/examples/flames/stflame1/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/stflame1/Makefile" ;; + "Cantera/python/examples/fuel_cells/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/fuel_cells/Makefile" ;; + "Cantera/python/examples/liquid_vapor/critProperties/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/liquid_vapor/critProperties/Makefile" ;; + "Cantera/python/examples/liquid_vapor/rankine/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/liquid_vapor/rankine/Makefile" ;; + "Cantera/python/examples/kinetics/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/kinetics/Makefile" ;; + "Cantera/python/examples/misc/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/misc/Makefile" ;; + "Cantera/python/examples/reactors/combustor_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/combustor_sim/Makefile" ;; + "Cantera/python/examples/reactors/functors_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/functors_sim/Makefile" ;; + "Cantera/python/examples/reactors/mix1_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/mix1_sim/Makefile" ;; + "Cantera/python/examples/reactors/mix2_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/mix2_sim/Makefile" ;; + "Cantera/python/examples/reactors/piston_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/piston_sim/Makefile" ;; + "Cantera/python/examples/reactors/reactor1_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/reactor1_sim/Makefile" ;; + "Cantera/python/examples/reactors/reactor2_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/reactor2_sim/Makefile" ;; + "Cantera/python/examples/reactors/sensitivity_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/sensitivity_sim/Makefile" ;; + "Cantera/python/examples/reactors/surf_pfr_sim/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/surf_pfr_sim/Makefile" ;; + "Cantera/python/examples/surface_chemistry/diamond_cvd/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/surface_chemistry/diamond_cvd/Makefile" ;; + "Cantera/python/examples/surface_chemistry/catcomb_stagflow/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/surface_chemistry/catcomb_stagflow/Makefile" ;; + "Cantera/python/examples/transport/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/transport/Makefile" ;; + "Cantera/python/examples/flames/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/flames/Makefile" ;; + "Cantera/python/examples/gasdynamics/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/gasdynamics/Makefile" ;; + "Cantera/python/examples/liquid_vapor/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/liquid_vapor/Makefile" ;; + "Cantera/python/examples/reactors/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/reactors/Makefile" ;; + "Cantera/python/examples/surface_chemistry/Makefile") CONFIG_FILES="$CONFIG_FILES Cantera/python/examples/surface_chemistry/Makefile" ;; + "ext/lapack/Makefile") CONFIG_FILES="$CONFIG_FILES ext/lapack/Makefile" ;; + "ext/blas/Makefile") CONFIG_FILES="$CONFIG_FILES ext/blas/Makefile" ;; + "ext/cvode/Makefile") CONFIG_FILES="$CONFIG_FILES ext/cvode/Makefile" ;; + "ext/math/Makefile") CONFIG_FILES="$CONFIG_FILES ext/math/Makefile" ;; + "ext/recipes/Makefile") CONFIG_FILES="$CONFIG_FILES ext/recipes/Makefile" ;; + "ext/tpx/Makefile") CONFIG_FILES="$CONFIG_FILES ext/tpx/Makefile" ;; + "ext/Makefile") CONFIG_FILES="$CONFIG_FILES ext/Makefile" ;; + "ext/f2c_libs/Makefile") CONFIG_FILES="$CONFIG_FILES ext/f2c_libs/Makefile" ;; + "ext/f2c_blas/Makefile") CONFIG_FILES="$CONFIG_FILES ext/f2c_blas/Makefile" ;; + "ext/f2c_lapack/Makefile") CONFIG_FILES="$CONFIG_FILES ext/f2c_lapack/Makefile" ;; + "ext/f2c_math/Makefile") CONFIG_FILES="$CONFIG_FILES ext/f2c_math/Makefile" ;; + "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; + "examples/cxx/Makefile") CONFIG_FILES="$CONFIG_FILES examples/cxx/Makefile" ;; + "docs/Makefile") CONFIG_FILES="$CONFIG_FILES docs/Makefile" ;; + "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; + "docs/Cantera.cfg") CONFIG_FILES="$CONFIG_FILES docs/Cantera.cfg" ;; + "tools/src/Makefile") CONFIG_FILES="$CONFIG_FILES tools/src/Makefile" ;; + "tools/src/sample.mak") CONFIG_FILES="$CONFIG_FILES tools/src/sample.mak" ;; + "tools/src/finish_install.py") CONFIG_FILES="$CONFIG_FILES tools/src/finish_install.py" ;; + "tools/src/package4mac") CONFIG_FILES="$CONFIG_FILES tools/src/package4mac" ;; + "tools/templates/f77/demo.mak") CONFIG_FILES="$CONFIG_FILES tools/templates/f77/demo.mak" ;; + "tools/templates/f90/demo.mak") CONFIG_FILES="$CONFIG_FILES tools/templates/f90/demo.mak" ;; + "tools/templates/cxx/demo.mak") CONFIG_FILES="$CONFIG_FILES tools/templates/cxx/demo.mak" ;; + "tools/testtools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/testtools/Makefile" ;; + "data/inputs/Makefile") CONFIG_FILES="$CONFIG_FILES data/inputs/Makefile" ;; + "data/inputs/mkxml") CONFIG_FILES="$CONFIG_FILES data/inputs/mkxml" ;; + "test_problems/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/Makefile" ;; + "test_problems/cxx_ex/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cxx_ex/Makefile" ;; + "test_problems/silane_equil/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/silane_equil/Makefile" ;; + "test_problems/surfkin/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/surfkin/Makefile" ;; + "test_problems/spectroscopy/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/spectroscopy/Makefile" ;; + "test_problems/surfSolverTest/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/surfSolverTest/Makefile" ;; + "test_problems/diamondSurf/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/diamondSurf/Makefile" ;; + "test_problems/diamondSurf_dupl/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/diamondSurf_dupl/Makefile" ;; + "test_problems/ChemEquil_gri_matrix/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_gri_matrix/Makefile" ;; + "test_problems/ChemEquil_gri_pairs/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_gri_pairs/Makefile" ;; + "test_problems/ChemEquil_ionizedGas/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_ionizedGas/Makefile" ;; + "test_problems/ChemEquil_red1/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/ChemEquil_red1/Makefile" ;; + "test_problems/CpJump/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/CpJump/Makefile" ;; + "test_problems/mixGasTransport/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/mixGasTransport/Makefile" ;; + "test_problems/multiGasTransport/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/multiGasTransport/Makefile" ;; + "test_problems/printUtilUnitTest/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/printUtilUnitTest/Makefile" ;; + "test_problems/fracCoeff/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/fracCoeff/Makefile" ;; + "test_problems/negATest/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/negATest/Makefile" ;; + "test_problems/NASA9poly_test/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/NASA9poly_test/Makefile" ;; + "test_problems/ck2cti_test/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/ck2cti_test/Makefile" ;; + "test_problems/ck2cti_test/runtest") CONFIG_FILES="$CONFIG_FILES test_problems/ck2cti_test/runtest" ;; + "test_problems/nasa9_reader/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/nasa9_reader/Makefile" ;; + "test_problems/nasa9_reader/runtest") CONFIG_FILES="$CONFIG_FILES test_problems/nasa9_reader/runtest" ;; + "test_problems/min_python/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/min_python/Makefile" ;; + "test_problems/min_python/minDiamond/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/min_python/minDiamond/Makefile" ;; + "test_problems/min_python/negATest/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/min_python/negATest/Makefile" ;; + "test_problems/pureFluidTest/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/pureFluidTest/Makefile" ;; + "test_problems/rankine_democxx/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/rankine_democxx/Makefile" ;; + "test_problems/python/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/python/Makefile" ;; + "test_problems/cathermo/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/Makefile" ;; + "test_problems/cathermo/issp/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/issp/Makefile" ;; + "test_problems/cathermo/ims/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/ims/Makefile" ;; + "test_problems/cathermo/stoichSubSSTP/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/stoichSubSSTP/Makefile" ;; + "test_problems/cathermo/testIAPWS/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testIAPWS/Makefile" ;; + "test_problems/cathermo/testIAPWSPres/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testIAPWSPres/Makefile" ;; + "test_problems/cathermo/testIAPWSTripP/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testIAPWSTripP/Makefile" ;; + "test_problems/cathermo/testWaterPDSS/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testWaterPDSS/Makefile" ;; + "test_problems/cathermo/testWaterTP/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/testWaterTP/Makefile" ;; + "test_problems/cathermo/HMW_test_1/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_test_1/Makefile" ;; + "test_problems/cathermo/HMW_test_3/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_test_3/Makefile" ;; + "test_problems/cathermo/HMW_graph_GvT/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_GvT/Makefile" ;; + "test_problems/cathermo/HMW_graph_GvI/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_GvI/Makefile" ;; + "test_problems/cathermo/HMW_graph_HvT/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_HvT/Makefile" ;; + "test_problems/cathermo/HMW_graph_CpvT/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_CpvT/Makefile" ;; + "test_problems/cathermo/HMW_graph_VvT/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_graph_VvT/Makefile" ;; + "test_problems/cathermo/DH_graph_1/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_1/Makefile" ;; + "test_problems/cathermo/DH_graph_acommon/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_acommon/Makefile" ;; + "test_problems/cathermo/DH_graph_NM/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_NM/Makefile" ;; + "test_problems/cathermo/DH_graph_Pitzer/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_Pitzer/Makefile" ;; + "test_problems/cathermo/DH_graph_bdotak/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/DH_graph_bdotak/Makefile" ;; + "test_problems/cathermo/HMW_dupl_test/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/HMW_dupl_test/Makefile" ;; + "test_problems/cathermo/VPissp/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/VPissp/Makefile" ;; + "test_problems/cathermo/wtWater/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/cathermo/wtWater/Makefile" ;; + "test_problems/VCSnonideal/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/VCSnonideal/Makefile" ;; + "test_problems/VPsilane_test/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/VPsilane_test/Makefile" ;; + "test_problems/VPsilane_test/runtest") CONFIG_FILES="$CONFIG_FILES test_problems/VPsilane_test/runtest" ;; + "test_problems/VCSnonideal/NaCl_equil/Makefile") CONFIG_FILES="$CONFIG_FILES test_problems/VCSnonideal/NaCl_equil/Makefile" ;; + "bin/install_tsc") CONFIG_FILES="$CONFIG_FILES bin/install_tsc" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done + # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely @@ -11489,698 +7711,550 @@ if $ac_need_defaults; then fi # Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason to put it here, and in addition, +# simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. -# Create a temporary directory, and hook for its removal unless debugging. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. $debug || { - trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 - trap '{ (exit 1); exit 1; }' 1 2 13 15 + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 } - # Create a (secure) tmp directory for tmp files. { - tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" } || { - tmp=./confstat$$-$RANDOM - (umask 077 && mkdir $tmp) -} || + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + { - echo "$me: cannot create a temporary directory in ." >&2 - { (exit 1); exit 1; } + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi -# -# CONFIG_FILES section. -# - -# No need to generate the scripts if there are no CONFIG_FILES. -# This happens for instance when ./config.status config.h -if test -n "\$CONFIG_FILES"; then - # Protect against being on the right side of a sed subst in config.status. - sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; - s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF -s,@SHELL@,$SHELL,;t t -s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t -s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t -s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t -s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t -s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t -s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t -s,@exec_prefix@,$exec_prefix,;t t -s,@prefix@,$prefix,;t t -s,@program_transform_name@,$program_transform_name,;t t -s,@bindir@,$bindir,;t t -s,@sbindir@,$sbindir,;t t -s,@libexecdir@,$libexecdir,;t t -s,@datadir@,$datadir,;t t -s,@sysconfdir@,$sysconfdir,;t t -s,@sharedstatedir@,$sharedstatedir,;t t -s,@localstatedir@,$localstatedir,;t t -s,@libdir@,$libdir,;t t -s,@includedir@,$includedir,;t t -s,@oldincludedir@,$oldincludedir,;t t -s,@infodir@,$infodir,;t t -s,@mandir@,$mandir,;t t -s,@build_alias@,$build_alias,;t t -s,@host_alias@,$host_alias,;t t -s,@target_alias@,$target_alias,;t t -s,@DEFS@,$DEFS,;t t -s,@ECHO_C@,$ECHO_C,;t t -s,@ECHO_N@,$ECHO_N,;t t -s,@ECHO_T@,$ECHO_T,;t t -s,@LIBS@,$LIBS,;t t -s,@BITCOMPILE@,$BITCOMPILE,;t t -s,@BITHARDWARE@,$BITHARDWARE,;t t -s,@BITCHANGE@,$BITCHANGE,;t t -s,@ldemulationarg@,$ldemulationarg,;t t -s,@CVF_LIBDIR@,$CVF_LIBDIR,;t t -s,@USE_CLIB_DLL@,$USE_CLIB_DLL,;t t -s,@local_inst@,$local_inst,;t t -s,@local_python_inst@,$local_python_inst,;t t -s,@python_prefix@,$python_prefix,;t t -s,@python_win_prefix@,$python_win_prefix,;t t -s,@ctversion@,$ctversion,;t t -s,@homedir@,$homedir,;t t -s,@ct_libdir@,$ct_libdir,;t t -s,@ct_bindir@,$ct_bindir,;t t -s,@ct_incdir@,$ct_incdir,;t t -s,@ct_incroot@,$ct_incroot,;t t -s,@ct_datadir@,$ct_datadir,;t t -s,@ct_demodir@,$ct_demodir,;t t -s,@ct_templdir@,$ct_templdir,;t t -s,@ct_tutdir@,$ct_tutdir,;t t -s,@ct_docdir@,$ct_docdir,;t t -s,@ct_dir@,$ct_dir,;t t -s,@ct_mandir@,$ct_mandir,;t t -s,@build@,$build,;t t -s,@build_cpu@,$build_cpu,;t t -s,@build_vendor@,$build_vendor,;t t -s,@build_os@,$build_os,;t t -s,@host@,$host,;t t -s,@host_cpu@,$host_cpu,;t t -s,@host_vendor@,$host_vendor,;t t -s,@host_os@,$host_os,;t t -s,@target@,$target,;t t -s,@target_cpu@,$target_cpu,;t t -s,@target_vendor@,$target_vendor,;t t -s,@target_os@,$target_os,;t t -s,@username@,$username,;t t -s,@ctroot@,$ctroot,;t t -s,@buildinc@,$buildinc,;t t -s,@buildlib@,$buildlib,;t t -s,@buildbin@,$buildbin,;t t -s,@MAKE@,$MAKE,;t t -s,@GRAPHVIZDIR@,$GRAPHVIZDIR,;t t -s,@ARCHIVE@,$ARCHIVE,;t t -s,@DO_RANLIB@,$DO_RANLIB,;t t -s,@RANLIB@,$RANLIB,;t t -s,@CXX_DEPENDS@,$CXX_DEPENDS,;t t -s,@USERDIR@,$USERDIR,;t t -s,@INCL_USER_CODE@,$INCL_USER_CODE,;t t -s,@CXX@,$CXX,;t t -s,@CXXFLAGS@,$CXXFLAGS,;t t -s,@LDFLAGS@,$LDFLAGS,;t t -s,@CPPFLAGS@,$CPPFLAGS,;t t -s,@ac_ct_CXX@,$ac_ct_CXX,;t t -s,@EXEEXT@,$EXEEXT,;t t -s,@OBJEXT@,$OBJEXT,;t t -s,@use_sundials@,$use_sundials,;t t -s,@CVODE_LIBS@,$CVODE_LIBS,;t t -s,@IDA_LIBS@,$IDA_LIBS,;t t -s,@sundials_include@,$sundials_include,;t t -s,@sundials_lib_dir@,$sundials_lib_dir,;t t -s,@sundials_lib@,$sundials_lib,;t t -s,@sundials_lib_dep@,$sundials_lib_dep,;t t -s,@CANTERA_DEBUG_MODE@,$CANTERA_DEBUG_MODE,;t t -s,@COMPILE_PURE_FLUIDS@,$COMPILE_PURE_FLUIDS,;t t -s,@phase_object_files@,$phase_object_files,;t t -s,@phase_header_files@,$phase_header_files,;t t -s,@COMPILE_IDEAL_SOLUTIONS@,$COMPILE_IDEAL_SOLUTIONS,;t t -s,@COMPILE_ELECTROLYTES@,$COMPILE_ELECTROLYTES,;t t -s,@NEED_CATHERMO@,$NEED_CATHERMO,;t t -s,@COMPILE_KINETICS@,$COMPILE_KINETICS,;t t -s,@COMPILE_HETEROKIN@,$COMPILE_HETEROKIN,;t t -s,@COMPILE_RXNPATH@,$COMPILE_RXNPATH,;t t -s,@WITH_REACTORS@,$WITH_REACTORS,;t t -s,@KERNEL@,$KERNEL,;t t -s,@KERNEL_OBJ@,$KERNEL_OBJ,;t t -s,@BUILD_CK@,$BUILD_CK,;t t -s,@LIB_DIR@,$LIB_DIR,;t t -s,@COMPILE_VCSNONIDEAL@,$COMPILE_VCSNONIDEAL,;t t -s,@COMPILE_H298MODIFY_CAPABILITY@,$COMPILE_H298MODIFY_CAPABILITY,;t t -s,@BOOST_INCLUDE@,$BOOST_INCLUDE,;t t -s,@BOOST_LIB@,$BOOST_LIB,;t t -s,@PURIFY@,$PURIFY,;t t -s,@build_lapack@,$build_lapack,;t t -s,@build_blas@,$build_blas,;t t -s,@BLAS_LAPACK_LIBS@,$BLAS_LAPACK_LIBS,;t t -s,@BLAS_LAPACK_LINK@,$BLAS_LAPACK_LINK,;t t -s,@BLAS_LAPACK_DIR@,$BLAS_LAPACK_DIR,;t t -s,@build_with_f2c@,$build_with_f2c,;t t -s,@build_f2c_lib@,$build_f2c_lib,;t t -s,@F2C_SYSTEMLIB@,$F2C_SYSTEMLIB,;t t -s,@BOOST_LIB_DIR@,$BOOST_LIB_DIR,;t t -s,@LOCAL_LIB_DIRS@,$LOCAL_LIB_DIRS,;t t -s,@LOCAL_LIBS@,$LOCAL_LIBS,;t t -s,@LOCAL_LIBS_DEP@,$LOCAL_LIBS_DEP,;t t -s,@INSTALL_LIBS_DEP@,$INSTALL_LIBS_DEP,;t t -s,@RAW_LIBS_DEP@,$RAW_LIBS_DEP,;t t -s,@CANTERA_CORE_LIBS@,$CANTERA_CORE_LIBS,;t t -s,@CANTERA_CORE_LIBS_DEP@,$CANTERA_CORE_LIBS_DEP,;t t -s,@CT_SHARED_LIB@,$CT_SHARED_LIB,;t t -s,@PYTHON_CMD@,$PYTHON_CMD,;t t -s,@BUILD_PYTHON@,$BUILD_PYTHON,;t t -s,@NUMPY_INC_DIR@,$NUMPY_INC_DIR,;t t -s,@NUMPY_HOME@,$NUMPY_HOME,;t t -s,@NUMARRAY_INC_DIR@,$NUMARRAY_INC_DIR,;t t -s,@NUMARRAY_HOME@,$NUMARRAY_HOME,;t t -s,@CANTERA_PYTHON_HOME@,$CANTERA_PYTHON_HOME,;t t -s,@CVSTAG@,$CVSTAG,;t t -s,@MATLAB_CMD@,$MATLAB_CMD,;t t -s,@BUILD_MATLAB@,$BUILD_MATLAB,;t t -s,@BUILD_CLIB@,$BUILD_CLIB,;t t -s,@export_name@,$export_name,;t t -s,@PIC@,$PIC,;t t -s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t -s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t -s,@INSTALL_DATA@,$INSTALL_DATA,;t t -s,@CC@,$CC,;t t -s,@CFLAGS@,$CFLAGS,;t t -s,@ac_ct_CC@,$ac_ct_CC,;t t -s,@CXXCPP@,$CXXCPP,;t t -s,@EGREP@,$EGREP,;t t -s,@SOEXT@,$SOEXT,;t t -s,@SHARED@,$SHARED,;t t -s,@CXX_INCLUDES@,$CXX_INCLUDES,;t t -s,@LCXX_FLAGS@,$LCXX_FLAGS,;t t -s,@LCXX_END_LIBS@,$LCXX_END_LIBS,;t t -s,@HAVE_STRIPSYMBOLS@,$HAVE_STRIPSYMBOLS,;t t -s,@F77@,$F77,;t t -s,@FFLAGS@,$FFLAGS,;t t -s,@ac_ct_F77@,$ac_ct_F77,;t t -s,@FLIBS@,$FLIBS,;t t -s,@F90@,$F90,;t t -s,@BUILD_F90@,$BUILD_F90,;t t -s,@F90FLAGS@,$F90FLAGS,;t t -s,@F90BUILDFLAGS@,$F90BUILDFLAGS,;t t -s,@F90LIBS@,$F90LIBS,;t t -s,@LCXX_FLIBS@,$LCXX_FLIBS,;t t -s,@precompile_headers@,$precompile_headers,;t t -s,@OS_IS_DARWIN@,$OS_IS_DARWIN,;t t -s,@OS_IS_WIN@,$OS_IS_WIN,;t t -s,@OS_IS_CYGWIN@,$OS_IS_CYGWIN,;t t -s,@SHARED_CTLIB@,$SHARED_CTLIB,;t t -s,@mex_ext@,$mex_ext,;t t -s,@F77_EXT@,$F77_EXT,;t t -s,@CXX_EXT@,$CXX_EXT,;t t -s,@OBJ_EXT@,$OBJ_EXT,;t t -s,@EXE_EXT@,$EXE_EXT,;t t -s,@math_libs@,$math_libs,;t t -s,@SO@,$SO,;t t -s,@LDSHARED@,$LDSHARED,;t t -s,@EXTRA_LINK@,$EXTRA_LINK,;t t -s,@TSCOMPARE_abs@,$TSCOMPARE_abs,;t t -s,@INSTALL_abs@,$INSTALL_abs,;t t -s,@INSTALL_VERBOSE@,$INSTALL_VERBOSE,;t t -s,@LIBOBJS@,$LIBOBJS,;t t -s,@LTLIBOBJS@,$LTLIBOBJS,;t t -CEOF - -_ACEOF - - cat >>$CONFIG_STATUS <<\_ACEOF - # Split the substitutions into bite-sized pieces for seds with - # small command number limits, like on Digital OSF/1 and HP-UX. - ac_max_sed_lines=48 - ac_sed_frag=1 # Number of current file. - ac_beg=1 # First line for current file. - ac_end=$ac_max_sed_lines # Line after last line for current file. - ac_more_lines=: - ac_sed_cmds= - while $ac_more_lines; do - if test $ac_beg -gt 1; then - sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag - else - sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag - fi - if test ! -s $tmp/subs.frag; then - ac_more_lines=false - else - # The purpose of the label and of the branching condition is to - # speed up the sed processing (if there are no `@' at all, there - # is no need to browse any of the substitutions). - # These are the two extra sed commands mentioned above. - (echo ':t - /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed - if test -z "$ac_sed_cmds"; then - ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" - else - ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" - fi - ac_sed_frag=`expr $ac_sed_frag + 1` - ac_beg=$ac_end - ac_end=`expr $ac_end + $ac_max_sed_lines` - fi - done - if test -z "$ac_sed_cmds"; then - ac_sed_cmds=cat - fi +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". - case $ac_file in - - | *:- | *:-:* ) # input from stdin - cat >$tmp/stdin - ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` - ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; - *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` - ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; - * ) ac_file_in=$ac_file.in ;; + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; esac - # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. - ac_dir=`(dirname "$ac_file") 2>/dev/null || + ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || -echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } - /^X\(\/\/\)[^/].*/{ s//\1/; q; } - /^X\(\/\/\)$/{ s//\1/; q; } - /^X\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` - { if $as_mkdir_p; then - mkdir -p "$ac_dir" - else - as_dir="$ac_dir" - as_dirs= - while test ! -d "$as_dir"; do - as_dirs="$as_dir $as_dirs" - as_dir=`(dirname "$as_dir") 2>/dev/null || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || -echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } - /^X\(\/\/\)[^/].*/{ s//\1/; q; } - /^X\(\/\/\)$/{ s//\1/; q; } - /^X\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` - done - test ! -n "$as_dirs" || mkdir $as_dirs - fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 -echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} - { (exit 1); exit 1; }; }; } - + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. -if test "$ac_dir" != .; then - ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` - # A "../" for each directory in $ac_dir_suffix. - ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` -else - ac_dir_suffix= ac_top_builddir= -fi +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix case $srcdir in - .) # No --srcdir option. We are building in place. + .) # We are building in place. ac_srcdir=. - if test -z "$ac_top_builddir"; then - ac_top_srcdir=. - else - ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` - fi ;; - [\\/]* | ?:[\\/]* ) # Absolute path. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir ;; - *) # Relative path. - ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_builddir$srcdir ;; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix -# Do not use `cd foo && pwd` to compute absolute paths, because -# the directories may not exist. -case `pwd` in -.) ac_abs_builddir="$ac_dir";; -*) - case "$ac_dir" in - .) ac_abs_builddir=`pwd`;; - [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; - *) ac_abs_builddir=`pwd`/"$ac_dir";; - esac;; -esac -case $ac_abs_builddir in -.) ac_abs_top_builddir=${ac_top_builddir}.;; -*) - case ${ac_top_builddir}. in - .) ac_abs_top_builddir=$ac_abs_builddir;; - [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; - *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; - esac;; -esac -case $ac_abs_builddir in -.) ac_abs_srcdir=$ac_srcdir;; -*) - case $ac_srcdir in - .) ac_abs_srcdir=$ac_abs_builddir;; - [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; - *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; - esac;; -esac -case $ac_abs_builddir in -.) ac_abs_top_srcdir=$ac_top_srcdir;; -*) - case $ac_top_srcdir in - .) ac_abs_top_srcdir=$ac_abs_builddir;; - [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; - *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; - esac;; -esac + case $ac_mode in + :F) + # + # CONFIG_FILE + # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac - - if test x"$ac_file" != x-; then - { echo "$as_me:$LINENO: creating $ac_file" >&5 -echo "$as_me: creating $ac_file" >&6;} - rm -f "$ac_file" - fi - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - if test x"$ac_file" = x-; then - configure_input= - else - configure_input="$ac_file. " - fi - configure_input=$configure_input"Generated from `echo $ac_file_in | - sed 's,.*/,,'` by configure." - - # First look for the input files in the build tree, otherwise in the - # src tree. - ac_file_inputs=`IFS=: - for f in $ac_file_in; do - case $f in - -) echo $tmp/stdin ;; - [\\/$]*) - # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 -echo "$as_me: error: cannot find input file: $f" >&2;} - { (exit 1); exit 1; }; } - echo "$f";; - *) # Relative - if test -f "$f"; then - # Build tree - echo "$f" - elif test -f "$srcdir/$f"; then - # Source tree - echo "$srcdir/$f" - else - # /dev/null tree - { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 -echo "$as_me: error: cannot find input file: $f" >&2;} - { (exit 1); exit 1; }; } - fi;; - esac - done` || { (exit 1); exit 1; } _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF - sed "$ac_vpsub + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub $extrasub _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s,@configure_input@,$configure_input,;t t -s,@srcdir@,$ac_srcdir,;t t -s,@abs_srcdir@,$ac_abs_srcdir,;t t -s,@top_srcdir@,$ac_top_srcdir,;t t -s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t -s,@builddir@,$ac_builddir,;t t -s,@abs_builddir@,$ac_abs_builddir,;t t -s,@top_builddir@,$ac_top_builddir,;t t -s,@abs_top_builddir@,$ac_abs_top_builddir,;t t -s,@INSTALL@,$ac_INSTALL,;t t -" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out - rm -f $tmp/stdin - if test x"$ac_file" != x-; then - mv $tmp/out $ac_file - else - cat $tmp/out - rm -f $tmp/out - fi +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 -done -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} -# -# CONFIG_HEADER section. -# - -# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where -# NAME is the cpp macro being defined and VALUE is the value it is being given. -# -# ac_d sets the value in "#define NAME VALUE" lines. -ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' -ac_dB='[ ].*$,\1#\2' -ac_dC=' ' -ac_dD=',;t' -# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". -ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_uB='$,\1#\2define\3' -ac_uC=' ' -ac_uD=',;t' - -for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue - # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + rm -f "$ac_tmp/stdin" case $ac_file in - - | *:- | *:-:* ) # input from stdin - cat >$tmp/stdin - ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` - ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; - *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` - ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; - * ) ac_file_in=$ac_file.in ;; - esac - - test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 -echo "$as_me: creating $ac_file" >&6;} - - # First look for the input files in the build tree, otherwise in the - # src tree. - ac_file_inputs=`IFS=: - for f in $ac_file_in; do - case $f in - -) echo $tmp/stdin ;; - [\\/$]*) - # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 -echo "$as_me: error: cannot find input file: $f" >&2;} - { (exit 1); exit 1; }; } - # Do quote $f, to prevent DOS paths from being IFS'd. - echo "$f";; - *) # Relative - if test -f "$f"; then - # Build tree - echo "$f" - elif test -f "$srcdir/$f"; then - # Source tree - echo "$srcdir/$f" - else - # /dev/null tree - { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 -echo "$as_me: error: cannot find input file: $f" >&2;} - { (exit 1); exit 1; }; } - fi;; - esac - done` || { (exit 1); exit 1; } - # Remove the trailing spaces. - sed 's/[ ]*$//' $ac_file_inputs >$tmp/in - -_ACEOF - -# Transform confdefs.h into two sed scripts, `conftest.defines' and -# `conftest.undefs', that substitutes the proper values into -# config.h.in to produce config.h. The first handles `#define' -# templates, and the second `#undef' templates. -# And first: Protect against being on the right side of a sed subst in -# config.status. Protect against being in an unquoted here document -# in config.status. -rm -f conftest.defines conftest.undefs -# Using a here document instead of a string reduces the quoting nightmare. -# Putting comments in sed scripts is not portable. -# -# `end' is used to avoid that the second main sed command (meant for -# 0-ary CPP macros) applies to n-ary macro definitions. -# See the Autoconf documentation for `clear'. -cat >confdef2sed.sed <<\_ACEOF -s/[\\&,]/\\&/g -s,[\\$`],\\&,g -t clear -: clear -s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp -t end -s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp -: end -_ACEOF -# If some macros were called several times there might be several times -# the same #defines, which is useless. Nevertheless, we may not want to -# sort them, since we want the *last* AC-DEFINE to be honored. -uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines -sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs -rm -f confdef2sed.sed - -# This sed command replaces #undef with comments. This is necessary, for -# example, in the case of _POSIX_SOURCE, which is predefined and required -# on some systems where configure will not decide to define it. -cat >>conftest.undefs <<\_ACEOF -s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, -_ACEOF - -# Break up conftest.defines because some shells have a limit on the size -# of here documents, and old seds have small limits too (100 cmds). -echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS -echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS -echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS -echo ' :' >>$CONFIG_STATUS -rm -f conftest.tail -while grep . conftest.defines >/dev/null -do - # Write a limited-size here document to $tmp/defines.sed. - echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS - # Speed up: don't consider the non `#define' lines. - echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS - # Work around the forget-to-reset-the-flag bug. - echo 't clr' >>$CONFIG_STATUS - echo ': clr' >>$CONFIG_STATUS - sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS - echo 'CEOF - sed -f $tmp/defines.sed $tmp/in >$tmp/out - rm -f $tmp/in - mv $tmp/out $tmp/in -' >>$CONFIG_STATUS - sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail - rm -f conftest.defines - mv conftest.tail conftest.defines -done -rm -f conftest.defines -echo ' fi # grep' >>$CONFIG_STATUS -echo >>$CONFIG_STATUS - -# Break up conftest.undefs because some shells have a limit on the size -# of here documents, and old seds have small limits too (100 cmds). -echo ' # Handle all the #undef templates' >>$CONFIG_STATUS -rm -f conftest.tail -while grep . conftest.undefs >/dev/null -do - # Write a limited-size here document to $tmp/undefs.sed. - echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS - # Speed up: don't consider the non `#undef' - echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS - # Work around the forget-to-reset-the-flag bug. - echo 't clr' >>$CONFIG_STATUS - echo ': clr' >>$CONFIG_STATUS - sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS - echo 'CEOF - sed -f $tmp/undefs.sed $tmp/in >$tmp/out - rm -f $tmp/in - mv $tmp/out $tmp/in -' >>$CONFIG_STATUS - sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail - rm -f conftest.undefs - mv conftest.tail conftest.undefs -done -rm -f conftest.undefs - -cat >>$CONFIG_STATUS <<\_ACEOF - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - if test x"$ac_file" = x-; then - echo "/* Generated by configure. */" >$tmp/config.h - else - echo "/* $ac_file. Generated by configure. */" >$tmp/config.h - fi - cat $tmp/in >>$tmp/config.h - rm -f $tmp/in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # if test x"$ac_file" != x-; then - if diff $ac_file $tmp/config.h >/dev/null 2>&1; then - { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 -echo "$as_me: $ac_file is unchanged" >&6;} + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} else - ac_dir=`(dirname "$ac_file") 2>/dev/null || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || -echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } - /^X\(\/\/\)[^/].*/{ s//\1/; q; } - /^X\(\/\/\)$/{ s//\1/; q; } - /^X\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` - { if $as_mkdir_p; then - mkdir -p "$ac_dir" - else - as_dir="$ac_dir" - as_dirs= - while test ! -d "$as_dir"; do - as_dirs="$as_dir $as_dirs" - as_dir=`(dirname "$as_dir") 2>/dev/null || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || -echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } - /^X\(\/\/\)[^/].*/{ s//\1/; q; } - /^X\(\/\/\)$/{ s//\1/; q; } - /^X\(\/\).*/{ s//\1/; q; } - s/.*/./; q'` - done - test ! -n "$as_dirs" || mkdir $as_dirs - fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 -echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} - { (exit 1); exit 1; }; }; } - - rm -f $ac_file - mv $tmp/config.h $ac_file + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else - cat $tmp/config.h - rm -f $tmp/config.h + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 fi -done -_ACEOF + ;; -cat >>$CONFIG_STATUS <<\_ACEOF -{ (exit 0); exit 0; } + esac + +done # for ac_tag + + +as_fn_exit 0 _ACEOF -chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. @@ -12200,7 +8274,11 @@ if test "$no_create" != yes; then exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || { (exit 1); exit 1; } + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # ) diff --git a/configure.in b/configure.in index 8631f8b89..6cc3fc616 100755 --- a/configure.in +++ b/configure.in @@ -2,6 +2,7 @@ dnl Process this file with autoconf to produce a configure script. define([AC_CACHE_LOAD], )dnl define([AC_CACHE_SAVE], )dnl AC_INIT(Cantera,1.7.0) + AC_CONFIG_HEADER(config.h) # AC_CONFIG_AUX_DIR(.) # AC_CONFIG_SRCDIR(./License.txt) @@ -79,6 +80,50 @@ fi AC_SUBST(BITCOMPILE) AC_SUBST(BITHARDWARE) AC_SUBST(BITCHANGE) +# +#----------------------------------------------------------------------- +# C++ and C Compilation - INITIAL SECTION +#----------------------------------------------------------------------- +# +# CFLAGS: flags that get attached to the C compiler +# statement. AFLAGS are base flags that +# get added to compilers and loaders. +# FFLAGS: flags that get attached to the Fortran compiler +# statement. AFLAGS are base flags that +# get added to compilers and loaders. +# +# CXXFLAGS: Flags that get attached to the CXX compiler +# statement. AFLAGS are base flags that +# get added to compilers and loaders. +# +if test -z "$AFLAGS" ; then + AFLAGS=" " +fi +if test -z "$CXXFLAGS" ; then + CXXFLAGS="$AFLAGS" +else + CXXFLAGS="$CXXFLAGS"" ""$AFLAGS" +fi +if test -z "$CFLAGS" ; then + CFLAGS="$AFLAGS" +else + CFLAGS="$CFLAGS"" ""$AFLAGS" +fi +if test -z "$FFLAGS" ; then + FFLAGS="$AFLAGS" +else + FFLAGS="$FFLAGS"" ""$AFLAGS" +fi +export CXXFLAGS +export AFLAGS +export CFLAGS +export FFLAGS +# +# Note these should not be within if blocks +# +AC_PROG_CXX() +AC_PROG_CC() + SHARED_CTLIB=0 @@ -306,12 +351,15 @@ AC_SUBST(CXX_DEPENDS) #---------------------------------------- -######################################################## +######################################################### # User Code ######################################################### USERDIR="" INCL_USER_CODE=0 -if test -n "$USER_SRC_DIR"; then USERDIR=$USER_SRC_DIR; INCL_USER_CODE=1; fi +if test -n "$USER_SRC_DIR"; then + USERDIR=$USER_SRC_DIR + INCL_USER_CODE=1 +fi AC_SUBST(USERDIR) AC_SUBST(INCL_USER_CODE) @@ -323,11 +371,11 @@ CVODE_LIBS='-lcvode' IDA_LIBS='' if test "x$SUNDIALS_HOME" = "x"; then -SUNDIALS_LIB_DIR=/usr/local/lib -SUNDIALS_INC_DIR=/usr/local/include + SUNDIALS_LIB_DIR=/usr/local/lib + SUNDIALS_INC_DIR=/usr/local/include else -SUNDIALS_LIB_DIR="$SUNDIALS_HOME/lib" -SUNDIALS_INC_DIR="$SUNDIALS_HOME/include" + SUNDIALS_LIB_DIR="$SUNDIALS_HOME/lib" + SUNDIALS_INC_DIR="$SUNDIALS_HOME/include" fi if test "$USE_SUNDIALS" = "default"; then @@ -336,8 +384,7 @@ if test "$USE_SUNDIALS" = "default"; then # SUNDIALS_LIB_DIR had a space in it, despite use of double quotes everywhere #ldsave="$LDFLAGS" #LDFLAGS='-L'"$SUNDIALS_LIB_DIR"' '"$ldsave" -AC_CHECK_LIB(sundials_cvodes, CVodeCreate, [use_sundials=1], [use_sundials=0],\ -[-lsundials_cvodes -lsundials_nvecserial -lm]) +AC_CHECK_LIB(sundials_cvodes, CVodeCreate, [use_sundials=1], [use_sundials=0], [-lsundials_cvodes -lsundials_nvecserial -lm] ) if test ${use_sundials} = 0 ; then tmpFile="$SUNDIALS_LIB_DIR/libsundials_cvodes.a" @@ -347,7 +394,7 @@ if test ${use_sundials} = 0 ; then fi if test ${use_sundials} = 1 ; then - echo SUNDIALS: succeeded in finding a sundials installation + echo "SUNDIALS: succeeded in finding a sundials installation" else echo SUNDIALS: failed at finding a sundials installation fi @@ -355,8 +402,9 @@ fi fi if test "x$USE_SUNDIALS" = "xy"; then -use_sundials=1 + use_sundials=1 fi +echo "Out of Block" sundials_lib_dir= sundials_lib= sundials_lib_dep= @@ -484,6 +532,13 @@ if test "$WITH_PURE_FLUIDS" = "y"; then fi AC_SUBST(COMPILE_PURE_FLUIDS) +if test "$WITH_REAL_GASSES" = "y"; then + AC_DEFINE(WITH_REAL_GASSES) + hdrs=$hdrs' RedlichKwongMFTP.h' + objs=$objs' RedlichKwongMFTP.o' +fi + + if test "$WITH_LATTICE_SOLID" = "y"; then AC_DEFINE(WITH_LATTICE_SOLID) hdrs=$hdrs' LatticeSolidPhase.h' @@ -615,6 +670,14 @@ fi AC_SUBST(COMPILE_H298MODIFY_CAPABILITY) +COMPILE_INTERMEDIATE_ZEROED_KINETICS=0 +if test "$KINETICS_WITH_INTERMEDIATE_ZEROED_KINETICS" = "y"; then + AC_DEFINE(KINETICS_WITH_INTERMEDIATE_ZEROED_KINETICS) + COMPILE_INTERMEDIATE_ZEROED_KINETICS=1 +fi +AC_SUBST(COMPILE_INTERMEDIATE_ZEROED_KINETICS) + + if test "$WITH_HTML_LOG_FILES" = "y"; then AC_DEFINE(WITH_HTML_LOGS) fi @@ -838,7 +901,7 @@ if test -n "$NEED_F2C" ; then build_f2c_lib=1 else case $ac_sys_system in - Linux) F2C_SYSTEMLIB="-lg2c" + Linux) F2C_SYSTEMLIB="" esac fi AC_SUBST(build_f2c_lib) @@ -978,7 +1041,7 @@ then RAW_LIBS_DEP=$RAW_LIBS_DEP' 'libctf2c.a else case $ac_sys_system in - Linux) LOCAL_LIBS=$LOCAL_LIBS' '-lg2c;; + Linux) LOCAL_LIBS=$LOCAL_LIBS;; esac fi # Darwin*) LOCAL_LIBS=$LOCAL_LIBS' '-lg2c;; @@ -1365,55 +1428,8 @@ esac # precompile_headers still relevant? # precompile_headers=no -# -# CFLAGS: flags that get attached to the C compiler -# statement. AFLAGS are base flags that -# get added to compilers and loaders. -# FFLAGS: flags that get attached to the Fortran compiler -# statement. AFLAGS are base flags that -# get added to compilers and loaders. -# -# CXXFLAGS: Flags that get attached to the CXX compiler -# statement. AFLAGS are base flags that -# get added to compilers and loaders. -# -if test -z "$AFLAGS" ; then - AFLAGS=" " -fi -if test -z "$CXXFLAGS" ; then - CXXFLAGS="$AFLAGS" -else - CXXFLAGS="$CXXFLAGS"" ""$AFLAGS" -fi -if test -z "$CFLAGS" ; then - CFLAGS="$AFLAGS" -else - CFLAGS="$CFLAGS"" ""$AFLAGS" -fi -if test -z "$FFLAGS" ; then - FFLAGS="$AFLAGS" -else - FFLAGS="$FFLAGS"" ""$AFLAGS" -fi - -if test "x$OS_IS_WIN" = "x1"; then - #CXX=cl.exe - #CC=cl.exe - #export CXX - AC_PROG_CXX() - AC_PROG_CC() -else - -# -# Determines the CXX compiler to use -# -export CXX -AC_PROG_CXX() -AC_PROG_CC() - - +if test "x$OS_IS_WIN" != "x1"; then AC_MSG_CHECKING(for ability to precompile headers) - if test -n "$GCC"; then msg=`rm -f *h.gch; $CXX testpch.h &> /dev/null` if test -f testpch.h.gch; then @@ -1461,12 +1477,6 @@ if test "$BUILD_WITH_F2C"="n"; then fi AC_SUBST(LCXX_FLAGS) - -# -# Ending Libs for compiling static applications and -# dynamically loaded libraries -# (sunpro solaris needs a few for dynamic linking) -# # # Check to see if we have a -lm line # @@ -1477,7 +1487,11 @@ AC_CHECK_LIB(m, printf, [add_stm=1], [add_stm=0], [ ]) # AC_CHECK_LIB(stdc++, printf, [add_stdc=1], [add_stdc=0], []) - +# +# Ending Libs for compiling static applications and +# dynamically loaded libraries +# (sunpro solaris needs a few for dynamic linking) +# if test -n "$NEED_F2C" ; then LCXX_END_LIBS="-lctf2c ""$LCXX_END_LIBS" fi @@ -1499,7 +1513,6 @@ if test $add_stdc = 1 ; then echo 'LCXX_END_LIBS = ' $LCXX_END_LIBS fi - AC_SUBST(LCXX_END_LIBS) @@ -1535,7 +1548,11 @@ AC_SUBST(HAVE_STRIPSYMBOLS) # Fortran #--------------------------------------------------------------------------- -#if test x"$build_with_f2c" = "x0"; then +# +# This macro sets the substitution variable, @F77@ and @G77@ +# +echo " this is $F77" +echo "this is a test" AC_PROG_F77() # if G77 is defined, then add a flag to turn off adding a second underscore @@ -1547,10 +1564,11 @@ else FFLAGS=$FFLAGS' -fno-second-underscore' fi fi - -dnl Checks for libraries. +F77LDRCLIBS= AC_F77_LIBRARY_LDFLAGS() +echo " Macro returned with FLIBS defined as " $FLIBS + override_f77_libs=0; #case $ac_sys_system in @@ -1677,7 +1695,6 @@ AC_OBJEXT AC_EXEEXT AC_SUBST(precompile_headers) -AC_SUBST(FLIBS) AC_SUBST(OS_IS_DARWIN) AC_SUBST(OS_IS_WIN) AC_SUBST(OS_IS_CYGWIN) @@ -1908,9 +1925,9 @@ AC_OUTPUT(Makefile \ ext/f2c_math/Makefile \ examples/Makefile \ examples/cxx/Makefile \ + docs/Makefile \ tools/Makefile \ - tools/doc/Cantera.cfg \ - tools/doc/Makefile \ + docs/Cantera.cfg \ tools/src/Makefile \ tools/src/sample.mak \ tools/src/finish_install.py \ diff --git a/data/thermo/nasathermo.dat b/data/thermo/nasathermo.dat index d78b570aa..b15f5cb12 100755 --- a/data/thermo/nasathermo.dat +++ b/data/thermo/nasathermo.dat @@ -1849,7 +1849,7 @@ LiO J 3/64LI 1.O 1. 0. 0.G 300.000 5000.000 22.94040 1 LiO- J12/67LI 1.O 1.E 1. 0.G 300.000 5000.000 22.94095 1 4.18102170E+00 4.17850000E-04-1.50248450E-07 2.83977320E-11-1.97891810E-15 2 -9.38497020E+03-1.42392337E-01 2.85158660E+00 5.01698800E-03-5.95474750E-06 3 - 3.03994510E-09-4.78729690E-13-9.07780760E+03 6.45947067E+00-8.05144594E+03 4 + 03994510E-09-4.78729690E-13-9.07780760E+03 6.45947067E+00-8.05144594E+03 4 LiOH J 6/71LI 1.O 1.H 1. 0.G 300.000 5000.000 23.94834 1 5.50969570E+00 1.36854640E-03-3.94414690E-07 5.23321950E-11-2.59586760E-15 2 -2.98992310E+04-6.50701600E+00 3.34623000E+00 1.17872530E-02-1.82526570E-05 3 @@ -4558,4 +4558,4 @@ ZrO2(L) J12/65ZR 1.O 2. 0. 0.C 2950.000 5000.000 123.22280 1 1.05676750E+01 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2 -1.28427450E+05-5.45922640E+01 1.05676750E+01 0.00000000E+00 0.00000000E+00 3 0.00000000E+00 0.00000000E+00-1.28427450E+05-5.45922640E+01 0.00000000E+00 4 -END \ No newline at end of file +END diff --git a/data/transport/misc_tran.dat b/data/transport/misc_tran.dat index 586df5bea..71bce0d79 100644 --- a/data/transport/misc_tran.dat +++ b/data/transport/misc_tran.dat @@ -3,9 +3,9 @@ ! ! Miscellaneous collection of transport parameters ! -! $Author: hkmoffa $ -! $Date: 2003/09/05 14:45:59 $ -! $Revision: 1.1 $ +! $Author$ +! $Date$ +! $Revision$ ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! diff --git a/tools/doc/Cantera.cfg.in b/docs/Cantera.cfg.in similarity index 95% rename from tools/doc/Cantera.cfg.in rename to docs/Cantera.cfg.in index 0ca8c8c93..5b260f5d0 100755 --- a/tools/doc/Cantera.cfg.in +++ b/docs/Cantera.cfg.in @@ -31,14 +31,20 @@ PROJECT_NAME = Cantera # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.7 +PROJECT_NUMBER = 1.8 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = @ctroot@/tools/doc + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @ctroot@/docs # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output @@ -235,7 +241,7 @@ EXTENSION_MAPPING = # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. -BUILTIN_STL_SUPPORT = NO +BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. @@ -317,7 +323,7 @@ EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. @@ -412,7 +418,7 @@ INLINE_INFO = YES # alphabetically by member name. If set to NO the members will appear in # declaration order. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically @@ -439,7 +445,7 @@ SORT_GROUP_NAMES = NO # Note: This option applies only to the class list, not to the # alphabetical list. -SORT_BY_SCOPE_NAME = NO +SORT_BY_SCOPE_NAME = YES # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo @@ -584,14 +590,14 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../../Cantera/src \ - ../../Cantera/src/base \ - ../../Cantera/src/numerics \ - ../../Cantera/src/thermo \ - ../../Cantera/src/equil \ - ../../Cantera/src/kinetics \ - ../../Cantera/src/transport \ - ../../Cantera/cxx/include \ +INPUT = ../Cantera/src \ + ../Cantera/src/base \ + ../Cantera/src/numerics \ + ../Cantera/src/thermo \ + ../Cantera/src/equil \ + ../Cantera/src/kinetics \ + ../Cantera/src/transport \ + ../Cantera/cxx/include \ doxyinput # This tag can be used to specify the character encoding of the source files @@ -609,8 +615,7 @@ INPUT_ENCODING = UTF-8 # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 -FILE_PATTERNS = Kinetics.h \ - Kinetics.cpp \ +FILE_PATTERNS = Kinetics.h Kinetics.cpp \ FactoryBase.h \ misc.cpp \ ct_defs.h \ @@ -656,10 +661,9 @@ FILE_PATTERNS = Kinetics.h \ SurfPhase.h \ EdgePhase.h \ SurfPhase.cpp \ - LatticePhase.h \ - LatticePhase.cpp \ - SpeciesThermoFactory.h \ - SpeciesThermoFactory.cpp \ + LatticePhase.h LatticePhase.cpp \ + LatticeSolidPhase.h LatticeSolidPhase.cpp \ + SpeciesThermoFactory.h SpeciesThermoFactory.cpp \ speciesThermoTypes.h \ SpeciesThermoMgr.h \ SpeciesThermoInterpType.h \ @@ -684,8 +688,6 @@ FILE_PATTERNS = Kinetics.h \ VPStandardStateTP.cpp \ SingleSpeciesTP.h \ SingleSpeciesTP.cpp \ - MetalSHEelectrons.h \ - MetalSHEelectrons.cpp \ MolalityVPSSTP.h \ MolalityVPSSTP.cpp \ IdealMolalSoln.h \ @@ -701,6 +703,14 @@ FILE_PATTERNS = Kinetics.h \ HMWSoln.h \ HMWSoln.cpp \ HMWSoln_input.cpp \ + GibbsExcessVPSSTP.h \ + GibbsExcessVPSSTP.cpp \ + MargulesVPSSTP.h \ + MargulesVPSSTP.cpp \ + RedlichKisterVPSSTP.h \ + RedlichKisterVPSSTP.cpp \ + IonsFromNeutralVPSSTP.h \ + IonsFromNeutralVPSSTP.cpp \ VPSSMgr.h \ VPSSMgr.cpp \ VPSSMgr_types.h \ @@ -724,6 +734,8 @@ FILE_PATTERNS = Kinetics.h \ PDSS_Water.cpp \ PDSS_HKFT.h \ PDSS_HKFT.cpp \ + PDSS_IonsFromNeutral.h \ + PDSS_IonsFromNeutral.cpp \ PDSS_SSVol.h \ PDSS_SSVol.cpp \ IdealSolnGasVPSS.h \ @@ -753,7 +765,48 @@ FILE_PATTERNS = Kinetics.h \ vcs_MultiPhaseEquil.h \ vcs_MultiPhaseEquil.cpp \ FalloffFactory.h \ - FalloffFactory.cpp + FalloffFactory.cpp \ + TransportBase.h \ + TransportBase.cpp \ + TransportParams.h \ + MMCollisionInt.h \ + L_matrix.h \ + MMCollisionInt.cpp \ + TransportFactory.h \ + TransportFactory.cpp \ + LTPspecies.h \ + LTPspecies.cpp \ + MultiTransport.h \ + MultiTransport.cpp \ + MixTransport.h \ + MixTransport.cpp \ + DustyGasTransport.h \ + DustyGasTransport.cpp \ + SolidTransport.h \ + SolidTransport.cpp \ + SimpleTransport.h \ + SimpleTransport.cpp \ + LiquidTransport.h \ + LiquidTransportParams.h \ + LiquidTransport.cpp \ + AqueousTransport.h \ + AqueousTransport.cpp \ + WaterTransport.h \ + WaterTransport.cpp \ + DenseMatrix.h \ + DenseMatrix.cpp \ + ResidJacEval.h \ + ResidJacEval.cpp \ + RootFind.h \ + RootFind.cpp \ + NonlinearSolver.h \ + NonlinearSolver.cpp \ + BandMatrix.h \ + BandMatrix.cpp \ + GeneralMatrix.h \ + GeneralMatrix.cpp \ + SquareMatrix.h \ + SquareMatrix.cpp # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -1440,7 +1493,7 @@ MACRO_EXPANSION = YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. -EXPAND_ONLY_PREDEF = YES +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. @@ -1471,14 +1524,15 @@ INCLUDE_FILE_PATTERNS = PREDEFINED = WITH_HTML_LOGS \ WITH_PURE_FLUIDS \ THREAD_SAFE_CANTERA \ - WITH_LATTICE_SOLID + WITH_LATTICE_SOLID \ + HAVE_CONFIG_H # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. -EXPAND_AS_DEFINED = YES +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone @@ -1619,7 +1673,7 @@ UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. -TEMPLATE_RELATIONS = YES +TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented @@ -1654,7 +1708,7 @@ CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. -GRAPHICAL_HIERARCHY = YES +GRAPHICAL_HIERARCHY = NO # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories diff --git a/tools/doc/Makefile.in b/docs/Makefile.in similarity index 80% rename from tools/doc/Makefile.in rename to docs/Makefile.in index 7a300e892..562e17866 100644 --- a/tools/doc/Makefile.in +++ b/docs/Makefile.in @@ -1,7 +1,7 @@ # -# $Revision: 1.2 $ +# $Revision: 255 $ # $Author: hkmoffa $ -# $Date: 2006/07/25 16:52:52 $ +# $Date: 2009-11-09 16:36:49 -0700 (Mon, 09 Nov 2009) $ # build_ck=@BUILD_CK@ diff --git a/tools/doc/doxyinput/Cantera.txt b/docs/doxyinput/Cantera.txt similarity index 94% rename from tools/doc/doxyinput/Cantera.txt rename to docs/doxyinput/Cantera.txt index 696124b8a..63a9fd587 100644 --- a/tools/doc/doxyinput/Cantera.txt +++ b/docs/doxyinput/Cantera.txt @@ -22,5 +22,6 @@ Choose one of the links below for an introduction to %Cantera, or use - Computing Properties of Matter - \subpage thermopage + - \subpage transportpage */ diff --git a/tools/doc/doxyinput/bindings.txt b/docs/doxyinput/bindings.txt similarity index 100% rename from tools/doc/doxyinput/bindings.txt rename to docs/doxyinput/bindings.txt diff --git a/tools/doc/doxyinput/build.txt b/docs/doxyinput/build.txt similarity index 100% rename from tools/doc/doxyinput/build.txt rename to docs/doxyinput/build.txt diff --git a/tools/doc/doxyinput/buildcygwin.txt b/docs/doxyinput/buildcygwin.txt similarity index 100% rename from tools/doc/doxyinput/buildcygwin.txt rename to docs/doxyinput/buildcygwin.txt diff --git a/tools/doc/doxyinput/configuring.txt b/docs/doxyinput/configuring.txt similarity index 100% rename from tools/doc/doxyinput/configuring.txt rename to docs/doxyinput/configuring.txt diff --git a/tools/doc/doxyinput/ctnew.txt b/docs/doxyinput/ctnew.txt similarity index 100% rename from tools/doc/doxyinput/ctnew.txt rename to docs/doxyinput/ctnew.txt diff --git a/tools/doc/doxyinput/cxx-headers.txt b/docs/doxyinput/cxx-headers.txt similarity index 100% rename from tools/doc/doxyinput/cxx-headers.txt rename to docs/doxyinput/cxx-headers.txt diff --git a/tools/doc/doxyinput/cxx-setup.txt b/docs/doxyinput/cxx-setup.txt similarity index 100% rename from tools/doc/doxyinput/cxx-setup.txt rename to docs/doxyinput/cxx-setup.txt diff --git a/tools/doc/doxyinput/demo.cpp b/docs/doxyinput/demo.cpp similarity index 100% rename from tools/doc/doxyinput/demo.cpp rename to docs/doxyinput/demo.cpp diff --git a/tools/doc/doxyinput/demo1.cpp b/docs/doxyinput/demo1.cpp similarity index 100% rename from tools/doc/doxyinput/demo1.cpp rename to docs/doxyinput/demo1.cpp diff --git a/tools/doc/doxyinput/demo1a.cpp b/docs/doxyinput/demo1a.cpp similarity index 100% rename from tools/doc/doxyinput/demo1a.cpp rename to docs/doxyinput/demo1a.cpp diff --git a/tools/doc/doxyinput/demoequil.cpp b/docs/doxyinput/demoequil.cpp similarity index 100% rename from tools/doc/doxyinput/demoequil.cpp rename to docs/doxyinput/demoequil.cpp diff --git a/tools/doc/doxyinput/edemo.cpp b/docs/doxyinput/edemo.cpp similarity index 100% rename from tools/doc/doxyinput/edemo.cpp rename to docs/doxyinput/edemo.cpp diff --git a/tools/doc/doxyinput/equildemo.txt b/docs/doxyinput/equildemo.txt similarity index 100% rename from tools/doc/doxyinput/equildemo.txt rename to docs/doxyinput/equildemo.txt diff --git a/tools/doc/doxyinput/ex1.cpp b/docs/doxyinput/ex1.cpp similarity index 100% rename from tools/doc/doxyinput/ex1.cpp rename to docs/doxyinput/ex1.cpp diff --git a/tools/doc/doxyinput/except.cpp b/docs/doxyinput/except.cpp similarity index 100% rename from tools/doc/doxyinput/except.cpp rename to docs/doxyinput/except.cpp diff --git a/tools/doc/doxyinput/exceptions.txt b/docs/doxyinput/exceptions.txt similarity index 100% rename from tools/doc/doxyinput/exceptions.txt rename to docs/doxyinput/exceptions.txt diff --git a/tools/doc/doxyinput/initthermo.txt b/docs/doxyinput/initthermo.txt similarity index 100% rename from tools/doc/doxyinput/initthermo.txt rename to docs/doxyinput/initthermo.txt diff --git a/tools/doc/doxyinput/introcxx.txt b/docs/doxyinput/introcxx.txt similarity index 100% rename from tools/doc/doxyinput/introcxx.txt rename to docs/doxyinput/introcxx.txt diff --git a/tools/doc/doxyinput/languages.txt b/docs/doxyinput/languages.txt similarity index 100% rename from tools/doc/doxyinput/languages.txt rename to docs/doxyinput/languages.txt diff --git a/tools/doc/doxyinput/matlab.txt b/docs/doxyinput/matlab.txt similarity index 100% rename from tools/doc/doxyinput/matlab.txt rename to docs/doxyinput/matlab.txt diff --git a/tools/doc/doxyinput/numarray.txt b/docs/doxyinput/numarray.txt similarity index 100% rename from tools/doc/doxyinput/numarray.txt rename to docs/doxyinput/numarray.txt diff --git a/tools/doc/doxyinput/thermo.txt b/docs/doxyinput/thermo.txt similarity index 78% rename from tools/doc/doxyinput/thermo.txt rename to docs/doxyinput/thermo.txt index cba0b3e18..8206d9729 100644 --- a/tools/doc/doxyinput/thermo.txt +++ b/docs/doxyinput/thermo.txt @@ -2,12 +2,9 @@ \page thermopage Thermodynamic Properties -%Cantera can be used to compute thermodynamic properties of pure -substances, solutions, and mixtures of various types, including ones -containing multiple phases. The first step is to create an object that -represents each phase. +%Cantera can be used to compute thermodynamic properties of pure substances, solutions, and mixtures of various types, including ones containing multiple phases. The first step is to create an object that +represents each phase. A simple complete program that creates an object representing a gas mixture and prints its temperature is shown below. -A simple complete program that creates an object representing a gas mixture and prints its temperature is shown below. \include ex1.cpp Class \link Cantera::ThermoPhase ThermoPhase \endlink @@ -21,15 +18,26 @@ potentials into array \c mu, and so on. Class ThermoPhase can be used to represent the intensive state of any single-phase solution of multiple species. The phase may be a bulk, -three-dimensional phase (a gas, a liquid, or a solid), or may be a +three-dimensional phase (a gas, a liquid, or a solid), or it may be a two-dimensional surface phase, or even a one-dimensional "edge" phase. The specific attributes of each type of phase are specified by -deriving a class from ThemoPhase and providing implementations for the -virtual methods of ThermoPhase. +deriving a class from %ThemoPhase and providing implementations for the +virtual methods of %ThermoPhase. + +%Cantera has a wide variety of models for bulk phase currently. Special +attention (in terms of the speed of execution) has been paid to an ideal gas phase implementation, where the +species thermodynamic polynomial representations adhere to either the NASA +polynomial form or to the Shomate polynomoial form. This is widely used in +combustion applications, the origin application that %Cantera was +designed for. Recently, a lot of effort has been placed into constructing non-ideal +liquid phase thermodynamics models that are used in electrochemistry and +battery applications. These models include a Pitzer implementation for brines +solutions and a Margules excess Gibbs free energy implementation for molten +salts. \section The Intensive Thermodynamic State -Class ThermoPhase and classes derived from it work only with the +Class %ThermoPhase and classes derived from it work only with the intensive thermodynamic state. That is, all extensive properties (enthalpy, entropy, internal energy, volume, etc.) are computed for a unit quantity (on a mass or mole basis). For example, there is a diff --git a/tools/doc/doxyinput/thermodemo.cpp b/docs/doxyinput/thermodemo.cpp similarity index 100% rename from tools/doc/doxyinput/thermodemo.cpp rename to docs/doxyinput/thermodemo.cpp diff --git a/tools/doc/doxyinput/thermodemo.txt b/docs/doxyinput/thermodemo.txt similarity index 100% rename from tools/doc/doxyinput/thermodemo.txt rename to docs/doxyinput/thermodemo.txt diff --git a/docs/doxyinput/transport.txt b/docs/doxyinput/transport.txt new file mode 100644 index 000000000..ad4c8a94f --- /dev/null +++ b/docs/doxyinput/transport.txt @@ -0,0 +1,23 @@ +/** + +\page transportpage Transport Properties + +%Cantera can be used to compute transport properties + + +\section nest Non-Equilibrium Statistical Thermodynamics + + +\section tbase Base Class for Transport Properties + + +The base class \link Cantera::Transport Transport \endlink is used for all +transport classes within Cantera. + + + +There is a list of classes which handle transport for species (see +\ref tranprops " Transport Properties for Species in Phases"). + + +*/ diff --git a/tools/doc/doxyinput/winbuild.txt b/docs/doxyinput/winbuild.txt similarity index 100% rename from tools/doc/doxyinput/winbuild.txt rename to docs/doxyinput/winbuild.txt diff --git a/tools/doc/html/banner4.jpg b/docs/html/banner4.jpg similarity index 100% rename from tools/doc/html/banner4.jpg rename to docs/html/banner4.jpg diff --git a/docs/README.txt b/docs/install_examples/README.txt similarity index 100% rename from docs/README.txt rename to docs/install_examples/README.txt diff --git a/docs/install_examples/cygwin_gcc344_f2c_numeric.sh b/docs/install_examples/cygwin_gcc344_f2c_numeric.sh new file mode 100755 index 000000000..71f82d694 --- /dev/null +++ b/docs/install_examples/cygwin_gcc344_f2c_numeric.sh @@ -0,0 +1,142 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# +# Example Cantera pre-preconfig configuration script +# +# Platform: cygwin +# Compiler: gcc +# python: v. 2.5.2 (full installation) +# matlab: no +# f2c: yes +# +# +# Specific places where the User must custimize the installation +# is indiciated with the USER_INPUT_NEEDED lines. +# +# +# Specify the installation directory here: +# USER_INPUT_NEEDED +# +# ----------------------------------------------------------------------------- +# +CANTERA_CONFIG_PREFIX=/cygdrive/c/cygwin_env/arch/cygwin/cantera-1.8_develop +export CANTERA_CONFIG_PREFIX + +SET_PYTHON_SITE_PACKAGE_TOPDIR=y +export SET_PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_SITE_PACKAGE_TOPDIR=$CANTERA_CONFIG_PREFIX +export PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_CMD=/usr/bin/python +export PYTHON_CMD + +# +# The full python package works within cygwin. Minimal is needed at the least +# +PYTHON_PACKAGE='full' +#PYTHON_PACKAGE='minimal' +export PYTHON_PACKAGE + +WITH_IDEAL_SOLUTIONS="y" +export WITH_IDEAL_SOLUTIONS + +WITH_ELECTROLYTES="y" +export WITH_ELECTROLYTES + +WITH_VCSNONIDEAL="y" +export WITH_VCSNONIDEAL + +# +# Matlab on the pc is supported through the windows vc++ 8.0 compilation +# environment +# +BUILD_MATLAB_TOOLBOX="n" +export BUILD_MATLAB_TOOLBOX + +NUMARRAY_HOME='' +export NUMARRAY_HOME +# +# Turns on extra debugging +# +DEBUG_MODE='y' +export DEBUG_MODE +# +# Numeric must have already been installed in the +# /usr/lib/python2.5/site-packages +# directory before the Cantera installation. If not, you can always +# do a minimal python installation and forego forming Cantera's python interface. +# +USE_NUMERIC="y" +export USE_NUMERIC +# +# We use F2C with the cygwin installation. However, the g77 interface should +# work too. +# +BUILD_WITH_F2C="y" +export BUILD_WITH_F2C + +BITCOMPILE="32" +export BITCOMPILE +# +# We use the default gcc compilers that come with cygwin. Currently, this +# is gcc v. 3.4.4. +# +CXX='g++' +export CXX +# +CC='gcc' +export CC +# +F77='g77' +export F77 +# +# Debug options +# +# -DDEBUG_HKM +# -DDEBUG_BASISOPTIMIZE +# -DDEBUG_CHEMEQUIL +# +CXXFLAGS="-g -Wall " +export CXXFLAGS + +CFLAGS=$CXXFLAGS +export CFLAGS + +FFLAGS="-g " +export FFLAGS + +LDFLAGS='-g' +export LDFLAGS + +LCXX_END_LIBS="-lm -lstdc++" +export LCXX_END_LIBS + +# The gcc compiler in cygwin will put a .exe extension on anyway. So, +# we might as well define this field as .exe. cygwin will automagically +# equate executable files with no extension as having an .exe extension. +# This is very mysterious. However, the mystery goes away if you define +# these files to have a .exe suffix from the getgo. +EXE_EXT=".exe" +export EXE_EXT + +EXTRA_LINK="" +export EXTRA_LINK + +MAKE=make +export MAKE +# +# Specify the SUNDIALS option +# +USE_SUNDIALS='n' +export USE_SUNDIALS +# +# Specify where to find the sundials installation directories +# +SUNDIALS_HOME='/cygdrive/c/cygwin_env/libraries/sundials' +export SUNDIALS_HOME +# +# Ok, fire off the main preconfig script +# +./preconfig + diff --git a/docs/install_examples/cygwin_gcc434_dbg_f2c_numpy.sh b/docs/install_examples/cygwin_gcc434_dbg_f2c_numpy.sh index 3fe470105..f6df415ab 100755 --- a/docs/install_examples/cygwin_gcc434_dbg_f2c_numpy.sh +++ b/docs/install_examples/cygwin_gcc434_dbg_f2c_numpy.sh @@ -25,11 +25,11 @@ Cantera_Install_Dir='/cygdrive/c/cygwin_env/arch/cygwin/cantera-1.8.0' # if you don't want to link sundials in # # Sundials_Home='' -Sundials_Home='/cygdrive/c/cygwin_env/arch/cygwin/sundials-2.3.0_dbg' +Sundials_Home='/cygdrive/c/cygwin_env/arch/cygwin/sundials-2.4.0_dbg' # # Specify the Sundials version number (either 2.2, 2.3, or 2.4) -Sundials_Version='2.3' -# Sundials_Version=2.4' +# Sundials_Version='2.3' +Sundials_Version=2.4' # ----------------------------------------------------------------------------- # CANTERA_CONFIG_PREFIX=$Cantera_Install_Dir diff --git a/docs/install_examples/linux.64_sierra_gcc444_python264_numpy b/docs/install_examples/linux.64_sierra_gcc444_python264_numpy new file mode 100755 index 000000000..39a93c332 --- /dev/null +++ b/docs/install_examples/linux.64_sierra_gcc444_python264_numpy @@ -0,0 +1,116 @@ +#!/bin/sh +# +# This is currently the test base. Meaning that the blessed versions +# of all test problems are created from this configuration. +# +CANTERA_CONFIG_PREFIX=${HOME}/arch/linux64_gcc444/cantera-1.8_liquidTransportDevelop +export CANTERA_CONFIG_PREFIX + +SET_PYTHON_SITE_PACKAGE_TOPDIR=y +export SET_PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_SITE_PACKAGE_TOPDIR=$CANTERA_CONFIG_PREFIX +export PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_CMD=${HOME}/arch/linux64_gcc444/python-2.6.4/bin/python +export PYTHON_CMD + +PYTHON_PACKAGE='full' +#PYTHON_PACKAGE='minimal' +export PYTHON_PACKAGE + +DEBUG_MODE='y' +export DEBUG_MODE + +WITH_IDEAL_SOLUTIONS="y" +export WITH_IDEAL_SOLUTIONS + +WITH_ELECTROLYTES="y" +export WITH_ELECTROLYTES + +WITH_VCSNONIDEAL="y" +export WITH_VCSNONIDEAL + +WITH_H298MODIFY_CAPABILITY='y' +export WITH_H298MODIFY_CAPABILITY + +WITH_REAL_GASSES='y' +export WITH_REAL_GASSES + +BUILD_MATLAB_TOOLBOX="y" +export BUILD_MATLAB_TOOLBOX + +INSTALL_BIN=config/install-sh +export INSTALL_BIN + +MATLAB_CMD="/usr/local/matlab/7.13/bin/matlab" +export MATLAB_CMD + +BUILD_F90_INTERFACE="y" +export BUILD_F90_INTERFACE + +NUMARRAY_HOME='' +export NUMARRAY_HOME + +USE_NUMPY='y' +export USE_NUMPY + +NUMPY_INC_DIR="${HOME}/arch/linux64_gcc444/python-2.6.4/lib/python2.6/site-packages/numpy/core/include" +export NUMPY_INC_DIR + +GRAPHVIZDIR=/usr/netpub/graphviz-2.26.3/bin +export GRAPHVIZDIR + +# +# +USE_NUMERIC="n" +export USE_NUMERIC + +BUILD_WITH_F2C="n" +export BUILD_WITH_F2C + +BITCOMPILE="64" +export BITCOMPILE + +AFLAGS='DEBUG' + +CXX='/sierra/Sntools/extras/compilers/gcc-4.4.4/bin/g++' +export CXX + +CXX_DEPENDS='/sierra/Sntools/extras/compilers/gcc-4.4.4/bin/g++ -MM' +export CXX_DEPENDS + +CC='/sierra/Sntools/extras/compilers/gcc-4.4.4/bin/gcc' +export CC + +F77='/sierra/Sntools/extras/compilers/gcc-4.4.4/bin/gfortran' +export F77 + +FFLAGS="-g " +export FFLAGS + +CFLAGS="-g " +export CFLAGS + +#CXXFLAGS="-g -Wall -Woverloaded-virtual -DDEBUG_HKM -DDEBUG_HKM_EPEQUIL -DDEBUG_NUMJAC" +CXXFLAGS="-g -Wall -Woverloaded-virtual -DDEBUG_HKM -DDEBUG_HKM_EPEQUIL " +export CXXFLAGS + +LDFLAGS=' ' +export LDFLAGS + +LCXX_END_LIBS="-lgfortran " +export LCXX_END_LIBS + +EXTRA_LINK=" " +export EXTRA_LINK + +MAKE=gmake +export MAKE + +USE_SUNDIALS='y' +export USE_SUNDIALS +SUNDIALS_HOME="${HOME}/arch/linux64_gcc444/sundials-2.4.0_dbg" +export SUNDIALS_HOME + +./preconfig diff --git a/docs/install_examples/linux_64_gcc424_dbg_python252_numpy b/docs/install_examples/linux_64_gcc424_dbg_python252_numpy index 2da813547..b95d79ce2 100755 --- a/docs/install_examples/linux_64_gcc424_dbg_python252_numpy +++ b/docs/install_examples/linux_64_gcc424_dbg_python252_numpy @@ -31,6 +31,9 @@ export WITH_ELECTROLYTES WITH_VCSNONIDEAL="y" export WITH_VCSNONIDEAL +WITH_H298MODIFY_CAPABILITY="y" +export WITH_H298MODIFY_CAPABILITY + BUILD_MATLAB_TOOLBOX="y" export BUILD_MATLAB_TOOLBOX diff --git a/docs/install_examples/linux_64_gcc424_opt_python252_numpy b/docs/install_examples/linux_64_gcc424_opt_python252_numpy index e0a4a2d57..09d12db05 100755 --- a/docs/install_examples/linux_64_gcc424_opt_python252_numpy +++ b/docs/install_examples/linux_64_gcc424_opt_python252_numpy @@ -29,6 +29,9 @@ export WITH_ELECTROLYTES WITH_VCSNONIDEAL="y" export WITH_VCSNONIDEAL +WITH_H298MODIFY_CAPABILITY="y" +export WITH_H298MODIFY_CAPABILITY + BUILD_MATLAB_TOOLBOX="y" export BUILD_MATLAB_TOOLBOX diff --git a/docs/install_examples/linux_rhel5_64_gcc424_dbg_python264_numpy b/docs/install_examples/linux_rhel5_64_gcc424_dbg_python264_numpy new file mode 100755 index 000000000..a7608e776 --- /dev/null +++ b/docs/install_examples/linux_rhel5_64_gcc424_dbg_python264_numpy @@ -0,0 +1,112 @@ +#!/bin/sh +# +# This is currently the test base. Meaning that the blessed versions +# of all test problems are created from this configuration. +# +CANTERA_CONFIG_PREFIX=${HOME}/arch/linux64_gcc424/cantera-1.8_liquidTransportDevelop +export CANTERA_CONFIG_PREFIX + +SET_PYTHON_SITE_PACKAGE_TOPDIR=y +export SET_PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_SITE_PACKAGE_TOPDIR=$CANTERA_CONFIG_PREFIX +export PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_CMD=${HOME}/arch/linux64_gcc424/python-2.6.4/bin/python +export PYTHON_CMD + +PYTHON_PACKAGE='full' +#PYTHON_PACKAGE='minimal' +export PYTHON_PACKAGE + +DEBUG_MODE='y' +export DEBUG_MODE + +WITH_IDEAL_SOLUTIONS="y" +export WITH_IDEAL_SOLUTIONS + +WITH_ELECTROLYTES="y" +export WITH_ELECTROLYTES + +WITH_VCSNONIDEAL="y" +export WITH_VCSNONIDEAL + +WITH_H298MODIFY_CAPABILITY='y' +export WITH_H298MODIFY_CAPABILITY + +BUILD_MATLAB_TOOLBOX="y" +export BUILD_MATLAB_TOOLBOX + +INSTALL_BIN=config/install-sh +export INSTALL_BIN + +MATLAB_CMD="/usr/local/matlab/7.9/bin/matlab" +export MATLAB_CMD + +BUILD_F90_INTERFACE="y" +export BUILD_F90_INTERFACE + +NUMARRAY_HOME='' +export NUMARRAY_HOME + +USE_NUMPY='y' +export USE_NUMPY + +NUMPY_INC_DIR="${HOME}/arch/linux64_gcc424/python-2.6.4/lib/python2.6/site-packages/numpy/core/include" +export NUMPY_INC_DIR + +GRAPHVIZDIR=${HOME}'/arch/linux/bin' +export GRAPHVIZDIR + +# +# +USE_NUMERIC="n" +export USE_NUMERIC + +BUILD_WITH_F2C="n" +export BUILD_WITH_F2C + +BITCOMPILE="64" +export BITCOMPILE + +AFLAGS='DEBUG' + +CXX='/sierra/Sntools/extras/compilers/gcc-4.2.4/bin/g++' +export CXX + +CXX_DEPENDS='/sierra/Sntools/extras/compilers/gcc-4.2.4/bin/g++ -MM' +export CXX_DEPENDS + +CC='/sierra/Sntools/extras/compilers/gcc-4.2.4/bin/gcc' +export CC + +F77='/sierra/Sntools/extras/compilers/gcc-4.2.4/bin/gfortran' +export F77 + +CFLAGS="-g -Wall" +export CFLAGS + +CXXFLAGS="-g -Wall -Woverloaded-virtual -DDEBUG_HKM -DDEBUG_HKM_EPEQUIL" +export CXXFLAGS + +FFLAGS="-g -DDEBUG_HKM -fno-second-underscore" +export FFLAGS + +LDFLAGS=' ' +export LDFLAGS + +LCXX_END_LIBS="-lgfortran -lm -lstdc++" +export LCXX_END_LIBS + +EXTRA_LINK=" " +export EXTRA_LINK + +MAKE=gmake +export MAKE + +USE_SUNDIALS='y' +export USE_SUNDIALS +SUNDIALS_HOME="${HOME}/arch/linux64_gcc424/sundials-2.4.0_dbg" +export SUNDIALS_HOME + +./preconfig diff --git a/docs/install_examples/mac_gcc401_python251_numpy b/docs/install_examples/mac_gcc401_python251_numpy index 3940a8e50..3317d1a4d 100755 --- a/docs/install_examples/mac_gcc401_python251_numpy +++ b/docs/install_examples/mac_gcc401_python251_numpy @@ -46,7 +46,7 @@ export BUILD_F90_INTERFACE USE_NUMPY='y' export USE_NUMPY -NUMPY_INC_DIR="/home/hkmoffa/arch/mac/lib/python2.5/site-packages/numpy/core/include" +NUMPY_INC_DIR="${HOME}/arch/mac/lib/python2.5/site-packages/numpy/core/include" export NUMPY_INC_DIR #GRAPHVIZDIR=${HOME}'/arch/linux/bin' @@ -100,7 +100,7 @@ export MAKE USE_SUNDIALS='n' export USE_SUNDIALS -SUNDIALS_HOME='/home/hkmoffa/arch/linux64/sundials' +SUNDIALS_HOME="${HOME}/arch/linux64/sundials" export SUNDIALS_HOME ./preconfig diff --git a/docs/install_examples/sol10_64bit_CC57_py24_numarray b/docs/install_examples/sol10_64bit_CC57_py24_numarray new file mode 100755 index 000000000..98d450e33 --- /dev/null +++ b/docs/install_examples/sol10_64bit_CC57_py24_numarray @@ -0,0 +1,141 @@ +#!/bin/sh +# +# Sierra 64 bit setup: +# -xO4 -xtarget=native64 -xarch=native64 -xcode=pic32 -DSUN10 -library=stlport4 +# +# Sierra warnings setup: +# +w2 -errtags -erroff=doubunder,reftotemp,ppextraw,inllargeint,inllargeuse,wnoelseretvalue,truncwarn,diffenumtype,notused,wvarhid enmem,badcastw,hidef -errwarn=%all,no%wunreachable,no%partinit +# +# Notes: +# When you add flsgs with % in them python won't build, because there is an +# error in the python distutils routines. I am currently manually +# fixing these. +# +# Program Names: +# +MAKE=gmake +export MAKE + +# +# Pointers to the 64 bit python built with Sunpro compilers +PYTHON_DIR=${HOME}/arch/sol_py64 +export PYTHON_DIR +PYTHON_CMD=${HOME}/arch/sol_py64/bin/python +export PYTHON_CMD + +# +# Use the CC compiler for C++ code +CXX=CC +export CXX +# +# Specification of the c compiler +# +CC=cc +export CC + +CXX_DEPENDS='CC -xM1' +export CXX_DEPENDS + +USE_NUMERIC='n' +export USE_NUMERIC + +# +# HKM 7/22/09 +# The matlab option is currently not working. Matlab uses the gcc +# compiler. This setup uses the solaris compiler. I can get +# the matlab extensions to compile. But, when I run matlab +# I get an unsatisfied external +# When I add the commands: +# -l/opt/SUNWspro/lib/f9 -lCrun -lCstd -lfsu +# to the matlab build, I can get rid of the runtime unsatisfied +# external. However, I immediate crash dump matlab. This +# suggests that there are duplicate Cstd routines from gcc and +# from the solaris compilers fighting it out. +# I believe the solution will involve compiling everything +# with gcc in order to get matlab on solaris to work. +# +BUILD_MATLAB_TOOLBOX="n" +export BUILD_MATLAB_TOOLBOX + +DEBUG_MODE="y" +export DEBUG_MODE + +# +# Compiler Flags +# +BITCOMPILE="64" +export BITCOMPILE +# +# remember the issue with % and python +# +EFLAGS=" +w2 -errtags -erroff=doubunder,reftotemp,ppextraw,inllargeint,inllargeuse,wnoelseretvalue,truncwarn,diffenumtype,notused,wvarhidenmem,badcastw,hidef -errwarn=%all,no%wunreachable,no%partinit" +#AFLAGS=" -xtarget=native64 -xarch=native64 -xcode=pic32 -library=stlport4" +AFLAGS=" -xtarget=native64 -xarch=native64 -xcode=pic32" +export AFLAGS + +F77=f77 +export F77 + +F90=f95 +export F90 + +FFLAGS="-g -xtarget=native64 -xarch=native64 -xcode=pic32 " +export FFLAGS + +CFLAGS="-g -xtarget=native64 -xarch=native64 -xcode=pic32 -v " +export CFLAGS + +CXXFLAGS="-g $AFLAGS $EFLAGS -DDEBUG_HKM" +export CXXFLAGS + +LCXX_END_LIBS="-lm " +export LCXX_END_LIBS + +# other useful endlibs for solaris 64 bit are +# -mt -lsunmath -lfsu + +USE_SUNDIALS='n' +export USE_SUNDIALS + +WITH_VCSNONIDEAL='y' +export WITH_VCSNONIDEAL + +# +# Location Variables - set the directory to point to +# a 64-bit specific directory. +# +CANTERA_INSTALL_DIR=${HOME}/arch/sol_py64/cantera-1.8 +export CANTERA_INSTALL_DIR + +CANTERA_CONFIG_PREFIX=${HOME}/arch/sol_py64/cantera-1.8 +export CANTERA_CONFIG_PREFIX + +#CANTERA_PYTHON_HOME=${CANTERA_PYTHON_HOME:="$HOME/python_modules"} +#export CANTERA_PYTHON_HOME + +SET_PYTHON_SITE_PACKAGE_TOPDIR="y" +export SET_PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_SITE_PACKAGE_TOPDIR=${HOME}"/arch/sol_py64/cantera-1.8" +export PYTHON_SITE_PACKAGE_TOPDIR + +PYTHON_PACKAGE="full" +#PYTHON_PACKAGE="minimal" +#PYTHON_PACKAGE="none" +export PYTHON_PACKAGE + +BUILD_WITH_F2C="n" +export BUILD_WITH_F2C + +# +# Archive commands +# +ARCHIVE="CC -xar -xcode=pic32 -o " +export ARCHIVE + + +# +# Invoke the regular configure script +# +./preconfig + diff --git a/tools/doc/python/.cvsignore b/docs/python/.cvsignore similarity index 100% rename from tools/doc/python/.cvsignore rename to docs/python/.cvsignore diff --git a/tools/doc/python/makedoc b/docs/python/makedoc similarity index 100% rename from tools/doc/python/makedoc rename to docs/python/makedoc diff --git a/tools/doc/python/mkmkdoc.py b/docs/python/mkmkdoc.py similarity index 100% rename from tools/doc/python/mkmkdoc.py rename to docs/python/mkmkdoc.py diff --git a/examples/cxx/equil_example1.cpp b/examples/cxx/equil_example1.cpp index 1d812033d..a3a414161 100755 --- a/examples/cxx/equil_example1.cpp +++ b/examples/cxx/equil_example1.cpp @@ -2,9 +2,9 @@ // // chemical equilibrium // -// $Author: hkmoffa $ -// $Revision: 1.15 $ -// $Date: 2008/02/16 21:33:37 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // @@ -25,6 +25,8 @@ using namespace Cantera; using namespace Cantera_CXX; +using namespace CanteraZeroD; +using namespace std; //------------------------------------------------------------------- // utility functions for plotting diff --git a/examples/cxx/example_utils.h b/examples/cxx/example_utils.h index 2439816e1..f9b529c43 100755 --- a/examples/cxx/example_utils.h +++ b/examples/cxx/example_utils.h @@ -4,10 +4,7 @@ #include #include -using namespace Cantera; -using namespace std; namespace CanteraZeroD{} -using namespace CanteraZeroD; // Save the temperature, density, pressure, and mole fractions at one // time @@ -47,22 +44,22 @@ void makeDataLabels(const G& gas, V& names) { } template -void plotSoln(string fname, string fmt, string title, const G& gas, const A& soln) { - vector names; +void plotSoln(std::string fname, std::string fmt, std::string title, const G& gas, const A& soln) { + std::vector names; makeDataLabels(gas, names); writePlotFile(fname, fmt, title, names, soln); } -inline void writeCanteraHeader(ostream& s) { - s << endl; +inline void writeCanteraHeader(std::ostream& s) { + s << std::endl; #ifdef CANTERA_VERSION - s << " Cantera version " << CANTERA_VERSION << endl; + s << " Cantera version " << CANTERA_VERSION << std::endl; #else - s << " ???" << endl; + s << " ???" << std::endl; #endif - s << " Copyright California Institute of Technology, 2002." << endl; - s << " http://www.cantera.org" << endl; - s << endl; + s << " Copyright California Institute of Technology, 2002." << std::endl; + s << " http://www.cantera.org" << std::endl; + s << std::endl; } #endif diff --git a/examples/cxx/kinetics_example1.cpp b/examples/cxx/kinetics_example1.cpp index 74500c287..ed8172356 100755 --- a/examples/cxx/kinetics_example1.cpp +++ b/examples/cxx/kinetics_example1.cpp @@ -2,9 +2,9 @@ // // zero-dimensional kinetics example program // -// $Author: hkmoffa $ -// $Revision: 1.13 $ -// $Date: 2009/07/11 17:25:05 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // diff --git a/examples/cxx/kinetics_example2.cpp b/examples/cxx/kinetics_example2.cpp index 391a7b7ea..5e1c74770 100755 --- a/examples/cxx/kinetics_example2.cpp +++ b/examples/cxx/kinetics_example2.cpp @@ -2,9 +2,9 @@ // // zero-dimensional kinetics example program // -// $Author: hkmoffa $ -// $Revision: 1.8 $ -// $Date: 2009/07/11 17:25:05 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // @@ -24,6 +24,8 @@ using namespace Cantera; using namespace Cantera_CXX; +using namespace CanteraZeroD; +using namespace std; /** * Same as kinetics_example1, except that it uses class GRI30 instead * of class IdealGasMix. diff --git a/examples/cxx/kinetics_example3.cpp b/examples/cxx/kinetics_example3.cpp index e2be7ff7b..f21973376 100644 --- a/examples/cxx/kinetics_example3.cpp +++ b/examples/cxx/kinetics_example3.cpp @@ -2,9 +2,9 @@ // // zero-dimensional kinetics example program // -// $Author: hkmoffa $ -// $Revision: 1.5 $ -// $Date: 2009/07/11 17:25:05 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2006 // @@ -24,6 +24,8 @@ using namespace Cantera; using namespace Cantera_CXX; +using namespace std; +using namespace CanteraZeroD; // Kinetics example. This is written as a function so that one // driver program can run multiple examples. diff --git a/examples/cxx/rxnpath_example1.cpp b/examples/cxx/rxnpath_example1.cpp index 9a7756aad..19cdc5777 100755 --- a/examples/cxx/rxnpath_example1.cpp +++ b/examples/cxx/rxnpath_example1.cpp @@ -2,9 +2,9 @@ // // reaction path diagrams // -// $Author: hkmoffa $ -// $Revision: 1.9 $ -// $Date: 2009/07/11 17:25:05 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // @@ -24,9 +24,10 @@ #include // #include -// using namespace std; +using namespace std; using namespace Cantera; using namespace Cantera_CXX; +using namespace CanteraZeroD; void writeRxnPathDiagram(double time, ReactionPathBuilder& b, IdealGasMix& gas, ostream& logfile, ostream& outfile) { diff --git a/examples/cxx/transport_example1.cpp b/examples/cxx/transport_example1.cpp index 65fd37499..a349396e6 100755 --- a/examples/cxx/transport_example1.cpp +++ b/examples/cxx/transport_example1.cpp @@ -2,9 +2,9 @@ // // mixture-averaged transport properties // -// $Author: hkmoffa $ -// $Revision: 1.7 $ -// $Date: 2008/02/16 21:33:37 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // @@ -24,6 +24,8 @@ using namespace Cantera; using namespace Cantera_CXX; +using namespace CanteraZeroD; +using namespace std; template void makeTransportDataLabels(const G& gas, V& names) { diff --git a/examples/cxx/transport_example2.cpp b/examples/cxx/transport_example2.cpp index 83086651b..da18303cb 100755 --- a/examples/cxx/transport_example2.cpp +++ b/examples/cxx/transport_example2.cpp @@ -2,9 +2,9 @@ // // mixture-averaged transport properties // -// $Author: hkmoffa $ -// $Revision: 1.6 $ -// $Date: 2008/02/16 21:33:38 $ +// $Author$ +// $Revision$ +// $Date$ // // copyright California Institute of Technology 2002 // @@ -25,6 +25,8 @@ using namespace Cantera; using namespace Cantera_CXX; +using namespace CanteraZeroD; +using namespace std; template void makeTransportDataLabels(const G& gas, V& names) { diff --git a/ext/Makefile.in b/ext/Makefile.in index d902d6cfe..6189ca913 100755 --- a/ext/Makefile.in +++ b/ext/Makefile.in @@ -1,9 +1,9 @@ #/bin/sh # # $Source: /cvsroot/cantera/cantera/ext/Makefile.in,v $ -# $Author: dggoodwin $ -# $Revision: 1.10 $ -# $Date: 2008/02/13 06:43:27 $ +# $Author$ +# $Revision$ +# $Date$ # # Makefile for ext directory # diff --git a/ext/blas/Makefile.in b/ext/blas/Makefile.in index caef518a0..e9417b30f 100755 --- a/ext/blas/Makefile.in +++ b/ext/blas/Makefile.in @@ -1,7 +1,7 @@ #/bin/sh # $License$ # -# $Id: Makefile.in,v 1.8 2008/12/30 21:49:41 hkmoffa Exp $ +# $Id$ # do_ranlib = @DO_RANLIB@ BLASLIB = @buildlib@/libctblas.a diff --git a/ext/cvode/Makefile.in b/ext/cvode/Makefile.in index ef438dc2b..494dc2185 100755 --- a/ext/cvode/Makefile.in +++ b/ext/cvode/Makefile.in @@ -1,8 +1,8 @@ # # $Source: /cvsroot/cantera/cantera/ext/cvode/Makefile.in,v $ -# $Author: hkmoffa $ -# $Revision: 1.10 $ -# $Date: 2008/12/30 21:49:42 $ +# $Author$ +# $Revision$ +# $Date$ # #---------------------------------------------------------------------------- # CVODE diff --git a/ext/f2c_blas/Makefile.in b/ext/f2c_blas/Makefile.in index e10e9f192..8c33bf26e 100755 --- a/ext/f2c_blas/Makefile.in +++ b/ext/f2c_blas/Makefile.in @@ -1,8 +1,8 @@ #/bin/sh #/bin/sh # -# $Revision: 1.10 $ -# $Date: 2009/01/12 19:34:14 $ +# $Revision$ +# $Date$ # .SUFFIXES : diff --git a/ext/f2c_lapack/Makefile.in b/ext/f2c_lapack/Makefile.in index 732ad0f0d..4b0e77110 100755 --- a/ext/f2c_lapack/Makefile.in +++ b/ext/f2c_lapack/Makefile.in @@ -1,9 +1,9 @@ #/bin/sh # # $Source: /cvsroot/cantera/cantera/ext/f2c_lapack/Makefile.in,v $ -# $Author: hkmoffa $ -# $Revision: 1.9 $ -# $Date: 2009/01/12 19:34:14 $ +# $Author$ +# $Revision$ +# $Date$ # .SUFFIXES : @@ -64,9 +64,11 @@ dgetri.o \ dgetrs.o \ dlabad.o \ dlabrd.o \ +dlacon.o \ dlacpy.o \ dlamch.o \ dlange.o \ +dlantr.o \ dlapy2.o \ dlarf.o \ dlarfb.o \ @@ -87,6 +89,7 @@ dlasrt.o \ dlassq.o \ dlasv2.o \ dlaswp.o \ +dlatrs.o \ dorg2r.o \ dorgbr.o \ dorgl2.o \ @@ -97,9 +100,20 @@ dormbr.o \ dorml2.o \ dormlq.o \ dormqr.o \ +dpotf2.o \ +dpotrf.o \ +dpotrs.o \ drscl.o \ +dtrcon.o \ dtrtri.o \ dtrti2.o \ +dtrtrs.o \ +dgecon.o \ +dgeequ.o \ +dgerfs.o \ +dgbcon.o \ +dgbequ.o \ +dlatbs.o \ ieeeck.o \ ilaenv.o diff --git a/ext/f2c_lapack/dgbcon.c b/ext/f2c_lapack/dgbcon.c new file mode 100644 index 000000000..72083f759 --- /dev/null +++ b/ext/f2c_lapack/dgbcon.c @@ -0,0 +1,283 @@ +/* dgbcon.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; + +/* Subroutine */ int dgbcon_(char *norm, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, integer *ipiv, doublereal *anorm, + doublereal *rcond, doublereal *work, integer *iwork, integer *info, + ftnlen norm_len) +{ + /* System generated locals */ + integer ab_dim1, ab_offset, i__1, i__2, i__3; + doublereal d__1; + + /* Local variables */ + static integer j; + static doublereal t; + static integer kd, lm, jp, ix, kase; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static integer kase1; + static doublereal scale; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int drscl_(integer *, doublereal *, doublereal *, + integer *); + static logical lnoti; + extern /* Subroutine */ int daxpy_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + extern doublereal dlamch_(char *, ftnlen); + extern /* Subroutine */ int dlacon_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlatbs_(char *, char *, char *, char *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, integer *, ftnlen, ftnlen, ftnlen, + ftnlen), xerbla_(char *, integer *, ftnlen); + static doublereal ainvnm; + static logical onenrm; + static char normin[1]; + static doublereal smlnum; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* September 30, 1994 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DGBCON estimates the reciprocal of the condition number of a real */ +/* general band matrix A, in either the 1-norm or the infinity-norm, */ +/* using the LU factorization computed by DGBTRF. */ + +/* An estimate is obtained for norm(inv(A)), and the reciprocal of the */ +/* condition number is computed as */ +/* RCOND = 1 / ( norm(A) * norm(inv(A)) ). */ + +/* Arguments */ +/* ========= */ + +/* NORM (input) CHARACTER*1 */ +/* Specifies whether the 1-norm condition number or the */ +/* infinity-norm condition number is required: */ +/* = '1' or 'O': 1-norm; */ +/* = 'I': Infinity-norm. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* KL (input) INTEGER */ +/* The number of subdiagonals within the band of A. KL >= 0. */ + +/* KU (input) INTEGER */ +/* The number of superdiagonals within the band of A. KU >= 0. */ + +/* AB (input) DOUBLE PRECISION array, dimension (LDAB,N) */ +/* Details of the LU factorization of the band matrix A, as */ +/* computed by DGBTRF. U is stored as an upper triangular band */ +/* matrix with KL+KU superdiagonals in rows 1 to KL+KU+1, and */ +/* the multipliers used during the factorization are stored in */ +/* rows KL+KU+2 to 2*KL+KU+1. */ + +/* LDAB (input) INTEGER */ +/* The leading dimension of the array AB. LDAB >= 2*KL+KU+1. */ + +/* IPIV (input) INTEGER array, dimension (N) */ +/* The pivot indices; for 1 <= i <= N, row i of the matrix was */ +/* interchanged with row IPIV(i). */ + +/* ANORM (input) DOUBLE PRECISION */ +/* If NORM = '1' or 'O', the 1-norm of the original matrix A. */ +/* If NORM = 'I', the infinity-norm of the original matrix A. */ + +/* RCOND (output) DOUBLE PRECISION */ +/* The reciprocal of the condition number of the matrix A, */ +/* computed as RCOND = 1/(norm(A) * norm(inv(A))). */ + +/* WORK (workspace) DOUBLE PRECISION array, dimension (3*N) */ + +/* IWORK (workspace) INTEGER array, dimension (N) */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + ab_dim1 = *ldab; + ab_offset = 1 + ab_dim1; + ab -= ab_offset; + --ipiv; + --work; + --iwork; + + /* Function Body */ + *info = 0; + onenrm = *(unsigned char *)norm == '1' || lsame_(norm, "O", (ftnlen)1, ( + ftnlen)1); + if (! onenrm && ! lsame_(norm, "I", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*kl < 0) { + *info = -3; + } else if (*ku < 0) { + *info = -4; + } else if (*ldab < (*kl << 1) + *ku + 1) { + *info = -6; + } else if (*anorm < 0.) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGBCON", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + *rcond = 0.; + if (*n == 0) { + *rcond = 1.; + return 0; + } else if (*anorm == 0.) { + return 0; + } + + smlnum = dlamch_("Safe minimum", (ftnlen)12); + +/* Estimate the norm of inv(A). */ + + ainvnm = 0.; + *(unsigned char *)normin = 'N'; + if (onenrm) { + kase1 = 1; + } else { + kase1 = 2; + } + kd = *kl + *ku + 1; + lnoti = *kl > 0; + kase = 0; +L10: + dlacon_(n, &work[*n + 1], &work[1], &iwork[1], &ainvnm, &kase); + if (kase != 0) { + if (kase == kase1) { + +/* Multiply by inv(L). */ + + if (lnoti) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__2 = *kl, i__3 = *n - j; + lm = min(i__2,i__3); + jp = ipiv[j]; + t = work[jp]; + if (jp != j) { + work[jp] = work[j]; + work[j] = t; + } + d__1 = -t; + daxpy_(&lm, &d__1, &ab[kd + 1 + j * ab_dim1], &c__1, & + work[j + 1], &c__1); +/* L20: */ + } + } + +/* Multiply by inv(U). */ + + i__1 = *kl + *ku; + dlatbs_("Upper", "No transpose", "Non-unit", normin, n, &i__1, & + ab[ab_offset], ldab, &work[1], &scale, &work[(*n << 1) + + 1], info, (ftnlen)5, (ftnlen)12, (ftnlen)8, (ftnlen)1); + } else { + +/* Multiply by inv(U'). */ + + i__1 = *kl + *ku; + dlatbs_("Upper", "Transpose", "Non-unit", normin, n, &i__1, &ab[ + ab_offset], ldab, &work[1], &scale, &work[(*n << 1) + 1], + info, (ftnlen)5, (ftnlen)9, (ftnlen)8, (ftnlen)1); + +/* Multiply by inv(L'). */ + + if (lnoti) { + for (j = *n - 1; j >= 1; --j) { +/* Computing MIN */ + i__1 = *kl, i__2 = *n - j; + lm = min(i__1,i__2); + work[j] -= ddot_(&lm, &ab[kd + 1 + j * ab_dim1], &c__1, & + work[j + 1], &c__1); + jp = ipiv[j]; + if (jp != j) { + t = work[jp]; + work[jp] = work[j]; + work[j] = t; + } +/* L30: */ + } + } + } + +/* Divide X by 1/SCALE if doing so will not cause overflow. */ + + *(unsigned char *)normin = 'Y'; + if (scale != 1.) { + ix = idamax_(n, &work[1], &c__1); + if (scale < (d__1 = work[ix], abs(d__1)) * smlnum || scale == 0.) + { + goto L40; + } + drscl_(n, &scale, &work[1], &c__1); + } + goto L10; + } + +/* Compute the estimate of the reciprocal condition number. */ + + if (ainvnm != 0.) { + *rcond = 1. / ainvnm / *anorm; + } + +L40: + return 0; + +/* End of DGBCON */ + +} /* dgbcon_ */ + diff --git a/ext/f2c_lapack/dgbequ.c b/ext/f2c_lapack/dgbequ.c new file mode 100644 index 000000000..1c26aadfd --- /dev/null +++ b/ext/f2c_lapack/dgbequ.c @@ -0,0 +1,321 @@ +/* dgbequ.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" + +/* Subroutine */ int dgbequ_(integer *m, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, doublereal *r__, doublereal *c__, + doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer * + info) +{ + /* System generated locals */ + integer ab_dim1, ab_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j, kd; + static doublereal rcmin, rcmax; + extern doublereal dlamch_(char *, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + static doublereal bignum, smlnum; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* March 31, 1993 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DGBEQU computes row and column scalings intended to equilibrate an */ +/* M-by-N band matrix A and reduce its condition number. R returns the */ +/* row scale factors and C the column scale factors, chosen to try to */ +/* make the largest element in each row and column of the matrix B with */ +/* elements B(i,j)=R(i)*A(i,j)*C(j) have absolute value 1. */ + +/* R(i) and C(j) are restricted to be between SMLNUM = smallest safe */ +/* number and BIGNUM = largest safe number. Use of these scaling */ +/* factors is not guaranteed to reduce the condition number of A but */ +/* works well in practice. */ + +/* Arguments */ +/* ========= */ + +/* M (input) INTEGER */ +/* The number of rows of the matrix A. M >= 0. */ + +/* N (input) INTEGER */ +/* The number of columns of the matrix A. N >= 0. */ + +/* KL (input) INTEGER */ +/* The number of subdiagonals within the band of A. KL >= 0. */ + +/* KU (input) INTEGER */ +/* The number of superdiagonals within the band of A. KU >= 0. */ + +/* AB (input) DOUBLE PRECISION array, dimension (LDAB,N) */ +/* The band matrix A, stored in rows 1 to KL+KU+1. The j-th */ +/* column of A is stored in the j-th column of the array AB as */ +/* follows: */ +/* AB(ku+1+i-j,j) = A(i,j) for max(1,j-ku)<=i<=min(m,j+kl). */ + +/* LDAB (input) INTEGER */ +/* The leading dimension of the array AB. LDAB >= KL+KU+1. */ + +/* R (output) DOUBLE PRECISION array, dimension (M) */ +/* If INFO = 0, or INFO > M, R contains the row scale factors */ +/* for A. */ + +/* C (output) DOUBLE PRECISION array, dimension (N) */ +/* If INFO = 0, C contains the column scale factors for A. */ + +/* ROWCND (output) DOUBLE PRECISION */ +/* If INFO = 0 or INFO > M, ROWCND contains the ratio of the */ +/* smallest R(i) to the largest R(i). If ROWCND >= 0.1 and */ +/* AMAX is neither too large nor too small, it is not worth */ +/* scaling by R. */ + +/* COLCND (output) DOUBLE PRECISION */ +/* If INFO = 0, COLCND contains the ratio of the smallest */ +/* C(i) to the largest C(i). If COLCND >= 0.1, it is not */ +/* worth scaling by C. */ + +/* AMAX (output) DOUBLE PRECISION */ +/* Absolute value of largest matrix element. If AMAX is very */ +/* close to overflow or very close to underflow, the matrix */ +/* should be scaled. */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ +/* > 0: if INFO = i, and i is */ +/* <= M: the i-th row of A is exactly zero */ +/* > M: the (i-M)-th column of A is exactly zero */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters */ + + /* Parameter adjustments */ + ab_dim1 = *ldab; + ab_offset = 1 + ab_dim1; + ab -= ab_offset; + --r__; + --c__; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*kl < 0) { + *info = -3; + } else if (*ku < 0) { + *info = -4; + } else if (*ldab < *kl + *ku + 1) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGBEQU", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + *rowcnd = 1.; + *colcnd = 1.; + *amax = 0.; + return 0; + } + +/* Get machine constants. */ + + smlnum = dlamch_("S", (ftnlen)1); + bignum = 1. / smlnum; + +/* Compute row scale factors. */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + r__[i__] = 0.; +/* L10: */ + } + +/* Find the maximum element in each row. */ + + kd = *ku + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = j - *ku; +/* Computing MIN */ + i__4 = j + *kl; + i__3 = min(i__4,*m); + for (i__ = max(i__2,1); i__ <= i__3; ++i__) { +/* Computing MAX */ + d__2 = r__[i__], d__3 = (d__1 = ab[kd + i__ - j + j * ab_dim1], + abs(d__1)); + r__[i__] = max(d__2,d__3); +/* L20: */ + } +/* L30: */ + } + +/* Find the maximum and minimum scale factors. */ + + rcmin = bignum; + rcmax = 0.; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = rcmax, d__2 = r__[i__]; + rcmax = max(d__1,d__2); +/* Computing MIN */ + d__1 = rcmin, d__2 = r__[i__]; + rcmin = min(d__1,d__2); +/* L40: */ + } + *amax = rcmax; + + if (rcmin == 0.) { + +/* Find the first zero scale factor and return an error code. */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + if (r__[i__] == 0.) { + *info = i__; + return 0; + } +/* L50: */ + } + } else { + +/* Invert the scale factors. */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MIN */ +/* Computing MAX */ + d__2 = r__[i__]; + d__1 = max(d__2,smlnum); + r__[i__] = 1. / min(d__1,bignum); +/* L60: */ + } + +/* Compute ROWCND = min(R(I)) / max(R(I)) */ + + *rowcnd = max(rcmin,smlnum) / min(rcmax,bignum); + } + +/* Compute column scale factors */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + c__[j] = 0.; +/* L70: */ + } + +/* Find the maximum element in each column, */ +/* assuming the row scaling computed above. */ + + kd = *ku + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__3 = j - *ku; +/* Computing MIN */ + i__4 = j + *kl; + i__2 = min(i__4,*m); + for (i__ = max(i__3,1); i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = c__[j], d__3 = (d__1 = ab[kd + i__ - j + j * ab_dim1], abs( + d__1)) * r__[i__]; + c__[j] = max(d__2,d__3); +/* L80: */ + } +/* L90: */ + } + +/* Find the maximum and minimum scale factors. */ + + rcmin = bignum; + rcmax = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + d__1 = rcmin, d__2 = c__[j]; + rcmin = min(d__1,d__2); +/* Computing MAX */ + d__1 = rcmax, d__2 = c__[j]; + rcmax = max(d__1,d__2); +/* L100: */ + } + + if (rcmin == 0.) { + +/* Find the first zero scale factor and return an error code. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (c__[j] == 0.) { + *info = *m + j; + return 0; + } +/* L110: */ + } + } else { + +/* Invert the scale factors. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ +/* Computing MAX */ + d__2 = c__[j]; + d__1 = max(d__2,smlnum); + c__[j] = 1. / min(d__1,bignum); +/* L120: */ + } + +/* Compute COLCND = min(C(J)) / max(C(J)) */ + + *colcnd = max(rcmin,smlnum) / min(rcmax,bignum); + } + + return 0; + +/* End of DGBEQU */ + +} /* dgbequ_ */ + diff --git a/ext/f2c_lapack/dgecon.c b/ext/f2c_lapack/dgecon.c new file mode 100644 index 000000000..277e922af --- /dev/null +++ b/ext/f2c_lapack/dgecon.c @@ -0,0 +1,228 @@ +/* dgecon.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; + +/* Subroutine */ int dgecon_(char *norm, integer *n, doublereal *a, integer * + lda, doublereal *anorm, doublereal *rcond, doublereal *work, integer * + iwork, integer *info, ftnlen norm_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1; + doublereal d__1; + + /* Local variables */ + static doublereal sl; + static integer ix; + static doublereal su; + static integer kase, kase1; + static doublereal scale; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int drscl_(integer *, doublereal *, doublereal *, + integer *); + extern doublereal dlamch_(char *, ftnlen); + extern /* Subroutine */ int dlacon_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + static doublereal ainvnm; + extern /* Subroutine */ int dlatrs_(char *, char *, char *, char *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, integer *, ftnlen, ftnlen, ftnlen, ftnlen); + static logical onenrm; + static char normin[1]; + static doublereal smlnum; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* February 29, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DGECON estimates the reciprocal of the condition number of a general */ +/* real matrix A, in either the 1-norm or the infinity-norm, using */ +/* the LU factorization computed by DGETRF. */ + +/* An estimate is obtained for norm(inv(A)), and the reciprocal of the */ +/* condition number is computed as */ +/* RCOND = 1 / ( norm(A) * norm(inv(A)) ). */ + +/* Arguments */ +/* ========= */ + +/* NORM (input) CHARACTER*1 */ +/* Specifies whether the 1-norm condition number or the */ +/* infinity-norm condition number is required: */ +/* = '1' or 'O': 1-norm; */ +/* = 'I': Infinity-norm. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The factors L and U from the factorization A = P*L*U */ +/* as computed by DGETRF. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* ANORM (input) DOUBLE PRECISION */ +/* If NORM = '1' or 'O', the 1-norm of the original matrix A. */ +/* If NORM = 'I', the infinity-norm of the original matrix A. */ + +/* RCOND (output) DOUBLE PRECISION */ +/* The reciprocal of the condition number of the matrix A, */ +/* computed as RCOND = 1/(norm(A) * norm(inv(A))). */ + +/* WORK (workspace) DOUBLE PRECISION array, dimension (4*N) */ + +/* IWORK (workspace) INTEGER array, dimension (N) */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + onenrm = *(unsigned char *)norm == '1' || lsame_(norm, "O", (ftnlen)1, ( + ftnlen)1); + if (! onenrm && ! lsame_(norm, "I", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*anorm < 0.) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGECON", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + *rcond = 0.; + if (*n == 0) { + *rcond = 1.; + return 0; + } else if (*anorm == 0.) { + return 0; + } + + smlnum = dlamch_("Safe minimum", (ftnlen)12); + +/* Estimate the norm of inv(A). */ + + ainvnm = 0.; + *(unsigned char *)normin = 'N'; + if (onenrm) { + kase1 = 1; + } else { + kase1 = 2; + } + kase = 0; +L10: + dlacon_(n, &work[*n + 1], &work[1], &iwork[1], &ainvnm, &kase); + if (kase != 0) { + if (kase == kase1) { + +/* Multiply by inv(L). */ + + dlatrs_("Lower", "No transpose", "Unit", normin, n, &a[a_offset], + lda, &work[1], &sl, &work[(*n << 1) + 1], info, (ftnlen)5, + (ftnlen)12, (ftnlen)4, (ftnlen)1); + +/* Multiply by inv(U). */ + + dlatrs_("Upper", "No transpose", "Non-unit", normin, n, &a[ + a_offset], lda, &work[1], &su, &work[*n * 3 + 1], info, ( + ftnlen)5, (ftnlen)12, (ftnlen)8, (ftnlen)1); + } else { + +/* Multiply by inv(U'). */ + + dlatrs_("Upper", "Transpose", "Non-unit", normin, n, &a[a_offset], + lda, &work[1], &su, &work[*n * 3 + 1], info, (ftnlen)5, ( + ftnlen)9, (ftnlen)8, (ftnlen)1); + +/* Multiply by inv(L'). */ + + dlatrs_("Lower", "Transpose", "Unit", normin, n, &a[a_offset], + lda, &work[1], &sl, &work[(*n << 1) + 1], info, (ftnlen)5, + (ftnlen)9, (ftnlen)4, (ftnlen)1); + } + +/* Divide X by 1/(SL*SU) if doing so will not cause overflow. */ + + scale = sl * su; + *(unsigned char *)normin = 'Y'; + if (scale != 1.) { + ix = idamax_(n, &work[1], &c__1); + if (scale < (d__1 = work[ix], abs(d__1)) * smlnum || scale == 0.) + { + goto L20; + } + drscl_(n, &scale, &work[1], &c__1); + } + goto L10; + } + +/* Compute the estimate of the reciprocal condition number. */ + + if (ainvnm != 0.) { + *rcond = 1. / ainvnm / *anorm; + } + +L20: + return 0; + +/* End of DGECON */ + +} /* dgecon_ */ + diff --git a/ext/f2c_lapack/dgeequ.c b/ext/f2c_lapack/dgeequ.c new file mode 100644 index 000000000..125849ce7 --- /dev/null +++ b/ext/f2c_lapack/dgeequ.c @@ -0,0 +1,297 @@ +/* dgeequ.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" + +/* Subroutine */ int dgeequ_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal + *colcnd, doublereal *amax, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j; + static doublereal rcmin, rcmax; + extern doublereal dlamch_(char *, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + static doublereal bignum, smlnum; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* March 31, 1993 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DGEEQU computes row and column scalings intended to equilibrate an */ +/* M-by-N matrix A and reduce its condition number. R returns the row */ +/* scale factors and C the column scale factors, chosen to try to make */ +/* the largest element in each row and column of the matrix B with */ +/* elements B(i,j)=R(i)*A(i,j)*C(j) have absolute value 1. */ + +/* R(i) and C(j) are restricted to be between SMLNUM = smallest safe */ +/* number and BIGNUM = largest safe number. Use of these scaling */ +/* factors is not guaranteed to reduce the condition number of A but */ +/* works well in practice. */ + +/* Arguments */ +/* ========= */ + +/* M (input) INTEGER */ +/* The number of rows of the matrix A. M >= 0. */ + +/* N (input) INTEGER */ +/* The number of columns of the matrix A. N >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The M-by-N matrix whose equilibration factors are */ +/* to be computed. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,M). */ + +/* R (output) DOUBLE PRECISION array, dimension (M) */ +/* If INFO = 0 or INFO > M, R contains the row scale factors */ +/* for A. */ + +/* C (output) DOUBLE PRECISION array, dimension (N) */ +/* If INFO = 0, C contains the column scale factors for A. */ + +/* ROWCND (output) DOUBLE PRECISION */ +/* If INFO = 0 or INFO > M, ROWCND contains the ratio of the */ +/* smallest R(i) to the largest R(i). If ROWCND >= 0.1 and */ +/* AMAX is neither too large nor too small, it is not worth */ +/* scaling by R. */ + +/* COLCND (output) DOUBLE PRECISION */ +/* If INFO = 0, COLCND contains the ratio of the smallest */ +/* C(i) to the largest C(i). If COLCND >= 0.1, it is not */ +/* worth scaling by C. */ + +/* AMAX (output) DOUBLE PRECISION */ +/* Absolute value of largest matrix element. If AMAX is very */ +/* close to overflow or very close to underflow, the matrix */ +/* should be scaled. */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ +/* > 0: if INFO = i, and i is */ +/* <= M: the i-th row of A is exactly zero */ +/* > M: the (i-M)-th column of A is exactly zero */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --r__; + --c__; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEEQU", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + *rowcnd = 1.; + *colcnd = 1.; + *amax = 0.; + return 0; + } + +/* Get machine constants. */ + + smlnum = dlamch_("S", (ftnlen)1); + bignum = 1. / smlnum; + +/* Compute row scale factors. */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + r__[i__] = 0.; +/* L10: */ + } + +/* Find the maximum element in each row. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = r__[i__], d__3 = (d__1 = a[i__ + j * a_dim1], abs(d__1)); + r__[i__] = max(d__2,d__3); +/* L20: */ + } +/* L30: */ + } + +/* Find the maximum and minimum scale factors. */ + + rcmin = bignum; + rcmax = 0.; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = rcmax, d__2 = r__[i__]; + rcmax = max(d__1,d__2); +/* Computing MIN */ + d__1 = rcmin, d__2 = r__[i__]; + rcmin = min(d__1,d__2); +/* L40: */ + } + *amax = rcmax; + + if (rcmin == 0.) { + +/* Find the first zero scale factor and return an error code. */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + if (r__[i__] == 0.) { + *info = i__; + return 0; + } +/* L50: */ + } + } else { + +/* Invert the scale factors. */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MIN */ +/* Computing MAX */ + d__2 = r__[i__]; + d__1 = max(d__2,smlnum); + r__[i__] = 1. / min(d__1,bignum); +/* L60: */ + } + +/* Compute ROWCND = min(R(I)) / max(R(I)) */ + + *rowcnd = max(rcmin,smlnum) / min(rcmax,bignum); + } + +/* Compute column scale factors */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + c__[j] = 0.; +/* L70: */ + } + +/* Find the maximum element in each column, */ +/* assuming the row scaling computed above. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = c__[j], d__3 = (d__1 = a[i__ + j * a_dim1], abs(d__1)) * + r__[i__]; + c__[j] = max(d__2,d__3); +/* L80: */ + } +/* L90: */ + } + +/* Find the maximum and minimum scale factors. */ + + rcmin = bignum; + rcmax = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + d__1 = rcmin, d__2 = c__[j]; + rcmin = min(d__1,d__2); +/* Computing MAX */ + d__1 = rcmax, d__2 = c__[j]; + rcmax = max(d__1,d__2); +/* L100: */ + } + + if (rcmin == 0.) { + +/* Find the first zero scale factor and return an error code. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (c__[j] == 0.) { + *info = *m + j; + return 0; + } +/* L110: */ + } + } else { + +/* Invert the scale factors. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ +/* Computing MAX */ + d__2 = c__[j]; + d__1 = max(d__2,smlnum); + c__[j] = 1. / min(d__1,bignum); +/* L120: */ + } + +/* Compute COLCND = min(C(J)) / max(C(J)) */ + + *colcnd = max(rcmin,smlnum) / min(rcmax,bignum); + } + + return 0; + +/* End of DGEEQU */ + +} /* dgeequ_ */ + diff --git a/ext/f2c_lapack/dgerfs.c b/ext/f2c_lapack/dgerfs.c new file mode 100644 index 000000000..5dcebe627 --- /dev/null +++ b/ext/f2c_lapack/dgerfs.c @@ -0,0 +1,420 @@ +/* dgerfs.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 doublereal c_b15 = -1.; +static doublereal c_b17 = 1.; + +/* Subroutine */ int dgerfs_(char *trans, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer * + ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, + integer *info, ftnlen trans_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, af_dim1, af_offset, b_dim1, b_offset, x_dim1, + x_offset, i__1, i__2, i__3; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j, k; + static doublereal s, xk; + static integer nz; + static doublereal eps; + static integer kase; + static doublereal safe1, safe2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, ftnlen), dcopy_(integer *, + doublereal *, integer *, doublereal *, integer *), daxpy_(integer + *, doublereal *, doublereal *, integer *, doublereal *, integer *) + ; + static integer count; + extern doublereal dlamch_(char *, ftnlen); + extern /* Subroutine */ int dlacon_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + static doublereal safmin; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen), dgetrs_( + char *, integer *, integer *, doublereal *, integer *, integer *, + doublereal *, integer *, integer *, ftnlen); + static logical notran; + static char transt[1]; + static doublereal lstres; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* September 30, 1994 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DGERFS improves the computed solution to a system of linear */ +/* equations and provides error bounds and backward error estimates for */ +/* the solution. */ + +/* Arguments */ +/* ========= */ + +/* TRANS (input) CHARACTER*1 */ +/* Specifies the form of the system of equations: */ +/* = 'N': A * X = B (No transpose) */ +/* = 'T': A**T * X = B (Transpose) */ +/* = 'C': A**H * X = B (Conjugate transpose = Transpose) */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* NRHS (input) INTEGER */ +/* The number of right hand sides, i.e., the number of columns */ +/* of the matrices B and X. NRHS >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The original N-by-N matrix A. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* AF (input) DOUBLE PRECISION array, dimension (LDAF,N) */ +/* The factors L and U from the factorization A = P*L*U */ +/* as computed by DGETRF. */ + +/* LDAF (input) INTEGER */ +/* The leading dimension of the array AF. LDAF >= max(1,N). */ + +/* IPIV (input) INTEGER array, dimension (N) */ +/* The pivot indices from DGETRF; for 1<=i<=N, row i of the */ +/* matrix was interchanged with row IPIV(i). */ + +/* B (input) DOUBLE PRECISION array, dimension (LDB,NRHS) */ +/* The right hand side matrix B. */ + +/* LDB (input) INTEGER */ +/* The leading dimension of the array B. LDB >= max(1,N). */ + +/* X (input/output) DOUBLE PRECISION array, dimension (LDX,NRHS) */ +/* On entry, the solution matrix X, as computed by DGETRS. */ +/* On exit, the improved solution matrix X. */ + +/* LDX (input) INTEGER */ +/* The leading dimension of the array X. LDX >= max(1,N). */ + +/* FERR (output) DOUBLE PRECISION array, dimension (NRHS) */ +/* The estimated forward error bound for each solution vector */ +/* X(j) (the j-th column of the solution matrix X). */ +/* If XTRUE is the true solution corresponding to X(j), FERR(j) */ +/* is an estimated upper bound for the magnitude of the largest */ +/* element in (X(j) - XTRUE) divided by the magnitude of the */ +/* largest element in X(j). The estimate is as reliable as */ +/* the estimate for RCOND, and is almost always a slight */ +/* overestimate of the true error. */ + +/* BERR (output) DOUBLE PRECISION array, dimension (NRHS) */ +/* The componentwise relative backward error of each solution */ +/* vector X(j) (i.e., the smallest relative change in */ +/* any element of A or B that makes X(j) an exact solution). */ + +/* WORK (workspace) DOUBLE PRECISION array, dimension (3*N) */ + +/* IWORK (workspace) INTEGER array, dimension (N) */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ + +/* Internal Parameters */ +/* =================== */ + +/* ITMAX is the maximum number of steps of iterative refinement. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + af_dim1 = *ldaf; + af_offset = 1 + af_dim1; + af -= af_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + --ferr; + --berr; + --work; + --iwork; + + /* Function Body */ + *info = 0; + notran = lsame_(trans, "N", (ftnlen)1, (ftnlen)1); + if (! notran && ! lsame_(trans, "T", (ftnlen)1, (ftnlen)1) && ! lsame_( + trans, "C", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldaf < max(1,*n)) { + *info = -7; + } else if (*ldb < max(1,*n)) { + *info = -10; + } else if (*ldx < max(1,*n)) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGERFS", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + i__1 = *nrhs; + for (j = 1; j <= i__1; ++j) { + ferr[j] = 0.; + berr[j] = 0.; +/* L10: */ + } + return 0; + } + + if (notran) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + +/* NZ = maximum number of nonzero elements in each row of A, plus 1 */ + + nz = *n + 1; + eps = dlamch_("Epsilon", (ftnlen)7); + safmin = dlamch_("Safe minimum", (ftnlen)12); + safe1 = nz * safmin; + safe2 = safe1 / eps; + +/* Do for each right hand side */ + + i__1 = *nrhs; + for (j = 1; j <= i__1; ++j) { + + count = 1; + lstres = 3.; +L20: + +/* Loop until stopping criterion is satisfied. */ + +/* Compute residual R = B - op(A) * X, */ +/* where op(A) = A, A**T, or A**H, depending on TRANS. */ + + dcopy_(n, &b[j * b_dim1 + 1], &c__1, &work[*n + 1], &c__1); + dgemv_(trans, n, n, &c_b15, &a[a_offset], lda, &x[j * x_dim1 + 1], & + c__1, &c_b17, &work[*n + 1], &c__1, (ftnlen)1); + +/* Compute componentwise relative backward error from formula */ + +/* max(i) ( abs(R(i)) / ( abs(op(A))*abs(X) + abs(B) )(i) ) */ + +/* where abs(Z) is the componentwise absolute value of the matrix */ +/* or vector Z. If the i-th component of the denominator is less */ +/* than SAFE2, then SAFE1 is added to the i-th components of the */ +/* numerator and denominator before dividing. */ + + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] = (d__1 = b[i__ + j * b_dim1], abs(d__1)); +/* L30: */ + } + +/* Compute abs(op(A))*abs(X) + abs(B). */ + + if (notran) { + i__2 = *n; + for (k = 1; k <= i__2; ++k) { + xk = (d__1 = x[k + j * x_dim1], abs(d__1)); + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + work[i__] += (d__1 = a[i__ + k * a_dim1], abs(d__1)) * xk; +/* L40: */ + } +/* L50: */ + } + } else { + i__2 = *n; + for (k = 1; k <= i__2; ++k) { + s = 0.; + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + s += (d__1 = a[i__ + k * a_dim1], abs(d__1)) * (d__2 = x[ + i__ + j * x_dim1], abs(d__2)); +/* L60: */ + } + work[k] += s; +/* L70: */ + } + } + s = 0.; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + if (work[i__] > safe2) { +/* Computing MAX */ + d__2 = s, d__3 = (d__1 = work[*n + i__], abs(d__1)) / work[ + i__]; + s = max(d__2,d__3); + } else { +/* Computing MAX */ + d__2 = s, d__3 = ((d__1 = work[*n + i__], abs(d__1)) + safe1) + / (work[i__] + safe1); + s = max(d__2,d__3); + } +/* L80: */ + } + berr[j] = s; + +/* Test stopping criterion. Continue iterating if */ +/* 1) The residual BERR(J) is larger than machine epsilon, and */ +/* 2) BERR(J) decreased by at least a factor of 2 during the */ +/* last iteration, and */ +/* 3) At most ITMAX iterations tried. */ + + if (berr[j] > eps && berr[j] * 2. <= lstres && count <= 5) { + +/* Update solution and try again. */ + + dgetrs_(trans, n, &c__1, &af[af_offset], ldaf, &ipiv[1], &work[*n + + 1], n, info, (ftnlen)1); + daxpy_(n, &c_b17, &work[*n + 1], &c__1, &x[j * x_dim1 + 1], &c__1) + ; + lstres = berr[j]; + ++count; + goto L20; + } + +/* Bound error from formula */ + +/* norm(X - XTRUE) / norm(X) .le. FERR = */ +/* norm( abs(inv(op(A)))* */ +/* ( abs(R) + NZ*EPS*( abs(op(A))*abs(X)+abs(B) ))) / norm(X) */ + +/* where */ +/* norm(Z) is the magnitude of the largest component of Z */ +/* inv(op(A)) is the inverse of op(A) */ +/* abs(Z) is the componentwise absolute value of the matrix or */ +/* vector Z */ +/* NZ is the maximum number of nonzeros in any row of A, plus 1 */ +/* EPS is machine epsilon */ + +/* The i-th component of abs(R)+NZ*EPS*(abs(op(A))*abs(X)+abs(B)) */ +/* is incremented by SAFE1 if the i-th component of */ +/* abs(op(A))*abs(X) + abs(B) is less than SAFE2. */ + +/* Use DLACON to estimate the infinity-norm of the matrix */ +/* inv(op(A)) * diag(W), */ +/* where W = abs(R) + NZ*EPS*( abs(op(A))*abs(X)+abs(B) ))) */ + + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + if (work[i__] > safe2) { + work[i__] = (d__1 = work[*n + i__], abs(d__1)) + nz * eps * + work[i__]; + } else { + work[i__] = (d__1 = work[*n + i__], abs(d__1)) + nz * eps * + work[i__] + safe1; + } +/* L90: */ + } + + kase = 0; +L100: + dlacon_(n, &work[(*n << 1) + 1], &work[*n + 1], &iwork[1], &ferr[j], & + kase); + if (kase != 0) { + if (kase == 1) { + +/* Multiply by diag(W)*inv(op(A)**T). */ + + dgetrs_(transt, n, &c__1, &af[af_offset], ldaf, &ipiv[1], & + work[*n + 1], n, info, (ftnlen)1); + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + work[*n + i__] = work[i__] * work[*n + i__]; +/* L110: */ + } + } else { + +/* Multiply by inv(op(A))*diag(W). */ + + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + work[*n + i__] = work[i__] * work[*n + i__]; +/* L120: */ + } + dgetrs_(trans, n, &c__1, &af[af_offset], ldaf, &ipiv[1], & + work[*n + 1], n, info, (ftnlen)1); + } + goto L100; + } + +/* Normalize error. */ + + lstres = 0.; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = lstres, d__3 = (d__1 = x[i__ + j * x_dim1], abs(d__1)); + lstres = max(d__2,d__3); +/* L130: */ + } + if (lstres != 0.) { + ferr[j] /= lstres; + } + +/* L140: */ + } + + return 0; + +/* End of DGERFS */ + +} /* dgerfs_ */ + diff --git a/ext/f2c_lapack/dlacon.c b/ext/f2c_lapack/dlacon.c new file mode 100644 index 000000000..2bc7054ab --- /dev/null +++ b/ext/f2c_lapack/dlacon.c @@ -0,0 +1,257 @@ +/* dlacon.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 doublereal c_b11 = 1.; + +/* Subroutine */ int dlacon_(integer *n, doublereal *v, doublereal *x, + integer *isgn, doublereal *est, integer *kase) +{ + /* System generated locals */ + integer i__1; + doublereal d__1; + + /* Builtin functions */ + double d_sign(doublereal *, doublereal *); + integer i_dnnt(doublereal *); + + /* Local variables */ + static integer i__, j, iter; + static doublereal temp; + static integer jump; + extern doublereal dasum_(integer *, doublereal *, integer *); + static integer jlast; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + extern integer idamax_(integer *, doublereal *, integer *); + static doublereal altsgn, estold; + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* February 29, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DLACON estimates the 1-norm of a square, real matrix A. */ +/* Reverse communication is used for evaluating matrix-vector products. */ + +/* Arguments */ +/* ========= */ + +/* N (input) INTEGER */ +/* The order of the matrix. N >= 1. */ + +/* V (workspace) DOUBLE PRECISION array, dimension (N) */ +/* On the final return, V = A*W, where EST = norm(V)/norm(W) */ +/* (W is not returned). */ + +/* X (input/output) DOUBLE PRECISION array, dimension (N) */ +/* On an intermediate return, X should be overwritten by */ +/* A * X, if KASE=1, */ +/* A' * X, if KASE=2, */ +/* and DLACON must be re-called with all the other parameters */ +/* unchanged. */ + +/* ISGN (workspace) INTEGER array, dimension (N) */ + +/* EST (output) DOUBLE PRECISION */ +/* An estimate (a lower bound) for norm(A). */ + +/* KASE (input/output) INTEGER */ +/* On the initial call to DLACON, KASE should be 0. */ +/* On an intermediate return, KASE will be 1 or 2, indicating */ +/* whether X should be overwritten by A * X or A' * X. */ +/* On the final return from DLACON, KASE will again be 0. */ + +/* Further Details */ +/* ======= ======= */ + +/* Contributed by Nick Higham, University of Manchester. */ +/* Originally named SONEST, dated March 16, 1988. */ + +/* Reference: N.J. Higham, "FORTRAN codes for estimating the one-norm of */ +/* a real or complex matrix, with applications to condition estimation", */ +/* ACM Trans. Math. Soft., vol. 14, no. 4, pp. 381-396, December 1988. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Save statement .. */ +/* .. */ +/* .. Executable Statements .. */ + + /* Parameter adjustments */ + --isgn; + --x; + --v; + + /* Function Body */ + if (*kase == 0) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + x[i__] = 1. / (doublereal) (*n); +/* L10: */ + } + *kase = 1; + jump = 1; + return 0; + } + + switch (jump) { + case 1: goto L20; + case 2: goto L40; + case 3: goto L70; + case 4: goto L110; + case 5: goto L140; + } + +/* ................ ENTRY (JUMP = 1) */ +/* FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. */ + +L20: + if (*n == 1) { + v[1] = x[1]; + *est = abs(v[1]); +/* ... QUIT */ + goto L150; + } + *est = dasum_(n, &x[1], &c__1); + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + x[i__] = d_sign(&c_b11, &x[i__]); + isgn[i__] = i_dnnt(&x[i__]); +/* L30: */ + } + *kase = 2; + jump = 2; + return 0; + +/* ................ ENTRY (JUMP = 2) */ +/* FIRST ITERATION. X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. */ + +L40: + j = idamax_(n, &x[1], &c__1); + iter = 2; + +/* MAIN LOOP - ITERATIONS 2,3,...,ITMAX. */ + +L50: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + x[i__] = 0.; +/* L60: */ + } + x[j] = 1.; + *kase = 1; + jump = 3; + return 0; + +/* ................ ENTRY (JUMP = 3) */ +/* X HAS BEEN OVERWRITTEN BY A*X. */ + +L70: + dcopy_(n, &x[1], &c__1, &v[1], &c__1); + estold = *est; + *est = dasum_(n, &v[1], &c__1); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__1 = d_sign(&c_b11, &x[i__]); + if (i_dnnt(&d__1) != isgn[i__]) { + goto L90; + } +/* L80: */ + } +/* REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. */ + goto L120; + +L90: +/* TEST FOR CYCLING. */ + if (*est <= estold) { + goto L120; + } + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + x[i__] = d_sign(&c_b11, &x[i__]); + isgn[i__] = i_dnnt(&x[i__]); +/* L100: */ + } + *kase = 2; + jump = 4; + return 0; + +/* ................ ENTRY (JUMP = 4) */ +/* X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. */ + +L110: + jlast = j; + j = idamax_(n, &x[1], &c__1); + if (x[jlast] != (d__1 = x[j], abs(d__1)) && iter < 5) { + ++iter; + goto L50; + } + +/* ITERATION COMPLETE. FINAL STAGE. */ + +L120: + altsgn = 1.; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + x[i__] = altsgn * ((doublereal) (i__ - 1) / (doublereal) (*n - 1) + + 1.); + altsgn = -altsgn; +/* L130: */ + } + *kase = 1; + jump = 5; + return 0; + +/* ................ ENTRY (JUMP = 5) */ +/* X HAS BEEN OVERWRITTEN BY A*X. */ + +L140: + temp = dasum_(n, &x[1], &c__1) / (doublereal) (*n * 3) * 2.; + if (temp > *est) { + dcopy_(n, &x[1], &c__1, &v[1], &c__1); + *est = temp; + } + +L150: + *kase = 0; + return 0; + +/* End of DLACON */ + +} /* dlacon_ */ + diff --git a/ext/f2c_lapack/dlantr.c b/ext/f2c_lapack/dlantr.c new file mode 100644 index 000000000..17a0e0724 --- /dev/null +++ b/ext/f2c_lapack/dlantr.c @@ -0,0 +1,401 @@ +/* dlantr.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; + +doublereal dlantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, + doublereal *a, integer *lda, doublereal *work, ftnlen norm_len, + ftnlen uplo_len, ftnlen diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + doublereal ret_val, d__1, d__2, d__3; + + /* Builtin functions */ + double sqrt(doublereal); + + /* Local variables */ + static integer i__, j; + static doublereal sum, scale; + static logical udiag; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + static doublereal value; + extern /* Subroutine */ int dlassq_(integer *, doublereal *, integer *, + doublereal *, doublereal *); + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DLANTR returns the value of the one norm, or the Frobenius norm, or */ +/* the infinity norm, or the element of largest absolute value of a */ +/* trapezoidal or triangular matrix A. */ + +/* Description */ +/* =========== */ + +/* DLANTR returns the value */ + +/* DLANTR = ( max(abs(A(i,j))), NORM = 'M' or 'm' */ +/* ( */ +/* ( norm1(A), NORM = '1', 'O' or 'o' */ +/* ( */ +/* ( normI(A), NORM = 'I' or 'i' */ +/* ( */ +/* ( normF(A), NORM = 'F', 'f', 'E' or 'e' */ + +/* where norm1 denotes the one norm of a matrix (maximum column sum), */ +/* normI denotes the infinity norm of a matrix (maximum row sum) and */ +/* normF denotes the Frobenius norm of a matrix (square root of sum of */ +/* squares). Note that max(abs(A(i,j))) is not a matrix norm. */ + +/* Arguments */ +/* ========= */ + +/* NORM (input) CHARACTER*1 */ +/* Specifies the value to be returned in DLANTR as described */ +/* above. */ + +/* UPLO (input) CHARACTER*1 */ +/* Specifies whether the matrix A is upper or lower trapezoidal. */ +/* = 'U': Upper trapezoidal */ +/* = 'L': Lower trapezoidal */ +/* Note that A is triangular instead of trapezoidal if M = N. */ + +/* DIAG (input) CHARACTER*1 */ +/* Specifies whether or not the matrix A has unit diagonal. */ +/* = 'N': Non-unit diagonal */ +/* = 'U': Unit diagonal */ + +/* M (input) INTEGER */ +/* The number of rows of the matrix A. M >= 0, and if */ +/* UPLO = 'U', M <= N. When M = 0, DLANTR is set to zero. */ + +/* N (input) INTEGER */ +/* The number of columns of the matrix A. N >= 0, and if */ +/* UPLO = 'L', N <= M. When N = 0, DLANTR is set to zero. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The trapezoidal matrix A (A is triangular if M = N). */ +/* If UPLO = 'U', the leading m by n upper trapezoidal part of */ +/* the array A contains the upper trapezoidal matrix, and the */ +/* strictly lower triangular part of A is not referenced. */ +/* If UPLO = 'L', the leading m by n lower trapezoidal part of */ +/* the array A contains the lower trapezoidal matrix, and the */ +/* strictly upper triangular part of A is not referenced. Note */ +/* that when DIAG = 'U', the diagonal elements of A are not */ +/* referenced and are assumed to be one. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(M,1). */ + +/* WORK (workspace) DOUBLE PRECISION array, dimension (LWORK), */ +/* where LWORK >= M when NORM = 'I'; otherwise, WORK is not */ +/* referenced. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (min(*m,*n) == 0) { + value = 0.; + } else if (lsame_(norm, "M", (ftnlen)1, (ftnlen)1)) { + +/* Find max(abs(A(i,j))). */ + + if (lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + value = 1.; + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = *m, i__4 = j - 1; + i__2 = min(i__3,i__4); + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs( + d__1)); + value = max(d__2,d__3); +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs( + d__1)); + value = max(d__2,d__3); +/* L30: */ + } +/* L40: */ + } + } + } else { + value = 0.; + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(*m,j); + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs( + d__1)); + value = max(d__2,d__3); +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs( + d__1)); + value = max(d__2,d__3); +/* L70: */ + } +/* L80: */ + } + } + } + } else if (lsame_(norm, "O", (ftnlen)1, (ftnlen)1) || *(unsigned char *) + norm == '1') { + +/* Find norm1(A). */ + + value = 0.; + udiag = lsame_(diag, "U", (ftnlen)1, (ftnlen)1); + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (udiag && j <= *m) { + sum = 1.; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + sum += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L90: */ + } + } else { + sum = 0.; + i__2 = min(*m,j); + for (i__ = 1; i__ <= i__2; ++i__) { + sum += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L100: */ + } + } + value = max(value,sum); +/* L110: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (udiag) { + sum = 1.; + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { + sum += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L120: */ + } + } else { + sum = 0.; + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + sum += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L130: */ + } + } + value = max(value,sum); +/* L140: */ + } + } + } else if (lsame_(norm, "I", (ftnlen)1, (ftnlen)1)) { + +/* Find normI(A). */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + if (lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 1.; +/* L150: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = *m, i__4 = j - 1; + i__2 = min(i__3,i__4); + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L160: */ + } +/* L170: */ + } + } else { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L180: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(*m,j); + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L190: */ + } +/* L200: */ + } + } + } else { + if (lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 1.; +/* L210: */ + } + i__1 = *m; + for (i__ = *n + 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L220: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { + work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L230: */ + } +/* L240: */ + } + } else { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L250: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L260: */ + } +/* L270: */ + } + } + } + value = 0.; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = work[i__]; + value = max(d__1,d__2); +/* L280: */ + } + } else if (lsame_(norm, "F", (ftnlen)1, (ftnlen)1) || lsame_(norm, "E", ( + ftnlen)1, (ftnlen)1)) { + +/* Find normF(A). */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + if (lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + scale = 1.; + sum = (doublereal) min(*m,*n); + i__1 = *n; + for (j = 2; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = *m, i__4 = j - 1; + i__2 = min(i__3,i__4); + dlassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L290: */ + } + } else { + scale = 0.; + sum = 1.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(*m,j); + dlassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L300: */ + } + } + } else { + if (lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + scale = 1.; + sum = (doublereal) min(*m,*n); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m - j; +/* Computing MIN */ + i__3 = *m, i__4 = j + 1; + dlassq_(&i__2, &a[min(i__3,i__4) + j * a_dim1], &c__1, & + scale, &sum); +/* L310: */ + } + } else { + scale = 0.; + sum = 1.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m - j + 1; + dlassq_(&i__2, &a[j + j * a_dim1], &c__1, &scale, &sum); +/* L320: */ + } + } + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of DLANTR */ + +} /* dlantr_ */ + diff --git a/ext/f2c_lapack/dlatbs.c b/ext/f2c_lapack/dlatbs.c new file mode 100644 index 000000000..eaea649f4 --- /dev/null +++ b/ext/f2c_lapack/dlatbs.c @@ -0,0 +1,855 @@ +/* dlatbs.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 doublereal c_b36 = .5; + +/* Subroutine */ int dlatbs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, integer *kd, doublereal *ab, integer *ldab, + doublereal *x, doublereal *scale, doublereal *cnorm, integer *info, + ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len, ftnlen normin_len) +{ + /* System generated locals */ + integer ab_dim1, ab_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j; + static doublereal xj, rec, tjj; + static integer jinc, jlen; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static doublereal xbnd; + static integer imax; + static doublereal tmax, tjjs, xmax, grow, sumj; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + static integer maind; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + static doublereal tscal, uscal; + extern doublereal dasum_(integer *, doublereal *, integer *); + static integer jlast; + extern /* Subroutine */ int dtbsv_(char *, char *, char *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *, + ftnlen, ftnlen, ftnlen), daxpy_(integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *); + static logical upper; + extern doublereal dlamch_(char *, ftnlen); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + static doublereal bignum; + static logical notran; + static integer jfirst; + static doublereal smlnum; + static logical nounit; + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* June 30, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DLATBS solves one of the triangular systems */ + +/* A *x = s*b or A'*x = s*b */ + +/* with scaling to prevent overflow, where A is an upper or lower */ +/* triangular band matrix. Here A' denotes the transpose of A, x and b */ +/* are n-element vectors, and s is a scaling factor, usually less than */ +/* or equal to 1, chosen so that the components of x will be less than */ +/* the overflow threshold. If the unscaled problem will not cause */ +/* overflow, the Level 2 BLAS routine DTBSV is called. If the matrix A */ +/* is singular (A(j,j) = 0 for some j), then s is set to 0 and a */ +/* non-trivial solution to A*x = 0 is returned. */ + +/* Arguments */ +/* ========= */ + +/* UPLO (input) CHARACTER*1 */ +/* Specifies whether the matrix A is upper or lower triangular. */ +/* = 'U': Upper triangular */ +/* = 'L': Lower triangular */ + +/* TRANS (input) CHARACTER*1 */ +/* Specifies the operation applied to A. */ +/* = 'N': Solve A * x = s*b (No transpose) */ +/* = 'T': Solve A'* x = s*b (Transpose) */ +/* = 'C': Solve A'* x = s*b (Conjugate transpose = Transpose) */ + +/* DIAG (input) CHARACTER*1 */ +/* Specifies whether or not the matrix A is unit triangular. */ +/* = 'N': Non-unit triangular */ +/* = 'U': Unit triangular */ + +/* NORMIN (input) CHARACTER*1 */ +/* Specifies whether CNORM has been set or not. */ +/* = 'Y': CNORM contains the column norms on entry */ +/* = 'N': CNORM is not set on entry. On exit, the norms will */ +/* be computed and stored in CNORM. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* KD (input) INTEGER */ +/* The number of subdiagonals or superdiagonals in the */ +/* triangular matrix A. KD >= 0. */ + +/* AB (input) DOUBLE PRECISION array, dimension (LDAB,N) */ +/* The upper or lower triangular band matrix A, stored in the */ +/* first KD+1 rows of the array. The j-th column of A is stored */ +/* in the j-th column of the array AB as follows: */ +/* if UPLO = 'U', AB(kd+1+i-j,j) = A(i,j) for max(1,j-kd)<=i<=j; */ +/* if UPLO = 'L', AB(1+i-j,j) = A(i,j) for j<=i<=min(n,j+kd). */ + +/* LDAB (input) INTEGER */ +/* The leading dimension of the array AB. LDAB >= KD+1. */ + +/* X (input/output) DOUBLE PRECISION array, dimension (N) */ +/* On entry, the right hand side b of the triangular system. */ +/* On exit, X is overwritten by the solution vector x. */ + +/* SCALE (output) DOUBLE PRECISION */ +/* The scaling factor s for the triangular system */ +/* A * x = s*b or A'* x = s*b. */ +/* If SCALE = 0, the matrix A is singular or badly scaled, and */ +/* the vector x is an exact or approximate solution to A*x = 0. */ + +/* CNORM (input or output) DOUBLE PRECISION array, dimension (N) */ + +/* If NORMIN = 'Y', CNORM is an input argument and CNORM(j) */ +/* contains the norm of the off-diagonal part of the j-th column */ +/* of A. If TRANS = 'N', CNORM(j) must be greater than or equal */ +/* to the infinity-norm, and if TRANS = 'T' or 'C', CNORM(j) */ +/* must be greater than or equal to the 1-norm. */ + +/* If NORMIN = 'N', CNORM is an output argument and CNORM(j) */ +/* returns the 1-norm of the offdiagonal part of the j-th column */ +/* of A. */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -k, the k-th argument had an illegal value */ + +/* Further Details */ +/* ======= ======= */ + +/* A rough bound on x is computed; if that is less than overflow, DTBSV */ +/* is called, otherwise, specific code is used which checks for possible */ +/* overflow or divide-by-zero at every operation. */ + +/* A columnwise scheme is used for solving A*x = b. The basic algorithm */ +/* if A is lower triangular is */ + +/* x[1:n] := b[1:n] */ +/* for j = 1, ..., n */ +/* x(j) := x(j) / A(j,j) */ +/* x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] */ +/* end */ + +/* Define bounds on the components of x after j iterations of the loop: */ +/* M(j) = bound on x[1:j] */ +/* G(j) = bound on x[j+1:n] */ +/* Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. */ + +/* Then for iteration j+1 we have */ +/* M(j+1) <= G(j) / | A(j+1,j+1) | */ +/* G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | */ +/* <= G(j) ( 1 + CNORM(j+1) / | A(j+1,j+1) | ) */ + +/* where CNORM(j+1) is greater than or equal to the infinity-norm of */ +/* column j+1 of A, not counting the diagonal. Hence */ + +/* G(j) <= G(0) product ( 1 + CNORM(i) / | A(i,i) | ) */ +/* 1<=i<=j */ +/* and */ + +/* |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + CNORM(i) / |A(i,i)| ) */ +/* 1<=i< j */ + +/* Since |x(j)| <= M(j), we use the Level 2 BLAS routine DTBSV if the */ +/* reciprocal of the largest M(j), j=1,..,n, is larger than */ +/* max(underflow, 1/overflow). */ + +/* The bound on x(j) is also used to determine when a step in the */ +/* columnwise method can be performed without fear of overflow. If */ +/* the computed bound is greater than a large constant, x is scaled to */ +/* prevent overflow, but if the bound overflows, x is set to 0, x(j) to */ +/* 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. */ + +/* Similarly, a row-wise scheme is used to solve A'*x = b. The basic */ +/* algorithm for A upper triangular is */ + +/* for j = 1, ..., n */ +/* x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) */ +/* end */ + +/* We simultaneously compute two bounds */ +/* G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j */ +/* M(j) = bound on x(i), 1<=i<=j */ + +/* The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we */ +/* add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. */ +/* Then the bound on x(j) is */ + +/* M(j) <= M(j-1) * ( 1 + CNORM(j) ) / | A(j,j) | */ + +/* <= M(0) * product ( ( 1 + CNORM(i) ) / |A(i,i)| ) */ +/* 1<=i<=j */ + +/* and we can safely call DTBSV if 1/M(n) and 1/G(n) are both greater */ +/* than max(underflow, 1/overflow). */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + + /* Parameter adjustments */ + ab_dim1 = *ldab; + ab_offset = 1 + ab_dim1; + ab -= ab_offset; + --x; + --cnorm; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1); + notran = lsame_(trans, "N", (ftnlen)1, (ftnlen)1); + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + +/* Test the input parameters. */ + + if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T", (ftnlen)1, (ftnlen)1) && ! + lsame_(trans, "C", (ftnlen)1, (ftnlen)1)) { + *info = -2; + } else if (! nounit && ! lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + *info = -3; + } else if (! lsame_(normin, "Y", (ftnlen)1, (ftnlen)1) && ! lsame_(normin, + "N", (ftnlen)1, (ftnlen)1)) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*kd < 0) { + *info = -6; + } else if (*ldab < *kd + 1) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLATBS", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine machine dependent parameters to control overflow. */ + + smlnum = dlamch_("Safe minimum", (ftnlen)12) / dlamch_("Precision", ( + ftnlen)9); + bignum = 1. / smlnum; + *scale = 1.; + + if (lsame_(normin, "N", (ftnlen)1, (ftnlen)1)) { + +/* Compute the 1-norm of each column, not including the diagonal. */ + + if (upper) { + +/* A is upper triangular. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__2 = *kd, i__3 = j - 1; + jlen = min(i__2,i__3); + cnorm[j] = dasum_(&jlen, &ab[*kd + 1 - jlen + j * ab_dim1], & + c__1); +/* L10: */ + } + } else { + +/* A is lower triangular. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__2 = *kd, i__3 = *n - j; + jlen = min(i__2,i__3); + if (jlen > 0) { + cnorm[j] = dasum_(&jlen, &ab[j * ab_dim1 + 2], &c__1); + } else { + cnorm[j] = 0.; + } +/* L20: */ + } + } + } + +/* Scale the column norms by TSCAL if the maximum element in CNORM is */ +/* greater than BIGNUM. */ + + imax = idamax_(n, &cnorm[1], &c__1); + tmax = cnorm[imax]; + if (tmax <= bignum) { + tscal = 1.; + } else { + tscal = 1. / (smlnum * tmax); + dscal_(n, &tscal, &cnorm[1], &c__1); + } + +/* Compute a bound on the computed solution vector to see if the */ +/* Level 2 BLAS routine DTBSV can be used. */ + + j = idamax_(n, &x[1], &c__1); + xmax = (d__1 = x[j], abs(d__1)); + xbnd = xmax; + if (notran) { + +/* Compute the growth in A * x = b. */ + + if (upper) { + jfirst = *n; + jlast = 1; + jinc = -1; + maind = *kd + 1; + } else { + jfirst = 1; + jlast = *n; + jinc = 1; + maind = 1; + } + + if (tscal != 1.) { + grow = 0.; + goto L50; + } + + if (nounit) { + +/* A is non-unit triangular. */ + +/* Compute GROW = 1/G(j) and XBND = 1/M(j). */ +/* Initially, G(0) = max{x(i), i=1,...,n}. */ + + grow = 1. / max(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L50; + } + +/* M(j) = G(j-1) / abs(A(j,j)) */ + + tjj = (d__1 = ab[maind + j * ab_dim1], abs(d__1)); +/* Computing MIN */ + d__1 = xbnd, d__2 = min(1.,tjj) * grow; + xbnd = min(d__1,d__2); + if (tjj + cnorm[j] >= smlnum) { + +/* G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) */ + + grow *= tjj / (tjj + cnorm[j]); + } else { + +/* G(j) could overflow, set GROW to 0. */ + + grow = 0.; + } +/* L30: */ + } + grow = xbnd; + } else { + +/* A is unit triangular. */ + +/* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. */ + +/* Computing MIN */ + d__1 = 1., d__2 = 1. / max(xbnd,smlnum); + grow = min(d__1,d__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L50; + } + +/* G(j) = G(j-1)*( 1 + CNORM(j) ) */ + + grow *= 1. / (cnorm[j] + 1.); +/* L40: */ + } + } +L50: + + ; + } else { + +/* Compute the growth in A' * x = b. */ + + if (upper) { + jfirst = 1; + jlast = *n; + jinc = 1; + maind = *kd + 1; + } else { + jfirst = *n; + jlast = 1; + jinc = -1; + maind = 1; + } + + if (tscal != 1.) { + grow = 0.; + goto L80; + } + + if (nounit) { + +/* A is non-unit triangular. */ + +/* Compute GROW = 1/G(j) and XBND = 1/M(j). */ +/* Initially, M(0) = max{x(i), i=1,...,n}. */ + + grow = 1. / max(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L80; + } + +/* G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) */ + + xj = cnorm[j] + 1.; +/* Computing MIN */ + d__1 = grow, d__2 = xbnd / xj; + grow = min(d__1,d__2); + +/* M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) */ + + tjj = (d__1 = ab[maind + j * ab_dim1], abs(d__1)); + if (xj > tjj) { + xbnd *= tjj / xj; + } +/* L60: */ + } + grow = min(grow,xbnd); + } else { + +/* A is unit triangular. */ + +/* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. */ + +/* Computing MIN */ + d__1 = 1., d__2 = 1. / max(xbnd,smlnum); + grow = min(d__1,d__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L80; + } + +/* G(j) = ( 1 + CNORM(j) )*G(j-1) */ + + xj = cnorm[j] + 1.; + grow /= xj; +/* L70: */ + } + } +L80: + ; + } + + if (grow * tscal > smlnum) { + +/* Use the Level 2 BLAS solve if the reciprocal of the bound on */ +/* elements of X is not too small. */ + + dtbsv_(uplo, trans, diag, n, kd, &ab[ab_offset], ldab, &x[1], &c__1, ( + ftnlen)1, (ftnlen)1, (ftnlen)1); + } else { + +/* Use a Level 1 BLAS solve, scaling intermediate results. */ + + if (xmax > bignum) { + +/* Scale X so that its components are less than or equal to */ +/* BIGNUM in absolute value. */ + + *scale = bignum / xmax; + dscal_(n, scale, &x[1], &c__1); + xmax = bignum; + } + + if (notran) { + +/* Solve A * x = b */ + + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Compute x(j) = b(j) / A(j,j), scaling x if necessary. */ + + xj = (d__1 = x[j], abs(d__1)); + if (nounit) { + tjjs = ab[maind + j * ab_dim1] * tscal; + } else { + tjjs = tscal; + if (tscal == 1.) { + goto L100; + } + } + tjj = abs(tjjs); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale x by 1/b(j). */ + + rec = 1. / xj; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + x[j] /= tjjs; + xj = (d__1 = x[j], abs(d__1)); + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM */ +/* to avoid overflow when dividing by A(j,j). */ + + rec = tjj * bignum / xj; + if (cnorm[j] > 1.) { + +/* Scale by 1/CNORM(j) to avoid overflow when */ +/* multiplying x(j) times column j. */ + + rec /= cnorm[j]; + } + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + x[j] /= tjjs; + xj = (d__1 = x[j], abs(d__1)); + } else { + +/* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and */ +/* scale = 0, and compute a solution to A*x = 0. */ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + x[i__] = 0.; +/* L90: */ + } + x[j] = 1.; + xj = 1.; + *scale = 0.; + xmax = 0.; + } +L100: + +/* Scale x if necessary to avoid overflow when adding a */ +/* multiple of column j of A. */ + + if (xj > 1.) { + rec = 1. / xj; + if (cnorm[j] > (bignum - xmax) * rec) { + +/* Scale x by 1/(2*abs(x(j))). */ + + rec *= .5; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + } + } else if (xj * cnorm[j] > bignum - xmax) { + +/* Scale x by 1/2. */ + + dscal_(n, &c_b36, &x[1], &c__1); + *scale *= .5; + } + + if (upper) { + if (j > 1) { + +/* Compute the update */ +/* x(max(1,j-kd):j-1) := x(max(1,j-kd):j-1) - */ +/* x(j)* A(max(1,j-kd):j-1,j) */ + +/* Computing MIN */ + i__3 = *kd, i__4 = j - 1; + jlen = min(i__3,i__4); + d__1 = -x[j] * tscal; + daxpy_(&jlen, &d__1, &ab[*kd + 1 - jlen + j * ab_dim1] + , &c__1, &x[j - jlen], &c__1); + i__3 = j - 1; + i__ = idamax_(&i__3, &x[1], &c__1); + xmax = (d__1 = x[i__], abs(d__1)); + } + } else if (j < *n) { + +/* Compute the update */ +/* x(j+1:min(j+kd,n)) := x(j+1:min(j+kd,n)) - */ +/* x(j) * A(j+1:min(j+kd,n),j) */ + +/* Computing MIN */ + i__3 = *kd, i__4 = *n - j; + jlen = min(i__3,i__4); + if (jlen > 0) { + d__1 = -x[j] * tscal; + daxpy_(&jlen, &d__1, &ab[j * ab_dim1 + 2], &c__1, &x[ + j + 1], &c__1); + } + i__3 = *n - j; + i__ = j + idamax_(&i__3, &x[j + 1], &c__1); + xmax = (d__1 = x[i__], abs(d__1)); + } +/* L110: */ + } + + } else { + +/* Solve A' * x = b */ + + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Compute x(j) = b(j) - sum A(k,j)*x(k). */ +/* k<>j */ + + xj = (d__1 = x[j], abs(d__1)); + uscal = tscal; + rec = 1. / max(xmax,1.); + if (cnorm[j] > (bignum - xj) * rec) { + +/* If x(j) could overflow, scale x by 1/(2*XMAX). */ + + rec *= .5; + if (nounit) { + tjjs = ab[maind + j * ab_dim1] * tscal; + } else { + tjjs = tscal; + } + tjj = abs(tjjs); + if (tjj > 1.) { + +/* Divide by A(j,j) when scaling x if A(j,j) > 1. */ + +/* Computing MIN */ + d__1 = 1., d__2 = rec * tjj; + rec = min(d__1,d__2); + uscal /= tjjs; + } + if (rec < 1.) { + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + + sumj = 0.; + if (uscal == 1.) { + +/* If the scaling needed for A in the dot product is 1, */ +/* call DDOT to perform the dot product. */ + + if (upper) { +/* Computing MIN */ + i__3 = *kd, i__4 = j - 1; + jlen = min(i__3,i__4); + sumj = ddot_(&jlen, &ab[*kd + 1 - jlen + j * ab_dim1], + &c__1, &x[j - jlen], &c__1); + } else { +/* Computing MIN */ + i__3 = *kd, i__4 = *n - j; + jlen = min(i__3,i__4); + if (jlen > 0) { + sumj = ddot_(&jlen, &ab[j * ab_dim1 + 2], &c__1, & + x[j + 1], &c__1); + } + } + } else { + +/* Otherwise, use in-line code for the dot product. */ + + if (upper) { +/* Computing MIN */ + i__3 = *kd, i__4 = j - 1; + jlen = min(i__3,i__4); + i__3 = jlen; + for (i__ = 1; i__ <= i__3; ++i__) { + sumj += ab[*kd + i__ - jlen + j * ab_dim1] * + uscal * x[j - jlen - 1 + i__]; +/* L120: */ + } + } else { +/* Computing MIN */ + i__3 = *kd, i__4 = *n - j; + jlen = min(i__3,i__4); + i__3 = jlen; + for (i__ = 1; i__ <= i__3; ++i__) { + sumj += ab[i__ + 1 + j * ab_dim1] * uscal * x[j + + i__]; +/* L130: */ + } + } + } + + if (uscal == tscal) { + +/* Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) */ +/* was not used to scale the dotproduct. */ + + x[j] -= sumj; + xj = (d__1 = x[j], abs(d__1)); + if (nounit) { + +/* Compute x(j) = x(j) / A(j,j), scaling if necessary. */ + + tjjs = ab[maind + j * ab_dim1] * tscal; + } else { + tjjs = tscal; + if (tscal == 1.) { + goto L150; + } + } + tjj = abs(tjjs); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale X by 1/abs(x(j)). */ + + rec = 1. / xj; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + x[j] /= tjjs; + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ + + rec = tjj * bignum / xj; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + x[j] /= tjjs; + } else { + +/* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and */ +/* scale = 0, and compute a solution to A'*x = 0. */ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + x[i__] = 0.; +/* L140: */ + } + x[j] = 1.; + *scale = 0.; + xmax = 0.; + } +L150: + ; + } else { + +/* Compute x(j) := x(j) / A(j,j) - sumj if the dot */ +/* product has already been divided by 1/A(j,j). */ + + x[j] = x[j] / tjjs - sumj; + } +/* Computing MAX */ + d__2 = xmax, d__3 = (d__1 = x[j], abs(d__1)); + xmax = max(d__2,d__3); +/* L160: */ + } + } + *scale /= tscal; + } + +/* Scale the column norms by 1/TSCAL for return. */ + + if (tscal != 1.) { + d__1 = 1. / tscal; + dscal_(n, &d__1, &cnorm[1], &c__1); + } + + return 0; + +/* End of DLATBS */ + +} /* dlatbs_ */ + diff --git a/ext/f2c_lapack/dlatrs.c b/ext/f2c_lapack/dlatrs.c new file mode 100644 index 000000000..a08a0f09f --- /dev/null +++ b/ext/f2c_lapack/dlatrs.c @@ -0,0 +1,820 @@ +/* dlatrs.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 doublereal c_b36 = .5; + +/* Subroutine */ int dlatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, doublereal *a, integer *lda, doublereal *x, + doublereal *scale, doublereal *cnorm, integer *info, ftnlen uplo_len, + ftnlen trans_len, ftnlen diag_len, ftnlen normin_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j; + static doublereal xj, rec, tjj; + static integer jinc; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static doublereal xbnd; + static integer imax; + static doublereal tmax, tjjs, xmax, grow, sumj; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *, ftnlen, ftnlen); + static doublereal tscal, uscal; + extern doublereal dasum_(integer *, doublereal *, integer *); + static integer jlast; + extern /* Subroutine */ int daxpy_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int dtrsv_(char *, char *, char *, integer *, + doublereal *, integer *, doublereal *, integer *, ftnlen, ftnlen, + ftnlen); + extern doublereal dlamch_(char *, ftnlen); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + static doublereal bignum; + static logical notran; + static integer jfirst; + static doublereal smlnum; + static logical nounit; + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* June 30, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DLATRS solves one of the triangular systems */ + +/* A *x = s*b or A'*x = s*b */ + +/* with scaling to prevent overflow. Here A is an upper or lower */ +/* triangular matrix, A' denotes the transpose of A, x and b are */ +/* n-element vectors, and s is a scaling factor, usually less than */ +/* or equal to 1, chosen so that the components of x will be less than */ +/* the overflow threshold. If the unscaled problem will not cause */ +/* overflow, the Level 2 BLAS routine DTRSV is called. If the matrix A */ +/* is singular (A(j,j) = 0 for some j), then s is set to 0 and a */ +/* non-trivial solution to A*x = 0 is returned. */ + +/* Arguments */ +/* ========= */ + +/* UPLO (input) CHARACTER*1 */ +/* Specifies whether the matrix A is upper or lower triangular. */ +/* = 'U': Upper triangular */ +/* = 'L': Lower triangular */ + +/* TRANS (input) CHARACTER*1 */ +/* Specifies the operation applied to A. */ +/* = 'N': Solve A * x = s*b (No transpose) */ +/* = 'T': Solve A'* x = s*b (Transpose) */ +/* = 'C': Solve A'* x = s*b (Conjugate transpose = Transpose) */ + +/* DIAG (input) CHARACTER*1 */ +/* Specifies whether or not the matrix A is unit triangular. */ +/* = 'N': Non-unit triangular */ +/* = 'U': Unit triangular */ + +/* NORMIN (input) CHARACTER*1 */ +/* Specifies whether CNORM has been set or not. */ +/* = 'Y': CNORM contains the column norms on entry */ +/* = 'N': CNORM is not set on entry. On exit, the norms will */ +/* be computed and stored in CNORM. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The triangular matrix A. If UPLO = 'U', the leading n by n */ +/* upper triangular part of the array A contains the upper */ +/* triangular matrix, and the strictly lower triangular part of */ +/* A is not referenced. If UPLO = 'L', the leading n by n lower */ +/* triangular part of the array A contains the lower triangular */ +/* matrix, and the strictly upper triangular part of A is not */ +/* referenced. If DIAG = 'U', the diagonal elements of A are */ +/* also not referenced and are assumed to be 1. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max (1,N). */ + +/* X (input/output) DOUBLE PRECISION array, dimension (N) */ +/* On entry, the right hand side b of the triangular system. */ +/* On exit, X is overwritten by the solution vector x. */ + +/* SCALE (output) DOUBLE PRECISION */ +/* The scaling factor s for the triangular system */ +/* A * x = s*b or A'* x = s*b. */ +/* If SCALE = 0, the matrix A is singular or badly scaled, and */ +/* the vector x is an exact or approximate solution to A*x = 0. */ + +/* CNORM (input or output) DOUBLE PRECISION array, dimension (N) */ + +/* If NORMIN = 'Y', CNORM is an input argument and CNORM(j) */ +/* contains the norm of the off-diagonal part of the j-th column */ +/* of A. If TRANS = 'N', CNORM(j) must be greater than or equal */ +/* to the infinity-norm, and if TRANS = 'T' or 'C', CNORM(j) */ +/* must be greater than or equal to the 1-norm. */ + +/* If NORMIN = 'N', CNORM is an output argument and CNORM(j) */ +/* returns the 1-norm of the offdiagonal part of the j-th column */ +/* of A. */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -k, the k-th argument had an illegal value */ + +/* Further Details */ +/* ======= ======= */ + +/* A rough bound on x is computed; if that is less than overflow, DTRSV */ +/* is called, otherwise, specific code is used which checks for possible */ +/* overflow or divide-by-zero at every operation. */ + +/* A columnwise scheme is used for solving A*x = b. The basic algorithm */ +/* if A is lower triangular is */ + +/* x[1:n] := b[1:n] */ +/* for j = 1, ..., n */ +/* x(j) := x(j) / A(j,j) */ +/* x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] */ +/* end */ + +/* Define bounds on the components of x after j iterations of the loop: */ +/* M(j) = bound on x[1:j] */ +/* G(j) = bound on x[j+1:n] */ +/* Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. */ + +/* Then for iteration j+1 we have */ +/* M(j+1) <= G(j) / | A(j+1,j+1) | */ +/* G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | */ +/* <= G(j) ( 1 + CNORM(j+1) / | A(j+1,j+1) | ) */ + +/* where CNORM(j+1) is greater than or equal to the infinity-norm of */ +/* column j+1 of A, not counting the diagonal. Hence */ + +/* G(j) <= G(0) product ( 1 + CNORM(i) / | A(i,i) | ) */ +/* 1<=i<=j */ +/* and */ + +/* |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + CNORM(i) / |A(i,i)| ) */ +/* 1<=i< j */ + +/* Since |x(j)| <= M(j), we use the Level 2 BLAS routine DTRSV if the */ +/* reciprocal of the largest M(j), j=1,..,n, is larger than */ +/* max(underflow, 1/overflow). */ + +/* The bound on x(j) is also used to determine when a step in the */ +/* columnwise method can be performed without fear of overflow. If */ +/* the computed bound is greater than a large constant, x is scaled to */ +/* prevent overflow, but if the bound overflows, x is set to 0, x(j) to */ +/* 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. */ + +/* Similarly, a row-wise scheme is used to solve A'*x = b. The basic */ +/* algorithm for A upper triangular is */ + +/* for j = 1, ..., n */ +/* x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) */ +/* end */ + +/* We simultaneously compute two bounds */ +/* G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j */ +/* M(j) = bound on x(i), 1<=i<=j */ + +/* The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we */ +/* add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. */ +/* Then the bound on x(j) is */ + +/* M(j) <= M(j-1) * ( 1 + CNORM(j) ) / | A(j,j) | */ + +/* <= M(0) * product ( ( 1 + CNORM(i) ) / |A(i,i)| ) */ +/* 1<=i<=j */ + +/* and we can safely call DTRSV if 1/M(n) and 1/G(n) are both greater */ +/* than max(underflow, 1/overflow). */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --cnorm; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1); + notran = lsame_(trans, "N", (ftnlen)1, (ftnlen)1); + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + +/* Test the input parameters. */ + + if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T", (ftnlen)1, (ftnlen)1) && ! + lsame_(trans, "C", (ftnlen)1, (ftnlen)1)) { + *info = -2; + } else if (! nounit && ! lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + *info = -3; + } else if (! lsame_(normin, "Y", (ftnlen)1, (ftnlen)1) && ! lsame_(normin, + "N", (ftnlen)1, (ftnlen)1)) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLATRS", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine machine dependent parameters to control overflow. */ + + smlnum = dlamch_("Safe minimum", (ftnlen)12) / dlamch_("Precision", ( + ftnlen)9); + bignum = 1. / smlnum; + *scale = 1.; + + if (lsame_(normin, "N", (ftnlen)1, (ftnlen)1)) { + +/* Compute the 1-norm of each column, not including the diagonal. */ + + if (upper) { + +/* A is upper triangular. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + cnorm[j] = dasum_(&i__2, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* A is lower triangular. */ + + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + cnorm[j] = dasum_(&i__2, &a[j + 1 + j * a_dim1], &c__1); +/* L20: */ + } + cnorm[*n] = 0.; + } + } + +/* Scale the column norms by TSCAL if the maximum element in CNORM is */ +/* greater than BIGNUM. */ + + imax = idamax_(n, &cnorm[1], &c__1); + tmax = cnorm[imax]; + if (tmax <= bignum) { + tscal = 1.; + } else { + tscal = 1. / (smlnum * tmax); + dscal_(n, &tscal, &cnorm[1], &c__1); + } + +/* Compute a bound on the computed solution vector to see if the */ +/* Level 2 BLAS routine DTRSV can be used. */ + + j = idamax_(n, &x[1], &c__1); + xmax = (d__1 = x[j], abs(d__1)); + xbnd = xmax; + if (notran) { + +/* Compute the growth in A * x = b. */ + + if (upper) { + jfirst = *n; + jlast = 1; + jinc = -1; + } else { + jfirst = 1; + jlast = *n; + jinc = 1; + } + + if (tscal != 1.) { + grow = 0.; + goto L50; + } + + if (nounit) { + +/* A is non-unit triangular. */ + +/* Compute GROW = 1/G(j) and XBND = 1/M(j). */ +/* Initially, G(0) = max{x(i), i=1,...,n}. */ + + grow = 1. / max(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L50; + } + +/* M(j) = G(j-1) / abs(A(j,j)) */ + + tjj = (d__1 = a[j + j * a_dim1], abs(d__1)); +/* Computing MIN */ + d__1 = xbnd, d__2 = min(1.,tjj) * grow; + xbnd = min(d__1,d__2); + if (tjj + cnorm[j] >= smlnum) { + +/* G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) */ + + grow *= tjj / (tjj + cnorm[j]); + } else { + +/* G(j) could overflow, set GROW to 0. */ + + grow = 0.; + } +/* L30: */ + } + grow = xbnd; + } else { + +/* A is unit triangular. */ + +/* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. */ + +/* Computing MIN */ + d__1 = 1., d__2 = 1. / max(xbnd,smlnum); + grow = min(d__1,d__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L50; + } + +/* G(j) = G(j-1)*( 1 + CNORM(j) ) */ + + grow *= 1. / (cnorm[j] + 1.); +/* L40: */ + } + } +L50: + + ; + } else { + +/* Compute the growth in A' * x = b. */ + + if (upper) { + jfirst = 1; + jlast = *n; + jinc = 1; + } else { + jfirst = *n; + jlast = 1; + jinc = -1; + } + + if (tscal != 1.) { + grow = 0.; + goto L80; + } + + if (nounit) { + +/* A is non-unit triangular. */ + +/* Compute GROW = 1/G(j) and XBND = 1/M(j). */ +/* Initially, M(0) = max{x(i), i=1,...,n}. */ + + grow = 1. / max(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L80; + } + +/* G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) */ + + xj = cnorm[j] + 1.; +/* Computing MIN */ + d__1 = grow, d__2 = xbnd / xj; + grow = min(d__1,d__2); + +/* M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) */ + + tjj = (d__1 = a[j + j * a_dim1], abs(d__1)); + if (xj > tjj) { + xbnd *= tjj / xj; + } +/* L60: */ + } + grow = min(grow,xbnd); + } else { + +/* A is unit triangular. */ + +/* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. */ + +/* Computing MIN */ + d__1 = 1., d__2 = 1. / max(xbnd,smlnum); + grow = min(d__1,d__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L80; + } + +/* G(j) = ( 1 + CNORM(j) )*G(j-1) */ + + xj = cnorm[j] + 1.; + grow /= xj; +/* L70: */ + } + } +L80: + ; + } + + if (grow * tscal > smlnum) { + +/* Use the Level 2 BLAS solve if the reciprocal of the bound on */ +/* elements of X is not too small. */ + + dtrsv_(uplo, trans, diag, n, &a[a_offset], lda, &x[1], &c__1, (ftnlen) + 1, (ftnlen)1, (ftnlen)1); + } else { + +/* Use a Level 1 BLAS solve, scaling intermediate results. */ + + if (xmax > bignum) { + +/* Scale X so that its components are less than or equal to */ +/* BIGNUM in absolute value. */ + + *scale = bignum / xmax; + dscal_(n, scale, &x[1], &c__1); + xmax = bignum; + } + + if (notran) { + +/* Solve A * x = b */ + + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Compute x(j) = b(j) / A(j,j), scaling x if necessary. */ + + xj = (d__1 = x[j], abs(d__1)); + if (nounit) { + tjjs = a[j + j * a_dim1] * tscal; + } else { + tjjs = tscal; + if (tscal == 1.) { + goto L100; + } + } + tjj = abs(tjjs); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale x by 1/b(j). */ + + rec = 1. / xj; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + x[j] /= tjjs; + xj = (d__1 = x[j], abs(d__1)); + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM */ +/* to avoid overflow when dividing by A(j,j). */ + + rec = tjj * bignum / xj; + if (cnorm[j] > 1.) { + +/* Scale by 1/CNORM(j) to avoid overflow when */ +/* multiplying x(j) times column j. */ + + rec /= cnorm[j]; + } + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + x[j] /= tjjs; + xj = (d__1 = x[j], abs(d__1)); + } else { + +/* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and */ +/* scale = 0, and compute a solution to A*x = 0. */ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + x[i__] = 0.; +/* L90: */ + } + x[j] = 1.; + xj = 1.; + *scale = 0.; + xmax = 0.; + } +L100: + +/* Scale x if necessary to avoid overflow when adding a */ +/* multiple of column j of A. */ + + if (xj > 1.) { + rec = 1. / xj; + if (cnorm[j] > (bignum - xmax) * rec) { + +/* Scale x by 1/(2*abs(x(j))). */ + + rec *= .5; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + } + } else if (xj * cnorm[j] > bignum - xmax) { + +/* Scale x by 1/2. */ + + dscal_(n, &c_b36, &x[1], &c__1); + *scale *= .5; + } + + if (upper) { + if (j > 1) { + +/* Compute the update */ +/* x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) */ + + i__3 = j - 1; + d__1 = -x[j] * tscal; + daxpy_(&i__3, &d__1, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + i__3 = j - 1; + i__ = idamax_(&i__3, &x[1], &c__1); + xmax = (d__1 = x[i__], abs(d__1)); + } + } else { + if (j < *n) { + +/* Compute the update */ +/* x(j+1:n) := x(j+1:n) - x(j) * A(j+1:n,j) */ + + i__3 = *n - j; + d__1 = -x[j] * tscal; + daxpy_(&i__3, &d__1, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + i__3 = *n - j; + i__ = j + idamax_(&i__3, &x[j + 1], &c__1); + xmax = (d__1 = x[i__], abs(d__1)); + } + } +/* L110: */ + } + + } else { + +/* Solve A' * x = b */ + + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Compute x(j) = b(j) - sum A(k,j)*x(k). */ +/* k<>j */ + + xj = (d__1 = x[j], abs(d__1)); + uscal = tscal; + rec = 1. / max(xmax,1.); + if (cnorm[j] > (bignum - xj) * rec) { + +/* If x(j) could overflow, scale x by 1/(2*XMAX). */ + + rec *= .5; + if (nounit) { + tjjs = a[j + j * a_dim1] * tscal; + } else { + tjjs = tscal; + } + tjj = abs(tjjs); + if (tjj > 1.) { + +/* Divide by A(j,j) when scaling x if A(j,j) > 1. */ + +/* Computing MIN */ + d__1 = 1., d__2 = rec * tjj; + rec = min(d__1,d__2); + uscal /= tjjs; + } + if (rec < 1.) { + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + + sumj = 0.; + if (uscal == 1.) { + +/* If the scaling needed for A in the dot product is 1, */ +/* call DDOT to perform the dot product. */ + + if (upper) { + i__3 = j - 1; + sumj = ddot_(&i__3, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + } else if (j < *n) { + i__3 = *n - j; + sumj = ddot_(&i__3, &a[j + 1 + j * a_dim1], &c__1, &x[ + j + 1], &c__1); + } + } else { + +/* Otherwise, use in-line code for the dot product. */ + + if (upper) { + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + sumj += a[i__ + j * a_dim1] * uscal * x[i__]; +/* L120: */ + } + } else if (j < *n) { + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + sumj += a[i__ + j * a_dim1] * uscal * x[i__]; +/* L130: */ + } + } + } + + if (uscal == tscal) { + +/* Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) */ +/* was not used to scale the dotproduct. */ + + x[j] -= sumj; + xj = (d__1 = x[j], abs(d__1)); + if (nounit) { + tjjs = a[j + j * a_dim1] * tscal; + } else { + tjjs = tscal; + if (tscal == 1.) { + goto L150; + } + } + +/* Compute x(j) = x(j) / A(j,j), scaling if necessary. */ + + tjj = abs(tjjs); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale X by 1/abs(x(j)). */ + + rec = 1. / xj; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + x[j] /= tjjs; + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ + + rec = tjj * bignum / xj; + dscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + x[j] /= tjjs; + } else { + +/* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and */ +/* scale = 0, and compute a solution to A'*x = 0. */ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + x[i__] = 0.; +/* L140: */ + } + x[j] = 1.; + *scale = 0.; + xmax = 0.; + } +L150: + ; + } else { + +/* Compute x(j) := x(j) / A(j,j) - sumj if the dot */ +/* product has already been divided by 1/A(j,j). */ + + x[j] = x[j] / tjjs - sumj; + } +/* Computing MAX */ + d__2 = xmax, d__3 = (d__1 = x[j], abs(d__1)); + xmax = max(d__2,d__3); +/* L160: */ + } + } + *scale /= tscal; + } + +/* Scale the column norms by 1/TSCAL for return. */ + + if (tscal != 1.) { + d__1 = 1. / tscal; + dscal_(n, &d__1, &cnorm[1], &c__1); + } + + return 0; + +/* End of DLATRS */ + +} /* dlatrs_ */ + diff --git a/ext/f2c_lapack/dpotf2.c b/ext/f2c_lapack/dpotf2.c new file mode 100644 index 000000000..4ceff060e --- /dev/null +++ b/ext/f2c_lapack/dpotf2.c @@ -0,0 +1,224 @@ +/* dpotf2.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 doublereal c_b10 = -1.; +static doublereal c_b12 = 1.; + +/* Subroutine */ int dpotf2_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info, ftnlen uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + + /* Builtin functions */ + double sqrt(doublereal); + + /* Local variables */ + static integer j; + static doublereal ajj; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, ftnlen); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* February 29, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DPOTF2 computes the Cholesky factorization of a real symmetric */ +/* positive definite matrix A. */ + +/* The factorization has the form */ +/* A = U' * U , if UPLO = 'U', or */ +/* A = L * L', if UPLO = 'L', */ +/* where U is an upper triangular matrix and L is lower triangular. */ + +/* This is the unblocked version of the algorithm, calling Level 2 BLAS. */ + +/* Arguments */ +/* ========= */ + +/* UPLO (input) CHARACTER*1 */ +/* Specifies whether the upper or lower triangular part of the */ +/* symmetric matrix A is stored. */ +/* = 'U': Upper triangular */ +/* = 'L': Lower triangular */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */ +/* On entry, the symmetric matrix A. If UPLO = 'U', the leading */ +/* n by n upper triangular part of A contains the upper */ +/* triangular part of the matrix A, and the strictly lower */ +/* triangular part of A is not referenced. If UPLO = 'L', the */ +/* leading n by n lower triangular part of A contains the lower */ +/* triangular part of the matrix A, and the strictly upper */ +/* triangular part of A is not referenced. */ + +/* On exit, if INFO = 0, the factor U or L from the Cholesky */ +/* factorization A = U'*U or A = L*L'. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -k, the k-th argument had an illegal value */ +/* > 0: if INFO = k, the leading minor of order k is not */ +/* positive definite, and the factorization could not be */ +/* completed. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1); + if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTF2", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute U(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - ddot_(&i__2, &a[j * a_dim1 + 1], &c__1, + &a[j * a_dim1 + 1], &c__1); + if (ajj <= 0.) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of row J. */ + + if (j < *n) { + i__2 = j - 1; + i__3 = *n - j; + dgemv_("Transpose", &i__2, &i__3, &c_b10, &a[(j + 1) * a_dim1 + + 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b12, &a[j + ( + j + 1) * a_dim1], lda, (ftnlen)9); + i__2 = *n - j; + d__1 = 1. / ajj; + dscal_(&i__2, &d__1, &a[j + (j + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute L(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - ddot_(&i__2, &a[j + a_dim1], lda, &a[j + + a_dim1], lda); + if (ajj <= 0.) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of column J. */ + + if (j < *n) { + i__2 = *n - j; + i__3 = j - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b10, &a[j + 1 + + a_dim1], lda, &a[j + a_dim1], lda, &c_b12, &a[j + 1 + + j * a_dim1], &c__1, (ftnlen)12); + i__2 = *n - j; + d__1 = 1. / ajj; + dscal_(&i__2, &d__1, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + goto L40; + +L30: + *info = j; + +L40: + return 0; + +/* End of DPOTF2 */ + +} /* dpotf2_ */ + diff --git a/ext/f2c_lapack/dpotrf.c b/ext/f2c_lapack/dpotrf.c new file mode 100644 index 000000000..4f55fb75b --- /dev/null +++ b/ext/f2c_lapack/dpotrf.c @@ -0,0 +1,254 @@ +/* dpotrf.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_n1 = -1; +static doublereal c_b13 = -1.; +static doublereal c_b14 = 1.; + +/* Subroutine */ int dpotrf_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info, ftnlen uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer j, jb, nb; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, ftnlen, ftnlen); + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, ftnlen, ftnlen, ftnlen, ftnlen); + static logical upper; + extern /* Subroutine */ int dsyrk_(char *, char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, doublereal *, + integer *, ftnlen, ftnlen), dpotf2_(char *, integer *, + doublereal *, integer *, integer *, ftnlen), xerbla_(char *, + integer *, ftnlen); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* March 31, 1993 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DPOTRF computes the Cholesky factorization of a real symmetric */ +/* positive definite matrix A. */ + +/* The factorization has the form */ +/* A = U**T * U, if UPLO = 'U', or */ +/* A = L * L**T, if UPLO = 'L', */ +/* where U is an upper triangular matrix and L is lower triangular. */ + +/* This is the block version of the algorithm, calling Level 3 BLAS. */ + +/* Arguments */ +/* ========= */ + +/* UPLO (input) CHARACTER*1 */ +/* = 'U': Upper triangle of A is stored; */ +/* = 'L': Lower triangle of A is stored. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */ +/* On entry, the symmetric matrix A. If UPLO = 'U', the leading */ +/* N-by-N upper triangular part of A contains the upper */ +/* triangular part of the matrix A, and the strictly lower */ +/* triangular part of A is not referenced. If UPLO = 'L', the */ +/* leading N-by-N lower triangular part of A contains the lower */ +/* triangular part of the matrix A, and the strictly upper */ +/* triangular part of A is not referenced. */ + +/* On exit, if INFO = 0, the factor U or L from the Cholesky */ +/* factorization A = U**T*U or A = L*L**T. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ +/* > 0: if INFO = i, the leading minor of order i is not */ +/* positive definite, and the factorization could not be */ +/* completed. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1); + if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTRF", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "DPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code. */ + + dpotf2_(uplo, n, &a[a_offset], lda, info, (ftnlen)1); + } else { + +/* Use blocked code. */ + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Update and factorize the current diagonal block and test */ +/* for non-positive-definiteness. */ + +/* Computing MIN */ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + dsyrk_("Upper", "Transpose", &jb, &i__3, &c_b13, &a[j * + a_dim1 + 1], lda, &c_b14, &a[j + j * a_dim1], lda, ( + ftnlen)5, (ftnlen)9); + dpotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info, (ftnlen) + 5); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block row. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + dgemm_("Transpose", "No transpose", &jb, &i__3, &i__4, & + c_b13, &a[j * a_dim1 + 1], lda, &a[(j + jb) * + a_dim1 + 1], lda, &c_b14, &a[j + (j + jb) * + a_dim1], lda, (ftnlen)9, (ftnlen)12); + i__3 = *n - j - jb + 1; + dtrsm_("Left", "Upper", "Transpose", "Non-unit", &jb, & + i__3, &c_b14, &a[j + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda, (ftnlen)4, (ftnlen)5, ( + ftnlen)9, (ftnlen)8); + } +/* L10: */ + } + + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__2 = *n; + i__1 = nb; + for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Update and factorize the current diagonal block and test */ +/* for non-positive-definiteness. */ + +/* Computing MIN */ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + dsyrk_("Lower", "No transpose", &jb, &i__3, &c_b13, &a[j + + a_dim1], lda, &c_b14, &a[j + j * a_dim1], lda, ( + ftnlen)5, (ftnlen)12); + dpotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info, (ftnlen) + 5); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block column. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + dgemm_("No transpose", "Transpose", &i__3, &jb, &i__4, & + c_b13, &a[j + jb + a_dim1], lda, &a[j + a_dim1], + lda, &c_b14, &a[j + jb + j * a_dim1], lda, ( + ftnlen)12, (ftnlen)9); + i__3 = *n - j - jb + 1; + dtrsm_("Right", "Lower", "Transpose", "Non-unit", &i__3, & + jb, &c_b14, &a[j + j * a_dim1], lda, &a[j + jb + + j * a_dim1], lda, (ftnlen)5, (ftnlen)5, (ftnlen)9, + (ftnlen)8); + } +/* L20: */ + } + } + } + goto L40; + +L30: + *info = *info + j - 1; + +L40: + return 0; + +/* End of DPOTRF */ + +} /* dpotrf_ */ + diff --git a/ext/f2c_lapack/dpotrs.c b/ext/f2c_lapack/dpotrs.c new file mode 100644 index 000000000..e5d632002 --- /dev/null +++ b/ext/f2c_lapack/dpotrs.c @@ -0,0 +1,171 @@ +/* dpotrs.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 doublereal c_b9 = 1.; + +/* Subroutine */ int dpotrs_(char *uplo, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + info, ftnlen uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, ftnlen, ftnlen, ftnlen, ftnlen); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* March 31, 1993 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DPOTRS solves a system of linear equations A*X = B with a symmetric */ +/* positive definite matrix A using the Cholesky factorization */ +/* A = U**T*U or A = L*L**T computed by DPOTRF. */ + +/* Arguments */ +/* ========= */ + +/* UPLO (input) CHARACTER*1 */ +/* = 'U': Upper triangle of A is stored; */ +/* = 'L': Lower triangle of A is stored. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* NRHS (input) INTEGER */ +/* The number of right hand sides, i.e., the number of columns */ +/* of the matrix B. NRHS >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The triangular factor U or L from the Cholesky factorization */ +/* A = U**T*U or A = L*L**T, as computed by DPOTRF. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) */ +/* On entry, the right hand side matrix B. */ +/* On exit, the solution matrix X. */ + +/* LDB (input) INTEGER */ +/* The leading dimension of the array B. LDB >= max(1,N). */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1); + if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTRS", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (upper) { + +/* Solve A*X = B where A = U'*U. */ + +/* Solve U'*X = B, overwriting B with X. */ + + dtrsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b9, &a[ + a_offset], lda, &b[b_offset], ldb, (ftnlen)4, (ftnlen)5, ( + ftnlen)9, (ftnlen)8); + +/* Solve U*X = B, overwriting B with X. */ + + dtrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b9, & + a[a_offset], lda, &b[b_offset], ldb, (ftnlen)4, (ftnlen)5, ( + ftnlen)12, (ftnlen)8); + } else { + +/* Solve A*X = B where A = L*L'. */ + +/* Solve L*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "No transpose", "Non-unit", n, nrhs, &c_b9, & + a[a_offset], lda, &b[b_offset], ldb, (ftnlen)4, (ftnlen)5, ( + ftnlen)12, (ftnlen)8); + +/* Solve L'*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "Transpose", "Non-unit", n, nrhs, &c_b9, &a[ + a_offset], lda, &b[b_offset], ldb, (ftnlen)4, (ftnlen)5, ( + ftnlen)9, (ftnlen)8); + } + + return 0; + +/* End of DPOTRS */ + +} /* dpotrs_ */ + diff --git a/ext/f2c_lapack/dtrcon.c b/ext/f2c_lapack/dtrcon.c new file mode 100644 index 000000000..6323a364e --- /dev/null +++ b/ext/f2c_lapack/dtrcon.c @@ -0,0 +1,242 @@ +/* dtrcon.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; + +/* Subroutine */ int dtrcon_(char *norm, char *uplo, char *diag, integer *n, + doublereal *a, integer *lda, doublereal *rcond, doublereal *work, + integer *iwork, integer *info, ftnlen norm_len, ftnlen uplo_len, + ftnlen diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1; + doublereal d__1; + + /* Local variables */ + static integer ix, kase, kase1; + static doublereal scale; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int drscl_(integer *, doublereal *, doublereal *, + integer *); + static doublereal anorm; + static logical upper; + static doublereal xnorm; + extern doublereal dlamch_(char *, ftnlen); + extern /* Subroutine */ int dlacon_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + extern doublereal dlantr_(char *, char *, char *, integer *, integer *, + doublereal *, integer *, doublereal *, ftnlen, ftnlen, ftnlen); + static doublereal ainvnm; + extern /* Subroutine */ int dlatrs_(char *, char *, char *, char *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, integer *, ftnlen, ftnlen, ftnlen, ftnlen); + static logical onenrm; + static char normin[1]; + static doublereal smlnum; + static logical nounit; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* March 31, 1993 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DTRCON estimates the reciprocal of the condition number of a */ +/* triangular matrix A, in either the 1-norm or the infinity-norm. */ + +/* The norm of A is computed and an estimate is obtained for */ +/* norm(inv(A)), then the reciprocal of the condition number is */ +/* computed as */ +/* RCOND = 1 / ( norm(A) * norm(inv(A)) ). */ + +/* Arguments */ +/* ========= */ + +/* NORM (input) CHARACTER*1 */ +/* Specifies whether the 1-norm condition number or the */ +/* infinity-norm condition number is required: */ +/* = '1' or 'O': 1-norm; */ +/* = 'I': Infinity-norm. */ + +/* UPLO (input) CHARACTER*1 */ +/* = 'U': A is upper triangular; */ +/* = 'L': A is lower triangular. */ + +/* DIAG (input) CHARACTER*1 */ +/* = 'N': A is non-unit triangular; */ +/* = 'U': A is unit triangular. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The triangular matrix A. If UPLO = 'U', the leading N-by-N */ +/* upper triangular part of the array A contains the upper */ +/* triangular matrix, and the strictly lower triangular part of */ +/* A is not referenced. If UPLO = 'L', the leading N-by-N lower */ +/* triangular part of the array A contains the lower triangular */ +/* matrix, and the strictly upper triangular part of A is not */ +/* referenced. If DIAG = 'U', the diagonal elements of A are */ +/* also not referenced and are assumed to be 1. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* RCOND (output) DOUBLE PRECISION */ +/* The reciprocal of the condition number of the matrix A, */ +/* computed as RCOND = 1/(norm(A) * norm(inv(A))). */ + +/* WORK (workspace) DOUBLE PRECISION array, dimension (3*N) */ + +/* IWORK (workspace) INTEGER array, dimension (N) */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1); + onenrm = *(unsigned char *)norm == '1' || lsame_(norm, "O", (ftnlen)1, ( + ftnlen)1); + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + + if (! onenrm && ! lsame_(norm, "I", (ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) { + *info = -2; + } else if (! nounit && ! lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*lda < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DTRCON", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + *rcond = 1.; + return 0; + } + + *rcond = 0.; + smlnum = dlamch_("Safe minimum", (ftnlen)12) * (doublereal) max(1,*n); + +/* Compute the norm of the triangular matrix A. */ + + anorm = dlantr_(norm, uplo, diag, n, n, &a[a_offset], lda, &work[1], ( + ftnlen)1, (ftnlen)1, (ftnlen)1); + +/* Continue only if ANORM > 0. */ + + if (anorm > 0.) { + +/* Estimate the norm of the inverse of A. */ + + ainvnm = 0.; + *(unsigned char *)normin = 'N'; + if (onenrm) { + kase1 = 1; + } else { + kase1 = 2; + } + kase = 0; +L10: + dlacon_(n, &work[*n + 1], &work[1], &iwork[1], &ainvnm, &kase); + if (kase != 0) { + if (kase == kase1) { + +/* Multiply by inv(A). */ + + dlatrs_(uplo, "No transpose", diag, normin, n, &a[a_offset], + lda, &work[1], &scale, &work[(*n << 1) + 1], info, ( + ftnlen)1, (ftnlen)12, (ftnlen)1, (ftnlen)1); + } else { + +/* Multiply by inv(A'). */ + + dlatrs_(uplo, "Transpose", diag, normin, n, &a[a_offset], lda, + &work[1], &scale, &work[(*n << 1) + 1], info, ( + ftnlen)1, (ftnlen)9, (ftnlen)1, (ftnlen)1); + } + *(unsigned char *)normin = 'Y'; + +/* Multiply by 1/SCALE if doing so will not cause overflow. */ + + if (scale != 1.) { + ix = idamax_(n, &work[1], &c__1); + xnorm = (d__1 = work[ix], abs(d__1)); + if (scale < xnorm * smlnum || scale == 0.) { + goto L20; + } + drscl_(n, &scale, &work[1], &c__1); + } + goto L10; + } + +/* Compute the estimate of the reciprocal condition number. */ + + if (ainvnm != 0.) { + *rcond = 1. / anorm / ainvnm; + } + } + +L20: + return 0; + +/* End of DTRCON */ + +} /* dtrcon_ */ + diff --git a/ext/f2c_lapack/dtrtrs.c b/ext/f2c_lapack/dtrtrs.c new file mode 100644 index 000000000..4c4035d8e --- /dev/null +++ b/ext/f2c_lapack/dtrtrs.c @@ -0,0 +1,187 @@ +/* dtrtrs.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 doublereal c_b12 = 1.; + +/* Subroutine */ int dtrtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer * + ldb, integer *info, ftnlen uplo_len, ftnlen trans_len, ftnlen + diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, ftnlen, ftnlen, ftnlen, ftnlen), xerbla_( + char *, integer *, ftnlen); + static logical nounit; + + +/* -- LAPACK routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* March 31, 1993 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DTRTRS solves a triangular system of the form */ + +/* A * X = B or A**T * X = B, */ + +/* where A is a triangular matrix of order N, and B is an N-by-NRHS */ +/* matrix. A check is made to verify that A is nonsingular. */ + +/* Arguments */ +/* ========= */ + +/* UPLO (input) CHARACTER*1 */ +/* = 'U': A is upper triangular; */ +/* = 'L': A is lower triangular. */ + +/* TRANS (input) CHARACTER*1 */ +/* Specifies the form of the system of equations: */ +/* = 'N': A * X = B (No transpose) */ +/* = 'T': A**T * X = B (Transpose) */ +/* = 'C': A**H * X = B (Conjugate transpose = Transpose) */ + +/* DIAG (input) CHARACTER*1 */ +/* = 'N': A is non-unit triangular; */ +/* = 'U': A is unit triangular. */ + +/* N (input) INTEGER */ +/* The order of the matrix A. N >= 0. */ + +/* NRHS (input) INTEGER */ +/* The number of right hand sides, i.e., the number of columns */ +/* of the matrix B. NRHS >= 0. */ + +/* A (input) DOUBLE PRECISION array, dimension (LDA,N) */ +/* The triangular matrix A. If UPLO = 'U', the leading N-by-N */ +/* upper triangular part of the array A contains the upper */ +/* triangular matrix, and the strictly lower triangular part of */ +/* A is not referenced. If UPLO = 'L', the leading N-by-N lower */ +/* triangular part of the array A contains the lower triangular */ +/* matrix, and the strictly upper triangular part of A is not */ +/* referenced. If DIAG = 'U', the diagonal elements of A are */ +/* also not referenced and are assumed to be 1. */ + +/* LDA (input) INTEGER */ +/* The leading dimension of the array A. LDA >= max(1,N). */ + +/* B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) */ +/* On entry, the right hand side matrix B. */ +/* On exit, if INFO = 0, the solution matrix X. */ + +/* LDB (input) INTEGER */ +/* The leading dimension of the array B. LDB >= max(1,N). */ + +/* INFO (output) INTEGER */ +/* = 0: successful exit */ +/* < 0: if INFO = -i, the i-th argument had an illegal value */ +/* > 0: if INFO = i, the i-th diagonal element of A is zero, */ +/* indicating that the matrix is singular and the solutions */ +/* X have not been computed. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + *info = -1; + } else if (! lsame_(trans, "N", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, + "T", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, "C", (ftnlen)1, ( + ftnlen)1)) { + *info = -2; + } else if (! nounit && ! lsame_(diag, "U", (ftnlen)1, (ftnlen)1)) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*nrhs < 0) { + *info = -5; + } else if (*lda < max(1,*n)) { + *info = -7; + } else if (*ldb < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DTRTRS", &i__1, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Check for singularity. */ + + if (nounit) { + i__1 = *n; + for (*info = 1; *info <= i__1; ++(*info)) { + if (a[*info + *info * a_dim1] == 0.) { + return 0; + } +/* L10: */ + } + } + *info = 0; + +/* Solve A * x = b or A' * x = b. */ + + dtrsm_("Left", uplo, trans, diag, n, nrhs, &c_b12, &a[a_offset], lda, &b[ + b_offset], ldb, (ftnlen)4, (ftnlen)1, (ftnlen)1, (ftnlen)1); + + return 0; + +/* End of DTRTRS */ + +} /* dtrtrs_ */ + diff --git a/ext/f2c_math/Makefile.in b/ext/f2c_math/Makefile.in index 35ead9668..5c74cc4bf 100644 --- a/ext/f2c_math/Makefile.in +++ b/ext/f2c_math/Makefile.in @@ -1,9 +1,9 @@ #/bin/sh # # $Source: /cvsroot/cantera/cantera/ext/f2c_math/Makefile.in,v $ -# $Author: hkmoffa $ -# $Revision: 1.10 $ -# $Date: 2008/12/30 21:49:42 $ +# $Author$ +# $Revision$ +# $Date$ # .SUFFIXES : diff --git a/ext/f2c_math/ddaspk.c b/ext/f2c_math/ddaspk.c index 44ffb2319..052eb72cd 100644 --- a/ext/f2c_math/ddaspk.c +++ b/ext/f2c_math/ddaspk.c @@ -8561,7 +8561,7 @@ L30: } i__2 = km1; for (j = 1; j <= i__2; ++j) { - i__ = (j - 1 << 1) + 1; + i__ = ((j - 1) << 1) + 1; t1 = a[j + k * a_dim1]; t2 = a[j + 1 + k * a_dim1]; c__ = q[i__]; @@ -8617,7 +8617,7 @@ L70: /* ----------------------------------------------------------------------- */ i__1 = nm1; for (k = 1; k <= i__1; ++k) { - i__ = (k - 1 << 1) + 1; + i__ = ((k - 1) << 1) + 1; t1 = a[k + *n * a_dim1]; t2 = a[k + 1 + *n * a_dim1]; c__ = q[i__]; @@ -8745,7 +8745,7 @@ L130: i__1 = *n; for (k = 1; k <= i__1; ++k) { kp1 = k + 1; - iq = (k - 1 << 1) + 1; + iq = ((k - 1) << 1) + 1; c__ = q[iq]; s = q[iq + 1]; t1 = b[k]; diff --git a/ext/f2c_math/gmres.h b/ext/f2c_math/gmres.h index 1f6a044d5..8bde197c2 100644 --- a/ext/f2c_math/gmres.h +++ b/ext/f2c_math/gmres.h @@ -33,7 +33,6 @@ gmres( int m, int N, const Matrix &A, const doublereal *b, doublereal *x, double #include "cblas.h" #include "../../Cantera/src/ctlapack.h" -using namespace Cantera; template< class Matrix > inline int diff --git a/ext/f2c_math/j4save.c b/ext/f2c_math/j4save.c index 733e9e848..db219b885 100644 --- a/ext/f2c_math/j4save.c +++ b/ext/f2c_math/j4save.c @@ -69,7 +69,7 @@ integer j4save_(integer *iwhich, integer *ivalue, logical *iset) /* ***END PROLOGUE J4SAVE */ /* SAVE IPARAM */ /* ***FIRST EXECUTABLE STATEMENT J4SAVE */ - ret_val = iparam[(0 + (0 + (*iwhich - 1 << 2))) / 4]; + ret_val = iparam[(0 + (0 + ((*iwhich - 1) << 2))) / 4]; if (*iset) { iparam[*iwhich - 1] = *ivalue; } diff --git a/ext/f2c_math/xermsg.c b/ext/f2c_math/xermsg.c index b1eac2ab1..2f23e5844 100644 --- a/ext/f2c_math/xermsg.c +++ b/ext/f2c_math/xermsg.c @@ -364,7 +364,7 @@ static logical c_true = TRUE_; /* THEN WHETHER THE PROGRAM WILL CONTINUE. */ - if (mkntrl == 2 && *level >= 1 || mkntrl == 1 && *level == 2) { + if ((mkntrl == 2 && *level >= 1) || (mkntrl == 1 && *level == 2)) { i__1 = ltemp; s_copy(temp + i__1, " PROG ABORTED,", ltemp + 14 - i__1, (ftnlen) 14); @@ -437,7 +437,7 @@ L20: /* CONTROL FLAG IS SET FOR RECOVERY, THEN RETURN. */ L30: - if (*level <= 0 || *level == 1 && mkntrl <= 1) { + if ((*level <= 0) || (*level == 1 && mkntrl <= 1)) { return 0; } diff --git a/ext/f2c_math/xersve.c b/ext/f2c_math/xersve.c index 3c93c4161..94735e8e2 100644 --- a/ext/f2c_math/xersve.c +++ b/ext/f2c_math/xersve.c @@ -143,8 +143,8 @@ static integer c__1 = 1; for (i__ = 1; i__ <= i__2; ++i__) { io___9.ciunit = iunit; s_wsfe(&io___9); - do_fio(&c__1, libtab + (i__ - 1 << 3), (ftnlen)8); - do_fio(&c__1, subtab + (i__ - 1 << 3), (ftnlen)8); + do_fio(&c__1, libtab + ((i__ - 1) << 3), (ftnlen)8); + do_fio(&c__1, subtab + ((i__ - 1) << 3), (ftnlen)8); do_fio(&c__1, mestab + (i__ - 1) * 20, (ftnlen)20); do_fio(&c__1, (char *)&nertab[i__ - 1], (ftnlen)sizeof( integer)); @@ -187,8 +187,8 @@ static integer c__1 = 1; s_copy(mes, messg, (ftnlen)20, messg_len); i__1 = nmsg; for (i__ = 1; i__ <= i__1; ++i__) { - if (s_cmp(lib, libtab + (i__ - 1 << 3), (ftnlen)8, (ftnlen)8) == - 0 && s_cmp(sub, subtab + (i__ - 1 << 3), (ftnlen)8, ( + if (s_cmp(lib, libtab + ((i__ - 1) << 3), (ftnlen)8, (ftnlen)8) == + 0 && s_cmp(sub, subtab + ((i__ - 1) << 3), (ftnlen)8, ( ftnlen)8) == 0 && s_cmp(mes, mestab + (i__ - 1) * 20, ( ftnlen)20, (ftnlen)20) == 0 && *nerr == nertab[i__ - 1] && *level == levtab[i__ - 1]) { @@ -204,8 +204,8 @@ static integer c__1 = 1; /* Empty slot found for new message. */ ++nmsg; - s_copy(libtab + (i__ - 1 << 3), lib, (ftnlen)8, (ftnlen)8); - s_copy(subtab + (i__ - 1 << 3), sub, (ftnlen)8, (ftnlen)8); + s_copy(libtab + ((i__ - 1) << 3), lib, (ftnlen)8, (ftnlen)8); + s_copy(subtab + ((i__ - 1) << 3), sub, (ftnlen)8, (ftnlen)8); s_copy(mestab + (i__ - 1) * 20, mes, (ftnlen)20, (ftnlen)20); nertab[i__ - 1] = *nerr; levtab[i__ - 1] = *level; diff --git a/ext/f2c_recipes/Makefile.in b/ext/f2c_recipes/Makefile.in index daaf914a0..1ed83b9d8 100644 --- a/ext/f2c_recipes/Makefile.in +++ b/ext/f2c_recipes/Makefile.in @@ -1,9 +1,9 @@ #/bin/sh # # $Source: /cvsroot/cantera/cantera/ext/f2c_recipes/Makefile.in,v $ -# $Author: hkmoffa $ -# $Revision: 1.5 $ -# $Date: 2008/12/30 21:49:42 $ +# $Author$ +# $Revision$ +# $Date$ # .SUFFIXES : diff --git a/ext/lapack/Makefile.in b/ext/lapack/Makefile.in index ce5e6e97e..b71f30b4f 100755 --- a/ext/lapack/Makefile.in +++ b/ext/lapack/Makefile.in @@ -1,5 +1,5 @@ # $License$ -# $Id: Makefile.in,v 1.10 2008/12/30 21:58:10 hkmoffa Exp $ +# $Id$ # #/bin/sh @@ -18,6 +18,7 @@ F_FLAGS = @FFLAGS@ $(PIC_FLAG) OBJS = \ dbdsqr.o \ +dgbcon.o \ dgbtrf.o \ dgbtf2.o \ dgbtrs.o \ @@ -35,15 +36,18 @@ dgetri.o \ dgetrs.o \ dlabad.o \ dlabrd.o \ +dlacon.o \ dlacpy.o \ dlamch.o \ dlange.o \ +dlantr.o \ dlapy2.o \ dlarf.o \ dlarfb.o \ dlarfg.o \ dlarft.o \ dlartg.o \ +dlatrs.o \ dlas2.o \ dlascl.o \ dlaset.o \ @@ -56,6 +60,7 @@ dlasrt.o \ dlassq.o \ dlasv2.o \ dlaswp.o \ +dlatbs.o \ dorg2r.o \ dorgbr.o \ dorgl2.o \ @@ -66,7 +71,15 @@ dormbr.o \ dorml2.o \ dormlq.o \ dormqr.o \ +dpotrf.o \ +dpotrs.o \ +dpotf2.o \ drscl.o \ +dtrcon.o \ +dtrtrs.o \ +dgerfs.o \ +dgecon.o \ +dgeequ.o \ ilaenv.o #SRCS = $(OBJS:.o=.cpp) diff --git a/ext/lapack/dgbcon.f b/ext/lapack/dgbcon.f new file mode 100644 index 000000000..ba613b735 --- /dev/null +++ b/ext/lapack/dgbcon.f @@ -0,0 +1,222 @@ + SUBROUTINE DGBCON( NORM, N, KL, KU, AB, LDAB, IPIV, ANORM, RCOND, + $ WORK, IWORK, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* September 30, 1994 +* +* .. Scalar Arguments .. + CHARACTER NORM + INTEGER INFO, KL, KU, LDAB, N + DOUBLE PRECISION ANORM, RCOND +* .. +* .. Array Arguments .. + INTEGER IPIV( * ), IWORK( * ) + DOUBLE PRECISION AB( LDAB, * ), WORK( * ) +* .. +* +* Purpose +* ======= +* +* DGBCON estimates the reciprocal of the condition number of a real +* general band matrix A, in either the 1-norm or the infinity-norm, +* using the LU factorization computed by DGBTRF. +* +* An estimate is obtained for norm(inv(A)), and the reciprocal of the +* condition number is computed as +* RCOND = 1 / ( norm(A) * norm(inv(A)) ). +* +* Arguments +* ========= +* +* NORM (input) CHARACTER*1 +* Specifies whether the 1-norm condition number or the +* infinity-norm condition number is required: +* = '1' or 'O': 1-norm; +* = 'I': Infinity-norm. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* KL (input) INTEGER +* The number of subdiagonals within the band of A. KL >= 0. +* +* KU (input) INTEGER +* The number of superdiagonals within the band of A. KU >= 0. +* +* AB (input) DOUBLE PRECISION array, dimension (LDAB,N) +* Details of the LU factorization of the band matrix A, as +* computed by DGBTRF. U is stored as an upper triangular band +* matrix with KL+KU superdiagonals in rows 1 to KL+KU+1, and +* the multipliers used during the factorization are stored in +* rows KL+KU+2 to 2*KL+KU+1. +* +* LDAB (input) INTEGER +* The leading dimension of the array AB. LDAB >= 2*KL+KU+1. +* +* IPIV (input) INTEGER array, dimension (N) +* The pivot indices; for 1 <= i <= N, row i of the matrix was +* interchanged with row IPIV(i). +* +* ANORM (input) DOUBLE PRECISION +* If NORM = '1' or 'O', the 1-norm of the original matrix A. +* If NORM = 'I', the infinity-norm of the original matrix A. +* +* RCOND (output) DOUBLE PRECISION +* The reciprocal of the condition number of the matrix A, +* computed as RCOND = 1/(norm(A) * norm(inv(A))). +* +* WORK (workspace) DOUBLE PRECISION array, dimension (3*N) +* +* IWORK (workspace) INTEGER array, dimension (N) +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL LNOTI, ONENRM + CHARACTER NORMIN + INTEGER IX, J, JP, KASE, KASE1, KD, LM + DOUBLE PRECISION AINVNM, SCALE, SMLNUM, T +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER IDAMAX + DOUBLE PRECISION DDOT, DLAMCH + EXTERNAL LSAME, IDAMAX, DDOT, DLAMCH +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DLACON, DLATBS, DRSCL, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + ONENRM = NORM.EQ.'1' .OR. LSAME( NORM, 'O' ) + IF( .NOT.ONENRM .AND. .NOT.LSAME( NORM, 'I' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( KL.LT.0 ) THEN + INFO = -3 + ELSE IF( KU.LT.0 ) THEN + INFO = -4 + ELSE IF( LDAB.LT.2*KL+KU+1 ) THEN + INFO = -6 + ELSE IF( ANORM.LT.ZERO ) THEN + INFO = -8 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DGBCON', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + RCOND = ZERO + IF( N.EQ.0 ) THEN + RCOND = ONE + RETURN + ELSE IF( ANORM.EQ.ZERO ) THEN + RETURN + END IF +* + SMLNUM = DLAMCH( 'Safe minimum' ) +* +* Estimate the norm of inv(A). +* + AINVNM = ZERO + NORMIN = 'N' + IF( ONENRM ) THEN + KASE1 = 1 + ELSE + KASE1 = 2 + END IF + KD = KL + KU + 1 + LNOTI = KL.GT.0 + KASE = 0 + 10 CONTINUE + CALL DLACON( N, WORK( N+1 ), WORK, IWORK, AINVNM, KASE ) + IF( KASE.NE.0 ) THEN + IF( KASE.EQ.KASE1 ) THEN +* +* Multiply by inv(L). +* + IF( LNOTI ) THEN + DO 20 J = 1, N - 1 + LM = MIN( KL, N-J ) + JP = IPIV( J ) + T = WORK( JP ) + IF( JP.NE.J ) THEN + WORK( JP ) = WORK( J ) + WORK( J ) = T + END IF + CALL DAXPY( LM, -T, AB( KD+1, J ), 1, WORK( J+1 ), 1 ) + 20 CONTINUE + END IF +* +* Multiply by inv(U). +* + CALL DLATBS( 'Upper', 'No transpose', 'Non-unit', NORMIN, N, + $ KL+KU, AB, LDAB, WORK, SCALE, WORK( 2*N+1 ), + $ INFO ) + ELSE +* +* Multiply by inv(U'). +* + CALL DLATBS( 'Upper', 'Transpose', 'Non-unit', NORMIN, N, + $ KL+KU, AB, LDAB, WORK, SCALE, WORK( 2*N+1 ), + $ INFO ) +* +* Multiply by inv(L'). +* + IF( LNOTI ) THEN + DO 30 J = N - 1, 1, -1 + LM = MIN( KL, N-J ) + WORK( J ) = WORK( J ) - DDOT( LM, AB( KD+1, J ), 1, + $ WORK( J+1 ), 1 ) + JP = IPIV( J ) + IF( JP.NE.J ) THEN + T = WORK( JP ) + WORK( JP ) = WORK( J ) + WORK( J ) = T + END IF + 30 CONTINUE + END IF + END IF +* +* Divide X by 1/SCALE if doing so will not cause overflow. +* + NORMIN = 'Y' + IF( SCALE.NE.ONE ) THEN + IX = IDAMAX( N, WORK, 1 ) + IF( SCALE.LT.ABS( WORK( IX ) )*SMLNUM .OR. SCALE.EQ.ZERO ) + $ GO TO 40 + CALL DRSCL( N, SCALE, WORK, 1 ) + END IF + GO TO 10 + END IF +* +* Compute the estimate of the reciprocal condition number. +* + IF( AINVNM.NE.ZERO ) + $ RCOND = ( ONE / AINVNM ) / ANORM +* + 40 CONTINUE + RETURN +* +* End of DGBCON +* + END diff --git a/ext/lapack/dgbequ.f b/ext/lapack/dgbequ.f new file mode 100644 index 000000000..309798c98 --- /dev/null +++ b/ext/lapack/dgbequ.f @@ -0,0 +1,240 @@ + SUBROUTINE DGBEQU( M, N, KL, KU, AB, LDAB, R, C, ROWCND, COLCND, + $ AMAX, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* March 31, 1993 +* +* .. Scalar Arguments .. + INTEGER INFO, KL, KU, LDAB, M, N + DOUBLE PRECISION AMAX, COLCND, ROWCND +* .. +* .. Array Arguments .. + DOUBLE PRECISION AB( LDAB, * ), C( * ), R( * ) +* .. +* +* Purpose +* ======= +* +* DGBEQU computes row and column scalings intended to equilibrate an +* M-by-N band matrix A and reduce its condition number. R returns the +* row scale factors and C the column scale factors, chosen to try to +* make the largest element in each row and column of the matrix B with +* elements B(i,j)=R(i)*A(i,j)*C(j) have absolute value 1. +* +* R(i) and C(j) are restricted to be between SMLNUM = smallest safe +* number and BIGNUM = largest safe number. Use of these scaling +* factors is not guaranteed to reduce the condition number of A but +* works well in practice. +* +* Arguments +* ========= +* +* M (input) INTEGER +* The number of rows of the matrix A. M >= 0. +* +* N (input) INTEGER +* The number of columns of the matrix A. N >= 0. +* +* KL (input) INTEGER +* The number of subdiagonals within the band of A. KL >= 0. +* +* KU (input) INTEGER +* The number of superdiagonals within the band of A. KU >= 0. +* +* AB (input) DOUBLE PRECISION array, dimension (LDAB,N) +* The band matrix A, stored in rows 1 to KL+KU+1. The j-th +* column of A is stored in the j-th column of the array AB as +* follows: +* AB(ku+1+i-j,j) = A(i,j) for max(1,j-ku)<=i<=min(m,j+kl). +* +* LDAB (input) INTEGER +* The leading dimension of the array AB. LDAB >= KL+KU+1. +* +* R (output) DOUBLE PRECISION array, dimension (M) +* If INFO = 0, or INFO > M, R contains the row scale factors +* for A. +* +* C (output) DOUBLE PRECISION array, dimension (N) +* If INFO = 0, C contains the column scale factors for A. +* +* ROWCND (output) DOUBLE PRECISION +* If INFO = 0 or INFO > M, ROWCND contains the ratio of the +* smallest R(i) to the largest R(i). If ROWCND >= 0.1 and +* AMAX is neither too large nor too small, it is not worth +* scaling by R. +* +* COLCND (output) DOUBLE PRECISION +* If INFO = 0, COLCND contains the ratio of the smallest +* C(i) to the largest C(i). If COLCND >= 0.1, it is not +* worth scaling by C. +* +* AMAX (output) DOUBLE PRECISION +* Absolute value of largest matrix element. If AMAX is very +* close to overflow or very close to underflow, the matrix +* should be scaled. +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* > 0: if INFO = i, and i is +* <= M: the i-th row of A is exactly zero +* > M: the (i-M)-th column of A is exactly zero +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, J, KD + DOUBLE PRECISION BIGNUM, RCMAX, RCMIN, SMLNUM +* .. +* .. External Functions .. + DOUBLE PRECISION DLAMCH + EXTERNAL DLAMCH +* .. +* .. External Subroutines .. + EXTERNAL XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters +* + INFO = 0 + IF( M.LT.0 ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( KL.LT.0 ) THEN + INFO = -3 + ELSE IF( KU.LT.0 ) THEN + INFO = -4 + ELSE IF( LDAB.LT.KL+KU+1 ) THEN + INFO = -6 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DGBEQU', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( M.EQ.0 .OR. N.EQ.0 ) THEN + ROWCND = ONE + COLCND = ONE + AMAX = ZERO + RETURN + END IF +* +* Get machine constants. +* + SMLNUM = DLAMCH( 'S' ) + BIGNUM = ONE / SMLNUM +* +* Compute row scale factors. +* + DO 10 I = 1, M + R( I ) = ZERO + 10 CONTINUE +* +* Find the maximum element in each row. +* + KD = KU + 1 + DO 30 J = 1, N + DO 20 I = MAX( J-KU, 1 ), MIN( J+KL, M ) + R( I ) = MAX( R( I ), ABS( AB( KD+I-J, J ) ) ) + 20 CONTINUE + 30 CONTINUE +* +* Find the maximum and minimum scale factors. +* + RCMIN = BIGNUM + RCMAX = ZERO + DO 40 I = 1, M + RCMAX = MAX( RCMAX, R( I ) ) + RCMIN = MIN( RCMIN, R( I ) ) + 40 CONTINUE + AMAX = RCMAX +* + IF( RCMIN.EQ.ZERO ) THEN +* +* Find the first zero scale factor and return an error code. +* + DO 50 I = 1, M + IF( R( I ).EQ.ZERO ) THEN + INFO = I + RETURN + END IF + 50 CONTINUE + ELSE +* +* Invert the scale factors. +* + DO 60 I = 1, M + R( I ) = ONE / MIN( MAX( R( I ), SMLNUM ), BIGNUM ) + 60 CONTINUE +* +* Compute ROWCND = min(R(I)) / max(R(I)) +* + ROWCND = MAX( RCMIN, SMLNUM ) / MIN( RCMAX, BIGNUM ) + END IF +* +* Compute column scale factors +* + DO 70 J = 1, N + C( J ) = ZERO + 70 CONTINUE +* +* Find the maximum element in each column, +* assuming the row scaling computed above. +* + KD = KU + 1 + DO 90 J = 1, N + DO 80 I = MAX( J-KU, 1 ), MIN( J+KL, M ) + C( J ) = MAX( C( J ), ABS( AB( KD+I-J, J ) )*R( I ) ) + 80 CONTINUE + 90 CONTINUE +* +* Find the maximum and minimum scale factors. +* + RCMIN = BIGNUM + RCMAX = ZERO + DO 100 J = 1, N + RCMIN = MIN( RCMIN, C( J ) ) + RCMAX = MAX( RCMAX, C( J ) ) + 100 CONTINUE +* + IF( RCMIN.EQ.ZERO ) THEN +* +* Find the first zero scale factor and return an error code. +* + DO 110 J = 1, N + IF( C( J ).EQ.ZERO ) THEN + INFO = M + J + RETURN + END IF + 110 CONTINUE + ELSE +* +* Invert the scale factors. +* + DO 120 J = 1, N + C( J ) = ONE / MIN( MAX( C( J ), SMLNUM ), BIGNUM ) + 120 CONTINUE +* +* Compute COLCND = min(C(J)) / max(C(J)) +* + COLCND = MAX( RCMIN, SMLNUM ) / MIN( RCMAX, BIGNUM ) + END IF +* + RETURN +* +* End of DGBEQU +* + END diff --git a/ext/lapack/dgecon.f b/ext/lapack/dgecon.f new file mode 100644 index 000000000..f6bd485f4 --- /dev/null +++ b/ext/lapack/dgecon.f @@ -0,0 +1,181 @@ + SUBROUTINE DGECON( NORM, N, A, LDA, ANORM, RCOND, WORK, IWORK, + $ INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* February 29, 1992 +* +* .. Scalar Arguments .. + CHARACTER NORM + INTEGER INFO, LDA, N + DOUBLE PRECISION ANORM, RCOND +* .. +* .. Array Arguments .. + INTEGER IWORK( * ) + DOUBLE PRECISION A( LDA, * ), WORK( * ) +* .. +* +* Purpose +* ======= +* +* DGECON estimates the reciprocal of the condition number of a general +* real matrix A, in either the 1-norm or the infinity-norm, using +* the LU factorization computed by DGETRF. +* +* An estimate is obtained for norm(inv(A)), and the reciprocal of the +* condition number is computed as +* RCOND = 1 / ( norm(A) * norm(inv(A)) ). +* +* Arguments +* ========= +* +* NORM (input) CHARACTER*1 +* Specifies whether the 1-norm condition number or the +* infinity-norm condition number is required: +* = '1' or 'O': 1-norm; +* = 'I': Infinity-norm. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The factors L and U from the factorization A = P*L*U +* as computed by DGETRF. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* ANORM (input) DOUBLE PRECISION +* If NORM = '1' or 'O', the 1-norm of the original matrix A. +* If NORM = 'I', the infinity-norm of the original matrix A. +* +* RCOND (output) DOUBLE PRECISION +* The reciprocal of the condition number of the matrix A, +* computed as RCOND = 1/(norm(A) * norm(inv(A))). +* +* WORK (workspace) DOUBLE PRECISION array, dimension (4*N) +* +* IWORK (workspace) INTEGER array, dimension (N) +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL ONENRM + CHARACTER NORMIN + INTEGER IX, KASE, KASE1 + DOUBLE PRECISION AINVNM, SCALE, SL, SMLNUM, SU +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER IDAMAX + DOUBLE PRECISION DLAMCH + EXTERNAL LSAME, IDAMAX, DLAMCH +* .. +* .. External Subroutines .. + EXTERNAL DLACON, DLATRS, DRSCL, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + ONENRM = NORM.EQ.'1' .OR. LSAME( NORM, 'O' ) + IF( .NOT.ONENRM .AND. .NOT.LSAME( NORM, 'I' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + ELSE IF( ANORM.LT.ZERO ) THEN + INFO = -5 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DGECON', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + RCOND = ZERO + IF( N.EQ.0 ) THEN + RCOND = ONE + RETURN + ELSE IF( ANORM.EQ.ZERO ) THEN + RETURN + END IF +* + SMLNUM = DLAMCH( 'Safe minimum' ) +* +* Estimate the norm of inv(A). +* + AINVNM = ZERO + NORMIN = 'N' + IF( ONENRM ) THEN + KASE1 = 1 + ELSE + KASE1 = 2 + END IF + KASE = 0 + 10 CONTINUE + CALL DLACON( N, WORK( N+1 ), WORK, IWORK, AINVNM, KASE ) + IF( KASE.NE.0 ) THEN + IF( KASE.EQ.KASE1 ) THEN +* +* Multiply by inv(L). +* + CALL DLATRS( 'Lower', 'No transpose', 'Unit', NORMIN, N, A, + $ LDA, WORK, SL, WORK( 2*N+1 ), INFO ) +* +* Multiply by inv(U). +* + CALL DLATRS( 'Upper', 'No transpose', 'Non-unit', NORMIN, N, + $ A, LDA, WORK, SU, WORK( 3*N+1 ), INFO ) + ELSE +* +* Multiply by inv(U'). +* + CALL DLATRS( 'Upper', 'Transpose', 'Non-unit', NORMIN, N, A, + $ LDA, WORK, SU, WORK( 3*N+1 ), INFO ) +* +* Multiply by inv(L'). +* + CALL DLATRS( 'Lower', 'Transpose', 'Unit', NORMIN, N, A, + $ LDA, WORK, SL, WORK( 2*N+1 ), INFO ) + END IF +* +* Divide X by 1/(SL*SU) if doing so will not cause overflow. +* + SCALE = SL*SU + NORMIN = 'Y' + IF( SCALE.NE.ONE ) THEN + IX = IDAMAX( N, WORK, 1 ) + IF( SCALE.LT.ABS( WORK( IX ) )*SMLNUM .OR. SCALE.EQ.ZERO ) + $ GO TO 20 + CALL DRSCL( N, SCALE, WORK, 1 ) + END IF + GO TO 10 + END IF +* +* Compute the estimate of the reciprocal condition number. +* + IF( AINVNM.NE.ZERO ) + $ RCOND = ( ONE / AINVNM ) / ANORM +* + 20 CONTINUE + RETURN +* +* End of DGECON +* + END diff --git a/ext/lapack/dgeequ.f b/ext/lapack/dgeequ.f new file mode 100644 index 000000000..a1be3c169 --- /dev/null +++ b/ext/lapack/dgeequ.f @@ -0,0 +1,226 @@ + SUBROUTINE DGEEQU( M, N, A, LDA, R, C, ROWCND, COLCND, AMAX, + $ INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* March 31, 1993 +* +* .. Scalar Arguments .. + INTEGER INFO, LDA, M, N + DOUBLE PRECISION AMAX, COLCND, ROWCND +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), C( * ), R( * ) +* .. +* +* Purpose +* ======= +* +* DGEEQU computes row and column scalings intended to equilibrate an +* M-by-N matrix A and reduce its condition number. R returns the row +* scale factors and C the column scale factors, chosen to try to make +* the largest element in each row and column of the matrix B with +* elements B(i,j)=R(i)*A(i,j)*C(j) have absolute value 1. +* +* R(i) and C(j) are restricted to be between SMLNUM = smallest safe +* number and BIGNUM = largest safe number. Use of these scaling +* factors is not guaranteed to reduce the condition number of A but +* works well in practice. +* +* Arguments +* ========= +* +* M (input) INTEGER +* The number of rows of the matrix A. M >= 0. +* +* N (input) INTEGER +* The number of columns of the matrix A. N >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The M-by-N matrix whose equilibration factors are +* to be computed. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,M). +* +* R (output) DOUBLE PRECISION array, dimension (M) +* If INFO = 0 or INFO > M, R contains the row scale factors +* for A. +* +* C (output) DOUBLE PRECISION array, dimension (N) +* If INFO = 0, C contains the column scale factors for A. +* +* ROWCND (output) DOUBLE PRECISION +* If INFO = 0 or INFO > M, ROWCND contains the ratio of the +* smallest R(i) to the largest R(i). If ROWCND >= 0.1 and +* AMAX is neither too large nor too small, it is not worth +* scaling by R. +* +* COLCND (output) DOUBLE PRECISION +* If INFO = 0, COLCND contains the ratio of the smallest +* C(i) to the largest C(i). If COLCND >= 0.1, it is not +* worth scaling by C. +* +* AMAX (output) DOUBLE PRECISION +* Absolute value of largest matrix element. If AMAX is very +* close to overflow or very close to underflow, the matrix +* should be scaled. +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* > 0: if INFO = i, and i is +* <= M: the i-th row of A is exactly zero +* > M: the (i-M)-th column of A is exactly zero +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, J + DOUBLE PRECISION BIGNUM, RCMAX, RCMIN, SMLNUM +* .. +* .. External Functions .. + DOUBLE PRECISION DLAMCH + EXTERNAL DLAMCH +* .. +* .. External Subroutines .. + EXTERNAL XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + IF( M.LT.0 ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, M ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DGEEQU', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( M.EQ.0 .OR. N.EQ.0 ) THEN + ROWCND = ONE + COLCND = ONE + AMAX = ZERO + RETURN + END IF +* +* Get machine constants. +* + SMLNUM = DLAMCH( 'S' ) + BIGNUM = ONE / SMLNUM +* +* Compute row scale factors. +* + DO 10 I = 1, M + R( I ) = ZERO + 10 CONTINUE +* +* Find the maximum element in each row. +* + DO 30 J = 1, N + DO 20 I = 1, M + R( I ) = MAX( R( I ), ABS( A( I, J ) ) ) + 20 CONTINUE + 30 CONTINUE +* +* Find the maximum and minimum scale factors. +* + RCMIN = BIGNUM + RCMAX = ZERO + DO 40 I = 1, M + RCMAX = MAX( RCMAX, R( I ) ) + RCMIN = MIN( RCMIN, R( I ) ) + 40 CONTINUE + AMAX = RCMAX +* + IF( RCMIN.EQ.ZERO ) THEN +* +* Find the first zero scale factor and return an error code. +* + DO 50 I = 1, M + IF( R( I ).EQ.ZERO ) THEN + INFO = I + RETURN + END IF + 50 CONTINUE + ELSE +* +* Invert the scale factors. +* + DO 60 I = 1, M + R( I ) = ONE / MIN( MAX( R( I ), SMLNUM ), BIGNUM ) + 60 CONTINUE +* +* Compute ROWCND = min(R(I)) / max(R(I)) +* + ROWCND = MAX( RCMIN, SMLNUM ) / MIN( RCMAX, BIGNUM ) + END IF +* +* Compute column scale factors +* + DO 70 J = 1, N + C( J ) = ZERO + 70 CONTINUE +* +* Find the maximum element in each column, +* assuming the row scaling computed above. +* + DO 90 J = 1, N + DO 80 I = 1, M + C( J ) = MAX( C( J ), ABS( A( I, J ) )*R( I ) ) + 80 CONTINUE + 90 CONTINUE +* +* Find the maximum and minimum scale factors. +* + RCMIN = BIGNUM + RCMAX = ZERO + DO 100 J = 1, N + RCMIN = MIN( RCMIN, C( J ) ) + RCMAX = MAX( RCMAX, C( J ) ) + 100 CONTINUE +* + IF( RCMIN.EQ.ZERO ) THEN +* +* Find the first zero scale factor and return an error code. +* + DO 110 J = 1, N + IF( C( J ).EQ.ZERO ) THEN + INFO = M + J + RETURN + END IF + 110 CONTINUE + ELSE +* +* Invert the scale factors. +* + DO 120 J = 1, N + C( J ) = ONE / MIN( MAX( C( J ), SMLNUM ), BIGNUM ) + 120 CONTINUE +* +* Compute COLCND = min(C(J)) / max(C(J)) +* + COLCND = MAX( RCMIN, SMLNUM ) / MIN( RCMAX, BIGNUM ) + END IF +* + RETURN +* +* End of DGEEQU +* + END diff --git a/ext/lapack/dgerfs.f b/ext/lapack/dgerfs.f new file mode 100644 index 000000000..aa6c13415 --- /dev/null +++ b/ext/lapack/dgerfs.f @@ -0,0 +1,332 @@ + SUBROUTINE DGERFS( TRANS, N, NRHS, A, LDA, AF, LDAF, IPIV, B, LDB, + $ X, LDX, FERR, BERR, WORK, IWORK, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* September 30, 1994 +* +* .. Scalar Arguments .. + CHARACTER TRANS + INTEGER INFO, LDA, LDAF, LDB, LDX, N, NRHS +* .. +* .. Array Arguments .. + INTEGER IPIV( * ), IWORK( * ) + DOUBLE PRECISION A( LDA, * ), AF( LDAF, * ), B( LDB, * ), + $ BERR( * ), FERR( * ), WORK( * ), X( LDX, * ) +* .. +* +* Purpose +* ======= +* +* DGERFS improves the computed solution to a system of linear +* equations and provides error bounds and backward error estimates for +* the solution. +* +* Arguments +* ========= +* +* TRANS (input) CHARACTER*1 +* Specifies the form of the system of equations: +* = 'N': A * X = B (No transpose) +* = 'T': A**T * X = B (Transpose) +* = 'C': A**H * X = B (Conjugate transpose = Transpose) +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* NRHS (input) INTEGER +* The number of right hand sides, i.e., the number of columns +* of the matrices B and X. NRHS >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The original N-by-N matrix A. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* AF (input) DOUBLE PRECISION array, dimension (LDAF,N) +* The factors L and U from the factorization A = P*L*U +* as computed by DGETRF. +* +* LDAF (input) INTEGER +* The leading dimension of the array AF. LDAF >= max(1,N). +* +* IPIV (input) INTEGER array, dimension (N) +* The pivot indices from DGETRF; for 1<=i<=N, row i of the +* matrix was interchanged with row IPIV(i). +* +* B (input) DOUBLE PRECISION array, dimension (LDB,NRHS) +* The right hand side matrix B. +* +* LDB (input) INTEGER +* The leading dimension of the array B. LDB >= max(1,N). +* +* X (input/output) DOUBLE PRECISION array, dimension (LDX,NRHS) +* On entry, the solution matrix X, as computed by DGETRS. +* On exit, the improved solution matrix X. +* +* LDX (input) INTEGER +* The leading dimension of the array X. LDX >= max(1,N). +* +* FERR (output) DOUBLE PRECISION array, dimension (NRHS) +* The estimated forward error bound for each solution vector +* X(j) (the j-th column of the solution matrix X). +* If XTRUE is the true solution corresponding to X(j), FERR(j) +* is an estimated upper bound for the magnitude of the largest +* element in (X(j) - XTRUE) divided by the magnitude of the +* largest element in X(j). The estimate is as reliable as +* the estimate for RCOND, and is almost always a slight +* overestimate of the true error. +* +* BERR (output) DOUBLE PRECISION array, dimension (NRHS) +* The componentwise relative backward error of each solution +* vector X(j) (i.e., the smallest relative change in +* any element of A or B that makes X(j) an exact solution). +* +* WORK (workspace) DOUBLE PRECISION array, dimension (3*N) +* +* IWORK (workspace) INTEGER array, dimension (N) +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* +* Internal Parameters +* =================== +* +* ITMAX is the maximum number of steps of iterative refinement. +* +* ===================================================================== +* +* .. Parameters .. + INTEGER ITMAX + PARAMETER ( ITMAX = 5 ) + DOUBLE PRECISION ZERO + PARAMETER ( ZERO = 0.0D+0 ) + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) + DOUBLE PRECISION TWO + PARAMETER ( TWO = 2.0D+0 ) + DOUBLE PRECISION THREE + PARAMETER ( THREE = 3.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL NOTRAN + CHARACTER TRANST + INTEGER COUNT, I, J, K, KASE, NZ + DOUBLE PRECISION EPS, LSTRES, S, SAFE1, SAFE2, SAFMIN, XK +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DCOPY, DGEMV, DGETRS, DLACON, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX +* .. +* .. External Functions .. + LOGICAL LSAME + DOUBLE PRECISION DLAMCH + EXTERNAL LSAME, DLAMCH +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + NOTRAN = LSAME( TRANS, 'N' ) + IF( .NOT.NOTRAN .AND. .NOT.LSAME( TRANS, 'T' ) .AND. .NOT. + $ LSAME( TRANS, 'C' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( NRHS.LT.0 ) THEN + INFO = -3 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -5 + ELSE IF( LDAF.LT.MAX( 1, N ) ) THEN + INFO = -7 + ELSE IF( LDB.LT.MAX( 1, N ) ) THEN + INFO = -10 + ELSE IF( LDX.LT.MAX( 1, N ) ) THEN + INFO = -12 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DGERFS', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 .OR. NRHS.EQ.0 ) THEN + DO 10 J = 1, NRHS + FERR( J ) = ZERO + BERR( J ) = ZERO + 10 CONTINUE + RETURN + END IF +* + IF( NOTRAN ) THEN + TRANST = 'T' + ELSE + TRANST = 'N' + END IF +* +* NZ = maximum number of nonzero elements in each row of A, plus 1 +* + NZ = N + 1 + EPS = DLAMCH( 'Epsilon' ) + SAFMIN = DLAMCH( 'Safe minimum' ) + SAFE1 = NZ*SAFMIN + SAFE2 = SAFE1 / EPS +* +* Do for each right hand side +* + DO 140 J = 1, NRHS +* + COUNT = 1 + LSTRES = THREE + 20 CONTINUE +* +* Loop until stopping criterion is satisfied. +* +* Compute residual R = B - op(A) * X, +* where op(A) = A, A**T, or A**H, depending on TRANS. +* + CALL DCOPY( N, B( 1, J ), 1, WORK( N+1 ), 1 ) + CALL DGEMV( TRANS, N, N, -ONE, A, LDA, X( 1, J ), 1, ONE, + $ WORK( N+1 ), 1 ) +* +* Compute componentwise relative backward error from formula +* +* max(i) ( abs(R(i)) / ( abs(op(A))*abs(X) + abs(B) )(i) ) +* +* where abs(Z) is the componentwise absolute value of the matrix +* or vector Z. If the i-th component of the denominator is less +* than SAFE2, then SAFE1 is added to the i-th components of the +* numerator and denominator before dividing. +* + DO 30 I = 1, N + WORK( I ) = ABS( B( I, J ) ) + 30 CONTINUE +* +* Compute abs(op(A))*abs(X) + abs(B). +* + IF( NOTRAN ) THEN + DO 50 K = 1, N + XK = ABS( X( K, J ) ) + DO 40 I = 1, N + WORK( I ) = WORK( I ) + ABS( A( I, K ) )*XK + 40 CONTINUE + 50 CONTINUE + ELSE + DO 70 K = 1, N + S = ZERO + DO 60 I = 1, N + S = S + ABS( A( I, K ) )*ABS( X( I, J ) ) + 60 CONTINUE + WORK( K ) = WORK( K ) + S + 70 CONTINUE + END IF + S = ZERO + DO 80 I = 1, N + IF( WORK( I ).GT.SAFE2 ) THEN + S = MAX( S, ABS( WORK( N+I ) ) / WORK( I ) ) + ELSE + S = MAX( S, ( ABS( WORK( N+I ) )+SAFE1 ) / + $ ( WORK( I )+SAFE1 ) ) + END IF + 80 CONTINUE + BERR( J ) = S +* +* Test stopping criterion. Continue iterating if +* 1) The residual BERR(J) is larger than machine epsilon, and +* 2) BERR(J) decreased by at least a factor of 2 during the +* last iteration, and +* 3) At most ITMAX iterations tried. +* + IF( BERR( J ).GT.EPS .AND. TWO*BERR( J ).LE.LSTRES .AND. + $ COUNT.LE.ITMAX ) THEN +* +* Update solution and try again. +* + CALL DGETRS( TRANS, N, 1, AF, LDAF, IPIV, WORK( N+1 ), N, + $ INFO ) + CALL DAXPY( N, ONE, WORK( N+1 ), 1, X( 1, J ), 1 ) + LSTRES = BERR( J ) + COUNT = COUNT + 1 + GO TO 20 + END IF +* +* Bound error from formula +* +* norm(X - XTRUE) / norm(X) .le. FERR = +* norm( abs(inv(op(A)))* +* ( abs(R) + NZ*EPS*( abs(op(A))*abs(X)+abs(B) ))) / norm(X) +* +* where +* norm(Z) is the magnitude of the largest component of Z +* inv(op(A)) is the inverse of op(A) +* abs(Z) is the componentwise absolute value of the matrix or +* vector Z +* NZ is the maximum number of nonzeros in any row of A, plus 1 +* EPS is machine epsilon +* +* The i-th component of abs(R)+NZ*EPS*(abs(op(A))*abs(X)+abs(B)) +* is incremented by SAFE1 if the i-th component of +* abs(op(A))*abs(X) + abs(B) is less than SAFE2. +* +* Use DLACON to estimate the infinity-norm of the matrix +* inv(op(A)) * diag(W), +* where W = abs(R) + NZ*EPS*( abs(op(A))*abs(X)+abs(B) ))) +* + DO 90 I = 1, N + IF( WORK( I ).GT.SAFE2 ) THEN + WORK( I ) = ABS( WORK( N+I ) ) + NZ*EPS*WORK( I ) + ELSE + WORK( I ) = ABS( WORK( N+I ) ) + NZ*EPS*WORK( I ) + SAFE1 + END IF + 90 CONTINUE +* + KASE = 0 + 100 CONTINUE + CALL DLACON( N, WORK( 2*N+1 ), WORK( N+1 ), IWORK, FERR( J ), + $ KASE ) + IF( KASE.NE.0 ) THEN + IF( KASE.EQ.1 ) THEN +* +* Multiply by diag(W)*inv(op(A)**T). +* + CALL DGETRS( TRANST, N, 1, AF, LDAF, IPIV, WORK( N+1 ), + $ N, INFO ) + DO 110 I = 1, N + WORK( N+I ) = WORK( I )*WORK( N+I ) + 110 CONTINUE + ELSE +* +* Multiply by inv(op(A))*diag(W). +* + DO 120 I = 1, N + WORK( N+I ) = WORK( I )*WORK( N+I ) + 120 CONTINUE + CALL DGETRS( TRANS, N, 1, AF, LDAF, IPIV, WORK( N+1 ), N, + $ INFO ) + END IF + GO TO 100 + END IF +* +* Normalize error. +* + LSTRES = ZERO + DO 130 I = 1, N + LSTRES = MAX( LSTRES, ABS( X( I, J ) ) ) + 130 CONTINUE + IF( LSTRES.NE.ZERO ) + $ FERR( J ) = FERR( J ) / LSTRES +* + 140 CONTINUE +* + RETURN +* +* End of DGERFS +* + END diff --git a/ext/lapack/dlacon.f b/ext/lapack/dlacon.f new file mode 100644 index 000000000..4efa0e816 --- /dev/null +++ b/ext/lapack/dlacon.f @@ -0,0 +1,204 @@ + SUBROUTINE DLACON( N, V, X, ISGN, EST, KASE ) +* +* -- LAPACK auxiliary routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* February 29, 1992 +* +* .. Scalar Arguments .. + INTEGER KASE, N + DOUBLE PRECISION EST +* .. +* .. Array Arguments .. + INTEGER ISGN( * ) + DOUBLE PRECISION V( * ), X( * ) +* .. +* +* Purpose +* ======= +* +* DLACON estimates the 1-norm of a square, real matrix A. +* Reverse communication is used for evaluating matrix-vector products. +* +* Arguments +* ========= +* +* N (input) INTEGER +* The order of the matrix. N >= 1. +* +* V (workspace) DOUBLE PRECISION array, dimension (N) +* On the final return, V = A*W, where EST = norm(V)/norm(W) +* (W is not returned). +* +* X (input/output) DOUBLE PRECISION array, dimension (N) +* On an intermediate return, X should be overwritten by +* A * X, if KASE=1, +* A' * X, if KASE=2, +* and DLACON must be re-called with all the other parameters +* unchanged. +* +* ISGN (workspace) INTEGER array, dimension (N) +* +* EST (output) DOUBLE PRECISION +* An estimate (a lower bound) for norm(A). +* +* KASE (input/output) INTEGER +* On the initial call to DLACON, KASE should be 0. +* On an intermediate return, KASE will be 1 or 2, indicating +* whether X should be overwritten by A * X or A' * X. +* On the final return from DLACON, KASE will again be 0. +* +* Further Details +* ======= ======= +* +* Contributed by Nick Higham, University of Manchester. +* Originally named SONEST, dated March 16, 1988. +* +* Reference: N.J. Higham, "FORTRAN codes for estimating the one-norm of +* a real or complex matrix, with applications to condition estimation", +* ACM Trans. Math. Soft., vol. 14, no. 4, pp. 381-396, December 1988. +* +* ===================================================================== +* +* .. Parameters .. + INTEGER ITMAX + PARAMETER ( ITMAX = 5 ) + DOUBLE PRECISION ZERO, ONE, TWO + PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0, TWO = 2.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, ITER, J, JLAST, JUMP + DOUBLE PRECISION ALTSGN, ESTOLD, TEMP +* .. +* .. External Functions .. + INTEGER IDAMAX + DOUBLE PRECISION DASUM + EXTERNAL IDAMAX, DASUM +* .. +* .. External Subroutines .. + EXTERNAL DCOPY +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, DBLE, NINT, SIGN +* .. +* .. Save statement .. + SAVE +* .. +* .. Executable Statements .. +* + IF( KASE.EQ.0 ) THEN + DO 10 I = 1, N + X( I ) = ONE / DBLE( N ) + 10 CONTINUE + KASE = 1 + JUMP = 1 + RETURN + END IF +* + GO TO ( 20, 40, 70, 110, 140 )JUMP +* +* ................ ENTRY (JUMP = 1) +* FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. +* + 20 CONTINUE + IF( N.EQ.1 ) THEN + V( 1 ) = X( 1 ) + EST = ABS( V( 1 ) ) +* ... QUIT + GO TO 150 + END IF + EST = DASUM( N, X, 1 ) +* + DO 30 I = 1, N + X( I ) = SIGN( ONE, X( I ) ) + ISGN( I ) = NINT( X( I ) ) + 30 CONTINUE + KASE = 2 + JUMP = 2 + RETURN +* +* ................ ENTRY (JUMP = 2) +* FIRST ITERATION. X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. +* + 40 CONTINUE + J = IDAMAX( N, X, 1 ) + ITER = 2 +* +* MAIN LOOP - ITERATIONS 2,3,...,ITMAX. +* + 50 CONTINUE + DO 60 I = 1, N + X( I ) = ZERO + 60 CONTINUE + X( J ) = ONE + KASE = 1 + JUMP = 3 + RETURN +* +* ................ ENTRY (JUMP = 3) +* X HAS BEEN OVERWRITTEN BY A*X. +* + 70 CONTINUE + CALL DCOPY( N, X, 1, V, 1 ) + ESTOLD = EST + EST = DASUM( N, V, 1 ) + DO 80 I = 1, N + IF( NINT( SIGN( ONE, X( I ) ) ).NE.ISGN( I ) ) + $ GO TO 90 + 80 CONTINUE +* REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. + GO TO 120 +* + 90 CONTINUE +* TEST FOR CYCLING. + IF( EST.LE.ESTOLD ) + $ GO TO 120 +* + DO 100 I = 1, N + X( I ) = SIGN( ONE, X( I ) ) + ISGN( I ) = NINT( X( I ) ) + 100 CONTINUE + KASE = 2 + JUMP = 4 + RETURN +* +* ................ ENTRY (JUMP = 4) +* X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. +* + 110 CONTINUE + JLAST = J + J = IDAMAX( N, X, 1 ) + IF( ( X( JLAST ).NE.ABS( X( J ) ) ) .AND. ( ITER.LT.ITMAX ) ) THEN + ITER = ITER + 1 + GO TO 50 + END IF +* +* ITERATION COMPLETE. FINAL STAGE. +* + 120 CONTINUE + ALTSGN = ONE + DO 130 I = 1, N + X( I ) = ALTSGN*( ONE+DBLE( I-1 ) / DBLE( N-1 ) ) + ALTSGN = -ALTSGN + 130 CONTINUE + KASE = 1 + JUMP = 5 + RETURN +* +* ................ ENTRY (JUMP = 5) +* X HAS BEEN OVERWRITTEN BY A*X. +* + 140 CONTINUE + TEMP = TWO*( DASUM( N, X, 1 ) / DBLE( 3*N ) ) + IF( TEMP.GT.EST ) THEN + CALL DCOPY( N, X, 1, V, 1 ) + EST = TEMP + END IF +* + 150 CONTINUE + KASE = 0 + RETURN +* +* End of DLACON +* + END diff --git a/ext/lapack/dlantr.f b/ext/lapack/dlantr.f new file mode 100644 index 000000000..19e9b5d92 --- /dev/null +++ b/ext/lapack/dlantr.f @@ -0,0 +1,277 @@ + DOUBLE PRECISION FUNCTION DLANTR( NORM, UPLO, DIAG, M, N, A, LDA, + $ WORK ) +* +* -- LAPACK auxiliary routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* October 31, 1992 +* +* .. Scalar Arguments .. + CHARACTER DIAG, NORM, UPLO + INTEGER LDA, M, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), WORK( * ) +* .. +* +* Purpose +* ======= +* +* DLANTR returns the value of the one norm, or the Frobenius norm, or +* the infinity norm, or the element of largest absolute value of a +* trapezoidal or triangular matrix A. +* +* Description +* =========== +* +* DLANTR returns the value +* +* DLANTR = ( max(abs(A(i,j))), NORM = 'M' or 'm' +* ( +* ( norm1(A), NORM = '1', 'O' or 'o' +* ( +* ( normI(A), NORM = 'I' or 'i' +* ( +* ( normF(A), NORM = 'F', 'f', 'E' or 'e' +* +* where norm1 denotes the one norm of a matrix (maximum column sum), +* normI denotes the infinity norm of a matrix (maximum row sum) and +* normF denotes the Frobenius norm of a matrix (square root of sum of +* squares). Note that max(abs(A(i,j))) is not a matrix norm. +* +* Arguments +* ========= +* +* NORM (input) CHARACTER*1 +* Specifies the value to be returned in DLANTR as described +* above. +* +* UPLO (input) CHARACTER*1 +* Specifies whether the matrix A is upper or lower trapezoidal. +* = 'U': Upper trapezoidal +* = 'L': Lower trapezoidal +* Note that A is triangular instead of trapezoidal if M = N. +* +* DIAG (input) CHARACTER*1 +* Specifies whether or not the matrix A has unit diagonal. +* = 'N': Non-unit diagonal +* = 'U': Unit diagonal +* +* M (input) INTEGER +* The number of rows of the matrix A. M >= 0, and if +* UPLO = 'U', M <= N. When M = 0, DLANTR is set to zero. +* +* N (input) INTEGER +* The number of columns of the matrix A. N >= 0, and if +* UPLO = 'L', N <= M. When N = 0, DLANTR is set to zero. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The trapezoidal matrix A (A is triangular if M = N). +* If UPLO = 'U', the leading m by n upper trapezoidal part of +* the array A contains the upper trapezoidal matrix, and the +* strictly lower triangular part of A is not referenced. +* If UPLO = 'L', the leading m by n lower trapezoidal part of +* the array A contains the lower trapezoidal matrix, and the +* strictly upper triangular part of A is not referenced. Note +* that when DIAG = 'U', the diagonal elements of A are not +* referenced and are assumed to be one. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(M,1). +* +* WORK (workspace) DOUBLE PRECISION array, dimension (LWORK), +* where LWORK >= M when NORM = 'I'; otherwise, WORK is not +* referenced. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UDIAG + INTEGER I, J + DOUBLE PRECISION SCALE, SUM, VALUE +* .. +* .. External Subroutines .. + EXTERNAL DLASSQ +* .. +* .. External Functions .. + LOGICAL LSAME + EXTERNAL LSAME +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX, MIN, SQRT +* .. +* .. Executable Statements .. +* + IF( MIN( M, N ).EQ.0 ) THEN + VALUE = ZERO + ELSE IF( LSAME( NORM, 'M' ) ) THEN +* +* Find max(abs(A(i,j))). +* + IF( LSAME( DIAG, 'U' ) ) THEN + VALUE = ONE + IF( LSAME( UPLO, 'U' ) ) THEN + DO 20 J = 1, N + DO 10 I = 1, MIN( M, J-1 ) + VALUE = MAX( VALUE, ABS( A( I, J ) ) ) + 10 CONTINUE + 20 CONTINUE + ELSE + DO 40 J = 1, N + DO 30 I = J + 1, M + VALUE = MAX( VALUE, ABS( A( I, J ) ) ) + 30 CONTINUE + 40 CONTINUE + END IF + ELSE + VALUE = ZERO + IF( LSAME( UPLO, 'U' ) ) THEN + DO 60 J = 1, N + DO 50 I = 1, MIN( M, J ) + VALUE = MAX( VALUE, ABS( A( I, J ) ) ) + 50 CONTINUE + 60 CONTINUE + ELSE + DO 80 J = 1, N + DO 70 I = J, M + VALUE = MAX( VALUE, ABS( A( I, J ) ) ) + 70 CONTINUE + 80 CONTINUE + END IF + END IF + ELSE IF( ( LSAME( NORM, 'O' ) ) .OR. ( NORM.EQ.'1' ) ) THEN +* +* Find norm1(A). +* + VALUE = ZERO + UDIAG = LSAME( DIAG, 'U' ) + IF( LSAME( UPLO, 'U' ) ) THEN + DO 110 J = 1, N + IF( ( UDIAG ) .AND. ( J.LE.M ) ) THEN + SUM = ONE + DO 90 I = 1, J - 1 + SUM = SUM + ABS( A( I, J ) ) + 90 CONTINUE + ELSE + SUM = ZERO + DO 100 I = 1, MIN( M, J ) + SUM = SUM + ABS( A( I, J ) ) + 100 CONTINUE + END IF + VALUE = MAX( VALUE, SUM ) + 110 CONTINUE + ELSE + DO 140 J = 1, N + IF( UDIAG ) THEN + SUM = ONE + DO 120 I = J + 1, M + SUM = SUM + ABS( A( I, J ) ) + 120 CONTINUE + ELSE + SUM = ZERO + DO 130 I = J, M + SUM = SUM + ABS( A( I, J ) ) + 130 CONTINUE + END IF + VALUE = MAX( VALUE, SUM ) + 140 CONTINUE + END IF + ELSE IF( LSAME( NORM, 'I' ) ) THEN +* +* Find normI(A). +* + IF( LSAME( UPLO, 'U' ) ) THEN + IF( LSAME( DIAG, 'U' ) ) THEN + DO 150 I = 1, M + WORK( I ) = ONE + 150 CONTINUE + DO 170 J = 1, N + DO 160 I = 1, MIN( M, J-1 ) + WORK( I ) = WORK( I ) + ABS( A( I, J ) ) + 160 CONTINUE + 170 CONTINUE + ELSE + DO 180 I = 1, M + WORK( I ) = ZERO + 180 CONTINUE + DO 200 J = 1, N + DO 190 I = 1, MIN( M, J ) + WORK( I ) = WORK( I ) + ABS( A( I, J ) ) + 190 CONTINUE + 200 CONTINUE + END IF + ELSE + IF( LSAME( DIAG, 'U' ) ) THEN + DO 210 I = 1, N + WORK( I ) = ONE + 210 CONTINUE + DO 220 I = N + 1, M + WORK( I ) = ZERO + 220 CONTINUE + DO 240 J = 1, N + DO 230 I = J + 1, M + WORK( I ) = WORK( I ) + ABS( A( I, J ) ) + 230 CONTINUE + 240 CONTINUE + ELSE + DO 250 I = 1, M + WORK( I ) = ZERO + 250 CONTINUE + DO 270 J = 1, N + DO 260 I = J, M + WORK( I ) = WORK( I ) + ABS( A( I, J ) ) + 260 CONTINUE + 270 CONTINUE + END IF + END IF + VALUE = ZERO + DO 280 I = 1, M + VALUE = MAX( VALUE, WORK( I ) ) + 280 CONTINUE + ELSE IF( ( LSAME( NORM, 'F' ) ) .OR. ( LSAME( NORM, 'E' ) ) ) THEN +* +* Find normF(A). +* + IF( LSAME( UPLO, 'U' ) ) THEN + IF( LSAME( DIAG, 'U' ) ) THEN + SCALE = ONE + SUM = MIN( M, N ) + DO 290 J = 2, N + CALL DLASSQ( MIN( M, J-1 ), A( 1, J ), 1, SCALE, SUM ) + 290 CONTINUE + ELSE + SCALE = ZERO + SUM = ONE + DO 300 J = 1, N + CALL DLASSQ( MIN( M, J ), A( 1, J ), 1, SCALE, SUM ) + 300 CONTINUE + END IF + ELSE + IF( LSAME( DIAG, 'U' ) ) THEN + SCALE = ONE + SUM = MIN( M, N ) + DO 310 J = 1, N + CALL DLASSQ( M-J, A( MIN( M, J+1 ), J ), 1, SCALE, + $ SUM ) + 310 CONTINUE + ELSE + SCALE = ZERO + SUM = ONE + DO 320 J = 1, N + CALL DLASSQ( M-J+1, A( J, J ), 1, SCALE, SUM ) + 320 CONTINUE + END IF + END IF + VALUE = SCALE*SQRT( SUM ) + END IF +* + DLANTR = VALUE + RETURN +* +* End of DLANTR +* + END diff --git a/ext/lapack/dlatbs.f b/ext/lapack/dlatbs.f new file mode 100644 index 000000000..fe7dd11cb --- /dev/null +++ b/ext/lapack/dlatbs.f @@ -0,0 +1,724 @@ + SUBROUTINE DLATBS( UPLO, TRANS, DIAG, NORMIN, N, KD, AB, LDAB, X, + $ SCALE, CNORM, INFO ) +* +* -- LAPACK auxiliary routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* June 30, 1992 +* +* .. Scalar Arguments .. + CHARACTER DIAG, NORMIN, TRANS, UPLO + INTEGER INFO, KD, LDAB, N + DOUBLE PRECISION SCALE +* .. +* .. Array Arguments .. + DOUBLE PRECISION AB( LDAB, * ), CNORM( * ), X( * ) +* .. +* +* Purpose +* ======= +* +* DLATBS solves one of the triangular systems +* +* A *x = s*b or A'*x = s*b +* +* with scaling to prevent overflow, where A is an upper or lower +* triangular band matrix. Here A' denotes the transpose of A, x and b +* are n-element vectors, and s is a scaling factor, usually less than +* or equal to 1, chosen so that the components of x will be less than +* the overflow threshold. If the unscaled problem will not cause +* overflow, the Level 2 BLAS routine DTBSV is called. If the matrix A +* is singular (A(j,j) = 0 for some j), then s is set to 0 and a +* non-trivial solution to A*x = 0 is returned. +* +* Arguments +* ========= +* +* UPLO (input) CHARACTER*1 +* Specifies whether the matrix A is upper or lower triangular. +* = 'U': Upper triangular +* = 'L': Lower triangular +* +* TRANS (input) CHARACTER*1 +* Specifies the operation applied to A. +* = 'N': Solve A * x = s*b (No transpose) +* = 'T': Solve A'* x = s*b (Transpose) +* = 'C': Solve A'* x = s*b (Conjugate transpose = Transpose) +* +* DIAG (input) CHARACTER*1 +* Specifies whether or not the matrix A is unit triangular. +* = 'N': Non-unit triangular +* = 'U': Unit triangular +* +* NORMIN (input) CHARACTER*1 +* Specifies whether CNORM has been set or not. +* = 'Y': CNORM contains the column norms on entry +* = 'N': CNORM is not set on entry. On exit, the norms will +* be computed and stored in CNORM. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* KD (input) INTEGER +* The number of subdiagonals or superdiagonals in the +* triangular matrix A. KD >= 0. +* +* AB (input) DOUBLE PRECISION array, dimension (LDAB,N) +* The upper or lower triangular band matrix A, stored in the +* first KD+1 rows of the array. The j-th column of A is stored +* in the j-th column of the array AB as follows: +* if UPLO = 'U', AB(kd+1+i-j,j) = A(i,j) for max(1,j-kd)<=i<=j; +* if UPLO = 'L', AB(1+i-j,j) = A(i,j) for j<=i<=min(n,j+kd). +* +* LDAB (input) INTEGER +* The leading dimension of the array AB. LDAB >= KD+1. +* +* X (input/output) DOUBLE PRECISION array, dimension (N) +* On entry, the right hand side b of the triangular system. +* On exit, X is overwritten by the solution vector x. +* +* SCALE (output) DOUBLE PRECISION +* The scaling factor s for the triangular system +* A * x = s*b or A'* x = s*b. +* If SCALE = 0, the matrix A is singular or badly scaled, and +* the vector x is an exact or approximate solution to A*x = 0. +* +* CNORM (input or output) DOUBLE PRECISION array, dimension (N) +* +* If NORMIN = 'Y', CNORM is an input argument and CNORM(j) +* contains the norm of the off-diagonal part of the j-th column +* of A. If TRANS = 'N', CNORM(j) must be greater than or equal +* to the infinity-norm, and if TRANS = 'T' or 'C', CNORM(j) +* must be greater than or equal to the 1-norm. +* +* If NORMIN = 'N', CNORM is an output argument and CNORM(j) +* returns the 1-norm of the offdiagonal part of the j-th column +* of A. +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -k, the k-th argument had an illegal value +* +* Further Details +* ======= ======= +* +* A rough bound on x is computed; if that is less than overflow, DTBSV +* is called, otherwise, specific code is used which checks for possible +* overflow or divide-by-zero at every operation. +* +* A columnwise scheme is used for solving A*x = b. The basic algorithm +* if A is lower triangular is +* +* x[1:n] := b[1:n] +* for j = 1, ..., n +* x(j) := x(j) / A(j,j) +* x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] +* end +* +* Define bounds on the components of x after j iterations of the loop: +* M(j) = bound on x[1:j] +* G(j) = bound on x[j+1:n] +* Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. +* +* Then for iteration j+1 we have +* M(j+1) <= G(j) / | A(j+1,j+1) | +* G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | +* <= G(j) ( 1 + CNORM(j+1) / | A(j+1,j+1) | ) +* +* where CNORM(j+1) is greater than or equal to the infinity-norm of +* column j+1 of A, not counting the diagonal. Hence +* +* G(j) <= G(0) product ( 1 + CNORM(i) / | A(i,i) | ) +* 1<=i<=j +* and +* +* |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + CNORM(i) / |A(i,i)| ) +* 1<=i< j +* +* Since |x(j)| <= M(j), we use the Level 2 BLAS routine DTBSV if the +* reciprocal of the largest M(j), j=1,..,n, is larger than +* max(underflow, 1/overflow). +* +* The bound on x(j) is also used to determine when a step in the +* columnwise method can be performed without fear of overflow. If +* the computed bound is greater than a large constant, x is scaled to +* prevent overflow, but if the bound overflows, x is set to 0, x(j) to +* 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. +* +* Similarly, a row-wise scheme is used to solve A'*x = b. The basic +* algorithm for A upper triangular is +* +* for j = 1, ..., n +* x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) +* end +* +* We simultaneously compute two bounds +* G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j +* M(j) = bound on x(i), 1<=i<=j +* +* The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we +* add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. +* Then the bound on x(j) is +* +* M(j) <= M(j-1) * ( 1 + CNORM(j) ) / | A(j,j) | +* +* <= M(0) * product ( ( 1 + CNORM(i) ) / |A(i,i)| ) +* 1<=i<=j +* +* and we can safely call DTBSV if 1/M(n) and 1/G(n) are both greater +* than max(underflow, 1/overflow). +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO, HALF, ONE + PARAMETER ( ZERO = 0.0D+0, HALF = 0.5D+0, ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL NOTRAN, NOUNIT, UPPER + INTEGER I, IMAX, J, JFIRST, JINC, JLAST, JLEN, MAIND + DOUBLE PRECISION BIGNUM, GROW, REC, SMLNUM, SUMJ, TJJ, TJJS, + $ TMAX, TSCAL, USCAL, XBND, XJ, XMAX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER IDAMAX + DOUBLE PRECISION DASUM, DDOT, DLAMCH + EXTERNAL LSAME, IDAMAX, DASUM, DDOT, DLAMCH +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DSCAL, DTBSV, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX, MIN +* .. +* .. Executable Statements .. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + NOTRAN = LSAME( TRANS, 'N' ) + NOUNIT = LSAME( DIAG, 'N' ) +* +* Test the input parameters. +* + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( .NOT.NOTRAN .AND. .NOT.LSAME( TRANS, 'T' ) .AND. .NOT. + $ LSAME( TRANS, 'C' ) ) THEN + INFO = -2 + ELSE IF( .NOT.NOUNIT .AND. .NOT.LSAME( DIAG, 'U' ) ) THEN + INFO = -3 + ELSE IF( .NOT.LSAME( NORMIN, 'Y' ) .AND. .NOT. + $ LSAME( NORMIN, 'N' ) ) THEN + INFO = -4 + ELSE IF( N.LT.0 ) THEN + INFO = -5 + ELSE IF( KD.LT.0 ) THEN + INFO = -6 + ELSE IF( LDAB.LT.KD+1 ) THEN + INFO = -8 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLATBS', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine machine dependent parameters to control overflow. +* + SMLNUM = DLAMCH( 'Safe minimum' ) / DLAMCH( 'Precision' ) + BIGNUM = ONE / SMLNUM + SCALE = ONE +* + IF( LSAME( NORMIN, 'N' ) ) THEN +* +* Compute the 1-norm of each column, not including the diagonal. +* + IF( UPPER ) THEN +* +* A is upper triangular. +* + DO 10 J = 1, N + JLEN = MIN( KD, J-1 ) + CNORM( J ) = DASUM( JLEN, AB( KD+1-JLEN, J ), 1 ) + 10 CONTINUE + ELSE +* +* A is lower triangular. +* + DO 20 J = 1, N + JLEN = MIN( KD, N-J ) + IF( JLEN.GT.0 ) THEN + CNORM( J ) = DASUM( JLEN, AB( 2, J ), 1 ) + ELSE + CNORM( J ) = ZERO + END IF + 20 CONTINUE + END IF + END IF +* +* Scale the column norms by TSCAL if the maximum element in CNORM is +* greater than BIGNUM. +* + IMAX = IDAMAX( N, CNORM, 1 ) + TMAX = CNORM( IMAX ) + IF( TMAX.LE.BIGNUM ) THEN + TSCAL = ONE + ELSE + TSCAL = ONE / ( SMLNUM*TMAX ) + CALL DSCAL( N, TSCAL, CNORM, 1 ) + END IF +* +* Compute a bound on the computed solution vector to see if the +* Level 2 BLAS routine DTBSV can be used. +* + J = IDAMAX( N, X, 1 ) + XMAX = ABS( X( J ) ) + XBND = XMAX + IF( NOTRAN ) THEN +* +* Compute the growth in A * x = b. +* + IF( UPPER ) THEN + JFIRST = N + JLAST = 1 + JINC = -1 + MAIND = KD + 1 + ELSE + JFIRST = 1 + JLAST = N + JINC = 1 + MAIND = 1 + END IF +* + IF( TSCAL.NE.ONE ) THEN + GROW = ZERO + GO TO 50 + END IF +* + IF( NOUNIT ) THEN +* +* A is non-unit triangular. +* +* Compute GROW = 1/G(j) and XBND = 1/M(j). +* Initially, G(0) = max{x(i), i=1,...,n}. +* + GROW = ONE / MAX( XBND, SMLNUM ) + XBND = GROW + DO 30 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 50 +* +* M(j) = G(j-1) / abs(A(j,j)) +* + TJJ = ABS( AB( MAIND, J ) ) + XBND = MIN( XBND, MIN( ONE, TJJ )*GROW ) + IF( TJJ+CNORM( J ).GE.SMLNUM ) THEN +* +* G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) +* + GROW = GROW*( TJJ / ( TJJ+CNORM( J ) ) ) + ELSE +* +* G(j) could overflow, set GROW to 0. +* + GROW = ZERO + END IF + 30 CONTINUE + GROW = XBND + ELSE +* +* A is unit triangular. +* +* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. +* + GROW = MIN( ONE, ONE / MAX( XBND, SMLNUM ) ) + DO 40 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 50 +* +* G(j) = G(j-1)*( 1 + CNORM(j) ) +* + GROW = GROW*( ONE / ( ONE+CNORM( J ) ) ) + 40 CONTINUE + END IF + 50 CONTINUE +* + ELSE +* +* Compute the growth in A' * x = b. +* + IF( UPPER ) THEN + JFIRST = 1 + JLAST = N + JINC = 1 + MAIND = KD + 1 + ELSE + JFIRST = N + JLAST = 1 + JINC = -1 + MAIND = 1 + END IF +* + IF( TSCAL.NE.ONE ) THEN + GROW = ZERO + GO TO 80 + END IF +* + IF( NOUNIT ) THEN +* +* A is non-unit triangular. +* +* Compute GROW = 1/G(j) and XBND = 1/M(j). +* Initially, M(0) = max{x(i), i=1,...,n}. +* + GROW = ONE / MAX( XBND, SMLNUM ) + XBND = GROW + DO 60 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 80 +* +* G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) +* + XJ = ONE + CNORM( J ) + GROW = MIN( GROW, XBND / XJ ) +* +* M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) +* + TJJ = ABS( AB( MAIND, J ) ) + IF( XJ.GT.TJJ ) + $ XBND = XBND*( TJJ / XJ ) + 60 CONTINUE + GROW = MIN( GROW, XBND ) + ELSE +* +* A is unit triangular. +* +* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. +* + GROW = MIN( ONE, ONE / MAX( XBND, SMLNUM ) ) + DO 70 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 80 +* +* G(j) = ( 1 + CNORM(j) )*G(j-1) +* + XJ = ONE + CNORM( J ) + GROW = GROW / XJ + 70 CONTINUE + END IF + 80 CONTINUE + END IF +* + IF( ( GROW*TSCAL ).GT.SMLNUM ) THEN +* +* Use the Level 2 BLAS solve if the reciprocal of the bound on +* elements of X is not too small. +* + CALL DTBSV( UPLO, TRANS, DIAG, N, KD, AB, LDAB, X, 1 ) + ELSE +* +* Use a Level 1 BLAS solve, scaling intermediate results. +* + IF( XMAX.GT.BIGNUM ) THEN +* +* Scale X so that its components are less than or equal to +* BIGNUM in absolute value. +* + SCALE = BIGNUM / XMAX + CALL DSCAL( N, SCALE, X, 1 ) + XMAX = BIGNUM + END IF +* + IF( NOTRAN ) THEN +* +* Solve A * x = b +* + DO 110 J = JFIRST, JLAST, JINC +* +* Compute x(j) = b(j) / A(j,j), scaling x if necessary. +* + XJ = ABS( X( J ) ) + IF( NOUNIT ) THEN + TJJS = AB( MAIND, J )*TSCAL + ELSE + TJJS = TSCAL + IF( TSCAL.EQ.ONE ) + $ GO TO 100 + END IF + TJJ = ABS( TJJS ) + IF( TJJ.GT.SMLNUM ) THEN +* +* abs(A(j,j)) > SMLNUM: +* + IF( TJJ.LT.ONE ) THEN + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale x by 1/b(j). +* + REC = ONE / XJ + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + END IF + X( J ) = X( J ) / TJJS + XJ = ABS( X( J ) ) + ELSE IF( TJJ.GT.ZERO ) THEN +* +* 0 < abs(A(j,j)) <= SMLNUM: +* + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM +* to avoid overflow when dividing by A(j,j). +* + REC = ( TJJ*BIGNUM ) / XJ + IF( CNORM( J ).GT.ONE ) THEN +* +* Scale by 1/CNORM(j) to avoid overflow when +* multiplying x(j) times column j. +* + REC = REC / CNORM( J ) + END IF + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + X( J ) = X( J ) / TJJS + XJ = ABS( X( J ) ) + ELSE +* +* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and +* scale = 0, and compute a solution to A*x = 0. +* + DO 90 I = 1, N + X( I ) = ZERO + 90 CONTINUE + X( J ) = ONE + XJ = ONE + SCALE = ZERO + XMAX = ZERO + END IF + 100 CONTINUE +* +* Scale x if necessary to avoid overflow when adding a +* multiple of column j of A. +* + IF( XJ.GT.ONE ) THEN + REC = ONE / XJ + IF( CNORM( J ).GT.( BIGNUM-XMAX )*REC ) THEN +* +* Scale x by 1/(2*abs(x(j))). +* + REC = REC*HALF + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + END IF + ELSE IF( XJ*CNORM( J ).GT.( BIGNUM-XMAX ) ) THEN +* +* Scale x by 1/2. +* + CALL DSCAL( N, HALF, X, 1 ) + SCALE = SCALE*HALF + END IF +* + IF( UPPER ) THEN + IF( J.GT.1 ) THEN +* +* Compute the update +* x(max(1,j-kd):j-1) := x(max(1,j-kd):j-1) - +* x(j)* A(max(1,j-kd):j-1,j) +* + JLEN = MIN( KD, J-1 ) + CALL DAXPY( JLEN, -X( J )*TSCAL, + $ AB( KD+1-JLEN, J ), 1, X( J-JLEN ), 1 ) + I = IDAMAX( J-1, X, 1 ) + XMAX = ABS( X( I ) ) + END IF + ELSE IF( J.LT.N ) THEN +* +* Compute the update +* x(j+1:min(j+kd,n)) := x(j+1:min(j+kd,n)) - +* x(j) * A(j+1:min(j+kd,n),j) +* + JLEN = MIN( KD, N-J ) + IF( JLEN.GT.0 ) + $ CALL DAXPY( JLEN, -X( J )*TSCAL, AB( 2, J ), 1, + $ X( J+1 ), 1 ) + I = J + IDAMAX( N-J, X( J+1 ), 1 ) + XMAX = ABS( X( I ) ) + END IF + 110 CONTINUE +* + ELSE +* +* Solve A' * x = b +* + DO 160 J = JFIRST, JLAST, JINC +* +* Compute x(j) = b(j) - sum A(k,j)*x(k). +* k<>j +* + XJ = ABS( X( J ) ) + USCAL = TSCAL + REC = ONE / MAX( XMAX, ONE ) + IF( CNORM( J ).GT.( BIGNUM-XJ )*REC ) THEN +* +* If x(j) could overflow, scale x by 1/(2*XMAX). +* + REC = REC*HALF + IF( NOUNIT ) THEN + TJJS = AB( MAIND, J )*TSCAL + ELSE + TJJS = TSCAL + END IF + TJJ = ABS( TJJS ) + IF( TJJ.GT.ONE ) THEN +* +* Divide by A(j,j) when scaling x if A(j,j) > 1. +* + REC = MIN( ONE, REC*TJJ ) + USCAL = USCAL / TJJS + END IF + IF( REC.LT.ONE ) THEN + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + END IF +* + SUMJ = ZERO + IF( USCAL.EQ.ONE ) THEN +* +* If the scaling needed for A in the dot product is 1, +* call DDOT to perform the dot product. +* + IF( UPPER ) THEN + JLEN = MIN( KD, J-1 ) + SUMJ = DDOT( JLEN, AB( KD+1-JLEN, J ), 1, + $ X( J-JLEN ), 1 ) + ELSE + JLEN = MIN( KD, N-J ) + IF( JLEN.GT.0 ) + $ SUMJ = DDOT( JLEN, AB( 2, J ), 1, X( J+1 ), 1 ) + END IF + ELSE +* +* Otherwise, use in-line code for the dot product. +* + IF( UPPER ) THEN + JLEN = MIN( KD, J-1 ) + DO 120 I = 1, JLEN + SUMJ = SUMJ + ( AB( KD+I-JLEN, J )*USCAL )* + $ X( J-JLEN-1+I ) + 120 CONTINUE + ELSE + JLEN = MIN( KD, N-J ) + DO 130 I = 1, JLEN + SUMJ = SUMJ + ( AB( I+1, J )*USCAL )*X( J+I ) + 130 CONTINUE + END IF + END IF +* + IF( USCAL.EQ.TSCAL ) THEN +* +* Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) +* was not used to scale the dotproduct. +* + X( J ) = X( J ) - SUMJ + XJ = ABS( X( J ) ) + IF( NOUNIT ) THEN +* +* Compute x(j) = x(j) / A(j,j), scaling if necessary. +* + TJJS = AB( MAIND, J )*TSCAL + ELSE + TJJS = TSCAL + IF( TSCAL.EQ.ONE ) + $ GO TO 150 + END IF + TJJ = ABS( TJJS ) + IF( TJJ.GT.SMLNUM ) THEN +* +* abs(A(j,j)) > SMLNUM: +* + IF( TJJ.LT.ONE ) THEN + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale X by 1/abs(x(j)). +* + REC = ONE / XJ + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + END IF + X( J ) = X( J ) / TJJS + ELSE IF( TJJ.GT.ZERO ) THEN +* +* 0 < abs(A(j,j)) <= SMLNUM: +* + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. +* + REC = ( TJJ*BIGNUM ) / XJ + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + X( J ) = X( J ) / TJJS + ELSE +* +* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and +* scale = 0, and compute a solution to A'*x = 0. +* + DO 140 I = 1, N + X( I ) = ZERO + 140 CONTINUE + X( J ) = ONE + SCALE = ZERO + XMAX = ZERO + END IF + 150 CONTINUE + ELSE +* +* Compute x(j) := x(j) / A(j,j) - sumj if the dot +* product has already been divided by 1/A(j,j). +* + X( J ) = X( J ) / TJJS - SUMJ + END IF + XMAX = MAX( XMAX, ABS( X( J ) ) ) + 160 CONTINUE + END IF + SCALE = SCALE / TSCAL + END IF +* +* Scale the column norms by 1/TSCAL for return. +* + IF( TSCAL.NE.ONE ) THEN + CALL DSCAL( N, ONE / TSCAL, CNORM, 1 ) + END IF +* + RETURN +* +* End of DLATBS +* + END diff --git a/ext/lapack/dlatrs.f b/ext/lapack/dlatrs.f new file mode 100644 index 000000000..591c966d2 --- /dev/null +++ b/ext/lapack/dlatrs.f @@ -0,0 +1,702 @@ + SUBROUTINE DLATRS( UPLO, TRANS, DIAG, NORMIN, N, A, LDA, X, SCALE, + $ CNORM, INFO ) +* +* -- LAPACK auxiliary routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* June 30, 1992 +* +* .. Scalar Arguments .. + CHARACTER DIAG, NORMIN, TRANS, UPLO + INTEGER INFO, LDA, N + DOUBLE PRECISION SCALE +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), CNORM( * ), X( * ) +* .. +* +* Purpose +* ======= +* +* DLATRS solves one of the triangular systems +* +* A *x = s*b or A'*x = s*b +* +* with scaling to prevent overflow. Here A is an upper or lower +* triangular matrix, A' denotes the transpose of A, x and b are +* n-element vectors, and s is a scaling factor, usually less than +* or equal to 1, chosen so that the components of x will be less than +* the overflow threshold. If the unscaled problem will not cause +* overflow, the Level 2 BLAS routine DTRSV is called. If the matrix A +* is singular (A(j,j) = 0 for some j), then s is set to 0 and a +* non-trivial solution to A*x = 0 is returned. +* +* Arguments +* ========= +* +* UPLO (input) CHARACTER*1 +* Specifies whether the matrix A is upper or lower triangular. +* = 'U': Upper triangular +* = 'L': Lower triangular +* +* TRANS (input) CHARACTER*1 +* Specifies the operation applied to A. +* = 'N': Solve A * x = s*b (No transpose) +* = 'T': Solve A'* x = s*b (Transpose) +* = 'C': Solve A'* x = s*b (Conjugate transpose = Transpose) +* +* DIAG (input) CHARACTER*1 +* Specifies whether or not the matrix A is unit triangular. +* = 'N': Non-unit triangular +* = 'U': Unit triangular +* +* NORMIN (input) CHARACTER*1 +* Specifies whether CNORM has been set or not. +* = 'Y': CNORM contains the column norms on entry +* = 'N': CNORM is not set on entry. On exit, the norms will +* be computed and stored in CNORM. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The triangular matrix A. If UPLO = 'U', the leading n by n +* upper triangular part of the array A contains the upper +* triangular matrix, and the strictly lower triangular part of +* A is not referenced. If UPLO = 'L', the leading n by n lower +* triangular part of the array A contains the lower triangular +* matrix, and the strictly upper triangular part of A is not +* referenced. If DIAG = 'U', the diagonal elements of A are +* also not referenced and are assumed to be 1. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max (1,N). +* +* X (input/output) DOUBLE PRECISION array, dimension (N) +* On entry, the right hand side b of the triangular system. +* On exit, X is overwritten by the solution vector x. +* +* SCALE (output) DOUBLE PRECISION +* The scaling factor s for the triangular system +* A * x = s*b or A'* x = s*b. +* If SCALE = 0, the matrix A is singular or badly scaled, and +* the vector x is an exact or approximate solution to A*x = 0. +* +* CNORM (input or output) DOUBLE PRECISION array, dimension (N) +* +* If NORMIN = 'Y', CNORM is an input argument and CNORM(j) +* contains the norm of the off-diagonal part of the j-th column +* of A. If TRANS = 'N', CNORM(j) must be greater than or equal +* to the infinity-norm, and if TRANS = 'T' or 'C', CNORM(j) +* must be greater than or equal to the 1-norm. +* +* If NORMIN = 'N', CNORM is an output argument and CNORM(j) +* returns the 1-norm of the offdiagonal part of the j-th column +* of A. +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -k, the k-th argument had an illegal value +* +* Further Details +* ======= ======= +* +* A rough bound on x is computed; if that is less than overflow, DTRSV +* is called, otherwise, specific code is used which checks for possible +* overflow or divide-by-zero at every operation. +* +* A columnwise scheme is used for solving A*x = b. The basic algorithm +* if A is lower triangular is +* +* x[1:n] := b[1:n] +* for j = 1, ..., n +* x(j) := x(j) / A(j,j) +* x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] +* end +* +* Define bounds on the components of x after j iterations of the loop: +* M(j) = bound on x[1:j] +* G(j) = bound on x[j+1:n] +* Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. +* +* Then for iteration j+1 we have +* M(j+1) <= G(j) / | A(j+1,j+1) | +* G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | +* <= G(j) ( 1 + CNORM(j+1) / | A(j+1,j+1) | ) +* +* where CNORM(j+1) is greater than or equal to the infinity-norm of +* column j+1 of A, not counting the diagonal. Hence +* +* G(j) <= G(0) product ( 1 + CNORM(i) / | A(i,i) | ) +* 1<=i<=j +* and +* +* |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + CNORM(i) / |A(i,i)| ) +* 1<=i< j +* +* Since |x(j)| <= M(j), we use the Level 2 BLAS routine DTRSV if the +* reciprocal of the largest M(j), j=1,..,n, is larger than +* max(underflow, 1/overflow). +* +* The bound on x(j) is also used to determine when a step in the +* columnwise method can be performed without fear of overflow. If +* the computed bound is greater than a large constant, x is scaled to +* prevent overflow, but if the bound overflows, x is set to 0, x(j) to +* 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. +* +* Similarly, a row-wise scheme is used to solve A'*x = b. The basic +* algorithm for A upper triangular is +* +* for j = 1, ..., n +* x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) +* end +* +* We simultaneously compute two bounds +* G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j +* M(j) = bound on x(i), 1<=i<=j +* +* The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we +* add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. +* Then the bound on x(j) is +* +* M(j) <= M(j-1) * ( 1 + CNORM(j) ) / | A(j,j) | +* +* <= M(0) * product ( ( 1 + CNORM(i) ) / |A(i,i)| ) +* 1<=i<=j +* +* and we can safely call DTRSV if 1/M(n) and 1/G(n) are both greater +* than max(underflow, 1/overflow). +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO, HALF, ONE + PARAMETER ( ZERO = 0.0D+0, HALF = 0.5D+0, ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL NOTRAN, NOUNIT, UPPER + INTEGER I, IMAX, J, JFIRST, JINC, JLAST + DOUBLE PRECISION BIGNUM, GROW, REC, SMLNUM, SUMJ, TJJ, TJJS, + $ TMAX, TSCAL, USCAL, XBND, XJ, XMAX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER IDAMAX + DOUBLE PRECISION DASUM, DDOT, DLAMCH + EXTERNAL LSAME, IDAMAX, DASUM, DDOT, DLAMCH +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DSCAL, DTRSV, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, MAX, MIN +* .. +* .. Executable Statements .. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + NOTRAN = LSAME( TRANS, 'N' ) + NOUNIT = LSAME( DIAG, 'N' ) +* +* Test the input parameters. +* + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( .NOT.NOTRAN .AND. .NOT.LSAME( TRANS, 'T' ) .AND. .NOT. + $ LSAME( TRANS, 'C' ) ) THEN + INFO = -2 + ELSE IF( .NOT.NOUNIT .AND. .NOT.LSAME( DIAG, 'U' ) ) THEN + INFO = -3 + ELSE IF( .NOT.LSAME( NORMIN, 'Y' ) .AND. .NOT. + $ LSAME( NORMIN, 'N' ) ) THEN + INFO = -4 + ELSE IF( N.LT.0 ) THEN + INFO = -5 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -7 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLATRS', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine machine dependent parameters to control overflow. +* + SMLNUM = DLAMCH( 'Safe minimum' ) / DLAMCH( 'Precision' ) + BIGNUM = ONE / SMLNUM + SCALE = ONE +* + IF( LSAME( NORMIN, 'N' ) ) THEN +* +* Compute the 1-norm of each column, not including the diagonal. +* + IF( UPPER ) THEN +* +* A is upper triangular. +* + DO 10 J = 1, N + CNORM( J ) = DASUM( J-1, A( 1, J ), 1 ) + 10 CONTINUE + ELSE +* +* A is lower triangular. +* + DO 20 J = 1, N - 1 + CNORM( J ) = DASUM( N-J, A( J+1, J ), 1 ) + 20 CONTINUE + CNORM( N ) = ZERO + END IF + END IF +* +* Scale the column norms by TSCAL if the maximum element in CNORM is +* greater than BIGNUM. +* + IMAX = IDAMAX( N, CNORM, 1 ) + TMAX = CNORM( IMAX ) + IF( TMAX.LE.BIGNUM ) THEN + TSCAL = ONE + ELSE + TSCAL = ONE / ( SMLNUM*TMAX ) + CALL DSCAL( N, TSCAL, CNORM, 1 ) + END IF +* +* Compute a bound on the computed solution vector to see if the +* Level 2 BLAS routine DTRSV can be used. +* + J = IDAMAX( N, X, 1 ) + XMAX = ABS( X( J ) ) + XBND = XMAX + IF( NOTRAN ) THEN +* +* Compute the growth in A * x = b. +* + IF( UPPER ) THEN + JFIRST = N + JLAST = 1 + JINC = -1 + ELSE + JFIRST = 1 + JLAST = N + JINC = 1 + END IF +* + IF( TSCAL.NE.ONE ) THEN + GROW = ZERO + GO TO 50 + END IF +* + IF( NOUNIT ) THEN +* +* A is non-unit triangular. +* +* Compute GROW = 1/G(j) and XBND = 1/M(j). +* Initially, G(0) = max{x(i), i=1,...,n}. +* + GROW = ONE / MAX( XBND, SMLNUM ) + XBND = GROW + DO 30 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 50 +* +* M(j) = G(j-1) / abs(A(j,j)) +* + TJJ = ABS( A( J, J ) ) + XBND = MIN( XBND, MIN( ONE, TJJ )*GROW ) + IF( TJJ+CNORM( J ).GE.SMLNUM ) THEN +* +* G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) +* + GROW = GROW*( TJJ / ( TJJ+CNORM( J ) ) ) + ELSE +* +* G(j) could overflow, set GROW to 0. +* + GROW = ZERO + END IF + 30 CONTINUE + GROW = XBND + ELSE +* +* A is unit triangular. +* +* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. +* + GROW = MIN( ONE, ONE / MAX( XBND, SMLNUM ) ) + DO 40 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 50 +* +* G(j) = G(j-1)*( 1 + CNORM(j) ) +* + GROW = GROW*( ONE / ( ONE+CNORM( J ) ) ) + 40 CONTINUE + END IF + 50 CONTINUE +* + ELSE +* +* Compute the growth in A' * x = b. +* + IF( UPPER ) THEN + JFIRST = 1 + JLAST = N + JINC = 1 + ELSE + JFIRST = N + JLAST = 1 + JINC = -1 + END IF +* + IF( TSCAL.NE.ONE ) THEN + GROW = ZERO + GO TO 80 + END IF +* + IF( NOUNIT ) THEN +* +* A is non-unit triangular. +* +* Compute GROW = 1/G(j) and XBND = 1/M(j). +* Initially, M(0) = max{x(i), i=1,...,n}. +* + GROW = ONE / MAX( XBND, SMLNUM ) + XBND = GROW + DO 60 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 80 +* +* G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) +* + XJ = ONE + CNORM( J ) + GROW = MIN( GROW, XBND / XJ ) +* +* M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) +* + TJJ = ABS( A( J, J ) ) + IF( XJ.GT.TJJ ) + $ XBND = XBND*( TJJ / XJ ) + 60 CONTINUE + GROW = MIN( GROW, XBND ) + ELSE +* +* A is unit triangular. +* +* Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. +* + GROW = MIN( ONE, ONE / MAX( XBND, SMLNUM ) ) + DO 70 J = JFIRST, JLAST, JINC +* +* Exit the loop if the growth factor is too small. +* + IF( GROW.LE.SMLNUM ) + $ GO TO 80 +* +* G(j) = ( 1 + CNORM(j) )*G(j-1) +* + XJ = ONE + CNORM( J ) + GROW = GROW / XJ + 70 CONTINUE + END IF + 80 CONTINUE + END IF +* + IF( ( GROW*TSCAL ).GT.SMLNUM ) THEN +* +* Use the Level 2 BLAS solve if the reciprocal of the bound on +* elements of X is not too small. +* + CALL DTRSV( UPLO, TRANS, DIAG, N, A, LDA, X, 1 ) + ELSE +* +* Use a Level 1 BLAS solve, scaling intermediate results. +* + IF( XMAX.GT.BIGNUM ) THEN +* +* Scale X so that its components are less than or equal to +* BIGNUM in absolute value. +* + SCALE = BIGNUM / XMAX + CALL DSCAL( N, SCALE, X, 1 ) + XMAX = BIGNUM + END IF +* + IF( NOTRAN ) THEN +* +* Solve A * x = b +* + DO 110 J = JFIRST, JLAST, JINC +* +* Compute x(j) = b(j) / A(j,j), scaling x if necessary. +* + XJ = ABS( X( J ) ) + IF( NOUNIT ) THEN + TJJS = A( J, J )*TSCAL + ELSE + TJJS = TSCAL + IF( TSCAL.EQ.ONE ) + $ GO TO 100 + END IF + TJJ = ABS( TJJS ) + IF( TJJ.GT.SMLNUM ) THEN +* +* abs(A(j,j)) > SMLNUM: +* + IF( TJJ.LT.ONE ) THEN + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale x by 1/b(j). +* + REC = ONE / XJ + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + END IF + X( J ) = X( J ) / TJJS + XJ = ABS( X( J ) ) + ELSE IF( TJJ.GT.ZERO ) THEN +* +* 0 < abs(A(j,j)) <= SMLNUM: +* + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM +* to avoid overflow when dividing by A(j,j). +* + REC = ( TJJ*BIGNUM ) / XJ + IF( CNORM( J ).GT.ONE ) THEN +* +* Scale by 1/CNORM(j) to avoid overflow when +* multiplying x(j) times column j. +* + REC = REC / CNORM( J ) + END IF + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + X( J ) = X( J ) / TJJS + XJ = ABS( X( J ) ) + ELSE +* +* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and +* scale = 0, and compute a solution to A*x = 0. +* + DO 90 I = 1, N + X( I ) = ZERO + 90 CONTINUE + X( J ) = ONE + XJ = ONE + SCALE = ZERO + XMAX = ZERO + END IF + 100 CONTINUE +* +* Scale x if necessary to avoid overflow when adding a +* multiple of column j of A. +* + IF( XJ.GT.ONE ) THEN + REC = ONE / XJ + IF( CNORM( J ).GT.( BIGNUM-XMAX )*REC ) THEN +* +* Scale x by 1/(2*abs(x(j))). +* + REC = REC*HALF + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + END IF + ELSE IF( XJ*CNORM( J ).GT.( BIGNUM-XMAX ) ) THEN +* +* Scale x by 1/2. +* + CALL DSCAL( N, HALF, X, 1 ) + SCALE = SCALE*HALF + END IF +* + IF( UPPER ) THEN + IF( J.GT.1 ) THEN +* +* Compute the update +* x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) +* + CALL DAXPY( J-1, -X( J )*TSCAL, A( 1, J ), 1, X, + $ 1 ) + I = IDAMAX( J-1, X, 1 ) + XMAX = ABS( X( I ) ) + END IF + ELSE + IF( J.LT.N ) THEN +* +* Compute the update +* x(j+1:n) := x(j+1:n) - x(j) * A(j+1:n,j) +* + CALL DAXPY( N-J, -X( J )*TSCAL, A( J+1, J ), 1, + $ X( J+1 ), 1 ) + I = J + IDAMAX( N-J, X( J+1 ), 1 ) + XMAX = ABS( X( I ) ) + END IF + END IF + 110 CONTINUE +* + ELSE +* +* Solve A' * x = b +* + DO 160 J = JFIRST, JLAST, JINC +* +* Compute x(j) = b(j) - sum A(k,j)*x(k). +* k<>j +* + XJ = ABS( X( J ) ) + USCAL = TSCAL + REC = ONE / MAX( XMAX, ONE ) + IF( CNORM( J ).GT.( BIGNUM-XJ )*REC ) THEN +* +* If x(j) could overflow, scale x by 1/(2*XMAX). +* + REC = REC*HALF + IF( NOUNIT ) THEN + TJJS = A( J, J )*TSCAL + ELSE + TJJS = TSCAL + END IF + TJJ = ABS( TJJS ) + IF( TJJ.GT.ONE ) THEN +* +* Divide by A(j,j) when scaling x if A(j,j) > 1. +* + REC = MIN( ONE, REC*TJJ ) + USCAL = USCAL / TJJS + END IF + IF( REC.LT.ONE ) THEN + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + END IF +* + SUMJ = ZERO + IF( USCAL.EQ.ONE ) THEN +* +* If the scaling needed for A in the dot product is 1, +* call DDOT to perform the dot product. +* + IF( UPPER ) THEN + SUMJ = DDOT( J-1, A( 1, J ), 1, X, 1 ) + ELSE IF( J.LT.N ) THEN + SUMJ = DDOT( N-J, A( J+1, J ), 1, X( J+1 ), 1 ) + END IF + ELSE +* +* Otherwise, use in-line code for the dot product. +* + IF( UPPER ) THEN + DO 120 I = 1, J - 1 + SUMJ = SUMJ + ( A( I, J )*USCAL )*X( I ) + 120 CONTINUE + ELSE IF( J.LT.N ) THEN + DO 130 I = J + 1, N + SUMJ = SUMJ + ( A( I, J )*USCAL )*X( I ) + 130 CONTINUE + END IF + END IF +* + IF( USCAL.EQ.TSCAL ) THEN +* +* Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) +* was not used to scale the dotproduct. +* + X( J ) = X( J ) - SUMJ + XJ = ABS( X( J ) ) + IF( NOUNIT ) THEN + TJJS = A( J, J )*TSCAL + ELSE + TJJS = TSCAL + IF( TSCAL.EQ.ONE ) + $ GO TO 150 + END IF +* +* Compute x(j) = x(j) / A(j,j), scaling if necessary. +* + TJJ = ABS( TJJS ) + IF( TJJ.GT.SMLNUM ) THEN +* +* abs(A(j,j)) > SMLNUM: +* + IF( TJJ.LT.ONE ) THEN + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale X by 1/abs(x(j)). +* + REC = ONE / XJ + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + END IF + X( J ) = X( J ) / TJJS + ELSE IF( TJJ.GT.ZERO ) THEN +* +* 0 < abs(A(j,j)) <= SMLNUM: +* + IF( XJ.GT.TJJ*BIGNUM ) THEN +* +* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. +* + REC = ( TJJ*BIGNUM ) / XJ + CALL DSCAL( N, REC, X, 1 ) + SCALE = SCALE*REC + XMAX = XMAX*REC + END IF + X( J ) = X( J ) / TJJS + ELSE +* +* A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and +* scale = 0, and compute a solution to A'*x = 0. +* + DO 140 I = 1, N + X( I ) = ZERO + 140 CONTINUE + X( J ) = ONE + SCALE = ZERO + XMAX = ZERO + END IF + 150 CONTINUE + ELSE +* +* Compute x(j) := x(j) / A(j,j) - sumj if the dot +* product has already been divided by 1/A(j,j). +* + X( J ) = X( J ) / TJJS - SUMJ + END IF + XMAX = MAX( XMAX, ABS( X( J ) ) ) + 160 CONTINUE + END IF + SCALE = SCALE / TSCAL + END IF +* +* Scale the column norms by 1/TSCAL for return. +* + IF( TSCAL.NE.ONE ) THEN + CALL DSCAL( N, ONE / TSCAL, CNORM, 1 ) + END IF +* + RETURN +* +* End of DLATRS +* + END diff --git a/ext/lapack/dpotf2.f b/ext/lapack/dpotf2.f new file mode 100644 index 000000000..f9e0de06e --- /dev/null +++ b/ext/lapack/dpotf2.f @@ -0,0 +1,168 @@ + SUBROUTINE DPOTF2( UPLO, N, A, LDA, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* February 29, 1992 +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ) +* .. +* +* Purpose +* ======= +* +* DPOTF2 computes the Cholesky factorization of a real symmetric +* positive definite matrix A. +* +* The factorization has the form +* A = U' * U , if UPLO = 'U', or +* A = L * L', if UPLO = 'L', +* where U is an upper triangular matrix and L is lower triangular. +* +* This is the unblocked version of the algorithm, calling Level 2 BLAS. +* +* Arguments +* ========= +* +* UPLO (input) CHARACTER*1 +* Specifies whether the upper or lower triangular part of the +* symmetric matrix A is stored. +* = 'U': Upper triangular +* = 'L': Lower triangular +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) +* On entry, the symmetric matrix A. If UPLO = 'U', the leading +* n by n upper triangular part of A contains the upper +* triangular part of the matrix A, and the strictly lower +* triangular part of A is not referenced. If UPLO = 'L', the +* leading n by n lower triangular part of A contains the lower +* triangular part of the matrix A, and the strictly upper +* triangular part of A is not referenced. +* +* On exit, if INFO = 0, the factor U or L from the Cholesky +* factorization A = U'*U or A = L*L'. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -k, the k-th argument had an illegal value +* > 0: if INFO = k, the leading minor of order k is not +* positive definite, and the factorization could not be +* completed. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER J + DOUBLE PRECISION AJJ +* .. +* .. External Functions .. + LOGICAL LSAME + DOUBLE PRECISION DDOT + EXTERNAL LSAME, DDOT +* .. +* .. External Subroutines .. + EXTERNAL DGEMV, DSCAL, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, SQRT +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DPOTF2', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* + IF( UPPER ) THEN +* +* Compute the Cholesky factorization A = U'*U. +* + DO 10 J = 1, N +* +* Compute U(J,J) and test for non-positive-definiteness. +* + AJJ = A( J, J ) - DDOT( J-1, A( 1, J ), 1, A( 1, J ), 1 ) + IF( AJJ.LE.ZERO ) THEN + A( J, J ) = AJJ + GO TO 30 + END IF + AJJ = SQRT( AJJ ) + A( J, J ) = AJJ +* +* Compute elements J+1:N of row J. +* + IF( J.LT.N ) THEN + CALL DGEMV( 'Transpose', J-1, N-J, -ONE, A( 1, J+1 ), + $ LDA, A( 1, J ), 1, ONE, A( J, J+1 ), LDA ) + CALL DSCAL( N-J, ONE / AJJ, A( J, J+1 ), LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute the Cholesky factorization A = L*L'. +* + DO 20 J = 1, N +* +* Compute L(J,J) and test for non-positive-definiteness. +* + AJJ = A( J, J ) - DDOT( J-1, A( J, 1 ), LDA, A( J, 1 ), + $ LDA ) + IF( AJJ.LE.ZERO ) THEN + A( J, J ) = AJJ + GO TO 30 + END IF + AJJ = SQRT( AJJ ) + A( J, J ) = AJJ +* +* Compute elements J+1:N of column J. +* + IF( J.LT.N ) THEN + CALL DGEMV( 'No transpose', N-J, J-1, -ONE, A( J+1, 1 ), + $ LDA, A( J, 1 ), LDA, ONE, A( J+1, J ), 1 ) + CALL DSCAL( N-J, ONE / AJJ, A( J+1, J ), 1 ) + END IF + 20 CONTINUE + END IF + GO TO 40 +* + 30 CONTINUE + INFO = J +* + 40 CONTINUE + RETURN +* +* End of DPOTF2 +* + END diff --git a/ext/lapack/dpotrf.f b/ext/lapack/dpotrf.f new file mode 100644 index 000000000..c4b0cb459 --- /dev/null +++ b/ext/lapack/dpotrf.f @@ -0,0 +1,184 @@ + SUBROUTINE DPOTRF( UPLO, N, A, LDA, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* March 31, 1993 +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ) +* .. +* +* Purpose +* ======= +* +* DPOTRF computes the Cholesky factorization of a real symmetric +* positive definite matrix A. +* +* The factorization has the form +* A = U**T * U, if UPLO = 'U', or +* A = L * L**T, if UPLO = 'L', +* where U is an upper triangular matrix and L is lower triangular. +* +* This is the block version of the algorithm, calling Level 3 BLAS. +* +* Arguments +* ========= +* +* UPLO (input) CHARACTER*1 +* = 'U': Upper triangle of A is stored; +* = 'L': Lower triangle of A is stored. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) +* On entry, the symmetric matrix A. If UPLO = 'U', the leading +* N-by-N upper triangular part of A contains the upper +* triangular part of the matrix A, and the strictly lower +* triangular part of A is not referenced. If UPLO = 'L', the +* leading N-by-N lower triangular part of A contains the lower +* triangular part of the matrix A, and the strictly upper +* triangular part of A is not referenced. +* +* On exit, if INFO = 0, the factor U or L from the Cholesky +* factorization A = U**T*U or A = L*L**T. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* > 0: if INFO = i, the leading minor of order i is not +* positive definite, and the factorization could not be +* completed. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER J, JB, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DGEMM, DPOTF2, DSYRK, DTRSM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DPOTRF', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine the block size for this environment. +* + NB = ILAENV( 1, 'DPOTRF', UPLO, N, -1, -1, -1 ) + IF( NB.LE.1 .OR. NB.GE.N ) THEN +* +* Use unblocked code. +* + CALL DPOTF2( UPLO, N, A, LDA, INFO ) + ELSE +* +* Use blocked code. +* + IF( UPPER ) THEN +* +* Compute the Cholesky factorization A = U'*U. +* + DO 10 J = 1, N, NB +* +* Update and factorize the current diagonal block and test +* for non-positive-definiteness. +* + JB = MIN( NB, N-J+1 ) + CALL DSYRK( 'Upper', 'Transpose', JB, J-1, -ONE, + $ A( 1, J ), LDA, ONE, A( J, J ), LDA ) + CALL DPOTF2( 'Upper', JB, A( J, J ), LDA, INFO ) + IF( INFO.NE.0 ) + $ GO TO 30 + IF( J+JB.LE.N ) THEN +* +* Compute the current block row. +* + CALL DGEMM( 'Transpose', 'No transpose', JB, N-J-JB+1, + $ J-1, -ONE, A( 1, J ), LDA, A( 1, J+JB ), + $ LDA, ONE, A( J, J+JB ), LDA ) + CALL DTRSM( 'Left', 'Upper', 'Transpose', 'Non-unit', + $ JB, N-J-JB+1, ONE, A( J, J ), LDA, + $ A( J, J+JB ), LDA ) + END IF + 10 CONTINUE +* + ELSE +* +* Compute the Cholesky factorization A = L*L'. +* + DO 20 J = 1, N, NB +* +* Update and factorize the current diagonal block and test +* for non-positive-definiteness. +* + JB = MIN( NB, N-J+1 ) + CALL DSYRK( 'Lower', 'No transpose', JB, J-1, -ONE, + $ A( J, 1 ), LDA, ONE, A( J, J ), LDA ) + CALL DPOTF2( 'Lower', JB, A( J, J ), LDA, INFO ) + IF( INFO.NE.0 ) + $ GO TO 30 + IF( J+JB.LE.N ) THEN +* +* Compute the current block column. +* + CALL DGEMM( 'No transpose', 'Transpose', N-J-JB+1, JB, + $ J-1, -ONE, A( J+JB, 1 ), LDA, A( J, 1 ), + $ LDA, ONE, A( J+JB, J ), LDA ) + CALL DTRSM( 'Right', 'Lower', 'Transpose', 'Non-unit', + $ N-J-JB+1, JB, ONE, A( J, J ), LDA, + $ A( J+JB, J ), LDA ) + END IF + 20 CONTINUE + END IF + END IF + GO TO 40 +* + 30 CONTINUE + INFO = INFO + J - 1 +* + 40 CONTINUE + RETURN +* +* End of DPOTRF +* + END diff --git a/ext/lapack/dpotrs.f b/ext/lapack/dpotrs.f new file mode 100644 index 000000000..ae3ab2f31 --- /dev/null +++ b/ext/lapack/dpotrs.f @@ -0,0 +1,133 @@ + SUBROUTINE DPOTRS( UPLO, N, NRHS, A, LDA, B, LDB, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* March 31, 1993 +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, LDB, N, NRHS +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), B( LDB, * ) +* .. +* +* Purpose +* ======= +* +* DPOTRS solves a system of linear equations A*X = B with a symmetric +* positive definite matrix A using the Cholesky factorization +* A = U**T*U or A = L*L**T computed by DPOTRF. +* +* Arguments +* ========= +* +* UPLO (input) CHARACTER*1 +* = 'U': Upper triangle of A is stored; +* = 'L': Lower triangle of A is stored. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* NRHS (input) INTEGER +* The number of right hand sides, i.e., the number of columns +* of the matrix B. NRHS >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The triangular factor U or L from the Cholesky factorization +* A = U**T*U or A = L*L**T, as computed by DPOTRF. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) +* On entry, the right hand side matrix B. +* On exit, the solution matrix X. +* +* LDB (input) INTEGER +* The leading dimension of the array B. LDB >= max(1,N). +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER +* .. +* .. External Functions .. + LOGICAL LSAME + EXTERNAL LSAME +* .. +* .. External Subroutines .. + EXTERNAL DTRSM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( NRHS.LT.0 ) THEN + INFO = -3 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -5 + ELSE IF( LDB.LT.MAX( 1, N ) ) THEN + INFO = -7 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DPOTRS', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 .OR. NRHS.EQ.0 ) + $ RETURN +* + IF( UPPER ) THEN +* +* Solve A*X = B where A = U'*U. +* +* Solve U'*X = B, overwriting B with X. +* + CALL DTRSM( 'Left', 'Upper', 'Transpose', 'Non-unit', N, NRHS, + $ ONE, A, LDA, B, LDB ) +* +* Solve U*X = B, overwriting B with X. +* + CALL DTRSM( 'Left', 'Upper', 'No transpose', 'Non-unit', N, + $ NRHS, ONE, A, LDA, B, LDB ) + ELSE +* +* Solve A*X = B where A = L*L'. +* +* Solve L*X = B, overwriting B with X. +* + CALL DTRSM( 'Left', 'Lower', 'No transpose', 'Non-unit', N, + $ NRHS, ONE, A, LDA, B, LDB ) +* +* Solve L'*X = B, overwriting B with X. +* + CALL DTRSM( 'Left', 'Lower', 'Transpose', 'Non-unit', N, NRHS, + $ ONE, A, LDA, B, LDB ) + END IF +* + RETURN +* +* End of DPOTRS +* + END diff --git a/ext/lapack/dtrcon.f b/ext/lapack/dtrcon.f new file mode 100644 index 000000000..8da58c760 --- /dev/null +++ b/ext/lapack/dtrcon.f @@ -0,0 +1,193 @@ + SUBROUTINE DTRCON( NORM, UPLO, DIAG, N, A, LDA, RCOND, WORK, + $ IWORK, INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* March 31, 1993 +* +* .. Scalar Arguments .. + CHARACTER DIAG, NORM, UPLO + INTEGER INFO, LDA, N + DOUBLE PRECISION RCOND +* .. +* .. Array Arguments .. + INTEGER IWORK( * ) + DOUBLE PRECISION A( LDA, * ), WORK( * ) +* .. +* +* Purpose +* ======= +* +* DTRCON estimates the reciprocal of the condition number of a +* triangular matrix A, in either the 1-norm or the infinity-norm. +* +* The norm of A is computed and an estimate is obtained for +* norm(inv(A)), then the reciprocal of the condition number is +* computed as +* RCOND = 1 / ( norm(A) * norm(inv(A)) ). +* +* Arguments +* ========= +* +* NORM (input) CHARACTER*1 +* Specifies whether the 1-norm condition number or the +* infinity-norm condition number is required: +* = '1' or 'O': 1-norm; +* = 'I': Infinity-norm. +* +* UPLO (input) CHARACTER*1 +* = 'U': A is upper triangular; +* = 'L': A is lower triangular. +* +* DIAG (input) CHARACTER*1 +* = 'N': A is non-unit triangular; +* = 'U': A is unit triangular. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The triangular matrix A. If UPLO = 'U', the leading N-by-N +* upper triangular part of the array A contains the upper +* triangular matrix, and the strictly lower triangular part of +* A is not referenced. If UPLO = 'L', the leading N-by-N lower +* triangular part of the array A contains the lower triangular +* matrix, and the strictly upper triangular part of A is not +* referenced. If DIAG = 'U', the diagonal elements of A are +* also not referenced and are assumed to be 1. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* RCOND (output) DOUBLE PRECISION +* The reciprocal of the condition number of the matrix A, +* computed as RCOND = 1/(norm(A) * norm(inv(A))). +* +* WORK (workspace) DOUBLE PRECISION array, dimension (3*N) +* +* IWORK (workspace) INTEGER array, dimension (N) +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL NOUNIT, ONENRM, UPPER + CHARACTER NORMIN + INTEGER IX, KASE, KASE1 + DOUBLE PRECISION AINVNM, ANORM, SCALE, SMLNUM, XNORM +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER IDAMAX + DOUBLE PRECISION DLAMCH, DLANTR + EXTERNAL LSAME, IDAMAX, DLAMCH, DLANTR +* .. +* .. External Subroutines .. + EXTERNAL DLACON, DLATRS, DRSCL, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, DBLE, MAX +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + ONENRM = NORM.EQ.'1' .OR. LSAME( NORM, 'O' ) + NOUNIT = LSAME( DIAG, 'N' ) +* + IF( .NOT.ONENRM .AND. .NOT.LSAME( NORM, 'I' ) ) THEN + INFO = -1 + ELSE IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -2 + ELSE IF( .NOT.NOUNIT .AND. .NOT.LSAME( DIAG, 'U' ) ) THEN + INFO = -3 + ELSE IF( N.LT.0 ) THEN + INFO = -4 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -6 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DTRCON', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) THEN + RCOND = ONE + RETURN + END IF +* + RCOND = ZERO + SMLNUM = DLAMCH( 'Safe minimum' )*DBLE( MAX( 1, N ) ) +* +* Compute the norm of the triangular matrix A. +* + ANORM = DLANTR( NORM, UPLO, DIAG, N, N, A, LDA, WORK ) +* +* Continue only if ANORM > 0. +* + IF( ANORM.GT.ZERO ) THEN +* +* Estimate the norm of the inverse of A. +* + AINVNM = ZERO + NORMIN = 'N' + IF( ONENRM ) THEN + KASE1 = 1 + ELSE + KASE1 = 2 + END IF + KASE = 0 + 10 CONTINUE + CALL DLACON( N, WORK( N+1 ), WORK, IWORK, AINVNM, KASE ) + IF( KASE.NE.0 ) THEN + IF( KASE.EQ.KASE1 ) THEN +* +* Multiply by inv(A). +* + CALL DLATRS( UPLO, 'No transpose', DIAG, NORMIN, N, A, + $ LDA, WORK, SCALE, WORK( 2*N+1 ), INFO ) + ELSE +* +* Multiply by inv(A'). +* + CALL DLATRS( UPLO, 'Transpose', DIAG, NORMIN, N, A, LDA, + $ WORK, SCALE, WORK( 2*N+1 ), INFO ) + END IF + NORMIN = 'Y' +* +* Multiply by 1/SCALE if doing so will not cause overflow. +* + IF( SCALE.NE.ONE ) THEN + IX = IDAMAX( N, WORK, 1 ) + XNORM = ABS( WORK( IX ) ) + IF( SCALE.LT.XNORM*SMLNUM .OR. SCALE.EQ.ZERO ) + $ GO TO 20 + CALL DRSCL( N, SCALE, WORK, 1 ) + END IF + GO TO 10 + END IF +* +* Compute the estimate of the reciprocal condition number. +* + IF( AINVNM.NE.ZERO ) + $ RCOND = ( ONE / ANORM ) / AINVNM + END IF +* + 20 CONTINUE + RETURN +* +* End of DTRCON +* + END diff --git a/ext/lapack/dtrtrs.f b/ext/lapack/dtrtrs.f new file mode 100644 index 000000000..c1b4c5c4c --- /dev/null +++ b/ext/lapack/dtrtrs.f @@ -0,0 +1,148 @@ + SUBROUTINE DTRTRS( UPLO, TRANS, DIAG, N, NRHS, A, LDA, B, LDB, + $ INFO ) +* +* -- LAPACK routine (version 3.0) -- +* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., +* Courant Institute, Argonne National Lab, and Rice University +* March 31, 1993 +* +* .. Scalar Arguments .. + CHARACTER DIAG, TRANS, UPLO + INTEGER INFO, LDA, LDB, N, NRHS +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), B( LDB, * ) +* .. +* +* Purpose +* ======= +* +* DTRTRS solves a triangular system of the form +* +* A * X = B or A**T * X = B, +* +* where A is a triangular matrix of order N, and B is an N-by-NRHS +* matrix. A check is made to verify that A is nonsingular. +* +* Arguments +* ========= +* +* UPLO (input) CHARACTER*1 +* = 'U': A is upper triangular; +* = 'L': A is lower triangular. +* +* TRANS (input) CHARACTER*1 +* Specifies the form of the system of equations: +* = 'N': A * X = B (No transpose) +* = 'T': A**T * X = B (Transpose) +* = 'C': A**H * X = B (Conjugate transpose = Transpose) +* +* DIAG (input) CHARACTER*1 +* = 'N': A is non-unit triangular; +* = 'U': A is unit triangular. +* +* N (input) INTEGER +* The order of the matrix A. N >= 0. +* +* NRHS (input) INTEGER +* The number of right hand sides, i.e., the number of columns +* of the matrix B. NRHS >= 0. +* +* A (input) DOUBLE PRECISION array, dimension (LDA,N) +* The triangular matrix A. If UPLO = 'U', the leading N-by-N +* upper triangular part of the array A contains the upper +* triangular matrix, and the strictly lower triangular part of +* A is not referenced. If UPLO = 'L', the leading N-by-N lower +* triangular part of the array A contains the lower triangular +* matrix, and the strictly upper triangular part of A is not +* referenced. If DIAG = 'U', the diagonal elements of A are +* also not referenced and are assumed to be 1. +* +* LDA (input) INTEGER +* The leading dimension of the array A. LDA >= max(1,N). +* +* B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) +* On entry, the right hand side matrix B. +* On exit, if INFO = 0, the solution matrix X. +* +* LDB (input) INTEGER +* The leading dimension of the array B. LDB >= max(1,N). +* +* INFO (output) INTEGER +* = 0: successful exit +* < 0: if INFO = -i, the i-th argument had an illegal value +* > 0: if INFO = i, the i-th diagonal element of A is zero, +* indicating that the matrix is singular and the solutions +* X have not been computed. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO, ONE + PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL NOUNIT +* .. +* .. External Functions .. + LOGICAL LSAME + EXTERNAL LSAME +* .. +* .. External Subroutines .. + EXTERNAL DTRSM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + NOUNIT = LSAME( DIAG, 'N' ) + IF( .NOT.LSAME( UPLO, 'U' ) .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( .NOT.LSAME( TRANS, 'N' ) .AND. .NOT. + $ LSAME( TRANS, 'T' ) .AND. .NOT.LSAME( TRANS, 'C' ) ) THEN + INFO = -2 + ELSE IF( .NOT.NOUNIT .AND. .NOT.LSAME( DIAG, 'U' ) ) THEN + INFO = -3 + ELSE IF( N.LT.0 ) THEN + INFO = -4 + ELSE IF( NRHS.LT.0 ) THEN + INFO = -5 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -7 + ELSE IF( LDB.LT.MAX( 1, N ) ) THEN + INFO = -9 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DTRTRS', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Check for singularity. +* + IF( NOUNIT ) THEN + DO 10 INFO = 1, N + IF( A( INFO, INFO ).EQ.ZERO ) + $ RETURN + 10 CONTINUE + END IF + INFO = 0 +* +* Solve A * x = b or A' * x = b. +* + CALL DTRSM( 'Left', UPLO, TRANS, DIAG, N, NRHS, ONE, A, LDA, B, + $ LDB ) +* + RETURN +* +* End of DTRTRS +* + END diff --git a/ext/math/Makefile.in b/ext/math/Makefile.in index aba77e6e2..4fdfdb9a3 100755 --- a/ext/math/Makefile.in +++ b/ext/math/Makefile.in @@ -1,8 +1,8 @@ # # $Source: /cvsroot/cantera/cantera/ext/math/Makefile.in,v $ -# $Author: hkmoffa $ -# $Revision: 1.13 $ -# $Date: 2008/12/30 21:58:10 $ +# $Author$ +# $Revision$ +# $Date$ # .SUFFIXES : diff --git a/ext/math/gmres.h b/ext/math/gmres.h index 1f6a044d5..8bde197c2 100755 --- a/ext/math/gmres.h +++ b/ext/math/gmres.h @@ -33,7 +33,6 @@ gmres( int m, int N, const Matrix &A, const doublereal *b, doublereal *x, double #include "cblas.h" #include "../../Cantera/src/ctlapack.h" -using namespace Cantera; template< class Matrix > inline int diff --git a/ext/recipes/Makefile.in b/ext/recipes/Makefile.in index dc81b0417..54f8922fb 100755 --- a/ext/recipes/Makefile.in +++ b/ext/recipes/Makefile.in @@ -1,6 +1,6 @@ # $License$ # -# $Id: Makefile.in,v 1.8 2008/12/30 21:49:42 hkmoffa Exp $ +# $Id$ # #/bin/sh .SUFFIXES : diff --git a/ext/tpx/CarbonDioxide.cpp b/ext/tpx/CarbonDioxide.cpp index d0859aa06..24774a51f 100755 --- a/ext/tpx/CarbonDioxide.cpp +++ b/ext/tpx/CarbonDioxide.cpp @@ -11,6 +11,8 @@ #include #include +using namespace std; + namespace tpx { /* @@ -26,7 +28,8 @@ static const double Gamma=5.0E-6; // [??] static const double u0=3.217405E5; // [] internal energy at To static const double s0=2.1396056E3; // [] entropy at To static const double Tp=250; // [K] ?? -static const double Pc=7.38350E6; // [Pa] critical pressure +//static const double Pc=7.38350E6; // [Pa] critical pressure +static const double Pc=7.3817589E6; // Adjusted to fit the actual functional form static const double M=44.01; // [kg/kmol] molar density /* @@ -311,7 +314,7 @@ double CarbonDioxide::Psat(){ double log, sum=0,P; if ((T < Tmn) || (T > Tc)) { - cout << " error in Psat " << TempError << endl; + std::cout << " error in Psat " << TempError << endl; set_Err(TempError); // Error("CarbonDioxide::Psat",TempError,T); } for (int i=1;i<=8;i++) diff --git a/ext/tpx/CarbonDioxide.h b/ext/tpx/CarbonDioxide.h index ed3467616..945acf24a 100755 --- a/ext/tpx/CarbonDioxide.h +++ b/ext/tpx/CarbonDioxide.h @@ -17,7 +17,9 @@ namespace tpx { class CarbonDioxide : public Substance{ public: - CarbonDioxide() { + CarbonDioxide() : + Substance() + { m_name="CarbonDioxide"; m_formula="CO2"; } diff --git a/ext/tpx/Makefile.in b/ext/tpx/Makefile.in index bf0ebca96..3284b2a74 100755 --- a/ext/tpx/Makefile.in +++ b/ext/tpx/Makefile.in @@ -1,6 +1,6 @@ #/bin/sh # -# $Id: Makefile.in,v 1.17 2009/03/28 19:10:17 hkmoffa Exp $ +# $Id$ # .SUFFIXES : .SUFFIXES : .cpp .d .o diff --git a/ext/tpx/Sub.cpp b/ext/tpx/Sub.cpp index dda02e7ab..7b9d66179 100755 --- a/ext/tpx/Sub.cpp +++ b/ext/tpx/Sub.cpp @@ -7,6 +7,8 @@ #include #include +using namespace std; + namespace tpx { static string fp2str(double x, string fmt="%g") { @@ -398,6 +400,12 @@ namespace tpx { if (sat >= Pcrit()) return 0; psat = sat; T = Tsat(psat); + if (T == Undef) { + Err = 0; + T = Tsave; + Rho = Rhosave; + return 0; + } } else { throw TPX_Error("Substance::Lever","general error"); diff --git a/ext/tpx/Sub.h b/ext/tpx/Sub.h index 3fd40eef8..3f3767bbf 100755 --- a/ext/tpx/Sub.h +++ b/ext/tpx/Sub.h @@ -21,19 +21,18 @@ #include #include -using namespace std; namespace tpx { class TPX_Error { public: - TPX_Error(string p, string e) { + TPX_Error(std::string p, std::string e) { ErrorMessage = e; ErrorProcedure = p; } virtual ~TPX_Error(){} - static string ErrorMessage; - static string ErrorProcedure; + static std::string ErrorMessage; + static std::string ErrorProcedure; }; @@ -70,7 +69,7 @@ namespace tpx { const double Undef = 999.1234; - string errorMsg(int flag); + std::string errorMsg(int flag); class Substance { public: @@ -90,10 +89,12 @@ namespace tpx { void setStdState(double h0 = 0.0, double s0 = 0.0, double t0 = 298.15, double p0 = 1.01325e5) { Set(TP, t0, p0); - double hoff = h0 - h(); - double soff = s0 - s(); - m_entropy_offset = soff; - m_energy_offset = hoff; + double hh = h(); + double ss = s(); + double hoff = h0 - hh; + double soff = s0 - ss; + m_entropy_offset += soff; + m_energy_offset += hoff; } // information about a substance: @@ -200,8 +201,8 @@ namespace tpx { int Err; double m_energy_offset; double m_entropy_offset; - string m_name; - string m_formula; + std::string m_name; + std::string m_formula; // virtual double Xm(int k) { return 1.0;} //virtual int Species() { return 1;} diff --git a/ext/tpx/utils.cpp b/ext/tpx/utils.cpp index be81b09ac..c050af3f0 100755 --- a/ext/tpx/utils.cpp +++ b/ext/tpx/utils.cpp @@ -1,6 +1,8 @@ #include "subs.h" #include "utils.h" +using namespace std; + namespace tpx { static string lowercase(string s) { diff --git a/preconfig b/preconfig index 7aa1de70e..5dbdadd95 100755 --- a/preconfig +++ b/preconfig @@ -228,6 +228,10 @@ WITH_IDEAL_SOLUTIONS=${WITH_IDEAL_SOLUTIONS:="y"} # models for electrolyte solutions WITH_ELECTROLYTES=${WITH_ELECTROLYTES:="y"} +# Enable Real Gas Equations of State +# This supports the multicomponent Redlich-Kwong equation of state. +WITH_REAL_GASSES=${WITH_REAL_GASSES:="y"} + # Enable generating phase models from PrIMe models. For more # information about PrIME, see http://www.primekinetics.org # WARNING: Support for PrIMe is experimental! @@ -238,6 +242,11 @@ WITH_PRIME=${WITH_PRIME:="n"} # to have a value of "y" WITH_H298MODIFY_CAPABILITY=${WITH_H298MODIFY_CAPABILITY:="n"} +# Capability in the planning and implementation stage +# Phases may be intermediates but actually have zero mole numbers +# in the InterfacialKinetics object +KINETICS_WITH_INTERMEDIATE_ZEROED_PHASES=${KINETICS_WITH_INTERMEDIATE_ZEROED_PHASES:="n"} + ###################################################################### # if set to 'y', the ck2cti program that converts Chemkin input files # to Cantera format will be built. If you don't use Chemkin format @@ -502,8 +511,7 @@ RPFONT=${RPFONT:="Helvetica"} # This field gets written into config.h and is also an autoconf variable. # # -CANTERA_VERSION=${CANTERA_VERSION:="1.8.x"} - +CANTERA_VERSION=${CANTERA_VERSION:="1.8_liquidTransportDevelop"} #----------------------------------------------------------------------- #------------------- don't change anything below!! --------------------- @@ -584,7 +592,8 @@ export WITH_ADSORBATE export WITH_SPECTRA export WITH_STOICH_SUBSTANCE export WITH_PURE_FLUIDS -export WITH_IDEAL_SOLUTIONS +export WITH_IDEAL_SOLUTION +export WITH_REAL_GASSES export WITH_ELECTROLYTES export WITH_PRIME export WITH_H298MODIFY_CAPABILITY diff --git a/test_problems/ChemEquil_gri_matrix/gri_matrix.cpp b/test_problems/ChemEquil_gri_matrix/gri_matrix.cpp index 4a5176c6b..8b016a734 100644 --- a/test_problems/ChemEquil_gri_matrix/gri_matrix.cpp +++ b/test_problems/ChemEquil_gri_matrix/gri_matrix.cpp @@ -1,7 +1,7 @@ /* - * $Author: hkmoffa $ - * $Date: 2008/02/16 21:41:06 $ - * $Revision: 1.5 $ + * $Author$ + * $Date$ + * $Revision$ * * Copyright 2002 California Institute of Technology * diff --git a/test_problems/ChemEquil_gri_pairs/gri_pairs.cpp b/test_problems/ChemEquil_gri_pairs/gri_pairs.cpp index 3e14cd6d2..ac6090ae3 100644 --- a/test_problems/ChemEquil_gri_pairs/gri_pairs.cpp +++ b/test_problems/ChemEquil_gri_pairs/gri_pairs.cpp @@ -1,7 +1,7 @@ /* - * $Author: hkmoffa $ - * $Date: 2008/02/16 21:40:10 $ - * $Revision: 1.3 $ + * $Author$ + * $Date$ + * $Revision$ * * Copyright 2002 California Institute of Technology * diff --git a/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp b/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp index b5e836263..bcfa933b6 100644 --- a/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp +++ b/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp @@ -1,7 +1,7 @@ /* - * $Author: hkmoffa $ - * $Date: 2008/02/16 21:43:06 $ - * $Revision: 1.5 $ + * $Author$ + * $Date$ + * $Revision$ * * */ diff --git a/test_problems/ChemEquil_ionizedGas/runtest b/test_problems/ChemEquil_ionizedGas/runtest index b69f109e8..59d783243 100755 --- a/test_problems/ChemEquil_ionizedGas/runtest +++ b/test_problems/ChemEquil_ionizedGas/runtest @@ -35,7 +35,7 @@ then fi else echo "Unsuccessful test comparison on " $testName " test" - if test $retnStat_csv != "1" + if test $retnStat_csv != "0" then echo " csv files are different - see diff_csv.txt" fi diff --git a/test_problems/ChemEquil_red1/basopt_red1.cpp b/test_problems/ChemEquil_red1/basopt_red1.cpp index 3630cbaca..7c9bea129 100644 --- a/test_problems/ChemEquil_red1/basopt_red1.cpp +++ b/test_problems/ChemEquil_red1/basopt_red1.cpp @@ -1,7 +1,7 @@ /* - * $Author: hkmoffa $ - * $Date: 2008/02/16 21:44:47 $ - * $Revision: 1.5 $ + * $Author$ + * $Date$ + * $Revision$ * */ diff --git a/test_problems/CpJump/CpJump.cpp b/test_problems/CpJump/CpJump.cpp index 0081d69f2..dd5205d2a 100644 --- a/test_problems/CpJump/CpJump.cpp +++ b/test_problems/CpJump/CpJump.cpp @@ -1,7 +1,7 @@ /* - * $Author: hkmoffa $ - * $Date: 2008/02/16 21:46:15 $ - * $Revision: 1.2 $ + * $Author$ + * $Date$ + * $Revision$ * * Copyright 2002 California Institute of Technology * diff --git a/test_problems/Makefile.in b/test_problems/Makefile.in index b2c381ba2..16b923a8f 100644 --- a/test_problems/Makefile.in +++ b/test_problems/Makefile.in @@ -1,7 +1,7 @@ # -# $Revision: 1.36 $ -# $Author: hkmoffa $ -# $Date: 2009/03/25 01:03:05 $ +# $Revision$ +# $Author$ +# $Date$ # # test_python=@BUILD_PYTHON@ diff --git a/test_problems/VCSnonideal/Makefile.in b/test_problems/VCSnonideal/Makefile.in index 704cb03d3..f5ea312c3 100644 --- a/test_problems/VCSnonideal/Makefile.in +++ b/test_problems/VCSnonideal/Makefile.in @@ -1,7 +1,7 @@ # -# $Revision: 1.1 $ -# $Author: hkmoffa $ -# $Date: 2007/12/20 23:47:41 $ +# $Revision$ +# $Author$ +# $Date$ # # test_vcs_nonideal=@COMPILE_VCSNONIDEAL@ diff --git a/test_problems/VCSnonideal/NaCl_equil/HMW_NaCl.xml b/test_problems/VCSnonideal/NaCl_equil/HMW_NaCl.xml index 59c471cf9..75cbc0e7f 100644 --- a/test_problems/VCSnonideal/NaCl_equil/HMW_NaCl.xml +++ b/test_problems/VCSnonideal/NaCl_equil/HMW_NaCl.xml @@ -1,6 +1,6 @@