diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca514b1629..ef5b558b7d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,11 +16,11 @@ on: jobs: ubuntu-multiple-pythons: - name: Ubuntu with Python ${{ matrix.python-version }} + name: ${{ matrix.os }} with Python ${{ matrix.python-version }} runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [ '3.5', '3.6', '3.7', '3.8', '3.9' ] + python-version: [ '3.6', '3.7', '3.8', '3.9' ] os: ['ubuntu-18.04', 'ubuntu-20.04'] fail-fast: false steps: @@ -40,7 +40,7 @@ jobs: - name: Install Python dependencies run: python3 -m pip install ruamel.yaml scons numpy cython h5py pandas - name: Build Cantera - run: python3 `which scons` build -j2 + run: python3 `which scons` build -j2 debug=n - name: Test Cantera run: python3 `which scons` test @@ -77,7 +77,7 @@ jobs: - name: Install Python dependencies run: python3 -m pip install ruamel.yaml scons numpy cython h5py pandas - name: Build Cantera - run: python3 `which scons` build -j2 + run: python3 `which scons` build -j2 debug=n - name: Test Cantera run: python3 `which scons` test @@ -101,7 +101,7 @@ jobs: architecture: x64 - name: Install Apt dependencies run: | - sudo apt-get install libboost-dev gfortran liblapack-dev libblas-dev + sudo apt-get install libboost-dev gfortran liblapack-dev libblas-dev libsundials-dev - name: Upgrade pip run: python3 -m pip install -U pip setuptools wheel - name: Install Python dependencies @@ -109,7 +109,7 @@ jobs: - name: Build Cantera run: | python3 `which scons` build blas_lapack_libs=lapack,blas coverage=y \ - optimize=n -j2 + optimize=n no_optimize_flags=-DNDEBUG -j2 - name: Test Cantera run: python3 `which scons` test - name: Upload Coverage to Codecov @@ -141,7 +141,7 @@ jobs: python3 -m pip install ruamel.yaml scons numpy cython sphinx\<4.0 \ sphinxcontrib-katex sphinxcontrib-matlabdomain sphinxcontrib-doxylink - name: Build Cantera with documentation - run: python3 `which scons` build -j2 doxygen_docs=y sphinx_docs=y + run: python3 `which scons` build -j2 doxygen_docs=y sphinx_docs=y debug=n optimize=n # The known_hosts key is generated with `ssh-keygen -F cantera.org` from a # machine that has previously logged in to cantera.org and trusts # that it logged in to the right machine @@ -180,7 +180,7 @@ jobs: python3-ruamel.yaml python-numpy cython3 libsundials-dev liblapack-dev \ libblas-dev - name: Build Cantera - run: scons build python_cmd=/usr/bin/python3 blas_lapack_libs=lapack,blas -j2 + run: scons build python_cmd=/usr/bin/python3 blas_lapack_libs=lapack,blas -j2 debug=n - name: Test Cantera run: scons test @@ -189,7 +189,7 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - python-version: ['3.5', '3.6', '3.7', '3.8', '3.9'] + python-version: ['3.6', '3.7', '3.8', '3.9'] fail-fast: false steps: - uses: actions/checkout@v2 @@ -208,7 +208,7 @@ jobs: - name: Install Python dependencies run: python3 -m pip install ruamel.yaml scons numpy cython h5py pandas matplotlib scipy - name: Build Cantera - run: python3 `which scons` build -j2 + run: python3 `which scons` build -j2 debug=n - name: Run the examples # See https://unix.stackexchange.com/a/392973 for an explanation of the -exec part run: | @@ -254,7 +254,7 @@ jobs: run: | scons build extra_inc_dirs=$CONDA_PREFIX/include:$CONDA_PREFIX/include/eigen3 \ extra_lib_dirs=$CONDA_PREFIX/lib system_fmt=y system_eigen=y system_yamlcpp=y \ - system_sundials=y -j2 VERBOSE=True + system_sundials=y -j2 VERBOSE=True debug=n shell: bash -l {0} - name: Test Cantera run: scons test @@ -282,7 +282,7 @@ jobs: python3 -m pip install ruamel.yaml scons numpy h5py pandas; python3 -m pip install https://github.com/cython/cython/archive/master.zip --install-option='--no-cython-compile'; - name: Build Cantera - run: python3 `which scons` build blas_lapack_libs=lapack,blas python_package='full' -j2 + run: python3 `which scons` build blas_lapack_libs=lapack,blas python_package='full' -j2 debug=n - name: Test Cantera run: python3 `which scons` test @@ -293,13 +293,10 @@ jobs: matrix: os: ['windows-2019'] vs-toolset: ['14.0', '14.2'] - python-version: [ '3.5', '3.6', '3.7', '3.8', '3.9' ] + python-version: [ '3.6', '3.7', '3.8', '3.9' ] # Must use windows-2016 image because it installs VS2017 (MSVC 14.1) # Scons cannot find MSVC 14.1 when VS2019 is installed include: - - os: 'windows-2016' - vs-toolset: '14.1' - python-version: '3.5' - os: 'windows-2016' vs-toolset: '14.1' python-version: '3.6' diff --git a/SConstruct b/SConstruct index 48d8fcd76c..da7b332a95 100644 --- a/SConstruct +++ b/SConstruct @@ -444,7 +444,12 @@ config_options = [ 'system_fmt', """Select whether to use the fmt library from a system installation ('y'), from a Git submodule ('n'), or to decide automatically - ('default').""", + ('default'). If you do not want to use the Git submodule and fmt + is not installed directly into system include and library + directories, then you will need to add those directories to + 'extra_inc_dirs' and 'extra_lib_dirs'. This installation of fmt + must include the shared version of the library, for example, + 'libfmt.so'.""", 'default', ('default', 'y', 'n')), EnumVariable( 'system_yamlcpp', @@ -866,8 +871,9 @@ if not conf.CheckCXXHeader('cmath', '<>'): config_error('The C++ compiler is not correctly configured.') -def get_expression_value(includes, expression): - s = ['#include ' + i for i in includes] +def get_expression_value(includes, expression, defines=()): + s = ['#define ' + d for d in defines] + s.extend('#include ' + i for i in includes) s.extend(('#define Q(x) #x', '#define QUOTE(x) Q(x)', '#include ', @@ -909,7 +915,7 @@ if env['system_fmt'] in ('n', 'default'): ' git submodule update --init --recursive ext/fmt\n') fmt_include = '' if env['system_fmt'] else '"../ext/fmt/include/fmt/format.h"' -fmt_version_source = get_expression_value([fmt_include], 'FMT_VERSION') +fmt_version_source = get_expression_value([fmt_include], 'FMT_VERSION', ['FMT_HEADER_ONLY']) retcode, fmt_lib_version = conf.TryRun(fmt_version_source, '.cpp') try: fmt_lib_version = divmod(float(fmt_lib_version.strip()), 10000) @@ -1665,6 +1671,10 @@ else: linkLibs.extend(env['sundials_libs']) linkSharedLibs.extend(env['sundials_libs']) +if env['system_fmt']: + linkLibs.append('fmt') + linkSharedLibs.append('fmt') + if env['system_yamlcpp']: linkLibs.append('yaml-cpp') linkSharedLibs.append('yaml-cpp') diff --git a/ext/SConscript b/ext/SConscript index 2046578fb5..4ea3cc6bef 100644 --- a/ext/SConscript +++ b/ext/SConscript @@ -44,6 +44,10 @@ for subdir, extensions, prepFunction in libs: if not env['system_fmt']: license_files.append(('fmtlib', 'fmt/LICENSE.rst')) + localenv = prep_default(env) + localenv.Prepend(CPPPATH=Dir('#ext/fmt/include')) + libraryTargets.extend( + localenv.SharedObject(mglob(localenv, 'fmt/src', 'cc'))) for name in ('format.h', 'ostream.h', 'printf.h', 'core.h', 'format-inl.h'): build(copyenv.Command("#include/cantera/ext/fmt/" + name, "#ext/fmt/include/fmt/" + name, diff --git a/include/cantera/base/AnyMap.h b/include/cantera/base/AnyMap.h index 5ad8a66cee..8dcdde0d0d 100644 --- a/include/cantera/base/AnyMap.h +++ b/include/cantera/base/AnyMap.h @@ -7,13 +7,9 @@ #define CT_ANYMAP_H #include "cantera/base/ct_defs.h" -#include "cantera/base/global.h" -#include "cantera/base/Units.h" #include "cantera/base/ctexceptions.h" +#include "cantera/base/Units.h" -#include -#include -#include #include #include diff --git a/include/cantera/base/Array.h b/include/cantera/base/Array.h index 92e7fe64d8..2efd9b5adf 100644 --- a/include/cantera/base/Array.h +++ b/include/cantera/base/Array.h @@ -8,10 +8,8 @@ #ifndef CT_ARRAY_H #define CT_ARRAY_H -#include "utilities.h" - +#include "ct_defs.h" #include -#include namespace Cantera { @@ -48,11 +46,7 @@ class Array2D /** * Default constructor. Create an empty array. */ - Array2D() : - m_data(0), - m_nrows(0), - m_ncols(0) { - } + Array2D(); //! Constructor. /*! @@ -62,10 +56,7 @@ class Array2D * @param n Number of columns * @param v Default fill value. The default is 0.0 */ - Array2D(const size_t m, const size_t n, const doublereal v = 0.0) - : m_data(0), m_nrows(m), m_ncols(n) { - m_data.assign(n*m, v); - } + Array2D(const size_t m, const size_t n, const double v=0.0); //! Constructor. /*! @@ -77,31 +68,13 @@ class Array2D * @param values Initial values of the array. Must be of length m*n, and * stored in column-major order. */ - Array2D(const size_t m, const size_t n, const doublereal* values) - : m_data(0), m_nrows(m), m_ncols(n) { - m_data.assign(values, values + n*m); - } + Array2D(const size_t m, const size_t n, const double* values); - Array2D(const Array2D& y) : - m_data(0), - m_nrows(0), - m_ncols(0) { - m_nrows = y.m_nrows; - m_ncols = y.m_ncols; - m_data = y.m_data; - } + Array2D(const Array2D& y); virtual ~Array2D() {} - Array2D& operator=(const Array2D& y) { - if (&y == this) { - return *this; - } - m_nrows = y.m_nrows; - m_ncols = y.m_ncols; - m_data = y.m_data; - return *this; - } + Array2D& operator=(const Array2D& y); //! Resize the array, and fill the new entries with 'v' /*! @@ -109,11 +82,7 @@ class Array2D * @param m This is the number of columns in the new matrix * @param v Default fill value -> defaults to zero. */ - void resize(size_t n, size_t m, doublereal v = 0.0) { - m_nrows = n; - m_ncols = m; - m_data.resize(n*m, v); - } + void resize(size_t n, size_t m, double v=0.0); //! Append a column to the existing matrix using a std vector /*! @@ -122,13 +91,7 @@ class Array2D * @param c This vector is the entries in the column to be added. It must * have a length equal to m_nrows or greater. */ - void appendColumn(const vector_fp& c) { - m_ncols++; - m_data.resize(m_nrows*m_ncols); - for (size_t m = 0; m < m_nrows; m++) { - value(m_ncols, m) = c[m]; - } - } + void appendColumn(const vector_fp& c); //! Append a column to the existing matrix /*! @@ -137,24 +100,14 @@ class Array2D * @param c This vector of doubles is the entries in the column to be * added. It must have a length equal to m_nrows or greater. */ - void appendColumn(const doublereal* const c) { - m_ncols++; - m_data.resize(m_nrows*m_ncols); - for (size_t m = 0; m < m_nrows; m++) { - value(m_ncols, m) = c[m]; - } - } + void appendColumn(const double* const c); //! Set the nth row to array rw /*! * @param n Index of the row to be changed * @param rw Vector for the row. Must have a length of m_ncols. */ - void setRow(size_t n, const doublereal* const rw) { - for (size_t j = 0; j < m_ncols; j++) { - m_data[m_nrows*j + n] = rw[j]; - } - } + void setRow(size_t n, const double* const rw); //! Get the nth row and return it in a vector /*! @@ -162,11 +115,7 @@ class Array2D * @param rw Return Vector for the operation. Must have a length of * m_ncols. */ - void getRow(size_t n, doublereal* const rw) { - for (size_t j = 0; j < m_ncols; j++) { - rw[j] = m_data[m_nrows*j + n]; - } - } + void getRow(size_t n, double* const rw); //! Set the values in column m to those in array col /*! @@ -175,11 +124,7 @@ class Array2D * @param m Column to set * @param col pointer to a col vector. Vector must have a length of m_nrows. */ - void setColumn(size_t m, doublereal* const col) { - for (size_t i = 0; i < m_nrows; i++) { - m_data[m_nrows*m + i] = col[i]; - } - } + void setColumn(size_t m, double* const col); //! Get the values in column m /*! @@ -188,11 +133,7 @@ class Array2D * @param m Column to set * @param col pointer to a col vector that will be returned */ - void getColumn(size_t m, doublereal* const col) { - for (size_t i = 0; i < m_nrows; i++) { - col[i] = m_data[m_nrows*m + i]; - } - } + void getColumn(size_t m, double* const col); //! Set all of the entries to zero void zero() { @@ -323,19 +264,7 @@ class Array2D * @param m Object of type Array2D that you are querying * @returns a reference to the ostream. */ -inline std::ostream& operator<<(std::ostream& s, const Array2D& m) -{ - size_t nr = m.nRows(); - size_t nc = m.nColumns(); - for (size_t i = 0; i < nr; i++) { - s << m(i,0); - for (size_t j = 1; j < nc; j++) { - s << ", " << m(i,j); - } - s << std::endl; - } - return s; -} +std::ostream& operator<<(std::ostream& s, const Array2D& m); //! Overload the times equals operator for multiplication of a matrix and a //! scalar. @@ -345,10 +274,7 @@ inline std::ostream& operator<<(std::ostream& s, const Array2D& m) * @param m Matrix * @param a scalar */ -inline void operator*=(Array2D& m, doublereal a) -{ - scale(m.begin(), m.end(), m.begin(), a); -} +void operator*=(Array2D& m, double a); } diff --git a/include/cantera/base/FactoryBase.h b/include/cantera/base/FactoryBase.h index ada0cf84c7..385f6f3c67 100644 --- a/include/cantera/base/FactoryBase.h +++ b/include/cantera/base/FactoryBase.h @@ -9,7 +9,6 @@ #ifndef CT_FACTORY_BASE #define CT_FACTORY_BASE -#include #include #include #include diff --git a/include/cantera/base/fmt.h b/include/cantera/base/fmt.h index a863f50699..68c0cfa3c7 100644 --- a/include/cantera/base/fmt.h +++ b/include/cantera/base/fmt.h @@ -7,10 +7,6 @@ //! the same name in kinetics/Group.h #define FMT_NO_FMT_STRING_ALIAS -//! Use header-only library to avoid relocation issues with linking to the -//! static libfmt.a -#define FMT_HEADER_ONLY - //! Versions 6.2.0 and 6.2.1 of fmtlib do not include this define before they //! include windows.h, breaking builds on Windows. Fixed in fmtlib 7.0.0 and //! newer. https://github.com/fmtlib/fmt/pull/1616 diff --git a/include/cantera/base/stringUtils.h b/include/cantera/base/stringUtils.h index 5daeee0e9b..c1705cbf9c 100644 --- a/include/cantera/base/stringUtils.h +++ b/include/cantera/base/stringUtils.h @@ -10,9 +10,6 @@ #define CT_STRINGUTILS_H #include "ct_defs.h" -#include "cantera/base/fmt.h" - -#include namespace Cantera { diff --git a/include/cantera/base/utilities.h b/include/cantera/base/utilities.h index dde4f8ed69..1883be750e 100644 --- a/include/cantera/base/utilities.h +++ b/include/cantera/base/utilities.h @@ -18,9 +18,6 @@ #define CT_UTILITIES_H #include "ct_defs.h" -#include "global.h" -#include - #include namespace Cantera diff --git a/include/cantera/base/xml.h b/include/cantera/base/xml.h index 47a8921092..88e1d6eb03 100644 --- a/include/cantera/base/xml.h +++ b/include/cantera/base/xml.h @@ -11,8 +11,7 @@ #ifndef CT_XML_H #define CT_XML_H -#include "ctexceptions.h" -#include "global.h" +#include "ct_defs.h" //@{ #define XML_INDENT 4 diff --git a/include/cantera/equil/ChemEquil.h b/include/cantera/equil/ChemEquil.h index d2da801165..25f3c1d507 100644 --- a/include/cantera/equil/ChemEquil.h +++ b/include/cantera/equil/ChemEquil.h @@ -8,16 +8,14 @@ #ifndef CT_CHEM_EQUIL_H #define CT_CHEM_EQUIL_H -// Cantera includes #include "cantera/base/ct_defs.h" -#include "cantera/base/ctexceptions.h" -#include "cantera/thermo/ThermoPhase.h" #include namespace Cantera { class DenseMatrix; +class ThermoPhase; /// map property strings to integers int _equilflag(const char* xy); @@ -91,7 +89,7 @@ class ChemEquil * * @param s ThermoPhase object that will be used in the equilibrium calls. */ - ChemEquil(thermo_t& s); + ChemEquil(ThermoPhase& s); virtual ~ChemEquil(); @@ -103,7 +101,7 @@ class ChemEquil * ThermoPhase object. The properties must be already contained within the * current thermodynamic state of the system. */ - int equilibrate(thermo_t& s, const char* XY, int loglevel = 0); + int equilibrate(ThermoPhase& s, const char* XY, int loglevel = 0); /*! * Compute the equilibrium composition for two specified properties and the @@ -121,7 +119,7 @@ class ChemEquil * Unsuccessful returns are indicated by a return value of -1 for lack * of convergence or -3 for a singular Jacobian. */ - int equilibrate(thermo_t& s, const char* XY, vector_fp& elMoles, + int equilibrate(ThermoPhase& s, const char* XY, vector_fp& elMoles, int loglevel = 0); /** @@ -137,7 +135,7 @@ class ChemEquil * input from the equilibrate function. Currently, this means that the 2 * ThermoPhases have to have consist of the same species and elements. */ - thermo_t* m_phase; + ThermoPhase* m_phase; //! number of atoms of element m in species k. doublereal nAtoms(size_t k, size_t m) const { @@ -148,7 +146,7 @@ class ChemEquil * Prepare for equilibrium calculations. * @param s object representing the solution phase. */ - void initialize(thermo_t& s); + void initialize(ThermoPhase& s); /*! * Set mixture to an equilibrium state consistent with specified element @@ -159,15 +157,15 @@ class ChemEquil * \f[ \lambda_m/RT \f]. * @param t temperature in K. */ - void setToEquilState(thermo_t& s, + void setToEquilState(ThermoPhase& s, const vector_fp& x, doublereal t); //! Estimate the initial mole numbers. This version borrows from the //! MultiPhaseEquil solver. - int setInitialMoles(thermo_t& s, vector_fp& elMoleGoal, int loglevel = 0); + int setInitialMoles(ThermoPhase& s, vector_fp& elMoleGoal, int loglevel = 0); //! Generate a starting estimate for the element potentials. - int estimateElementPotentials(thermo_t& s, vector_fp& lambda, + int estimateElementPotentials(ThermoPhase& s, vector_fp& lambda, vector_fp& elMolesGoal, int loglevel = 0); /*! @@ -203,7 +201,7 @@ class ChemEquil * * NOTE: update for activity coefficients. */ - int estimateEP_Brinkley(thermo_t& s, vector_fp& lambda, vector_fp& elMoles); + int estimateEP_Brinkley(ThermoPhase& s, vector_fp& lambda, vector_fp& elMoles); //! Find an acceptable step size and take it. /*! @@ -218,25 +216,25 @@ class ChemEquil * limited to a factor of 2 jump in the values from this method. Near * convergence, the delta damping gets out of the way. */ - int dampStep(thermo_t& s, vector_fp& oldx, + int dampStep(ThermoPhase& s, vector_fp& oldx, double oldf, vector_fp& grad, vector_fp& step, vector_fp& x, double& f, vector_fp& elmols, double xval, double yval); /** * Evaluates the residual vector F, of length #m_mm */ - void equilResidual(thermo_t& s, const vector_fp& x, + void equilResidual(ThermoPhase& s, const vector_fp& x, const vector_fp& elmtotal, vector_fp& resid, double xval, double yval, int loglevel = 0); - void equilJacobian(thermo_t& s, vector_fp& x, + void equilJacobian(ThermoPhase& s, vector_fp& x, const vector_fp& elmols, DenseMatrix& jac, double xval, double yval, int loglevel = 0); - void adjustEloc(thermo_t& s, vector_fp& elMolesGoal); + void adjustEloc(ThermoPhase& s, vector_fp& elMolesGoal); //! Update internally stored state information. - void update(const thermo_t& s); + void update(const ThermoPhase& s); /** * Given a vector of dimensionless element abundances, this routine @@ -244,7 +242,7 @@ class ChemEquil * * @param[in] x = current dimensionless element potentials.. */ - double calcEmoles(thermo_t& s, vector_fp& x, + double calcEmoles(ThermoPhase& s, vector_fp& x, const double& n_t, const vector_fp& Xmol_i_calc, vector_fp& eMolesCalc, vector_fp& n_i_calc, double pressureConst); diff --git a/include/cantera/equil/MultiPhase.h b/include/cantera/equil/MultiPhase.h index 03cb31fbcf..6173f598a0 100644 --- a/include/cantera/equil/MultiPhase.h +++ b/include/cantera/equil/MultiPhase.h @@ -11,11 +11,12 @@ #define CT_MULTIPHASE_H #include "cantera/numerics/DenseMatrix.h" -#include "cantera/thermo/ThermoPhase.h" namespace Cantera { +class ThermoPhase; + //! @defgroup equilfunctions //! A class for multiphase mixtures. The mixture can contain any @@ -201,7 +202,7 @@ class MultiPhase * @param n Phase Index * @return Reference to the ThermoPhase object for the phase */ - thermo_t& phase(size_t n); + ThermoPhase& phase(size_t n); //! Check that the specified phase index is in range //! Throws an exception if m is greater than nPhases() @@ -666,21 +667,7 @@ class MultiPhase * @param x Reference to a MultiPhase * @returns a reference to the ostream */ -inline std::ostream& operator<<(std::ostream& s, MultiPhase& x) -{ - x.updatePhases(); - for (size_t ip = 0; ip < x.nPhases(); ip++) { - if (x.phase(ip).name() != "") { - s << "*************** " << x.phase(ip).name() << " *****************" << std::endl; - } else { - s << "*************** Phase " << ip << " *****************" << std::endl; - } - s << "Moles: " << x.phaseMoles(ip) << std::endl; - - s << x.phase(ip).report() << std::endl; - } - return s; -} +std::ostream& operator<<(std::ostream& s, MultiPhase& x); //! Choose the optimum basis of species for the equilibrium calculations. /*! diff --git a/include/cantera/equil/vcs_SpeciesProperties.h b/include/cantera/equil/vcs_SpeciesProperties.h index c3077e1014..7207250236 100644 --- a/include/cantera/equil/vcs_SpeciesProperties.h +++ b/include/cantera/equil/vcs_SpeciesProperties.h @@ -57,7 +57,19 @@ class vcs_SpeciesProperties double ReferenceMoleFraction; vcs_SpeciesProperties(size_t indexPhase, size_t indexSpeciesPhase, - vcs_VolPhase* owning); + vcs_VolPhase* owning) + : IndexPhase(indexPhase) + , IndexSpeciesPhase(indexSpeciesPhase) + , OwningPhase(owning) + , SpeciesThermo(0) + , WtSpecies(0.0) + , Charge(0.0) + , SurfaceSpecies(0) + , VolPM(0.0) + , ReferenceMoleFraction(1.0E-6) + { + } + virtual ~vcs_SpeciesProperties() {} }; diff --git a/include/cantera/equil/vcs_VolPhase.h b/include/cantera/equil/vcs_VolPhase.h index 5a4945d013..f00f0320dd 100644 --- a/include/cantera/equil/vcs_VolPhase.h +++ b/include/cantera/equil/vcs_VolPhase.h @@ -17,10 +17,6 @@ namespace Cantera class ThermoPhase; -//! Models for the standard state volume of each species -#define VCS_SSVOL_IDEALGAS 0 -#define VCS_SSVOL_CONSTANT 1 - /* * DEFINITIONS FOR THE vcs_VolPhase structure * diff --git a/include/cantera/equil/vcs_defs.h b/include/cantera/equil/vcs_defs.h index fa114bea81..5d877009ec 100644 --- a/include/cantera/equil/vcs_defs.h +++ b/include/cantera/equil/vcs_defs.h @@ -25,6 +25,10 @@ namespace Cantera #define VCS_MP_FAIL -6 //@} +//! Models for the standard state volume of each species +#define VCS_SSVOL_IDEALGAS 0 +#define VCS_SSVOL_CONSTANT 1 + /*! * @name Sizes of Phases and Cutoff Mole Numbers * diff --git a/include/cantera/equil/vcs_internal.h b/include/cantera/equil/vcs_internal.h index 7d51d3885a..0e3929a8d3 100644 --- a/include/cantera/equil/vcs_internal.h +++ b/include/cantera/equil/vcs_internal.h @@ -25,9 +25,6 @@ namespace Cantera */ extern int vcs_timing_print_lvl; -// Forward references -class VCS_SPECIES_THERMO; - //! Class to keep track of time and iterations /*! * class keeps all of the counters together. diff --git a/include/cantera/equil/vcs_species_thermo.h b/include/cantera/equil/vcs_species_thermo.h index 9148c7a930..62f484caed 100644 --- a/include/cantera/equil/vcs_species_thermo.h +++ b/include/cantera/equil/vcs_species_thermo.h @@ -6,7 +6,7 @@ #ifndef VCS_SPECIES_THERMO_H #define VCS_SPECIES_THERMO_H -#include +#include "cantera/equil/vcs_defs.h" namespace Cantera { @@ -81,7 +81,23 @@ class VCS_SPECIES_THERMO //! parameter that is used in the VCS_SSVOL_CONSTANT model. double SSStar_Vol0; - VCS_SPECIES_THERMO(); + VCS_SPECIES_THERMO() + : IndexPhase(0) + , IndexSpeciesPhase(0) + , OwningPhase(0) + , SS0_Model(VCS_SS0_CONSTANT) + , SS0_feSave(0.0) + , SS0_TSave(-90.0) + , SS0_T0(273.15) + , SS0_H0(0.0) + , SS0_S0(0.0) + , SS0_Cp0(0.0) + , SS0_Pref(1.01325E5) + , SSStar_Model(VCS_SSSTAR_CONSTANT) + , SSStar_Vol_Model(VCS_SSVOL_IDEALGAS) + , SSStar_Vol0(-1.0) + { + } }; } diff --git a/include/cantera/kinetics/BulkKinetics.h b/include/cantera/kinetics/BulkKinetics.h index 17d490cc11..52672639c0 100644 --- a/include/cantera/kinetics/BulkKinetics.h +++ b/include/cantera/kinetics/BulkKinetics.h @@ -21,7 +21,7 @@ class ElementaryReaction; class BulkKinetics : public Kinetics { public: - BulkKinetics(thermo_t* thermo = 0); + BulkKinetics(ThermoPhase* thermo = 0); virtual bool isReversible(size_t i); diff --git a/include/cantera/kinetics/Falloff.h b/include/cantera/kinetics/Falloff.h index 66eae6f829..0adefb56c4 100644 --- a/include/cantera/kinetics/Falloff.h +++ b/include/cantera/kinetics/Falloff.h @@ -4,8 +4,7 @@ #ifndef CT_FALLOFF_H #define CT_FALLOFF_H -#include "cantera/kinetics/reaction_defs.h" -#include "cantera/base/global.h" +#include "cantera/base/ct_defs.h" namespace Cantera { diff --git a/include/cantera/kinetics/FalloffMgr.h b/include/cantera/kinetics/FalloffMgr.h index 5bbbecdd61..f665cabe89 100644 --- a/include/cantera/kinetics/FalloffMgr.h +++ b/include/cantera/kinetics/FalloffMgr.h @@ -8,13 +8,12 @@ #ifndef CT_FALLOFFMGR_H #define CT_FALLOFFMGR_H -#include "reaction_defs.h" -#include "FalloffFactory.h" -#include "cantera/base/global.h" +#include "Falloff.h" namespace Cantera { + /** * A falloff manager that implements any set of falloff functions. * @ingroup falloffGroup @@ -25,8 +24,6 @@ class FalloffMgr //! Constructor. FalloffMgr() : m_worksize(0) { - m_factory = FalloffFactory::factory(); // RFB:TODO This raw pointer should be encapsulated - // because accessing a 'Singleton Factory' } //! Install a new falloff function calculator. @@ -94,7 +91,6 @@ class FalloffMgr protected: std::vector m_rxn; std::vector > m_falloff; - FalloffFactory* m_factory; vector_int m_loc; std::vector m_offset; size_t m_worksize; diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 3e9c413670..1973323a7c 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -33,7 +33,7 @@ class GasKinetics : public BulkKinetics /*! * @param thermo Pointer to the gas ThermoPhase (optional) */ - GasKinetics(thermo_t* thermo = 0); + GasKinetics(ThermoPhase* thermo = 0); virtual std::string kineticsType() const { return "Gas"; diff --git a/include/cantera/kinetics/InterfaceKinetics.h b/include/cantera/kinetics/InterfaceKinetics.h index e15e5b1a79..fec3d801b5 100644 --- a/include/cantera/kinetics/InterfaceKinetics.h +++ b/include/cantera/kinetics/InterfaceKinetics.h @@ -10,7 +10,6 @@ #define CT_IFACEKINETICS_H #include "Kinetics.h" -#include "Reaction.h" #include "RateCoeffMgr.h" namespace Cantera @@ -19,6 +18,7 @@ namespace Cantera // forward declarations class SurfPhase; class ImplicitSurfChem; +class InterfaceReaction; //! A kinetics manager for heterogeneous reaction mechanisms. The reactions are //! assumed to occur at a 2D interface between two 3D phases. @@ -65,7 +65,7 @@ class InterfaceKinetics : public Kinetics * probably require multiple ThermoPhase objects, this is * probably not a good idea to have this parameter. */ - InterfaceKinetics(thermo_t* thermo = 0); + InterfaceKinetics(ThermoPhase* thermo = 0); virtual ~InterfaceKinetics(); @@ -194,7 +194,7 @@ class InterfaceKinetics : public Kinetics * * @param thermo Reference to the ThermoPhase to be added. */ - virtual void addPhase(thermo_t& thermo); + virtual void addPhase(ThermoPhase& thermo); virtual void init(); virtual void resizeSpecies(); diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 6f59438a2f..ff2c1ee755 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -11,14 +11,16 @@ #ifndef CT_KINETICS_H #define CT_KINETICS_H -#include "cantera/thermo/ThermoPhase.h" #include "StoichManager.h" -#include "cantera/kinetics/Reaction.h" -#include "cantera/base/global.h" +#include "cantera/base/ValueCache.h" namespace Cantera { +class ThermoPhase; +class Reaction; +class Solution; + /** * @defgroup chemkinetics Chemical Kinetics */ @@ -224,10 +226,10 @@ class Kinetics * * @param n Index of the ThermoPhase being sought. */ - thermo_t& thermo(size_t n=0) { + ThermoPhase& thermo(size_t n=0) { return *m_thermo[n]; } - const thermo_t& thermo(size_t n=0) const { + const ThermoPhase& thermo(size_t n=0) const { return *m_thermo[n]; } @@ -308,8 +310,8 @@ class Kinetics * * @param nm String containing the name of the species. */ - thermo_t& speciesPhase(const std::string& nm); - const thermo_t& speciesPhase(const std::string& nm) const; + ThermoPhase& speciesPhase(const std::string& nm); + const ThermoPhase& speciesPhase(const std::string& nm) const; /** * This function takes as an argument the kineticsSpecies index @@ -318,7 +320,7 @@ class Kinetics * * @param k Species index */ - thermo_t& speciesPhase(size_t k) { + ThermoPhase& speciesPhase(size_t k) { return thermo(speciesPhaseIndex(k)); } @@ -600,9 +602,7 @@ class Kinetics * * @param i reaction index */ - virtual int reactionType(size_t i) const { - return m_reactions[i]->reaction_type; - } + virtual int reactionType(size_t i) const; /** * True if reaction i has been declared to be reversible. If isReversible(i) @@ -620,19 +620,13 @@ class Kinetics * * @param i reaction index */ - std::string reactionString(size_t i) const { - return m_reactions[i]->equation(); - } + std::string reactionString(size_t i) const; //! Returns a string containing the reactants side of the reaction equation. - std::string reactantString(size_t i) const { - return m_reactions[i]->reactantString(); - } + std::string reactantString(size_t i) const; //! Returns a string containing the products side of the reaction equation. - std::string productString(size_t i) const { - return m_reactions[i]->productString(); - } + std::string productString(size_t i) const; /** * Return the forward rate constants @@ -687,7 +681,7 @@ class Kinetics * * @param thermo Reference to the ThermoPhase to be added. */ - virtual void addPhase(thermo_t& thermo); + virtual void addPhase(ThermoPhase& thermo); /** * Prepare the class for the addition of reactions, after all phases have @@ -811,8 +805,8 @@ class Kinetics * @param phase_data Output array where the values for the the specified * phase are to be written. */ - void selectPhase(const doublereal* data, const thermo_t* phase, - doublereal* phase_data); + void selectPhase(const double* data, const ThermoPhase* phase, + double* phase_data); //! Set root Solution holding all phase information virtual void setRoot(std::shared_ptr root) { @@ -891,7 +885,7 @@ class Kinetics * Note that this kinetics object doesn't own these ThermoPhase objects * and is not responsible for creating or deleting them. */ - std::vector m_thermo; + std::vector m_thermo; /** * m_start is a vector of integers specifying the beginning position for the diff --git a/include/cantera/kinetics/KineticsFactory.h b/include/cantera/kinetics/KineticsFactory.h index 7bfd803d79..6d064c27e1 100644 --- a/include/cantera/kinetics/KineticsFactory.h +++ b/include/cantera/kinetics/KineticsFactory.h @@ -10,6 +10,7 @@ #include "Kinetics.h" #include "cantera/base/FactoryBase.h" +#include "cantera/base/AnyMap.h" namespace Cantera { diff --git a/include/cantera/kinetics/Reaction.h b/include/cantera/kinetics/Reaction.h index 6147ed110a..e8a300f175 100644 --- a/include/cantera/kinetics/Reaction.h +++ b/include/cantera/kinetics/Reaction.h @@ -8,15 +8,15 @@ #ifndef CT_REACTION_H #define CT_REACTION_H -#include "cantera/base/utilities.h" #include "cantera/base/AnyMap.h" #include "cantera/kinetics/RxnRates.h" -#include "cantera/kinetics/Falloff.h" namespace Cantera { class Kinetics; +class Falloff; +class XML_Node; //! Intermediate class which stores data about a reaction and its rate //! parameterization so that it can be added to a Kinetics object. @@ -99,9 +99,7 @@ class ThirdBody explicit ThirdBody(double default_efficiency=1.0); //! Get the third-body efficiency for species *k* - double efficiency(const std::string& k) const { - return getValue(efficiencies, k, default_efficiency); - } + double efficiency(const std::string& k) const; //! Map of species to third body efficiency Composition efficiencies; diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index a473d57971..c5e07de478 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -10,10 +10,6 @@ #include "cantera/kinetics/reaction_defs.h" #include "cantera/base/ctexceptions.h" -#include "cantera/base/stringUtils.h" -#include "cantera/base/global.h" - -#include namespace Cantera { diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index 66c2a138ba..e011edfea9 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -8,7 +8,6 @@ #ifndef CT_STOICH_MGR_H #define CT_STOICH_MGR_H -#include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" namespace Cantera diff --git a/include/cantera/kinetics/importKinetics.h b/include/cantera/kinetics/importKinetics.h index 01168c34a9..227b265266 100644 --- a/include/cantera/kinetics/importKinetics.h +++ b/include/cantera/kinetics/importKinetics.h @@ -21,6 +21,8 @@ namespace Cantera { +class XML_Node; + //! Install information about reactions into the kinetics object, kin. /*! * At this point, parent usually refers to the phase XML element. One of the diff --git a/include/cantera/numerics/ResidEval.h b/include/cantera/numerics/ResidEval.h index c7ee92bd7e..dc94a4d25c 100644 --- a/include/cantera/numerics/ResidEval.h +++ b/include/cantera/numerics/ResidEval.h @@ -9,8 +9,7 @@ #include "cantera/base/ct_defs.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/utilities.h" - -#include +#include "cantera/base/global.h" namespace Cantera { diff --git a/include/cantera/oneD/Boundary1D.h b/include/cantera/oneD/Boundary1D.h index 3209a0cbd6..2793dfc211 100644 --- a/include/cantera/oneD/Boundary1D.h +++ b/include/cantera/oneD/Boundary1D.h @@ -264,9 +264,7 @@ class Surf1D : public Boundary1D virtual void showSolution_s(std::ostream& s, const double* x); - virtual void showSolution(const double* x) { - writelog(" Temperature: {:10.4g} K \n\n", m_temp); - } + virtual void showSolution(const double* x); }; /** diff --git a/include/cantera/oneD/Domain1D.h b/include/cantera/oneD/Domain1D.h index a3174fc3f4..b11cdf38e2 100644 --- a/include/cantera/oneD/Domain1D.h +++ b/include/cantera/oneD/Domain1D.h @@ -6,10 +6,7 @@ #ifndef CT_DOMAIN1D_H #define CT_DOMAIN1D_H -#include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" -#include "cantera/base/global.h" -#include "refine.h" namespace Cantera { @@ -29,6 +26,7 @@ const int cPorousType = 109; class MultiJac; class OneDim; +class Refiner; class XML_Node; /** @@ -46,7 +44,7 @@ class Domain1D */ Domain1D(size_t nv=1, size_t points=1, double time=0.0); - virtual ~Domain1D() {} + virtual ~Domain1D(); Domain1D(const Domain1D&) = delete; Domain1D& operator=(const Domain1D&) = delete; diff --git a/include/cantera/oneD/StFlow.h b/include/cantera/oneD/StFlow.h index 77e1df46bc..f50b3aa9b9 100644 --- a/include/cantera/oneD/StFlow.h +++ b/include/cantera/oneD/StFlow.h @@ -60,7 +60,7 @@ class StFlow : public Domain1D virtual void resetBadValues(double* xg); - thermo_t& phase() { + ThermoPhase& phase() { return *m_thermo; } Kinetics& kinetics() { diff --git a/include/cantera/onedim.h b/include/cantera/onedim.h index fd50998564..55116ae182 100644 --- a/include/cantera/onedim.h +++ b/include/cantera/onedim.h @@ -15,5 +15,6 @@ #include "oneD/Domain1D.h" #include "oneD/Boundary1D.h" #include "oneD/StFlow.h" +#include "oneD/refine.h" #endif diff --git a/include/cantera/thermo/BinarySolutionTabulatedThermo.h b/include/cantera/thermo/BinarySolutionTabulatedThermo.h index b754dcd926..d1f05b7eda 100644 --- a/include/cantera/thermo/BinarySolutionTabulatedThermo.h +++ b/include/cantera/thermo/BinarySolutionTabulatedThermo.h @@ -113,20 +113,17 @@ namespace Cantera class BinarySolutionTabulatedThermo : public IdealSolidSolnPhase { public: - //! Default constructor for BinarySolutionTabulatedThermo - BinarySolutionTabulatedThermo(); - //! Construct and initialize an BinarySolutionTabulatedThermo ThermoPhase object //! directly from an input file /*! * This constructor will also fully initialize the object. * * @param infile File name for the input file containing information - * for this phase + * for this phase. If not specified, an empty phase will be created. * @param id The name of this phase. This is used to look up * the phase in the input file. */ - BinarySolutionTabulatedThermo(const std::string& infile, const std::string& id=""); + explicit BinarySolutionTabulatedThermo(const std::string& infile="", const std::string& id=""); //! Construct and initialize an BinarySolutionTabulatedThermo ThermoPhase object //! directly from an XML database diff --git a/include/cantera/thermo/ConstCpPoly.h b/include/cantera/thermo/ConstCpPoly.h index f7f55cb196..4ba4b353ba 100644 --- a/include/cantera/thermo/ConstCpPoly.h +++ b/include/cantera/thermo/ConstCpPoly.h @@ -12,6 +12,7 @@ #define CT_CONSTCPPOLY_H #include "cantera/thermo/SpeciesThermoInterpType.h" +#include "cantera/thermo/speciesThermoTypes.h" namespace Cantera { diff --git a/include/cantera/thermo/DebyeHuckel.h b/include/cantera/thermo/DebyeHuckel.h index e826f40a5c..d9a81c9673 100644 --- a/include/cantera/thermo/DebyeHuckel.h +++ b/include/cantera/thermo/DebyeHuckel.h @@ -558,17 +558,16 @@ class PDSS_Water; class DebyeHuckel : public MolalityVPSSTP { public: - //! Default Constructor - DebyeHuckel(); - virtual ~DebyeHuckel(); //! Full constructor for creating the phase. /*! - * @param inputFile File name containing the definition of the phase + * @param inputFile File name containing the definition of the phase. + * If blank, an empty phase will be created. * @param id id attribute containing the name of the phase. */ - DebyeHuckel(const std::string& inputFile, const std::string& id = ""); + explicit DebyeHuckel(const std::string& inputFile="", + const std::string& id=""); //! Full constructor for creating the phase. /*! diff --git a/include/cantera/thermo/EdgePhase.h b/include/cantera/thermo/EdgePhase.h index 2825fde0a5..0c6d7620ac 100644 --- a/include/cantera/thermo/EdgePhase.h +++ b/include/cantera/thermo/EdgePhase.h @@ -33,8 +33,10 @@ class EdgePhase : public SurfPhase //! Constructor /*! * @param n0 Surface site density (kmol m-1). + * @deprecated The `n0` constructor argument is deprecated and will be + * removed after Cantera 2.6. Use setSiteDensity() instead. */ - EdgePhase(doublereal n0=1.0); + EdgePhase(doublereal n0=-1.0); virtual std::string type() const { return "Edge"; diff --git a/include/cantera/thermo/HMWSoln.h b/include/cantera/thermo/HMWSoln.h index 2aeb7e7efa..4b9a509af3 100644 --- a/include/cantera/thermo/HMWSoln.h +++ b/include/cantera/thermo/HMWSoln.h @@ -1038,8 +1038,6 @@ class WaterProps; class HMWSoln : public MolalityVPSSTP { public: - //! Default Constructor - HMWSoln(); ~HMWSoln(); //! Construct and initialize an HMWSoln ThermoPhase object @@ -1049,11 +1047,12 @@ class HMWSoln : public MolalityVPSSTP * a reference to the parsed input file to get the info for the phase. * * @param inputFile Name of the input file containing the phase definition - * to set up the object + * to set up the object. If blank, an empty phase will be + * created. * @param id ID of the phase in the input file. Defaults to the * empty string. */ - HMWSoln(const std::string& inputFile, const std::string& id = ""); + explicit HMWSoln(const std::string& inputFile="", const std::string& id=""); //! Construct and initialize an HMWSoln ThermoPhase object //! directly from an XML database diff --git a/include/cantera/thermo/IdealGasPhase.h b/include/cantera/thermo/IdealGasPhase.h index a74e84e403..c5fe4eb2dd 100644 --- a/include/cantera/thermo/IdealGasPhase.h +++ b/include/cantera/thermo/IdealGasPhase.h @@ -287,18 +287,17 @@ namespace Cantera class IdealGasPhase: public ThermoPhase { public: - //! Default empty Constructor - IdealGasPhase(); - //! Construct and initialize an IdealGasPhase ThermoPhase object //! directly from an ASCII input file /*! * @param inputFile Name of the input file containing the phase definition - * to set up the object + * to set up the object. If blank, an empty phase will be + * created. * @param id ID of the phase in the input file. Defaults to the * empty string. */ - IdealGasPhase(const std::string& inputFile, const std::string& id = ""); + explicit IdealGasPhase(const std::string& inputFile="", + const std::string& id=""); //! Construct and initialize an IdealGasPhase ThermoPhase object //! directly from an XML database diff --git a/include/cantera/thermo/IdealMolalSoln.h b/include/cantera/thermo/IdealMolalSoln.h index 7120b12b10..03c3457b4e 100644 --- a/include/cantera/thermo/IdealMolalSoln.h +++ b/include/cantera/thermo/IdealMolalSoln.h @@ -78,19 +78,17 @@ namespace Cantera class IdealMolalSoln : public MolalityVPSSTP { public: - /// Constructor - IdealMolalSoln(); - //! Constructor for phase initialization /*! * This constructor will initialize a phase, by reading the required * information from an input file. * * @param inputFile Name of the Input file that contains information - * about the phase + * about the phase. If blank, an empty phase will be created. * @param id id of the phase within the input file */ - IdealMolalSoln(const std::string& inputFile, const std::string& id = ""); + explicit IdealMolalSoln(const std::string& inputFile="", + const std::string& id=""); //! Constructor for phase initialization /*! diff --git a/include/cantera/thermo/IdealSolidSolnPhase.h b/include/cantera/thermo/IdealSolidSolnPhase.h index 70dccfa290..2a991402df 100644 --- a/include/cantera/thermo/IdealSolidSolnPhase.h +++ b/include/cantera/thermo/IdealSolidSolnPhase.h @@ -46,8 +46,10 @@ class IdealSolidSolnPhase : public ThermoPhase * is supplied in the constructor or read from the input file. * * @param formCG This parameter initializes the #m_formGC variable. + * @deprecated the formGC argument is deprecated and will be removed after + * Cantera 2.6. Use the setStandardConcentrationModel method instead. */ - IdealSolidSolnPhase(int formCG=0); + IdealSolidSolnPhase(int formCG=-1); //! Construct and initialize an IdealSolidSolnPhase ThermoPhase object //! directly from an ASCII input file @@ -58,12 +60,16 @@ class IdealSolidSolnPhase : public ThermoPhase * is supplied in the constructor or read from the input file. * * @param infile File name for the input file containing information - * for this phase + * for this phase. If blank, an empty phase will be + * created. * @param id The name of this phase. This is used to look up * the phase in the input file. * @param formCG This parameter initializes the #m_formGC variable. + * @deprecated the formGC argument is deprecated and will be removed after + * Cantera 2.6. Use the setStandardConcentrationModel method instead. */ - IdealSolidSolnPhase(const std::string& infile, const std::string& id="", int formCG=0); + explicit IdealSolidSolnPhase(const std::string& infile, + const std::string& id="", int formCG=-1); //! Construct and initialize an IdealSolidSolnPhase ThermoPhase object //! directly from an XML database @@ -82,7 +88,7 @@ class IdealSolidSolnPhase : public ThermoPhase * @deprecated The XML input format is deprecated and will be removed in * Cantera 3.0. */ - IdealSolidSolnPhase(XML_Node& root, const std::string& id="", int formCG=0); + IdealSolidSolnPhase(XML_Node& root, const std::string& id="", int formCG=-1); virtual std::string type() const { return "IdealSolidSoln"; diff --git a/include/cantera/thermo/IdealSolnGasVPSS.h b/include/cantera/thermo/IdealSolnGasVPSS.h index 96d158cdfe..3deae06b0c 100644 --- a/include/cantera/thermo/IdealSolnGasVPSS.h +++ b/include/cantera/thermo/IdealSolnGasVPSS.h @@ -27,15 +27,8 @@ namespace Cantera class IdealSolnGasVPSS : public VPStandardStateTP { public: - /*! - * @name Constructors and Duplicators for IdealSolnGasVPSS - */ - //! @{ - - IdealSolnGasVPSS(); - /// Create an object from an input file - IdealSolnGasVPSS(const std::string& infile, std::string id=""); + explicit IdealSolnGasVPSS(const std::string& infile="", std::string id=""); //@} //! @name Utilities (IdealSolnGasVPSS) diff --git a/include/cantera/thermo/IonsFromNeutralVPSSTP.h b/include/cantera/thermo/IonsFromNeutralVPSSTP.h index c16afbab40..1526b110b2 100644 --- a/include/cantera/thermo/IonsFromNeutralVPSSTP.h +++ b/include/cantera/thermo/IonsFromNeutralVPSSTP.h @@ -70,19 +70,15 @@ class IonsFromNeutralVPSSTP : public GibbsExcessVPSSTP //! @name Constructors //! @{ - /*! - * Default constructor - */ - IonsFromNeutralVPSSTP(); - //! Construct an IonsFromNeutralVPSSTP object from an input file /*! - * @param inputFile Name of the input file containing the phase definition + * @param inputFile Name of the input file containing the phase definition. + * If blank, an empty phase will be created. * @param id name (ID) of the phase in the input file. If empty, the * first phase definition in the input file will be used. */ - IonsFromNeutralVPSSTP(const std::string& inputFile, - const std::string& id = ""); + explicit IonsFromNeutralVPSSTP(const std::string& inputFile="", + const std::string& id=""); //! Construct and initialize an IonsFromNeutralVPSSTP object //! directly from an XML database diff --git a/include/cantera/thermo/LatticePhase.h b/include/cantera/thermo/LatticePhase.h index adc08a445e..725d772616 100644 --- a/include/cantera/thermo/LatticePhase.h +++ b/include/cantera/thermo/LatticePhase.h @@ -230,15 +230,14 @@ namespace Cantera class LatticePhase : public ThermoPhase { public: - //! Base Empty constructor - LatticePhase(); - //! Full constructor for a lattice phase /*! - * @param inputFile String name of the input file + * @param inputFile String name of the input file. If blank, + * an empty phase will be created. * @param id string id of the phase name */ - LatticePhase(const std::string& inputFile, const std::string& id = ""); + explicit LatticePhase(const std::string& inputFile="", + const std::string& id=""); //! Full constructor for a water phase /*! diff --git a/include/cantera/thermo/MargulesVPSSTP.h b/include/cantera/thermo/MargulesVPSSTP.h index 72d6e952d9..def54ea821 100644 --- a/include/cantera/thermo/MargulesVPSSTP.h +++ b/include/cantera/thermo/MargulesVPSSTP.h @@ -214,15 +214,15 @@ namespace Cantera class MargulesVPSSTP : public GibbsExcessVPSSTP { public: - MargulesVPSSTP(); - //! Construct a MargulesVPSSTP object from an input file /*! - * @param inputFile Name of the input file containing the phase definition + * @param inputFile Name of the input file containing the phase definition. + * If blank, an empty phase will be created. * @param id name (ID) of the phase in the input file. If empty, the * first phase definition in the input file will be used. */ - MargulesVPSSTP(const std::string& inputFile, const std::string& id = ""); + explicit MargulesVPSSTP(const std::string& inputFile="", + const std::string& id=""); //! Construct and initialize a MargulesVPSSTP ThermoPhase object directly //! from an XML database diff --git a/include/cantera/thermo/Mu0Poly.h b/include/cantera/thermo/Mu0Poly.h index 8354a9cabb..42fbf65194 100644 --- a/include/cantera/thermo/Mu0Poly.h +++ b/include/cantera/thermo/Mu0Poly.h @@ -13,6 +13,7 @@ #define CT_MU0POLY_H #include "cantera/thermo/SpeciesThermoInterpType.h" +#include "cantera/thermo/speciesThermoTypes.h" namespace Cantera { diff --git a/include/cantera/thermo/Nasa9Poly1.h b/include/cantera/thermo/Nasa9Poly1.h index 694d828804..99c0d9cf94 100644 --- a/include/cantera/thermo/Nasa9Poly1.h +++ b/include/cantera/thermo/Nasa9Poly1.h @@ -15,6 +15,7 @@ #define CT_NASA9POLY1_H #include "SpeciesThermoInterpType.h" +#include "speciesThermoTypes.h" namespace Cantera { diff --git a/include/cantera/thermo/NasaPoly1.h b/include/cantera/thermo/NasaPoly1.h index ef7b105556..75ed200047 100644 --- a/include/cantera/thermo/NasaPoly1.h +++ b/include/cantera/thermo/NasaPoly1.h @@ -15,6 +15,7 @@ #define CT_NASAPOLY1_H #include "SpeciesThermoInterpType.h" +#include "cantera/thermo/speciesThermoTypes.h" namespace Cantera { diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index cc9cd2a45d..b267d97551 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -10,14 +10,16 @@ #define CT_PHASE_H #include "cantera/base/ctexceptions.h" -#include "cantera/base/Solution.h" #include "cantera/thermo/Elements.h" -#include "cantera/thermo/Species.h" #include "cantera/base/ValueCache.h" namespace Cantera { +class Solution; +class Species; +class XML_Node; + /** * @defgroup phases Models of Phases of Matter * @@ -859,9 +861,7 @@ class Phase } //! Set root Solution holding all phase information - virtual void setRoot(std::shared_ptr root) { - m_root = root; - } + virtual void setRoot(std::shared_ptr root); //! Converts a compositionMap to a vector with entries for each species //! Species that are not specified are set to zero in the vector diff --git a/include/cantera/thermo/RedlichKisterVPSSTP.h b/include/cantera/thermo/RedlichKisterVPSSTP.h index 229916155e..c0a49fe289 100644 --- a/include/cantera/thermo/RedlichKisterVPSSTP.h +++ b/include/cantera/thermo/RedlichKisterVPSSTP.h @@ -216,19 +216,15 @@ namespace Cantera class RedlichKisterVPSSTP : public GibbsExcessVPSSTP { public: - //! Constructor - /*! - * This doesn't do much more than initialize constants with default values. - */ - RedlichKisterVPSSTP(); - //! Construct a RedlichKisterVPSSTP object from an input file /*! - * @param inputFile Name of the input file containing the phase definition + * @param inputFile Name of the input file containing the phase definition. + * If blank, an empty phase will be created. * @param id name (ID) of the phase in the input file. If empty, the * first phase definition in the input file will be used. */ - RedlichKisterVPSSTP(const std::string& inputFile, const std::string& id = ""); + explicit RedlichKisterVPSSTP(const std::string& inputFile="", + const std::string& id=""); //! Construct and initialize a RedlichKisterVPSSTP ThermoPhase object //! directly from an XML database diff --git a/include/cantera/thermo/RedlichKwongMFTP.h b/include/cantera/thermo/RedlichKwongMFTP.h index fa5e4f0eb5..d6317e33d9 100644 --- a/include/cantera/thermo/RedlichKwongMFTP.h +++ b/include/cantera/thermo/RedlichKwongMFTP.h @@ -19,19 +19,15 @@ namespace Cantera class RedlichKwongMFTP : public MixtureFugacityTP { public: - //! @name Constructors and Duplicators - //! @{ - - //! Base constructor. - RedlichKwongMFTP(); - //! Construct a RedlichKwongMFTP object from an input file /*! - * @param inputFile Name of the input file containing the phase definition + * @param inputFile Name of the input file containing the phase definition. + * If blank, an empty phase will be created. * @param id name (ID) of the phase in the input file. If empty, the * first phase definition in the input file will be used. */ - RedlichKwongMFTP(const std::string& infile, const std::string& id=""); + explicit RedlichKwongMFTP(const std::string& infile="", + const std::string& id=""); //! Construct and initialize a RedlichKwongMFTP object directly from an //! XML database diff --git a/include/cantera/thermo/SpeciesThermoInterpType.h b/include/cantera/thermo/SpeciesThermoInterpType.h index 0858f54512..1230370124 100644 --- a/include/cantera/thermo/SpeciesThermoInterpType.h +++ b/include/cantera/thermo/SpeciesThermoInterpType.h @@ -13,9 +13,7 @@ #define CT_SPECIESTHERMOINTERPTYPE_H #include "cantera/base/ct_defs.h" -#include "speciesThermoTypes.h" #include "cantera/base/ctexceptions.h" -#include "cantera/base/global.h" namespace Cantera { diff --git a/include/cantera/thermo/StoichSubstance.h b/include/cantera/thermo/StoichSubstance.h index ead757b3d7..06f4ad7145 100644 --- a/include/cantera/thermo/StoichSubstance.h +++ b/include/cantera/thermo/StoichSubstance.h @@ -149,17 +149,16 @@ namespace Cantera class StoichSubstance : public SingleSpeciesTP { public: - //! Default constructor for the StoichSubstance class - StoichSubstance() {} - //! Construct and initialize a StoichSubstance ThermoPhase object directly //! from an ASCII input file /*! - * @param infile name of the input file + * @param infile name of the input file. If blank, an empty phase will be + * created. * @param id name of the phase id in the file. * If this is blank, the first phase in the file is used. */ - StoichSubstance(const std::string& infile, const std::string& id = ""); + explicit StoichSubstance(const std::string& infile="", + const std::string& id=""); //! Construct and initialize a StoichSubstance ThermoPhase object directly //! from an XML database diff --git a/include/cantera/thermo/SurfPhase.h b/include/cantera/thermo/SurfPhase.h index d19698f2bc..185b3e3a86 100644 --- a/include/cantera/thermo/SurfPhase.h +++ b/include/cantera/thermo/SurfPhase.h @@ -146,8 +146,10 @@ class SurfPhase : public ThermoPhase /*! * @param n0 Site Density of the Surface Phase * Units: kmol m-2. + * @deprecated The `n0` constructor argument is deprecated and will be + * removed after Cantera 2.6. Use setSiteDensity() instead. */ - SurfPhase(doublereal n0 = 1.0); + SurfPhase(doublereal n0 = -1.0); //! Construct and initialize a SurfPhase ThermoPhase object directly from an //! ASCII input file @@ -156,7 +158,7 @@ class SurfPhase : public ThermoPhase * @param id name of the phase id in the file. * If this is blank, the first phase in the file is used. */ - SurfPhase(const std::string& infile, const std::string& id); + explicit SurfPhase(const std::string& infile, const std::string& id=""); //! Construct and initialize a SurfPhase ThermoPhase object directly from an //! XML database diff --git a/include/cantera/thermo/ThermoPhase.h b/include/cantera/thermo/ThermoPhase.h index d49ded492b..639c5ed960 100644 --- a/include/cantera/thermo/ThermoPhase.h +++ b/include/cantera/thermo/ThermoPhase.h @@ -13,7 +13,8 @@ #include "Phase.h" #include "MultiSpeciesThermo.h" -#include "cantera/base/global.h" +#include "cantera/base/Units.h" +#include "cantera/base/AnyMap.h" namespace Cantera { @@ -1613,7 +1614,7 @@ class ThermoPhase : public Phase * @internal */ virtual MultiSpeciesThermo& speciesThermo(int k = -1); - + virtual const MultiSpeciesThermo& speciesThermo(int k = -1) const; /** @@ -1623,7 +1624,8 @@ class ThermoPhase : public Phase * Used to implement constructors for derived classes which take a * file name and phase name as arguments. * - * @param inputFile Input file containing the description of the phase + * @param inputFile Input file containing the description of the phase. If blank, + * no setup will be performed. * @param id Optional parameter identifying the name of the phase. If * blank, the first phase definition encountered will be used. */ @@ -1905,6 +1907,7 @@ class ThermoPhase : public Phase }; //! typedef for the ThermoPhase class +//! @deprecated To be removed after Cantera 2.6. typedef ThermoPhase thermo_t; } diff --git a/include/cantera/thermo/VPStandardStateTP.h b/include/cantera/thermo/VPStandardStateTP.h index 998397ed46..cec8e4882a 100644 --- a/include/cantera/thermo/VPStandardStateTP.h +++ b/include/cantera/thermo/VPStandardStateTP.h @@ -13,10 +13,12 @@ #define CT_VPSTANDARDSTATETP_H #include "ThermoPhase.h" -#include "PDSS.h" namespace Cantera { + +class PDSS; + /** * @ingroup thermoprops * @@ -46,6 +48,8 @@ class VPStandardStateTP : public ThermoPhase /// Constructor. VPStandardStateTP(); + virtual ~VPStandardStateTP(); + //@} virtual bool isCompressible() const { diff --git a/include/cantera/thermo/WaterSSTP.h b/include/cantera/thermo/WaterSSTP.h index e6850d5a9a..19ffa58f54 100644 --- a/include/cantera/thermo/WaterSSTP.h +++ b/include/cantera/thermo/WaterSSTP.h @@ -119,15 +119,13 @@ class WaterProps; class WaterSSTP : public SingleSpeciesTP { public: - //! Base constructor - WaterSSTP(); - //! Full constructor for a water phase /*! * @param inputFile String name of the input file * @param id string id of the phase name */ - explicit WaterSSTP(const std::string& inputFile, const std::string& id = ""); + explicit WaterSSTP(const std::string& inputFile="", + const std::string& id=""); //! Full constructor for a water phase /*! diff --git a/include/cantera/transport/DustyGasTransport.h b/include/cantera/transport/DustyGasTransport.h index 61e2003ae2..ecf1bc9058 100644 --- a/include/cantera/transport/DustyGasTransport.h +++ b/include/cantera/transport/DustyGasTransport.h @@ -67,11 +67,11 @@ class DustyGasTransport : public Transport * @param thermo Pointer to the ThermoPhase object for this phase. * Defaults to zero. */ - DustyGasTransport(thermo_t* thermo=0); + DustyGasTransport(ThermoPhase* thermo=0); // overloaded base class methods - virtual void setThermo(thermo_t& thermo); + virtual void setThermo(ThermoPhase& thermo); virtual std::string transportType() const { return "DustyGas"; diff --git a/include/cantera/transport/GasTransport.h b/include/cantera/transport/GasTransport.h index 125ca060a9..27d73145eb 100644 --- a/include/cantera/transport/GasTransport.h +++ b/include/cantera/transport/GasTransport.h @@ -115,7 +115,7 @@ class GasTransport : public Transport */ virtual void getMixDiffCoeffsMass(doublereal* const d); - virtual void init(thermo_t* thermo, int mode=0, int log_level=0); + virtual void init(ThermoPhase* thermo, int mode=0, int log_level=0); protected: GasTransport(ThermoPhase* thermo=0); diff --git a/include/cantera/transport/HighPressureGasTransport.h b/include/cantera/transport/HighPressureGasTransport.h index cd5344bea2..d6b933c933 100644 --- a/include/cantera/transport/HighPressureGasTransport.h +++ b/include/cantera/transport/HighPressureGasTransport.h @@ -42,7 +42,7 @@ class HighPressureGasTransport : public MultiTransport /*! * @param thermo Optional parameter for the pointer to the ThermoPhase object */ - HighPressureGasTransport(thermo_t* thermo=0); + HighPressureGasTransport(ThermoPhase* thermo=0); public: virtual std::string transportType() const { diff --git a/include/cantera/transport/IonGasTransport.h b/include/cantera/transport/IonGasTransport.h index e208002b09..3dd95f186f 100644 --- a/include/cantera/transport/IonGasTransport.h +++ b/include/cantera/transport/IonGasTransport.h @@ -55,7 +55,7 @@ class IonGasTransport : public MixTransport return "Ion"; } - virtual void init(thermo_t* thermo, int mode, int log_level); + virtual void init(ThermoPhase* thermo, int mode, int log_level); //! Viscosity of the mixture (kg/m/s). //! Only Neutral species contribute to Viscosity. diff --git a/include/cantera/transport/MixTransport.h b/include/cantera/transport/MixTransport.h index 63c7ae7b54..6991b380fc 100644 --- a/include/cantera/transport/MixTransport.h +++ b/include/cantera/transport/MixTransport.h @@ -149,15 +149,9 @@ class MixTransport : public GasTransport size_t ldx, const doublereal* const grad_X, size_t ldf, doublereal* const fluxes); - virtual void init(thermo_t* thermo, int mode=0, int log_level=0); + virtual void init(ThermoPhase* thermo, int mode=0, int log_level=0); protected: - //! Calculate the pressure from the ideal gas law - doublereal pressure_ig() const { - return (m_thermo->molarDensity() * GasConstant * - m_thermo->temperature()); - } - //! Update the temperature dependent parts of the species thermal //! conductivities /*! diff --git a/include/cantera/transport/MultiTransport.h b/include/cantera/transport/MultiTransport.h index 70962525ee..110dda1f22 100644 --- a/include/cantera/transport/MultiTransport.h +++ b/include/cantera/transport/MultiTransport.h @@ -30,7 +30,7 @@ class MultiTransport : public GasTransport /*! * @param thermo Optional parameter for the pointer to the ThermoPhase object */ - MultiTransport(thermo_t* thermo=0); + MultiTransport(ThermoPhase* thermo=0); virtual std::string transportType() const { return (m_mode == CK_Mode) ? "CK_Multi" : "Multi"; @@ -188,9 +188,7 @@ class MultiTransport : public GasTransport void eval_L0101(const doublereal* x); bool hasInternalModes(size_t j); - doublereal pressure_ig() { - return m_thermo->molarDensity() * GasConstant * m_thermo->temperature(); - } + double pressure_ig(); virtual void solveLMatrixEquation(); DenseMatrix incl; diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index 1726c2ea19..86dfc9e356 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -19,11 +19,15 @@ #ifndef CT_TRANSPORTBASE_H #define CT_TRANSPORTBASE_H -#include "cantera/thermo/ThermoPhase.h" +#include "cantera/base/ct_defs.h" +#include "cantera/base/ctexceptions.h" namespace Cantera { +class ThermoPhase; +class Solution; + /*! * \addtogroup tranprops */ @@ -142,7 +146,7 @@ class Transport * * @see TransportFactory */ - Transport(thermo_t* thermo=0, size_t ndim = 1); + Transport(ThermoPhase* thermo=0, size_t ndim = 1); virtual ~Transport() {} @@ -162,7 +166,7 @@ class Transport * gas mixture, a surface, etc. This method returns a reference to the * object representing the phase itself. */ - thermo_t& thermo() { + ThermoPhase& thermo() { return *m_thermo; } @@ -637,7 +641,7 @@ class Transport * specification of the collision integrals. defaults to no. * @param log_level Defaults to zero, no logging */ - virtual void init(thermo_t* thermo, int mode=0, int log_level=0) {} + virtual void init(ThermoPhase* thermo, int mode=0, int log_level=0) {} //! Specifies the ThermoPhase object. /*! @@ -652,12 +656,10 @@ class Transport * @param thermo Reference to the ThermoPhase object that the transport * object will use */ - virtual void setThermo(thermo_t& thermo); + virtual void setThermo(ThermoPhase& thermo); //! Set root Solution holding all phase information - virtual void setRoot(std::shared_ptr root) { - m_root = root; - } + virtual void setRoot(std::shared_ptr root); protected: //! Enable the transport object for use. @@ -671,7 +673,7 @@ class Transport //@} //! pointer to the object representing the phase - thermo_t* m_thermo; + ThermoPhase* m_thermo; //! true if finalize has been called bool m_ready; diff --git a/include/cantera/transport/TransportFactory.h b/include/cantera/transport/TransportFactory.h index da52cf471a..d0da84ca54 100644 --- a/include/cantera/transport/TransportFactory.h +++ b/include/cantera/transport/TransportFactory.h @@ -61,7 +61,7 @@ class TransportFactory : public Factory * @param thermo ThermoPhase object * @param log_level log level */ - virtual Transport* newTransport(const std::string& model, thermo_t* thermo, int log_level=0); + virtual Transport* newTransport(const std::string& model, ThermoPhase* thermo, int log_level=0); //! Build a new transport manager using the default transport manager //! in the phase description and return a base class pointer to it @@ -69,7 +69,7 @@ class TransportFactory : public Factory * @param thermo ThermoPhase object * @param log_level log level */ - virtual Transport* newTransport(thermo_t* thermo, int log_level=0); + virtual Transport* newTransport(ThermoPhase* thermo, int log_level=0); private: //! Static instance of the factor -> This is the only instance of this @@ -92,9 +92,9 @@ class TransportFactory : public Factory std::map m_CK_mode; }; -//! @copydoc TransportFactory::newTransport(const std::string&, thermo_t*, int, int) +//! @copydoc TransportFactory::newTransport(const std::string&, ThermoPhase*, int, int) Transport* newTransportMgr(const std::string& transportModel = "", - thermo_t* thermo = 0, int loglevel = 0); + ThermoPhase* thermo = 0, int loglevel = 0); //! Create a new transport manager instance. /*! @@ -103,7 +103,7 @@ Transport* newTransportMgr(const std::string& transportModel = "", * @returns a transport manager for the phase * @ingroup tranprops */ -Transport* newDefaultTransportMgr(thermo_t* thermo, int loglevel = 0); +Transport* newDefaultTransportMgr(ThermoPhase* thermo, int loglevel = 0); } // End of namespace Cantera diff --git a/include/cantera/transport/UnityLewisTransport.h b/include/cantera/transport/UnityLewisTransport.h index bd8c393666..605fcdd58c 100644 --- a/include/cantera/transport/UnityLewisTransport.h +++ b/include/cantera/transport/UnityLewisTransport.h @@ -13,6 +13,7 @@ #define CT_UNITYLEWISTRAN_H #include "MixTransport.h" +#include "cantera/thermo/ThermoPhase.h" namespace Cantera { diff --git a/include/cantera/transport/WaterTransport.h b/include/cantera/transport/WaterTransport.h index f72202e3d2..66da6e5108 100644 --- a/include/cantera/transport/WaterTransport.h +++ b/include/cantera/transport/WaterTransport.h @@ -26,7 +26,7 @@ class WaterTransport : public Transport * @param ndim Number of dimensions of the flux expressions. * Defaults to a value of one. */ - WaterTransport(thermo_t* thermo = 0, int ndim = 1); + WaterTransport(ThermoPhase* thermo = 0, int ndim = 1); virtual std::string transportType() const { return "Water"; @@ -69,7 +69,7 @@ class WaterTransport : public Transport */ virtual doublereal thermalConductivity(); - virtual void init(thermo_t* thermo, int mode=0, int log_level=0); + virtual void init(ThermoPhase* thermo, int mode=0, int log_level=0); }; } #endif diff --git a/include/cantera/zeroD/FlowDevice.h b/include/cantera/zeroD/FlowDevice.h index 17eec48420..3c61b3aeca 100644 --- a/include/cantera/zeroD/FlowDevice.h +++ b/include/cantera/zeroD/FlowDevice.h @@ -8,7 +8,6 @@ #include "cantera/base/ct_defs.h" #include "cantera/base/global.h" -#include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" namespace Cantera diff --git a/include/cantera/zeroD/FlowReactor.h b/include/cantera/zeroD/FlowReactor.h index 99b2216955..02666fc21d 100644 --- a/include/cantera/zeroD/FlowReactor.h +++ b/include/cantera/zeroD/FlowReactor.h @@ -34,14 +34,7 @@ class FlowReactor : public Reactor doublereal* ydot, doublereal* params); virtual void updateState(doublereal* y); - void setMassFlowRate(doublereal mdot) { - m_rho0 = m_thermo->density(); - m_speed = mdot/m_rho0; - m_speed0 = m_speed; - m_T = m_thermo->temperature(); - m_P0 = m_thermo->pressure() + m_rho0*m_speed*m_speed; - m_h0 = m_thermo->enthalpy_mass() + 0.5*m_speed*m_speed; - } + void setMassFlowRate(double mdot); void setTimeConstant(doublereal tau) { m_fctr = 1.0/tau; diff --git a/include/cantera/zeroD/Reactor.h b/include/cantera/zeroD/Reactor.h index 692563ea12..8f4b08a640 100644 --- a/include/cantera/zeroD/Reactor.h +++ b/include/cantera/zeroD/Reactor.h @@ -7,11 +7,12 @@ #define CT_REACTOR_H #include "ReactorBase.h" -#include "cantera/kinetics/Kinetics.h" namespace Cantera { +class Solution; + /** * Class Reactor is a general-purpose class for stirred reactors. The reactor * may have an arbitrary number of inlets and outlets, each of which may be @@ -59,10 +60,7 @@ class Reactor : public ReactorBase setKineticsMgr(contents); } - void insert(shared_ptr sol) { - setThermoMgr(*sol->thermo()); - setKineticsMgr(*sol->kinetics()); - } + void insert(shared_ptr sol); virtual void setKineticsMgr(Kinetics& kin); diff --git a/include/cantera/zeroD/ReactorBase.h b/include/cantera/zeroD/ReactorBase.h index 357ef57c7f..e80471e779 100644 --- a/include/cantera/zeroD/ReactorBase.h +++ b/include/cantera/zeroD/ReactorBase.h @@ -6,7 +6,8 @@ #ifndef CT_REACTORBASE_H #define CT_REACTORBASE_H -#include "cantera/thermo/ThermoPhase.h" +#include "cantera/base/global.h" +#include "cantera/base/ctexceptions.h" //! Namespace for classes implementing zero-dimensional reactor networks. namespace Cantera @@ -16,6 +17,7 @@ class WallBase; class ReactorNet; class ReactorSurface; class Kinetics; +class ThermoPhase; enum class SensParameterType { reaction, @@ -79,7 +81,7 @@ class ReactorBase //! Specify the mixture contained in the reactor. Note that a pointer to //! this substance is stored, and as the integration proceeds, the state of //! the substance is modified. - virtual void setThermoMgr(thermo_t& thermo); + virtual void setThermoMgr(ThermoPhase& thermo); //! Specify chemical kinetics governing the reactor. virtual void setKineticsMgr(Kinetics& kin) { @@ -154,12 +156,7 @@ class ReactorBase //! Set the state of the Phase object associated with this reactor to the //! reactor's current state. - void restoreState() { - if (!m_thermo) { - throw CanteraError("ReactorBase::restoreState", "No phase defined."); - } - m_thermo->restoreState(m_state); - } + void restoreState(); //! Set the state of the reactor to correspond to the state of the //! associated ThermoPhase object. This is the inverse of restoreState(). @@ -167,7 +164,7 @@ class ReactorBase virtual void syncState(); //! return a reference to the contents. - thermo_t& contents() { + ThermoPhase& contents() { if (!m_thermo) { throw CanteraError("ReactorBase::contents", "Reactor contents not defined."); @@ -175,7 +172,7 @@ class ReactorBase return *m_thermo; } - const thermo_t& contents() const { + const ThermoPhase& contents() const { if (!m_thermo) { throw CanteraError("ReactorBase::contents", "Reactor contents not defined."); @@ -251,7 +248,7 @@ class ReactorBase //! Number of homogeneous species in the mixture size_t m_nsp; - thermo_t* m_thermo; + ThermoPhase* m_thermo; doublereal m_vol; doublereal m_enthalpy; doublereal m_intEnergy; diff --git a/include/cantera/zeroD/ReactorNet.h b/include/cantera/zeroD/ReactorNet.h index af656e0731..2a8049d019 100644 --- a/include/cantera/zeroD/ReactorNet.h +++ b/include/cantera/zeroD/ReactorNet.h @@ -8,12 +8,13 @@ #include "Reactor.h" #include "cantera/numerics/FuncEval.h" -#include "cantera/numerics/Integrator.h" -#include "cantera/base/Array.h" namespace Cantera { +class Array2D; +class Integrator; + //! A class representing a network of connected reactors. /*! * This class is used to integrate the time-dependent governing equations for @@ -24,7 +25,7 @@ class ReactorNet : public FuncEval { public: ReactorNet(); - virtual ~ReactorNet() {}; + virtual ~ReactorNet(); ReactorNet(const ReactorNet&) = delete; ReactorNet& operator=(const ReactorNet&) = delete; @@ -234,16 +235,12 @@ class ReactorNet : public FuncEval //! integrator will take before reaching the next output time //! @param nmax The maximum number of steps, setting this value //! to zero disables this option. - virtual void setMaxSteps(int nmax) { - m_integ->setMaxSteps(nmax); - } + virtual void setMaxSteps(int nmax); //! Returns the maximum number of internal integration time-steps the //! integrator will take before reaching the next output time //! - virtual int maxSteps() { - return m_integ->maxSteps(); - } + virtual int maxSteps(); //! Set absolute step size limits during advance void setAdvanceLimits(const double* limits); @@ -264,9 +261,7 @@ class ReactorNet : public FuncEval //! Returns the order used for last solution step of the ODE integrator //! The function is intended for internal use by ReactorNet::advance //! and deliberately not exposed in external interfaces. - virtual int lastOrder() { - return m_integ->lastOrder(); - } + virtual int lastOrder(); std::vector m_reactors; std::unique_ptr m_integ; diff --git a/include/cantera/zeroD/Reservoir.h b/include/cantera/zeroD/Reservoir.h index c60543becf..67343145ad 100644 --- a/include/cantera/zeroD/Reservoir.h +++ b/include/cantera/zeroD/Reservoir.h @@ -7,6 +7,7 @@ #define CT_RESERVOIR_H #include "ReactorBase.h" +#include "cantera/base/Solution.h" namespace Cantera { diff --git a/platform/posix/SConscript b/platform/posix/SConscript index 3ad644cb38..7796574c13 100644 --- a/platform/posix/SConscript +++ b/platform/posix/SConscript @@ -34,7 +34,7 @@ pc_libdirs = [] pc_incdirs = [] pc_cflags = list(localenv['CXXFLAGS']) -localenv['mak_corelibs'] = '-lcantera' +localenv['mak_corelibs'] = ' '.join('-l' + lib for lib in localenv['cantera_libs']) localenv['mak_extra_includes'] = ' '.join('-I%s' % s for s in localenv['extra_inc_dirs']) pc_incdirs.extend(localenv['extra_inc_dirs']) diff --git a/samples/cxx/demo/demo.cpp b/samples/cxx/demo/demo.cpp index 2f68d2f48f..c477b867ea 100644 --- a/samples/cxx/demo/demo.cpp +++ b/samples/cxx/demo/demo.cpp @@ -12,9 +12,10 @@ // to include core headers directly, use the format "cantera/module/*.h". #include "cantera/thermo/IdealGasPhase.h" // defines class IdealGasPhase +#include "cantera/base/Solution.h" #include "cantera/kinetics/GasKinetics.h" #include "cantera/transport.h" // transport properties -#include +#include // All Cantera kernel names are in namespace Cantera. You can either // reference everything as Cantera::, or include the following diff --git a/samples/cxx/flamespeed/flamespeed.cpp b/samples/cxx/flamespeed/flamespeed.cpp index 6082aba129..16af69e704 100644 --- a/samples/cxx/flamespeed/flamespeed.cpp +++ b/samples/cxx/flamespeed/flamespeed.cpp @@ -9,6 +9,8 @@ #include "cantera/oneD/StFlow.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/transport.h" +#include "cantera/base/Solution.h" +#include "cantera/base/stringUtils.h" #include using namespace Cantera; diff --git a/samples/cxx/gas_transport/gas_transport.cpp b/samples/cxx/gas_transport/gas_transport.cpp index 92d8e85cc4..855934fb7b 100644 --- a/samples/cxx/gas_transport/gas_transport.cpp +++ b/samples/cxx/gas_transport/gas_transport.cpp @@ -9,6 +9,7 @@ #include "cantera/thermo.h" #include "cantera/transport.h" +#include "cantera/base/Solution.h" #include "cantera/base/Array.h" #include "cantera/base/plots.h" diff --git a/samples/cxx/kinetics1/kinetics1.cpp b/samples/cxx/kinetics1/kinetics1.cpp index edb0ebfad9..7e0f18931f 100644 --- a/samples/cxx/kinetics1/kinetics1.cpp +++ b/samples/cxx/kinetics1/kinetics1.cpp @@ -9,6 +9,7 @@ #include "cantera/zerodim.h" #include "cantera/thermo/IdealGasPhase.h" +#include "cantera/numerics/Integrator.h" #include "example_utils.h" using namespace Cantera; diff --git a/samples/cxx/rankine/rankine.cpp b/samples/cxx/rankine/rankine.cpp index 51601470c8..cde3c74e71 100644 --- a/samples/cxx/rankine/rankine.cpp +++ b/samples/cxx/rankine/rankine.cpp @@ -1,6 +1,7 @@ // An open Rankine cycle #include "cantera/thermo/PureFluidPhase.h" +#include "cantera/base/global.h" using namespace Cantera; diff --git a/samples/f77/demo_ftnlib.cpp b/samples/f77/demo_ftnlib.cpp index 8e050d0122..3fc09ac680 100644 --- a/samples/f77/demo_ftnlib.cpp +++ b/samples/f77/demo_ftnlib.cpp @@ -29,6 +29,7 @@ // add any other Cantera header files you need here #include "cantera/thermo/IdealGasPhase.h" #include "cantera/kinetics/GasKinetics.h" +#include "cantera/base/Solution.h" #include "cantera/transport.h" #include diff --git a/src/base/AnyMap.cpp b/src/base/AnyMap.cpp index 541763e979..241528c302 100644 --- a/src/base/AnyMap.cpp +++ b/src/base/AnyMap.cpp @@ -7,6 +7,7 @@ #include "application.h" #include "cantera/base/yaml.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/global.h" #ifdef CT_USE_DEMANGLE #include #endif diff --git a/src/base/Array.cpp b/src/base/Array.cpp new file mode 100644 index 0000000000..831b988967 --- /dev/null +++ b/src/base/Array.cpp @@ -0,0 +1,125 @@ +/** + * @file Array.cpp Implementation file for class Cantera::Array2D + */ + +// This file is part of Cantera. See License.txt in the top-level directory or +// at https://cantera.org/license.txt for license and copyright information. + +#include "cantera/base/Array.h" +#include "cantera/base/utilities.h" + +namespace Cantera +{ + +Array2D::Array2D() + : m_nrows(0) + , m_ncols(0) +{ +} + +Array2D::Array2D(const size_t m, const size_t n, const double v) + : m_nrows(m) + , m_ncols(n) +{ + m_data.assign(n*m, v); +} + +Array2D::Array2D(const size_t m, const size_t n, const double* values) + : m_nrows(m) + , m_ncols(n) +{ + m_data.assign(values, values + n*m); +} + +Array2D::Array2D(const Array2D& y) + : m_data(y.m_data) + , m_nrows(y.m_nrows) + , m_ncols(y.m_ncols) +{ +} + +Array2D& Array2D::operator=(const Array2D& y) +{ + if (&y == this) { + return *this; + } + m_nrows = y.m_nrows; + m_ncols = y.m_ncols; + m_data = y.m_data; + return *this; +} + +void Array2D::resize(size_t n, size_t m, double v) +{ + m_nrows = n; + m_ncols = m; + m_data.resize(n*m, v); +} + +void Array2D::appendColumn(const vector_fp& c) +{ + m_ncols++; + m_data.resize(m_nrows * m_ncols); + for (size_t m = 0; m < m_nrows; m++) { + value(m_ncols, m) = c[m]; + } +} + +void Array2D::appendColumn(const double* const c) +{ + m_ncols++; + m_data.resize(m_nrows * m_ncols); + for (size_t m = 0; m < m_nrows; m++) { + value(m_ncols, m) = c[m]; + } +} + +void Array2D::setRow(size_t n, const double* const rw) +{ + for (size_t j = 0; j < m_ncols; j++) { + m_data[m_nrows*j + n] = rw[j]; + } +} + +void Array2D::getRow(size_t n, double* const rw) +{ + for (size_t j = 0; j < m_ncols; j++) { + rw[j] = m_data[m_nrows*j + n]; + } +} + +void Array2D::setColumn(size_t m, double* const col) +{ + for (size_t i = 0; i < m_nrows; i++) { + m_data[m_nrows*m + i] = col[i]; + } +} + +void Array2D::getColumn(size_t m, double* const col) +{ + for (size_t i = 0; i < m_nrows; i++) { + col[i] = m_data[m_nrows*m + i]; + } +} + + +std::ostream& operator<<(std::ostream& s, const Array2D& m) +{ + size_t nr = m.nRows(); + size_t nc = m.nColumns(); + for (size_t i = 0; i < nr; i++) { + s << m(i,0); + for (size_t j = 1; j < nc; j++) { + s << ", " << m(i,j); + } + s << std::endl; + } + return s; +} + +void operator*=(Array2D& m, double a) +{ + scale(m.begin(), m.end(), m.begin(), a); +} + +} diff --git a/src/base/ct2ctml.cpp b/src/base/ct2ctml.cpp index 262a2700fc..0ff97682e3 100644 --- a/src/base/ct2ctml.cpp +++ b/src/base/ct2ctml.cpp @@ -9,6 +9,8 @@ #include "cantera/base/ctml.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/ctexceptions.h" +#include "cantera/base/global.h" #include "../../ext/libexecstream/exec-stream.h" #include diff --git a/src/base/ctml.cpp b/src/base/ctml.cpp index 0d6a33a08c..e7940034c9 100644 --- a/src/base/ctml.cpp +++ b/src/base/ctml.cpp @@ -9,6 +9,8 @@ #include "cantera/base/ctml.h" #include "cantera/base/stringUtils.h" #include "cantera/base/Array.h" +#include "cantera/base/ctexceptions.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/base/stringUtils.cpp b/src/base/stringUtils.cpp index 2a2cfdf30b..6fde1a3156 100644 --- a/src/base/stringUtils.cpp +++ b/src/base/stringUtils.cpp @@ -19,12 +19,11 @@ #include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" -#include "cantera/base/ctml.h" #include "cantera/base/utilities.h" +#include "cantera/base/global.h" #include #include -#include namespace ba = boost::algorithm; diff --git a/src/base/xml.cpp b/src/base/xml.cpp index ef39468453..67b27dea4f 100644 --- a/src/base/xml.cpp +++ b/src/base/xml.cpp @@ -12,6 +12,7 @@ #include "cantera/base/stringUtils.h" #include "cantera/base/global.h" #include "cantera/base/utilities.h" +#include "cantera/base/ctexceptions.h" #include #include diff --git a/src/clib/Cabinet.h b/src/clib/Cabinet.h index 449b381936..77a6eebf53 100644 --- a/src/clib/Cabinet.h +++ b/src/clib/Cabinet.h @@ -8,9 +8,7 @@ #ifndef CT_CABINET_H #define CT_CABINET_H -#include "cantera/base/stringUtils.h" #include "cantera/base/ctexceptions.h" -#include "cantera/base/global.h" #include "clib_utils.h" /** diff --git a/src/clib/clib_utils.h b/src/clib/clib_utils.h index ed9fa1b083..60c8f25e93 100644 --- a/src/clib/clib_utils.h +++ b/src/clib/clib_utils.h @@ -8,7 +8,6 @@ #ifndef CT_CLIB_UTILS_H #define CT_CLIB_UTILS_H -#include "cantera/base/global.h" #include "cantera/base/ctexceptions.h" #include "../base/application.h" #include "cantera/clib/clib_defs.h" diff --git a/src/clib/ct.cpp b/src/clib/ct.cpp index a9c40a2cb2..35985f8bc5 100644 --- a/src/clib/ct.cpp +++ b/src/clib/ct.cpp @@ -18,6 +18,7 @@ #include "cantera/kinetics/KineticsFactory.h" #include "cantera/transport/TransportFactory.h" #include "cantera/base/ctml.h" +#include "cantera/base/stringUtils.h" #include "cantera/kinetics/importKinetics.h" #include "cantera/thermo/ThermoFactory.h" #include "Cabinet.h" @@ -367,7 +368,7 @@ extern "C" { { try { XML_Node& x = XmlCabinet::item(mxml); - thermo_t* th = newPhase(x); + ThermoPhase* th = newPhase(x); return ThermoCabinet::add(th); } catch (...) { return handleAllExceptions(-1, ERR); @@ -881,7 +882,7 @@ extern "C" { int neighbor3, int neighbor4) { try { - vector phases; + vector phases; phases.push_back(&ThermoCabinet::item(reactingPhase)); if (neighbor1 >= 0) { phases.push_back(&ThermoCabinet::item(neighbor1)); @@ -908,7 +909,7 @@ extern "C" { { try { XML_Node& x = XmlCabinet::item(mxml); - vector phases; + vector phases; phases.push_back(&ThermoCabinet::item(iphase)); if (neighbor1 >= 0) { phases.push_back(&ThermoCabinet::item(neighbor1)); diff --git a/src/clib/ctfunc.cpp b/src/clib/ctfunc.cpp index d22df4224e..c64a8a7a48 100644 --- a/src/clib/ctfunc.cpp +++ b/src/clib/ctfunc.cpp @@ -9,7 +9,9 @@ #include "cantera/clib/ctfunc.h" #include "cantera/numerics/Func1.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/base/ctexceptions.h" +#include "cantera/base/stringUtils.h" #include "Cabinet.h" diff --git a/src/clib/ctmultiphase.cpp b/src/clib/ctmultiphase.cpp index 0cb91c5aaa..293591dd94 100644 --- a/src/clib/ctmultiphase.cpp +++ b/src/clib/ctmultiphase.cpp @@ -10,6 +10,7 @@ // Cantera includes #include "cantera/equil/MultiPhase.h" +#include "cantera/thermo/ThermoPhase.h" #include "Cabinet.h" using namespace std; diff --git a/src/clib/ctonedim.cpp b/src/clib/ctonedim.cpp index 52b9c31c84..f0644ca689 100644 --- a/src/clib/ctonedim.cpp +++ b/src/clib/ctonedim.cpp @@ -14,6 +14,7 @@ #include "cantera/oneD/Boundary1D.h" #include "cantera/transport/TransportBase.h" #include "Cabinet.h" +#include "cantera/base/stringUtils.h" #include diff --git a/src/clib/ctreactor.cpp b/src/clib/ctreactor.cpp index 6b959327ae..3bc9d47d6b 100644 --- a/src/clib/ctreactor.cpp +++ b/src/clib/ctreactor.cpp @@ -10,6 +10,8 @@ // Cantera includes #include "cantera/numerics/Func1.h" +#include "cantera/thermo/ThermoPhase.h" +#include "cantera/kinetics/Kinetics.h" #include "cantera/zerodim.h" #include "Cabinet.h" diff --git a/src/clib/ctxml.cpp b/src/clib/ctxml.cpp index 1595bffe8d..8fb24545b2 100644 --- a/src/clib/ctxml.cpp +++ b/src/clib/ctxml.cpp @@ -11,6 +11,8 @@ // Cantera includes #include "cantera/base/ctml.h" #include "Cabinet.h" +#include "cantera/base/global.h" +#include "cantera/base/stringUtils.h" #include #include diff --git a/src/equil/BasisOptimize.cpp b/src/equil/BasisOptimize.cpp index 1a9a61b803..ea87681da5 100644 --- a/src/equil/BasisOptimize.cpp +++ b/src/equil/BasisOptimize.cpp @@ -7,6 +7,8 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/equil/MultiPhase.h" +#include "cantera/base/utilities.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/equil/ChemEquil.cpp b/src/equil/ChemEquil.cpp index c6a919bfc3..973a8a58e8 100644 --- a/src/equil/ChemEquil.cpp +++ b/src/equil/ChemEquil.cpp @@ -10,11 +10,12 @@ #include "cantera/equil/ChemEquil.h" #include "cantera/base/stringUtils.h" #include "cantera/equil/MultiPhaseEquil.h" +#include "cantera/thermo/ThermoPhase.h" +#include "cantera/base/utilities.h" +#include "cantera/base/global.h" using namespace std; -#include - namespace Cantera { @@ -47,7 +48,7 @@ ChemEquil::ChemEquil() : m_skip(npos), m_elementTotalSum(1.0), m_doResPerturb(false) {} -ChemEquil::ChemEquil(thermo_t& s) : +ChemEquil::ChemEquil(ThermoPhase& s) : m_skip(npos), m_elementTotalSum(1.0), m_p0(OneAtm), m_eloc(npos), @@ -61,7 +62,7 @@ ChemEquil::~ChemEquil() { } -void ChemEquil::initialize(thermo_t& s) +void ChemEquil::initialize(ThermoPhase& s) { // store a pointer to s and some of its properties locally. m_phase = &s; @@ -129,7 +130,7 @@ void ChemEquil::initialize(thermo_t& s) } } -void ChemEquil::setToEquilState(thermo_t& s, +void ChemEquil::setToEquilState(ThermoPhase& s, const vector_fp& lambda_RT, doublereal t) { // Construct the chemical potentials by summing element potentials @@ -150,7 +151,7 @@ void ChemEquil::setToEquilState(thermo_t& s, update(s); } -void ChemEquil::update(const thermo_t& s) +void ChemEquil::update(const ThermoPhase& s) { // get the mole fractions, temperature, and density s.getMoleFractions(m_molefractions.data()); @@ -179,7 +180,7 @@ void ChemEquil::update(const thermo_t& s) } } -int ChemEquil::setInitialMoles(thermo_t& s, vector_fp& elMoleGoal, +int ChemEquil::setInitialMoles(ThermoPhase& s, vector_fp& elMoleGoal, int loglevel) { MultiPhase mp; @@ -215,7 +216,7 @@ int ChemEquil::setInitialMoles(thermo_t& s, vector_fp& elMoleGoal, return 0; } -int ChemEquil::estimateElementPotentials(thermo_t& s, vector_fp& lambda_RT, +int ChemEquil::estimateElementPotentials(ThermoPhase& s, vector_fp& lambda_RT, vector_fp& elMolesGoal, int loglevel) { vector_fp b(m_mm, -999.0); @@ -305,7 +306,7 @@ int ChemEquil::estimateElementPotentials(thermo_t& s, vector_fp& lambda_RT, return info; } -int ChemEquil::equilibrate(thermo_t& s, const char* XY, int loglevel) +int ChemEquil::equilibrate(ThermoPhase& s, const char* XY, int loglevel) { initialize(s); update(s); @@ -313,7 +314,7 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XY, int loglevel) return equilibrate(s, XY, elMolesGoal, loglevel-1); } -int ChemEquil::equilibrate(thermo_t& s, const char* XYstr, +int ChemEquil::equilibrate(ThermoPhase& s, const char* XYstr, vector_fp& elMolesGoal, int loglevel) { int fail = 0; @@ -686,7 +687,7 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr, } -int ChemEquil::dampStep(thermo_t& mix, vector_fp& oldx, +int ChemEquil::dampStep(ThermoPhase& mix, vector_fp& oldx, double oldf, vector_fp& grad, vector_fp& step, vector_fp& x, double& f, vector_fp& elmols, double xval, double yval) { @@ -725,7 +726,7 @@ int ChemEquil::dampStep(thermo_t& mix, vector_fp& oldx, return 1; } -void ChemEquil::equilResidual(thermo_t& s, const vector_fp& x, +void ChemEquil::equilResidual(ThermoPhase& s, const vector_fp& x, const vector_fp& elmFracGoal, vector_fp& resid, doublereal xval, doublereal yval, int loglevel) { @@ -771,7 +772,7 @@ void ChemEquil::equilResidual(thermo_t& s, const vector_fp& x, } } -void ChemEquil::equilJacobian(thermo_t& s, vector_fp& x, +void ChemEquil::equilJacobian(ThermoPhase& s, vector_fp& x, const vector_fp& elmols, DenseMatrix& jac, doublereal xval, doublereal yval, int loglevel) { @@ -804,7 +805,7 @@ void ChemEquil::equilJacobian(thermo_t& s, vector_fp& x, m_doResPerturb = false; } -double ChemEquil::calcEmoles(thermo_t& s, vector_fp& x, const double& n_t, +double ChemEquil::calcEmoles(ThermoPhase& s, vector_fp& x, const double& n_t, const vector_fp& Xmol_i_calc, vector_fp& eMolesCalc, vector_fp& n_i_calc, double pressureConst) @@ -840,7 +841,7 @@ double ChemEquil::calcEmoles(thermo_t& s, vector_fp& x, const double& n_t, return n_t_calc; } -int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x, +int ChemEquil::estimateEP_Brinkley(ThermoPhase& s, vector_fp& x, vector_fp& elMoles) { // Before we do anything, we will save the state of the solution. Then, if @@ -1311,7 +1312,7 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x, } -void ChemEquil::adjustEloc(thermo_t& s, vector_fp& elMolesGoal) +void ChemEquil::adjustEloc(ThermoPhase& s, vector_fp& elMolesGoal) { if (m_eloc == npos) { return; diff --git a/src/equil/MultiPhase.cpp b/src/equil/MultiPhase.cpp index cf31d37488..5c7653ee6b 100644 --- a/src/equil/MultiPhase.cpp +++ b/src/equil/MultiPhase.cpp @@ -11,7 +11,9 @@ #include "cantera/equil/MultiPhase.h" #include "cantera/equil/MultiPhaseEquil.h" #include "cantera/equil/vcs_MultiPhaseEquil.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/utilities.h" using namespace std; @@ -834,4 +836,21 @@ void MultiPhase::updatePhases() const } } } + +std::ostream& operator<<(std::ostream& s, MultiPhase& x) +{ + x.updatePhases(); + for (size_t ip = 0; ip < x.nPhases(); ip++) { + if (x.phase(ip).name() != "") { + s << "*************** " << x.phase(ip).name() << " *****************" << std::endl; + } else { + s << "*************** Phase " << ip << " *****************" << std::endl; + } + s << "Moles: " << x.phaseMoles(ip) << std::endl; + + s << x.phase(ip).report() << std::endl; + } + return s; +} + } diff --git a/src/equil/MultiPhaseEquil.cpp b/src/equil/MultiPhaseEquil.cpp index 7cb869cbe5..0c4efb2962 100644 --- a/src/equil/MultiPhaseEquil.cpp +++ b/src/equil/MultiPhaseEquil.cpp @@ -10,6 +10,7 @@ #include "cantera/base/stringUtils.h" #include +#include using namespace std; diff --git a/src/equil/vcs_Gibbs.cpp b/src/equil/vcs_Gibbs.cpp deleted file mode 100644 index d027c173e4..0000000000 --- a/src/equil/vcs_Gibbs.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file vcs_Gibbs.cpp - * Functions which calculate the extrinsic Gibbs Free energies - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" - -namespace Cantera -{ -double VCS_SOLVE::vcs_Total_Gibbs(double* molesSp, double* chemPot, - double* tPhMoles) -{ - double g = 0.0; - - for (size_t iph = 0; iph < m_numPhases; iph++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); - if ((TPhInertMoles[iph] > 0.0) && (tPhMoles[iph] > 0.0)) { - g += TPhInertMoles[iph] * - log(TPhInertMoles[iph] / tPhMoles[iph]); - if (Vphase->m_gasPhase) { - g += TPhInertMoles[iph] * log(m_pressurePA/(1.01325E5)); - } - } - } - - for (size_t kspec = 0; kspec < m_numSpeciesRdc; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - g += molesSp[kspec] * chemPot[kspec]; - } - } - - return g; -} - -double VCS_SOLVE::vcs_GibbsPhase(size_t iphase, const double* const w, - const double* const fe) -{ - double g = 0.0; - double phaseMols = 0.0; - for (size_t kspec = 0; kspec < m_numSpeciesRdc; ++kspec) { - if (m_phaseID[kspec] == iphase && m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - g += w[kspec] * fe[kspec]; - phaseMols += w[kspec]; - } - } - - if (TPhInertMoles[iphase] > 0.0) { - phaseMols += TPhInertMoles[iphase]; - g += TPhInertMoles[iphase] * log(TPhInertMoles[iphase] / phaseMols); - vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); - if (Vphase->m_gasPhase) { - g += TPhInertMoles[iphase] * log(m_pressurePA/1.01325E5); - } - } - - return g; -} - -} diff --git a/src/equil/vcs_SpeciesProperties.cpp b/src/equil/vcs_SpeciesProperties.cpp deleted file mode 100644 index 2842324ac3..0000000000 --- a/src/equil/vcs_SpeciesProperties.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file vcs_SpeciesProperties.cpp - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_SpeciesProperties.h" - -using namespace std; - -namespace Cantera -{ - -vcs_SpeciesProperties::vcs_SpeciesProperties(size_t indexPhase, - size_t indexSpeciesPhase, - vcs_VolPhase* owning) : - IndexPhase(indexPhase), - IndexSpeciesPhase(indexSpeciesPhase), - OwningPhase(owning), - SpeciesThermo(0), - WtSpecies(0.0), - Charge(0.0), - SurfaceSpecies(0), - VolPM(0.0), - ReferenceMoleFraction(1.0E-6) -{ -} - -} diff --git a/src/equil/vcs_TP.cpp b/src/equil/vcs_TP.cpp deleted file mode 100644 index d26cb62f7f..0000000000 --- a/src/equil/vcs_TP.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//! @file vcs_TP.cpp - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" - -namespace Cantera -{ -int VCS_SOLVE::vcs_TP(int ipr, int ip1, int maxit, double T_arg, double pres_arg) -{ - // Store the temperature and pressure in the private global variables - m_temperature = T_arg; - m_pressurePA = pres_arg; - m_Faraday_dim = Faraday / (m_temperature * GasConstant); - - // Evaluate the standard state free energies - // at the current temperatures and pressures. - int iconv = vcs_evalSS_TP(ipr, ip1, m_temperature, pres_arg); - - // Prep the fe field - vcs_fePrep_TP(); - - // Decide whether we need an initial estimate of the solution If so, go get - // one. If not, then - if (m_doEstimateEquil) { - int retn = vcs_inest_TP(); - if (retn != VCS_SUCCESS) { - plogf("vcs_inest_TP returned a failure flag\n"); - } - } - - // Solve the problem at a fixed Temperature and Pressure (all information - // concerning Temperature and Pressure has already been derived. The free - // energies are now in dimensionless form.) - iconv = vcs_solve_TP(ipr, ip1, maxit); - - // Return the convergence success flag. - return iconv; -} - -int VCS_SOLVE::vcs_evalSS_TP(int ipr, int ip1, double Temp, double pres) -{ - for (size_t iph = 0; iph < m_numPhases; iph++) { - vcs_VolPhase* vph = m_VolPhaseList[iph].get(); - vph->setState_TP(m_temperature, m_pressurePA); - vph->sendToVCS_GStar(&m_SSfeSpecies[0]); - } - for (size_t k = 0; k < m_nsp; k++) { - m_SSfeSpecies[k] /= GasConstant * m_temperature; - } - - return VCS_SUCCESS; -} - -void VCS_SOLVE::vcs_fePrep_TP() -{ - for (size_t i = 0; i < m_nsp; ++i) { - // For single species phases, initialize the chemical potential with the - // value of the standard state chemical potential. This value doesn't - // change during the calculation - if (m_SSPhase[i]) { - m_feSpecies_old[i] = m_SSfeSpecies[i]; - m_feSpecies_new[i] = m_SSfeSpecies[i]; - } - } -} - -} diff --git a/src/equil/vcs_elem.cpp b/src/equil/vcs_elem.cpp deleted file mode 100644 index dd6278be0b..0000000000 --- a/src/equil/vcs_elem.cpp +++ /dev/null @@ -1,439 +0,0 @@ -/** - * @file vcs_elem.cpp - * This file contains the algorithm for checking the satisfaction of the - * element abundances constraints and the algorithm for fixing violations - * of the element abundances constraints. - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/base/ctexceptions.h" -#include "cantera/numerics/DenseMatrix.h" - -namespace Cantera -{ -void VCS_SOLVE::vcs_elab() -{ - for (size_t j = 0; j < m_nelem; ++j) { - m_elemAbundances[j] = 0.0; - for (size_t i = 0; i < m_nsp; ++i) { - if (m_speciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - m_elemAbundances[j] += m_formulaMatrix(i,j) * m_molNumSpecies_old[i]; - } - } - } -} - -bool VCS_SOLVE::vcs_elabcheck(int ibound) -{ - size_t top = m_numComponents; - if (ibound) { - top = m_nelem; - } - - for (size_t i = 0; i < top; ++i) { - // Require 12 digits of accuracy on non-zero constraints. - if (m_elementActive[i] && fabs(m_elemAbundances[i] - m_elemAbundancesGoal[i]) > fabs(m_elemAbundancesGoal[i]) * 1.0e-12) { - // This logic is for charge neutrality condition - if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY && - m_elemAbundancesGoal[i] != 0.0) { - throw CanteraError("VCS_SOLVE::vcs_elabcheck", - "Problem with charge neutrality condition"); - } - if (m_elemAbundancesGoal[i] == 0.0 || (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE)) { - double scale = VCS_DELETE_MINORSPECIES_CUTOFF; - - // Find out if the constraint is a multisign constraint. If it - // is, then we have to worry about roundoff error in the - // addition of terms. We are limited to 13 digits of finite - // arithmetic accuracy. - bool multisign = false; - for (size_t kspec = 0; kspec < m_nsp; kspec++) { - double eval = m_formulaMatrix(kspec,i); - if (eval < 0.0) { - multisign = true; - } - if (eval != 0.0) { - scale = std::max(scale, fabs(eval * m_molNumSpecies_old[kspec])); - } - } - if (multisign) { - if (fabs(m_elemAbundances[i] - m_elemAbundancesGoal[i]) > 1e-11 * scale) { - return false; - } - } else { - if (fabs(m_elemAbundances[i] - m_elemAbundancesGoal[i]) > VCS_DELETE_MINORSPECIES_CUTOFF) { - return false; - } - } - } else { - // For normal element balances, we require absolute compliance - // even for ridiculously small numbers. - if (m_elType[i] == VCS_ELEM_TYPE_ABSPOS) { - return false; - } else { - return false; - } - } - } - } - return true; -} - -void VCS_SOLVE::vcs_elabPhase(size_t iphase, double* const elemAbundPhase) -{ - for (size_t j = 0; j < m_nelem; ++j) { - elemAbundPhase[j] = 0.0; - for (size_t i = 0; i < m_nsp; ++i) { - if (m_speciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE && m_phaseID[i] == iphase) { - elemAbundPhase[j] += m_formulaMatrix(i,j) * m_molNumSpecies_old[i]; - } - } - } -} - -int VCS_SOLVE::vcs_elcorr(double aa[], double x[]) -{ - int retn = 0; - - vector_fp ga_save(m_elemAbundances); - if (m_debug_print_lvl >= 2) { - plogf(" --- vcsc_elcorr: Element abundances correction routine"); - if (m_nelem != m_numComponents) { - plogf(" (m_numComponents != m_nelem)"); - } - plogf("\n"); - } - - for (size_t i = 0; i < m_nelem; ++i) { - x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i]; - } - double l2before = 0.0; - for (size_t i = 0; i < m_nelem; ++i) { - l2before += x[i] * x[i]; - } - l2before = sqrt(l2before/m_nelem); - - // Special section to take out single species, single component, - // moles. These are species which have non-zero entries in the - // formula matrix, and no other species have zero values either. - bool changed = false; - for (size_t i = 0; i < m_nelem; ++i) { - int numNonZero = 0; - bool multisign = false; - for (size_t kspec = 0; kspec < m_nsp; kspec++) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - double eval = m_formulaMatrix(kspec,i); - if (eval < 0.0) { - multisign = true; - } - if (eval != 0.0) { - numNonZero++; - } - } - } - if (!multisign) { - if (numNonZero < 2) { - for (size_t kspec = 0; kspec < m_nsp; kspec++) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - double eval = m_formulaMatrix(kspec,i); - if (eval > 0.0) { - m_molNumSpecies_old[kspec] = m_elemAbundancesGoal[i] / eval; - changed = true; - } - } - } - } else { - int numCompNonZero = 0; - size_t compID = npos; - for (size_t kspec = 0; kspec < m_numComponents; kspec++) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - double eval = m_formulaMatrix(kspec,i); - if (eval > 0.0) { - compID = kspec; - numCompNonZero++; - } - } - } - if (numCompNonZero == 1) { - double diff = m_elemAbundancesGoal[i]; - for (size_t kspec = m_numComponents; kspec < m_nsp; kspec++) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - double eval = m_formulaMatrix(kspec,i); - diff -= eval * m_molNumSpecies_old[kspec]; - } - m_molNumSpecies_old[compID] = std::max(0.0,diff/m_formulaMatrix(compID,i)); - changed = true; - } - } - } - } - } - if (changed) { - vcs_elab(); - } - - // Section to check for maximum bounds errors on all species due to - // elements. This may only be tried on element types which are - // VCS_ELEM_TYPE_ABSPOS. This is because no other species may have a - // negative number of these. - // - // Note, also we can do this over ne, the number of elements, not just the - // number of components. - changed = false; - for (size_t i = 0; i < m_nelem; ++i) { - int elType = m_elType[i]; - if (elType == VCS_ELEM_TYPE_ABSPOS) { - for (size_t kspec = 0; kspec < m_nsp; kspec++) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - double atomComp = m_formulaMatrix(kspec,i); - if (atomComp > 0.0) { - double maxPermissible = m_elemAbundancesGoal[i] / atomComp; - if (m_molNumSpecies_old[kspec] > maxPermissible) { - if (m_debug_print_lvl >= 3) { - plogf(" --- vcs_elcorr: Reduced species %s from %g to %g " - "due to %s max bounds constraint\n", - m_speciesName[kspec], m_molNumSpecies_old[kspec], - maxPermissible, m_elementName[i]); - } - m_molNumSpecies_old[kspec] = maxPermissible; - changed = true; - if (m_molNumSpecies_old[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF) { - m_molNumSpecies_old[kspec] = 0.0; - if (m_SSPhase[kspec]) { - m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS; - } else { - m_speciesStatus[kspec] = VCS_SPECIES_ACTIVEBUTZERO; - } - if (m_debug_print_lvl >= 2) { - plogf(" --- vcs_elcorr: Zeroed species %s and changed " - "status to %d due to max bounds constraint\n", - m_speciesName[kspec], m_speciesStatus[kspec]); - } - } - } - } - } - } - } - } - - // Recalculate the element abundances if something has changed. - if (changed) { - vcs_elab(); - } - - // Ok, do the general case. Linear algebra problem is of length nc, not ne, - // as there may be degenerate rows when nc .ne. ne. - DenseMatrix A(m_numComponents, m_numComponents); - for (size_t i = 0; i < m_numComponents; ++i) { - x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i]; - if (fabs(x[i]) > 1.0E-13) { - retn = 1; - } - for (size_t j = 0; j < m_numComponents; ++j) { - A(j, i) = - m_formulaMatrix(i,j); - } - } - - solve(A, x, 1, m_nelem); - - // Now apply the new direction without creating negative species. - double par = 0.5; - for (size_t i = 0; i < m_numComponents; ++i) { - if (m_molNumSpecies_old[i] > 0.0) { - par = std::max(par, -x[i] / m_molNumSpecies_old[i]); - } - } - par = std::min(par, 100.0); - par = 1.0 / par; - if (par < 1.0 && par > 0.0) { - retn = 2; - par *= 0.9999; - for (size_t i = 0; i < m_numComponents; ++i) { - double tmp = m_molNumSpecies_old[i] + par * x[i]; - if (tmp > 0.0) { - m_molNumSpecies_old[i] = tmp; - } else { - if (m_SSPhase[i]) { - m_molNumSpecies_old[i] = 0.0; - } else { - m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001; - } - } - } - } else { - for (size_t i = 0; i < m_numComponents; ++i) { - double tmp = m_molNumSpecies_old[i] + x[i]; - if (tmp > 0.0) { - m_molNumSpecies_old[i] = tmp; - } else { - if (m_SSPhase[i]) { - m_molNumSpecies_old[i] = 0.0; - } else { - m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001; - } - } - } - } - - // We have changed the element abundances. Calculate them again - vcs_elab(); - - // We have changed the total moles in each phase. Calculate them again - vcs_tmoles(); - - // Try some ad hoc procedures for fixing the problem - if (retn >= 2) { - // First find a species whose adjustment is a win-win situation. - for (size_t kspec = 0; kspec < m_nsp; kspec++) { - if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - continue; - } - double saveDir = 0.0; - bool goodSpec = true; - for (size_t i = 0; i < m_numComponents; ++i) { - double dir = m_formulaMatrix(kspec,i) * (m_elemAbundancesGoal[i] - m_elemAbundances[i]); - if (fabs(dir) > 1.0E-10) { - if (dir > 0.0) { - if (saveDir < 0.0) { - goodSpec = false; - break; - } - } else { - if (saveDir > 0.0) { - goodSpec = false; - break; - } - } - saveDir = dir; - } else { - if (m_formulaMatrix(kspec,i) != 0.) { - goodSpec = false; - break; - } - } - } - if (goodSpec) { - int its = 0; - double xx = 0.0; - for (size_t i = 0; i < m_numComponents; ++i) { - if (m_formulaMatrix(kspec,i) != 0.0) { - xx += (m_elemAbundancesGoal[i] - m_elemAbundances[i]) / m_formulaMatrix(kspec,i); - its++; - } - } - if (its > 0) { - xx /= its; - } - m_molNumSpecies_old[kspec] += xx; - m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 1.0E-10); - - // If we are dealing with a deleted species, then we need to - // reinsert it into the active list. - if (kspec >= m_numSpeciesRdc) { - vcs_reinsert_deleted(kspec); - m_molNumSpecies_old[m_numSpeciesRdc - 1] = xx; - vcs_elab(); - goto L_CLEANUP; - } - vcs_elab(); - } - } - } - if (vcs_elabcheck(0)) { - retn = 1; - goto L_CLEANUP; - } - - for (size_t i = 0; i < m_nelem; ++i) { - if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY || - (m_elType[i] == VCS_ELEM_TYPE_ABSPOS && m_elemAbundancesGoal[i] == 0.0)) { - for (size_t kspec = 0; kspec < m_numSpeciesRdc; kspec++) { - if (m_elemAbundances[i] > 0.0 && m_formulaMatrix(kspec,i) < 0.0) { - m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix(kspec,i); - m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); - vcs_elab(); - break; - } - if (m_elemAbundances[i] < 0.0 && m_formulaMatrix(kspec,i) > 0.0) { - m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix(kspec,i); - m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); - vcs_elab(); - break; - } - } - } - } - if (vcs_elabcheck(1)) { - retn = 1; - goto L_CLEANUP; - } - - // For electron charges element types, we try positive deltas in the species - // concentrations to match the desired electron charge exactly. - for (size_t i = 0; i < m_nelem; ++i) { - double dev = m_elemAbundancesGoal[i] - m_elemAbundances[i]; - if (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE && (fabs(dev) > 1.0E-300)) { - bool useZeroed = true; - for (size_t kspec = 0; kspec < m_numSpeciesRdc; kspec++) { - if (dev < 0.0) { - if (m_formulaMatrix(kspec,i) < 0.0 && m_molNumSpecies_old[kspec] > 0.0) { - useZeroed = false; - } - } else { - if (m_formulaMatrix(kspec,i) > 0.0 && m_molNumSpecies_old[kspec] > 0.0) { - useZeroed = false; - } - } - } - for (size_t kspec = 0; kspec < m_numSpeciesRdc; kspec++) { - if (m_molNumSpecies_old[kspec] > 0.0 || useZeroed) { - if (dev < 0.0 && m_formulaMatrix(kspec,i) < 0.0) { - double delta = dev / m_formulaMatrix(kspec,i); - m_molNumSpecies_old[kspec] += delta; - m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); - vcs_elab(); - break; - } - if (dev > 0.0 && m_formulaMatrix(kspec,i) > 0.0) { - double delta = dev / m_formulaMatrix(kspec,i); - m_molNumSpecies_old[kspec] += delta; - m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); - vcs_elab(); - break; - } - } - } - } - } - if (vcs_elabcheck(1)) { - retn = 1; - goto L_CLEANUP; - } - -L_CLEANUP: - ; - vcs_tmoles(); - double l2after = 0.0; - for (size_t i = 0; i < m_nelem; ++i) { - l2after += pow(m_elemAbundances[i] - m_elemAbundancesGoal[i], 2); - } - l2after = sqrt(l2after/m_nelem); - if (m_debug_print_lvl >= 2) { - plogf(" --- Elem_Abund: Correct Initial " - " Final\n"); - for (size_t i = 0; i < m_nelem; ++i) { - plogf(" --- "); - plogf("%-2.2s", m_elementName[i]); - plogf(" %20.12E %20.12E %20.12E\n", m_elemAbundancesGoal[i], ga_save[i], m_elemAbundances[i]); - } - plogf(" --- Diff_Norm: %20.12E %20.12E\n", - l2before, l2after); - } - return retn; -} - -} diff --git a/src/equil/vcs_elem_rearrange.cpp b/src/equil/vcs_elem_rearrange.cpp deleted file mode 100644 index 8c3ad70069..0000000000 --- a/src/equil/vcs_elem_rearrange.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @file vcs_elem_rearrange.cpp - * Contains implementations for rearranging the element columns, and - * it contains the algorithm for choosing the rearrangement. - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" -#include "cantera/base/stringUtils.h" -#include "cantera/base/ctexceptions.h" - -namespace Cantera -{ - -int VCS_SOLVE::vcs_elem_rearrange(double* const aw, double* const sa, - double* const sm, double* const ss) -{ - size_t ncomponents = m_numComponents; - if (m_debug_print_lvl >= 2) { - plogf(" "); - writeline('-', 77); - plogf(" --- Subroutine elem_rearrange() called to "); - plogf("check stoich. coefficient matrix\n"); - plogf(" --- and to rearrange the element ordering once\n"); - } - - // Use a temporary work array for the element numbers - // Also make sure the value of test is unique. - bool lindep = true; - double test = -1.0E10; - while (lindep) { - lindep = false; - for (size_t i = 0; i < m_nelem; ++i) { - test -= 1.0; - aw[i] = m_elemAbundancesGoal[i]; - if (test == aw[i]) { - lindep = true; - } - } - } - - // Top of a loop of some sort based on the index JR. JR is the current - // number independent elements found. - size_t jr = 0; - while (jr < ncomponents) { - size_t k; - - // Top of another loop point based on finding a linearly independent - // species - while (true) { - // Search the remaining part of the mole fraction vector, AW, for - // the largest remaining species. Return its identity in K. - k = m_nelem; - for (size_t ielem = jr; ielem < m_nelem; ielem++) { - if (m_elementActive[ielem] && aw[ielem] != test) { - k = ielem; - break; - } - } - if (k == m_nelem) { - throw CanteraError("VCS_SOLVE::vcs_elem_rearrange", - "Shouldn't be here. Algorithm misfired."); - } - - // Assign a large negative number to the element that we have just - // found, in order to take it out of further consideration. - aw[k] = test; - - // CHECK LINEAR INDEPENDENCE OF CURRENT FORMULA MATRIX LINE WITH - // PREVIOUS LINES OF THE FORMULA MATRIX - // - // Modified Gram-Schmidt Method, p. 202 Dalquist QR factorization of - // a matrix without row pivoting. - size_t jl = jr; - - // Fill in the row for the current element, k, under consideration - // The row will contain the Formula matrix value for that element - // from the current component. - for (size_t j = 0; j < ncomponents; ++j) { - sm[j + jr*ncomponents] = m_formulaMatrix(j,k); - } - if (jl > 0) { - // Compute the coefficients of JA column of the the upper - // triangular R matrix, SS(J) = R_J_JR (this is slightly - // different than Dalquist) R_JA_JA = 1 - for (size_t j = 0; j < jl; ++j) { - ss[j] = 0.0; - for (size_t i = 0; i < ncomponents; ++i) { - ss[j] += sm[i + jr*ncomponents] * sm[i + j*ncomponents]; - } - ss[j] /= sa[j]; - } - - // Now make the new column, (*,JR), orthogonal to the previous - // columns - for (size_t j = 0; j < jl; ++j) { - for (size_t i = 0; i < ncomponents; ++i) { - sm[i + jr*ncomponents] -= ss[j] * sm[i + j*ncomponents]; - } - } - } - - // Find the new length of the new column in Q. It will be used in - // the denominator in future row calcs. - sa[jr] = 0.0; - for (size_t ml = 0; ml < ncomponents; ++ml) { - sa[jr] += pow(sm[ml + jr*ncomponents], 2); - } - // IF NORM OF NEW ROW .LT. 1E-6 REJECT - if (sa[jr] > 1.0e-6) { - break; - } - } - // REARRANGE THE DATA - if (jr != k) { - if (m_debug_print_lvl >= 2) { - plogf(" --- %-2.2s(%9.2g) replaces %-2.2s(%9.2g) as element %3d\n", - m_elementName[k], m_elemAbundancesGoal[k], - m_elementName[jr], m_elemAbundancesGoal[jr], jr); - } - vcs_switch_elem_pos(jr, k); - std::swap(aw[jr], aw[k]); - } - - // If we haven't found enough components, go back and find some more. - jr++; - } - return VCS_SUCCESS; -} - -void VCS_SOLVE::vcs_switch_elem_pos(size_t ipos, size_t jpos) -{ - if (ipos == jpos) { - return; - } - AssertThrowMsg(ipos < m_nelem && jpos < m_nelem, - "vcs_switch_elem_pos", - "inappropriate args: {} {}", ipos, jpos); - - // Change the element Global Index list in each vcs_VolPhase object - // to reflect the switch in the element positions. - for (size_t iph = 0; iph < m_numPhases; iph++) { - vcs_VolPhase* volPhase = m_VolPhaseList[iph].get(); - for (size_t e = 0; e < volPhase->nElemConstraints(); e++) { - if (volPhase->elemGlobalIndex(e) == ipos) { - volPhase->setElemGlobalIndex(e, jpos); - } - if (volPhase->elemGlobalIndex(e) == jpos) { - volPhase->setElemGlobalIndex(e, ipos); - } - } - } - std::swap(m_elemAbundancesGoal[ipos], m_elemAbundancesGoal[jpos]); - std::swap(m_elemAbundances[ipos], m_elemAbundances[jpos]); - std::swap(m_elementMapIndex[ipos], m_elementMapIndex[jpos]); - std::swap(m_elType[ipos], m_elType[jpos]); - std::swap(m_elementActive[ipos], m_elementActive[jpos]); - for (size_t j = 0; j < m_nsp; ++j) { - std::swap(m_formulaMatrix(j,ipos), m_formulaMatrix(j,jpos)); - } - std::swap(m_elementName[ipos], m_elementName[jpos]); -} -} diff --git a/src/equil/vcs_inest.cpp b/src/equil/vcs_inest.cpp deleted file mode 100644 index f8843ab178..0000000000 --- a/src/equil/vcs_inest.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/** - * @file vcs_inest.cpp - * Implementation methods for obtaining a good initial guess - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" - -#include "cantera/base/clockWC.h" - -namespace Cantera -{ - -static char pprefix[20] = " --- vcs_inest: "; - -void VCS_SOLVE::vcs_inest(double* const aw, double* const sa, double* const sm, - double* const ss, double test) -{ - size_t nrxn = m_numRxnTot; - - // CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB AND - // molNum(I) .GE. 0.0. Note, both of these programs do this. - vcs_setMolesLinProg(); - - if (m_debug_print_lvl >= 2) { - plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n", - pprefix); - plogf("%s SPECIES MOLE_NUMBER -SS_ChemPotential\n", pprefix); - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - plogf("%s ", pprefix); - plogf("%-12.12s", m_speciesName[kspec]); - plogf(" %15.5g %12.3g\n", m_molNumSpecies_old[kspec], -m_SSfeSpecies[kspec]); - } - plogf("%s Element Abundance Agreement returned from linear " - "programming (vcs_inest initial guess):\n", pprefix); - plogf("%s Element Goal Actual\n", pprefix); - for (size_t j = 0; j < m_nelem; j++) { - if (m_elementActive[j]) { - double tmp = 0.0; - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - tmp += m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec]; - } - plogf("%s ", pprefix); - plogf(" %-9.9s", m_elementName[j]); - plogf(" %12.3g %12.3g\n", m_elemAbundancesGoal[j], tmp); - } - } - writelogendl(); - } - - // Make sure all species have positive definite mole numbers Set voltages to - // zero for now, until we figure out what to do - m_deltaMolNumSpecies.assign(m_deltaMolNumSpecies.size(), 0.0); - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - if (m_molNumSpecies_old[kspec] <= 0.0) { - // HKM Should eventually include logic here for non SS phases - if (!m_SSPhase[kspec]) { - m_molNumSpecies_old[kspec] = 1.0e-30; - } - } - } else { - m_molNumSpecies_old[kspec] = 0.0; - } - } - - // Now find the optimized basis that spans the stoichiometric coefficient - // matrix - bool conv; - vcs_basopt(false, aw, sa, sm, ss, test, &conv); - - // CALCULATE TOTAL MOLES, CHEMICAL POTENTIALS OF BASIS - - // Calculate TMoles and m_tPhaseMoles_old[] - vcs_tmoles(); - - // m_tPhaseMoles_new[] will consist of just the component moles - for (size_t iph = 0; iph < m_numPhases; iph++) { - m_tPhaseMoles_new[iph] = TPhInertMoles[iph] + 1.0E-20; - } - for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { - if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { - m_tPhaseMoles_new[m_phaseID[kspec]] += m_molNumSpecies_old[kspec]; - } - } - double TMolesMultiphase = 0.0; - for (size_t iph = 0; iph < m_numPhases; iph++) { - if (! m_VolPhaseList[iph]->m_singleSpecies) { - TMolesMultiphase += m_tPhaseMoles_new[iph]; - } - } - m_molNumSpecies_new = m_molNumSpecies_old; - for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_MOLNUM) { - m_molNumSpecies_new[kspec] = 0.0; - } - } - m_feSpecies_new = m_SSfeSpecies; - - for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { - if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { - if (! m_SSPhase[kspec]) { - size_t iph = m_phaseID[kspec]; - m_feSpecies_new[kspec] += log(m_molNumSpecies_new[kspec] / m_tPhaseMoles_old[iph]); - } - } else { - m_molNumSpecies_new[kspec] = 0.0; - } - } - vcs_deltag(0, true, VCS_STATECALC_NEW); - if (m_debug_print_lvl >= 2) { - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - plogf("%s", pprefix); - plogf("%-12.12s", m_speciesName[kspec]); - if (kspec < m_numComponents) { - plogf("fe* = %15.5g ff = %15.5g\n", m_feSpecies_new[kspec], - m_SSfeSpecies[kspec]); - } else { - plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n", - m_feSpecies_new[kspec], m_SSfeSpecies[kspec], m_deltaGRxn_new[kspec-m_numComponents]); - } - } - } - - // ESTIMATE REACTION ADJUSTMENTS - vector_fp& xtphMax = m_TmpPhase; - vector_fp& xtphMin = m_TmpPhase2; - m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0); - for (size_t iph = 0; iph < m_numPhases; iph++) { - xtphMax[iph] = log(m_tPhaseMoles_new[iph] * 1.0E32); - xtphMin[iph] = log(m_tPhaseMoles_new[iph] * 1.0E-32); - } - for (size_t irxn = 0; irxn < nrxn; ++irxn) { - size_t kspec = m_indexRxnToSpecies[irxn]; - - // For single species phases, we will not estimate the mole numbers. If - // the phase exists, it stays. If it doesn't exist in the estimate, it - // doesn't come into existence here. - if (! m_SSPhase[kspec]) { - size_t iph = m_phaseID[kspec]; - if (m_deltaGRxn_new[irxn] > xtphMax[iph]) { - m_deltaGRxn_new[irxn] = 0.8 * xtphMax[iph]; - } - if (m_deltaGRxn_new[irxn] < xtphMin[iph]) { - m_deltaGRxn_new[irxn] = 0.8 * xtphMin[iph]; - } - - // HKM -> The TMolesMultiphase is a change of mine. It more evenly - // distributes the initial moles amongst multiple multispecies - // phases according to the relative values of the standard state - // free energies. There is no change for problems with one - // multispecies phase. It cut diamond4.vin iterations down from 62 - // to 14. - m_deltaMolNumSpecies[kspec] = 0.5 * (m_tPhaseMoles_new[iph] + TMolesMultiphase) - * exp(-m_deltaGRxn_new[irxn]); - - for (size_t k = 0; k < m_numComponents; ++k) { - m_deltaMolNumSpecies[k] += m_stoichCoeffRxnMatrix(k,irxn) * m_deltaMolNumSpecies[kspec]; - } - - for (iph = 0; iph < m_numPhases; iph++) { - m_deltaPhaseMoles[iph] += m_deltaMolNumPhase(iph,irxn) * m_deltaMolNumSpecies[kspec]; - } - } - } - if (m_debug_print_lvl >= 2) { - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - plogf("%sdirection (", pprefix); - plogf("%-12.12s", m_speciesName[kspec]); - plogf(") = %g", m_deltaMolNumSpecies[kspec]); - if (m_SSPhase[kspec]) { - if (m_molNumSpecies_old[kspec] > 0.0) { - plogf(" (ssPhase exists at w = %g moles)", m_molNumSpecies_old[kspec]); - } else { - plogf(" (ssPhase doesn't exist -> stability not checked)"); - } - } - writelogendl(); - } - } - } - - // KEEP COMPONENT SPECIES POSITIVE - double par = 0.5; - for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE && - par < -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]) { - par = -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]; - } - } - par = 1. / par; - if (par <= 1.0 && par > 0.0) { - par *= 0.8; - } else { - par = 1.0; - } - - // CALCULATE NEW MOLE NUMBERS - size_t lt = 0; - size_t ikl = 0; - double s1 = 0.0; - while (true) { - for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - m_molNumSpecies_old[kspec] = m_molNumSpecies_new[kspec] + par * m_deltaMolNumSpecies[kspec]; - } else { - m_deltaMolNumSpecies[kspec] = 0.0; - } - } - for (size_t kspec = m_numComponents; kspec < m_nsp; ++kspec) { - if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE && - m_deltaMolNumSpecies[kspec] != 0.0) { - m_molNumSpecies_old[kspec] = m_deltaMolNumSpecies[kspec] * par; - } - } - - // We have a new w[] estimate, go get the TMoles and m_tPhaseMoles_old[] - // values - vcs_tmoles(); - if (lt > 0) { - break; - } - - // CONVERGENCE FORCING SECTION - vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD); - vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_nsp); - double s = 0.0; - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - s += m_deltaMolNumSpecies[kspec] * m_feSpecies_old[kspec]; - } - if (s == 0.0) { - break; - } - if (s < 0.0 && ikl == 0) { - break; - } - - // TRY HALF STEP SIZE - if (ikl == 0) { - s1 = s; - par *= 0.5; - ikl = 1; - continue; - } - - // FIT PARABOLA THROUGH HALF AND FULL STEPS - double xl = (1.0 - s / (s1 - s)) * 0.5; - if (xl < 0.0) { - // POOR DIRECTION, REDUCE STEP SIZE TO 0.2 - par *= 0.2; - } else { - if (xl > 1.0) { - // TOO BIG A STEP, TAKE ORIGINAL FULL STEP - par *= 2.0; - } else { - // ACCEPT RESULTS OF FORCER - par = par * 2.0 * xl; - } - } - lt = 1; - } - - if (m_debug_print_lvl >= 2) { - plogf("%s Final Mole Numbers produced by inest:\n", - pprefix); - plogf("%s SPECIES MOLE_NUMBER\n", pprefix); - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - plogf("%s %-12.12s %g\n", - pprefix, m_speciesName[kspec], m_molNumSpecies_old[kspec]); - } - } -} - -int VCS_SOLVE::vcs_inest_TP() -{ - int retn = 0; - clockWC tickTock; - if (m_doEstimateEquil > 0) { - // Calculate the elemental abundances - vcs_elab(); - if (vcs_elabcheck(0)) { - if (m_debug_print_lvl >= 2) { - plogf("%s Initial guess passed element abundances on input\n", pprefix); - plogf("%s m_doEstimateEquil = 1 so will use the input mole " - "numbers as estimates\n", pprefix); - } - return retn; - } else if (m_debug_print_lvl >= 2) { - plogf("%s Initial guess failed element abundances on input\n", pprefix); - plogf("%s m_doEstimateEquil = 1 so will discard input " - "mole numbers and find our own estimate\n", pprefix); - } - } - - // temporary space for usage in this routine and in subroutines - vector_fp sm(m_nelem*m_nelem, 0.0); - vector_fp ss(m_nelem, 0.0); - vector_fp sa(m_nelem, 0.0); - vector_fp aw(m_nsp + m_nelem, 0.0); - - // Go get the estimate of the solution - if (m_debug_print_lvl >= 2) { - plogf("%sGo find an initial estimate for the equilibrium problem\n", - pprefix); - } - double test = -1.0E20; - vcs_inest(&aw[0], &sa[0], &sm[0], &ss[0], test); - - // Calculate the elemental abundances - vcs_elab(); - - // If we still fail to achieve the correct elemental abundances, try to fix - // the problem again by calling the main elemental abundances fixer routine, - // used in the main program. This attempts to tweak the mole numbers of the - // component species to satisfy the element abundance constraints. - // - // Note: We won't do this unless we have to since it involves inverting a - // matrix. - bool rangeCheck = vcs_elabcheck(1); - if (!vcs_elabcheck(0)) { - if (m_debug_print_lvl >= 2) { - plogf("%sInitial guess failed element abundances\n", pprefix); - plogf("%sCall vcs_elcorr to attempt fix\n", pprefix); - } - vcs_elcorr(&sm[0], &aw[0]); - rangeCheck = vcs_elabcheck(1); - if (!vcs_elabcheck(0)) { - plogf("%sInitial guess still fails element abundance equations\n", - pprefix); - plogf("%s - Inability to ever satisfy element abundance " - "constraints is probable\n", pprefix); - retn = -1; - } else { - if (m_debug_print_lvl >= 2) { - if (rangeCheck) { - plogf("%sInitial guess now satisfies element abundances\n", pprefix); - } else { - plogf("%sElement Abundances RANGE ERROR\n", pprefix); - plogf("%s - Initial guess satisfies NC=%d element abundances, " - "BUT not NE=%d element abundances\n", pprefix, - m_numComponents, m_nelem); - } - } - } - } else { - if (m_debug_print_lvl >= 2) { - if (rangeCheck) { - plogf("%sInitial guess satisfies element abundances\n", pprefix); - } else { - plogf("%sElement Abundances RANGE ERROR\n", pprefix); - plogf("%s - Initial guess satisfies NC=%d element abundances, " - "BUT not NE=%d element abundances\n", pprefix, - m_numComponents, m_nelem); - } - } - } - - if (m_debug_print_lvl >= 2) { - plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E\n", pprefix, - vcs_Total_Gibbs(&m_molNumSpecies_old[0], &m_feSpecies_new[0], - &m_tPhaseMoles_old[0])); - } - - // Record time - m_VCount->T_Time_inest += tickTock.secondsWC(); - m_VCount->T_Calls_Inest++; - return retn; -} - -} diff --git a/src/equil/vcs_phaseStability.cpp b/src/equil/vcs_phaseStability.cpp deleted file mode 100644 index f064f01dd4..0000000000 --- a/src/equil/vcs_phaseStability.cpp +++ /dev/null @@ -1,614 +0,0 @@ -/** - * @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 ). - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" -#include "cantera/base/stringUtils.h" -#include "cantera/base/ctexceptions.h" - -using namespace std; - -namespace Cantera -{ - -bool VCS_SOLVE::vcs_popPhasePossible(const size_t iphasePop) const -{ - vcs_VolPhase* Vphase = m_VolPhaseList[iphasePop].get(); - AssertThrowMsg(!Vphase->exists(), "VCS_SOLVE::vcs_popPhasePossible", - "called for a phase that exists!"); - - // Loop through all of the species in the phase. We say the phase can be - // popped, if there is one species in the phase that can be popped. This - // does not mean that the phase will be popped or that it leads to a lower - // Gibbs free energy. - for (size_t k = 0; k < Vphase->nSpecies(); k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - AssertThrowMsg(m_molNumSpecies_old[kspec] <= 0.0, - "VCS_SOLVE::vcs_popPhasePossible", - "we shouldn't be here {}: {} > 0.0", kspec, - m_molNumSpecies_old[kspec]); - size_t irxn = kspec - m_numComponents; - if (kspec >= m_numComponents) { - bool iPopPossible = true; - - // Note one case is if the component is a member of the popping - // phase. This component will be zeroed and the logic here will - // negate the current species from causing a positive if this - // component is consumed. - for (size_t j = 0; j < m_numComponents; ++j) { - if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { - double stoicC = m_stoichCoeffRxnMatrix(j,irxn); - if (stoicC != 0.0) { - double negChangeComp = - stoicC; - if (negChangeComp > 0.0) { - // If there is no component to give, then the - // species can't be created - if (m_molNumSpecies_old[j] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { - iPopPossible = false; - } - } - } - } - } - // We are here when the species can be popped because all its needed - // components have positive mole numbers - if (iPopPossible) { - return true; - } - } else { - // We are here when the species, k, 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. - for (size_t jrxn = 0; jrxn < m_numRxnRdc; jrxn++) { - bool foundJrxn = false; - // First, if the component is a product of the reaction - if (m_stoichCoeffRxnMatrix(kspec,jrxn) > 0.0) { - foundJrxn = true; - // We can do the reaction if all other reactant components - // have positive mole fractions - for (size_t kcomp = 0; kcomp < m_numComponents; kcomp++) { - if (m_stoichCoeffRxnMatrix(kcomp,jrxn) < 0.0 && m_molNumSpecies_old[kcomp] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { - foundJrxn = false; - } - } - if (foundJrxn) { - return true; - } - } else if (m_stoichCoeffRxnMatrix(kspec,jrxn) < 0.0) { - // Second we are here if the component is a reactant in the - // reaction, and the reaction goes backwards. - foundJrxn = true; - size_t jspec = jrxn + m_numComponents; - if (m_molNumSpecies_old[jspec] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { - foundJrxn = false; - continue; - } - // We can do the backwards reaction if all of the product - // components species are positive - for (size_t kcomp = 0; kcomp < m_numComponents; kcomp++) { - if (m_stoichCoeffRxnMatrix(kcomp,jrxn) > 0.0 && m_molNumSpecies_old[kcomp] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { - foundJrxn = false; - } - } - if (foundJrxn) { - return true; - } - } - } - } - } - return false; -} - -size_t VCS_SOLVE::vcs_popPhaseID(std::vector & phasePopPhaseIDs) -{ - size_t iphasePop = npos; - doublereal FephaseMax = -1.0E30; - doublereal Fephase = -1.0E30; - - char anote[128]; - if (m_debug_print_lvl >= 2) { - plogf(" --- vcs_popPhaseID() called\n"); - plogf(" --- Phase Status F_e MoleNum\n"); - plogf(" --------------------------------------------------------------------------\n"); - } - for (size_t iph = 0; iph < m_numPhases; iph++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); - int existence = Vphase->exists(); - strcpy(anote, ""); - if (existence > 0) { - if (m_debug_print_lvl >= 2) { - plogf(" --- %18s %5d NA %11.3e\n", - Vphase->PhaseName, existence, m_tPhaseMoles_old[iph]); - } - } else { - if (Vphase->m_singleSpecies) { - // Single Phase Stability Resolution - size_t kspec = Vphase->spGlobalIndexVCS(0); - size_t irxn = kspec - m_numComponents; - if (irxn > m_deltaGRxn_old.size()) { - throw CanteraError("VCS_SOLVE::vcs_popPhaseID", - "Index out of bounds due to logic error."); - } - doublereal deltaGRxn = m_deltaGRxn_old[irxn]; - Fephase = exp(-deltaGRxn) - 1.0; - if (Fephase > 0.0) { - strcpy(anote," (ready to be birthed)"); - if (Fephase > FephaseMax) { - iphasePop = iph; - FephaseMax = Fephase; - strcpy(anote," (chosen to be birthed)"); - } - } - if (Fephase < 0.0) { - strcpy(anote," (not stable)"); - AssertThrowMsg(m_tPhaseMoles_old[iph] <= 0.0, - "VCS_SOLVE::vcs_popPhaseID", "shouldn't be here"); - } - - if (m_debug_print_lvl >= 2) { - plogf(" --- %18s %5d %10.3g %10.3g %s\n", - Vphase->PhaseName, existence, Fephase, - m_tPhaseMoles_old[iph], anote); - } - } else { - // MultiSpecies Phase Stability Resolution - if (vcs_popPhasePossible(iph)) { - Fephase = vcs_phaseStabilityTest(iph); - if (Fephase > 0.0) { - if (Fephase > FephaseMax) { - iphasePop = iph; - FephaseMax = Fephase; - } - } else { - FephaseMax = std::max(FephaseMax, Fephase); - } - if (m_debug_print_lvl >= 2) { - plogf(" --- %18s %5d %11.3g %11.3g\n", - Vphase->PhaseName, existence, Fephase, - m_tPhaseMoles_old[iph]); - } - } else { - if (m_debug_print_lvl >= 2) { - plogf(" --- %18s %5d blocked %11.3g\n", - Vphase->PhaseName, - existence, m_tPhaseMoles_old[iph]); - } - } - } - } - } - phasePopPhaseIDs.resize(0); - if (iphasePop != npos) { - phasePopPhaseIDs.push_back(iphasePop); - } - - // Insert logic here to figure out if phase pops are linked together. Only - // do one linked pop at a time. - if (m_debug_print_lvl >= 2) { - plogf(" ---------------------------------------------------------------------\n"); - } - return iphasePop; -} - -int VCS_SOLVE::vcs_popPhaseRxnStepSizes(const size_t iphasePop) -{ - vcs_VolPhase* Vphase = m_VolPhaseList[iphasePop].get(); - // Identify the first species in the phase - size_t kspec = Vphase->spGlobalIndexVCS(0); - // Identify the formation reaction for that species - size_t irxn = kspec - m_numComponents; - std::vector creationGlobalRxnNumbers; - - // Calculate the initial moles of the phase being born. - // Here we set it to 10x of the value which would cause the phase to be - // zeroed out within the algorithm. We may later adjust the value. - doublereal tPhaseMoles = 10. * m_totalMolNum * VCS_DELETE_PHASE_CUTOFF; - - AssertThrowMsg(!Vphase->exists(), "VCS_SOLVE::vcs_popPhaseRxnStepSizes", - "called for a phase that exists!"); - if (m_debug_print_lvl >= 2) { - plogf(" --- vcs_popPhaseRxnStepSizes() called to pop phase %s %d into existence\n", - Vphase->PhaseName, iphasePop); - } - // Section for a single-species phase - if (Vphase->m_singleSpecies) { - double s = 0.0; - for (size_t j = 0; j < m_numComponents; ++j) { - if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) { - s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j]; - } - } - for (size_t j = 0; j < m_numPhases; j++) { - Vphase = m_VolPhaseList[j].get(); - if (! Vphase->m_singleSpecies && m_tPhaseMoles_old[j] > 0.0) { - s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j]; - } - } - if (s != 0.0) { - double s_old = s; - s = vcs_Hessian_diag_adj(irxn, s_old); - m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s; - } else { - // Ok, s is equal to zero. We can not apply a sophisticated theory - // to birth the phase. Just pick a small delta and go with it. - m_deltaMolNumSpecies[kspec] = tPhaseMoles; - } - - // section to do damping of the m_deltaMolNumSpecies[] - for (size_t j = 0; j < m_numComponents; ++j) { - double stoicC = m_stoichCoeffRxnMatrix(j,irxn); - if (stoicC != 0.0 && m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { - double negChangeComp = - stoicC * m_deltaMolNumSpecies[kspec]; - if (negChangeComp > m_molNumSpecies_old[j]) { - if (m_molNumSpecies_old[j] > 0.0) { - m_deltaMolNumSpecies[kspec] = - 0.5 * m_molNumSpecies_old[j] / stoicC; - } else { - m_deltaMolNumSpecies[kspec] = 0.0; - } - } - } - } - // Implement a damping term that limits m_deltaMolNumSpecies to the size - // of the mole number - if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) { - m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; - } - } else { - vector_fp fracDelta(Vphase->nSpecies()); - vector_fp X_est(Vphase->nSpecies()); - fracDelta = Vphase->creationMoleNumbers(creationGlobalRxnNumbers); - - double sumFrac = 0.0; - for (size_t k = 0; k < Vphase->nSpecies(); k++) { - sumFrac += fracDelta[k]; - } - for (size_t k = 0; k < Vphase->nSpecies(); k++) { - X_est[k] = fracDelta[k] / sumFrac; - } - - doublereal deltaMolNumPhase = tPhaseMoles; - doublereal damp = 1.0; - m_deltaGRxn_tmp = m_molNumSpecies_old; - double* molNumSpecies_tmp = m_deltaGRxn_tmp.data(); - - for (size_t k = 0; k < Vphase->nSpecies(); k++) { - kspec = Vphase->spGlobalIndexVCS(k); - double delmol = deltaMolNumPhase * X_est[k]; - if (kspec >= m_numComponents) { - irxn = kspec - m_numComponents; - if (irxn > m_stoichCoeffRxnMatrix.nColumns()) { - throw CanteraError("VCS_SOLVE::vcs_popPhaseRxnStepSizes", - "Index out of bounds due to logic error."); - } - for (size_t j = 0; j < m_numComponents; ++j) { - double stoicC = m_stoichCoeffRxnMatrix(j,irxn); - if (stoicC != 0.0 && m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { - molNumSpecies_tmp[j] += stoicC * delmol; - } - } - } - } - - doublereal ratioComp = 0.0; - for (size_t j = 0; j < m_numComponents; ++j) { - double deltaJ = m_molNumSpecies_old[j] - molNumSpecies_tmp[j]; - if (molNumSpecies_tmp[j] < 0.0) { - ratioComp = 1.0; - if (deltaJ > 0.0) { - double delta0 = m_molNumSpecies_old[j]; - damp = std::min(damp, delta0 / deltaJ * 0.9); - } - } else { - if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { - size_t jph = m_phaseID[j]; - if ((jph != iphasePop) && (!m_SSPhase[j])) { - double fdeltaJ = fabs(deltaJ); - if (m_molNumSpecies_old[j] > 0.0) { - ratioComp = std::max(ratioComp, fdeltaJ/ m_molNumSpecies_old[j]); - } - } - } - } - } - - // We may have greatly underestimated the deltaMoles for the phase pop - // Here we create a damp > 1 to account for this possibility. We adjust - // upwards to make sure that a component in an existing multispecies - // phase is modified by a factor of 1/1000. - if (ratioComp > 1.0E-30 && ratioComp < 0.001) { - damp = 0.001 / ratioComp; - } - if (damp <= 1.0E-6) { - return 3; - } - - for (size_t k = 0; k < Vphase->nSpecies(); k++) { - kspec = Vphase->spGlobalIndexVCS(k); - if (kspec < m_numComponents) { - m_speciesStatus[kspec] = VCS_SPECIES_COMPONENT; - } else { - m_deltaMolNumSpecies[kspec] = deltaMolNumPhase * X_est[k] * damp; - if (X_est[k] > 1.0E-3) { - m_speciesStatus[kspec] = VCS_SPECIES_MAJOR; - } else { - m_speciesStatus[kspec] = VCS_SPECIES_MINOR; - } - } - } - } - return 0; -} - -double VCS_SOLVE::vcs_phaseStabilityTest(const size_t iph) -{ - // We will use the _new state calc here - vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); - const size_t nsp = Vphase->nSpecies(); - int minNumberIterations = 3; - if (nsp <= 1) { - minNumberIterations = 1; - } - - // We will do a full Newton calculation later, but for now, ... - bool doSuccessiveSubstitution = true; - double funcPhaseStability; - vector_fp X_est(nsp, 0.0); - vector_fp delFrac(nsp, 0.0); - vector_fp E_phi(nsp, 0.0); - vector_fp fracDelta_old(nsp, 0.0); - vector_fp fracDelta_raw(nsp, 0.0); - vector creationGlobalRxnNumbers(nsp, npos); - m_deltaGRxn_Deficient = m_deltaGRxn_old; - vector_fp feSpecies_Deficient = m_feSpecies_old; - - // get the activity coefficients - Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, &m_actCoeffSpecies_new[0]); - - // Get the stored estimate for the composition of the phase if - // it gets created - vector_fp fracDelta_new = Vphase->creationMoleNumbers(creationGlobalRxnNumbers); - - std::vector componentList; - for (size_t k = 0; k < nsp; k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - if (kspec < m_numComponents) { - componentList.push_back(k); - } - } - - double normUpdate = 0.1 * vcs_l2norm(fracDelta_new); - double damp = 1.0E-2; - - if (doSuccessiveSubstitution) { - int KP = 0; - if (m_debug_print_lvl >= 2) { - plogf(" --- vcs_phaseStabilityTest() called\n"); - plogf(" --- Its X_old[%2d] FracDel_old[%2d] deltaF[%2d] FracDel_new[%2d]" - " normUpdate damp FuncPhaseStability\n", KP, KP, KP, KP); - plogf(" --------------------------------------------------------------" - "--------------------------------------------------------\n"); - } else if (m_debug_print_lvl == 1) { - plogf(" --- vcs_phaseStabilityTest() called for phase %d\n", iph); - } - - for (size_t k = 0; k < nsp; k++) { - if (fracDelta_new[k] < 1.0E-13) { - fracDelta_new[k] =1.0E-13; - } - } - bool converged = false; - double dirProd = 0.0; - for (int its = 0; its < 200 && (!converged); its++) { - double dampOld = damp; - double normUpdateOld = normUpdate; - fracDelta_old = fracDelta_new; - double dirProdOld = dirProd; - - // Given a set of fracDelta's, we calculate the fracDelta's - // for the component species, if any - for (size_t i = 0; i < componentList.size(); i++) { - size_t kc = componentList[i]; - size_t kc_spec = Vphase->spGlobalIndexVCS(kc); - fracDelta_old[kc] = 0.0; - for (size_t k = 0; k < nsp; k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - if (kspec >= m_numComponents) { - size_t irxn = kspec - m_numComponents; - fracDelta_old[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_old[k]; - } - } - } - - // Now, calculate the predicted mole fractions, X_est[k] - double sumFrac = 0.0; - for (size_t k = 0; k < nsp; 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 (size_t k = 0; k < nsp; k++) { - X_est[k] = fracDelta_old[k] / sumFrac; - if (Vphase->spGlobalIndexVCS(k) < m_numComponents) { - sum_Xcomp += X_est[k]; - } - } - - // Feed the newly formed estimate of the mole fractions back into the - // ThermoPhase object - Vphase->setMoleFractionsState(0.0, &X_est[0], VCS_STATECALC_PHASESTABILITY); - - // get the activity coefficients - Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, &m_actCoeffSpecies_new[0]); - - // First calculate altered chemical potentials for component species - // belonging to this phase. - for (size_t i = 0; i < componentList.size(); i++) { - size_t kc = componentList[i]; - size_t kc_spec = Vphase->spGlobalIndexVCS(kc); - if (X_est[kc] > VCS_DELETE_MINORSPECIES_CUTOFF) { - feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] - + log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]); - } else { - feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] - + log(m_actCoeffSpecies_new[kc_spec] * VCS_DELETE_MINORSPECIES_CUTOFF); - } - } - - for (size_t i = 0; i < componentList.size(); i++) { - size_t kc_spec = Vphase->spGlobalIndexVCS(componentList[i]); - for (size_t k = 0; k < Vphase->nSpecies(); k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - if (kspec >= m_numComponents) { - size_t irxn = kspec - m_numComponents; - if (i == 0) { - m_deltaGRxn_Deficient[irxn] = m_deltaGRxn_old[irxn]; - } - if (m_stoichCoeffRxnMatrix(kc_spec,irxn) != 0.0) { - m_deltaGRxn_Deficient[irxn] += - m_stoichCoeffRxnMatrix(kc_spec,irxn) * (feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]); - } - } - } - } - - // Calculate the E_phi's - double sum = 0.0; - funcPhaseStability = sum_Xcomp - 1.0; - for (size_t k = 0; k < nsp; k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - if (kspec >= m_numComponents) { - size_t irxn = kspec - m_numComponents; - double deltaGRxn = clip(m_deltaGRxn_Deficient[irxn], -50.0, 50.0); - E_phi[k] = std::exp(-deltaGRxn) / m_actCoeffSpecies_new[kspec]; - sum += E_phi[k]; - funcPhaseStability += E_phi[k]; - } else { - E_phi[k] = 0.0; - } - } - - // Calculate the raw estimate of the new fracs - for (size_t k = 0; k < nsp; k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - double b = E_phi[k] / sum * (1.0 - sum_Xcomp); - if (kspec >= m_numComponents) { - fracDelta_raw[k] = b; - } - } - - // Given a set of fracDelta's, we calculate the fracDelta's - // for the component species, if any - for (size_t i = 0; i < componentList.size(); i++) { - size_t kc = componentList[i]; - size_t kc_spec = Vphase->spGlobalIndexVCS(kc); - fracDelta_raw[kc] = 0.0; - for (size_t k = 0; k < nsp; k++) { - size_t kspec = Vphase->spGlobalIndexVCS(k); - if (kspec >= m_numComponents) { - size_t irxn = kspec - m_numComponents; - fracDelta_raw[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_raw[k]; - } - } - } - - // Now possibly dampen the estimate. - doublereal sumADel = 0.0; - for (size_t k = 0; k < nsp; k++) { - delFrac[k] = fracDelta_raw[k] - fracDelta_old[k]; - sumADel += fabs(delFrac[k]); - } - normUpdate = vcs_l2norm(delFrac); - - dirProd = 0.0; - for (size_t k = 0; k < nsp; k++) { - dirProd += fracDelta_old[k] * delFrac[k]; - } - bool crossedSign = false; - if (dirProd * dirProdOld < 0.0) { - crossedSign = true; - } - - damp = 0.5; - if (dampOld < 0.25) { - damp = 2.0 * dampOld; - } - if (crossedSign) { - if (normUpdate *1.5 > normUpdateOld) { - damp = 0.5 * dampOld; - } else if (normUpdate *2.0 > normUpdateOld) { - damp = 0.8 * dampOld; - } - } else { - if (normUpdate > normUpdateOld * 2.0) { - damp = 0.6 * dampOld; - } else if (normUpdate > normUpdateOld * 1.2) { - damp = 0.9 * dampOld; - } - } - - for (size_t k = 0; k < nsp; k++) { - if (fabs(damp * delFrac[k]) > 0.3*fabs(fracDelta_old[k])) { - damp = std::max(0.3*fabs(fracDelta_old[k]) / fabs(delFrac[k]), - 1.0E-8/fabs(delFrac[k])); - } - if (delFrac[k] < 0.0 && 2.0 * damp * (-delFrac[k]) > fracDelta_old[k]) { - damp = fracDelta_old[k] / (2.0 * -delFrac[k]); - } - if (delFrac[k] > 0.0 && 2.0 * damp * delFrac[k] > fracDelta_old[k]) { - damp = fracDelta_old[k] / (2.0 * delFrac[k]); - } - } - damp = std::max(damp, 0.000001); - for (size_t k = 0; k < nsp; k++) { - fracDelta_new[k] = fracDelta_old[k] + damp * delFrac[k]; - } - - if (m_debug_print_lvl >= 2) { - plogf(" --- %3d %12g %12g %12g %12g %12g %12g %12g\n", its, X_est[KP], fracDelta_old[KP], - delFrac[KP], fracDelta_new[KP], normUpdate, damp, funcPhaseStability); - } - - if (normUpdate < 1.0E-5 * damp) { - converged = true; - if (its < minNumberIterations) { - converged = false; - } - } - } - - if (converged) { - // Save the final optimized stated back into the VolPhase object for later use - Vphase->setMoleFractionsState(0.0, &X_est[0], VCS_STATECALC_PHASESTABILITY); - - // Save fracDelta for later use to initialize the problem better - // @TODO creationGlobalRxnNumbers needs to be calculated here and stored. - Vphase->setCreationMoleNumbers(&fracDelta_new[0], creationGlobalRxnNumbers); - } - } else { - throw CanteraError("VCS_SOLVE::vcs_phaseStabilityTest", "not done yet"); - } - if (m_debug_print_lvl >= 2) { - plogf(" ------------------------------------------------------------" - "-------------------------------------------------------------\n"); - } else if (m_debug_print_lvl == 1) { - if (funcPhaseStability > 0.0) { - plogf(" --- phase %d with func = %g is to be born\n", iph, funcPhaseStability); - } else { - plogf(" --- phase %d with func = %g stays dead\n", iph, funcPhaseStability); - } - } - return funcPhaseStability; -} - -} diff --git a/src/equil/vcs_prep.cpp b/src/equil/vcs_prep.cpp deleted file mode 100644 index 3b3eeaa1f3..0000000000 --- a/src/equil/vcs_prep.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/** - * @file vcs_prep.cpp - * This file contains some prepatory functions. - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" -#include "cantera/equil/MultiPhase.h" - -namespace Cantera -{ -void VCS_SOLVE::vcs_SSPhase() -{ - vector_int numPhSpecies(m_numPhases, 0); - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - numPhSpecies[m_phaseID[kspec]]++; - } - - // Handle the special case of a single species in a phase that has been - // earmarked as a multispecies phase. Treat that species as a single-species - // phase - for (size_t iph = 0; iph < m_numPhases; iph++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); - Vphase->m_singleSpecies = false; - if (TPhInertMoles[iph] > 0.0) { - Vphase->setExistence(2); - } - if (numPhSpecies[iph] <= 1 && TPhInertMoles[iph] == 0.0) { - Vphase->m_singleSpecies = true; - } - } - - // Fill in some useful arrays here that have to do with the static - // information concerning the phase ID of species. SSPhase = Boolean - // indicating whether a species is in a single species phase or not. - for (size_t kspec = 0; kspec < m_nsp; kspec++) { - size_t iph = m_phaseID[kspec]; - vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); - if (Vphase->m_singleSpecies) { - m_SSPhase[kspec] = true; - } else { - m_SSPhase[kspec] = false; - } - } -} - -int VCS_SOLVE::vcs_prep(int printLvl) -{ - int retn = VCS_SUCCESS; - m_debug_print_lvl = printLvl; - - // Calculate the Single Species status of phases - // Also calculate the number of species per phase - vcs_SSPhase(); - - // Set an initial estimate for the number of noncomponent species equal to - // nspecies - nelements. This may be changed below - if (m_nelem > m_nsp) { - m_numRxnTot = 0; - } else { - m_numRxnTot = m_nsp - m_nelem; - } - m_numRxnRdc = m_numRxnTot; - m_numSpeciesRdc = m_nsp; - for (size_t i = 0; i < m_numRxnRdc; ++i) { - m_indexRxnToSpecies[i] = m_nelem + i; - } - - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - size_t pID = m_phaseID[kspec]; - size_t spPhIndex = m_speciesLocalPhaseIndex[kspec]; - vcs_VolPhase* vPhase = m_VolPhaseList[pID].get(); - vcs_SpeciesProperties* spProp = vPhase->speciesProperty(spPhIndex); - double sz = 0.0; - size_t eSize = spProp->FormulaMatrixCol.size(); - for (size_t e = 0; e < eSize; e++) { - sz += fabs(spProp->FormulaMatrixCol[e]); - } - if (sz > 0.0) { - m_spSize[kspec] = sz; - } else { - m_spSize[kspec] = 1.0; - } - } - - // DETERMINE THE NUMBER OF COMPONENTS - // - // Obtain a valid estimate of the mole fraction. This will be used as an - // initial ordering vector for prioritizing which species are defined as - // components. - // - // If a mole number estimate was supplied from the input file, use that mole - // number estimate. - // - // If a solution estimate wasn't supplied from the input file, supply an - // initial estimate for the mole fractions based on the relative reverse - // ordering of the chemical potentials. - // - // For voltage unknowns, set these to zero for the moment. - double test = -1.0e-10; - bool modifiedSoln = false; - if (m_doEstimateEquil < 0) { - double sum = 0.0; - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { - sum += fabs(m_molNumSpecies_old[kspec]); - } - } - if (fabs(sum) < 1.0E-6) { - modifiedSoln = true; - double pres = (m_pressurePA <= 0.0) ? 1.01325E5 : m_pressurePA; - retn = vcs_evalSS_TP(0, 0, m_temperature, pres); - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { - m_molNumSpecies_old[kspec] = - m_SSfeSpecies[kspec]; - } else { - m_molNumSpecies_old[kspec] = 0.0; - } - } - } - test = -1.0e20; - } - - // NC = number of components is in the vcs.h common block. This call to - // BASOPT doesn't calculate the stoichiometric reaction matrix. - vector_fp awSpace(m_nsp + (m_nelem + 2)*(m_nelem), 0.0); - double* aw = &awSpace[0]; - if (aw == NULL) { - plogf("vcs_prep_oneTime: failed to get memory: global bailout\n"); - return VCS_NOMEMORY; - } - double* sa = aw + m_nsp; - double* sm = sa + m_nelem; - double* ss = sm + m_nelem * m_nelem; - bool conv; - retn = vcs_basopt(true, aw, sa, sm, ss, test, &conv); - if (retn != VCS_SUCCESS) { - plogf("vcs_prep_oneTime:"); - plogf(" Determination of number of components failed: %d\n", - retn); - plogf(" Global Bailout!\n"); - return retn; - } - - if (m_nsp >= m_numComponents) { - m_numRxnTot = m_numRxnRdc = m_nsp - m_numComponents; - for (size_t i = 0; i < m_numRxnRdc; ++i) { - m_indexRxnToSpecies[i] = m_numComponents + i; - } - } else { - m_numRxnTot = m_numRxnRdc = 0; - } - - // The elements might need to be rearranged. - awSpace.resize(m_nelem + (m_nelem + 2)*m_nelem, 0.0); - aw = &awSpace[0]; - sa = aw + m_nelem; - sm = sa + m_nelem; - ss = sm + m_nelem * m_nelem; - retn = vcs_elem_rearrange(aw, sa, sm, ss); - if (retn != VCS_SUCCESS) { - plogf("vcs_prep_oneTime:"); - plogf(" Determination of element reordering failed: %d\n", - retn); - plogf(" Global Bailout!\n"); - return retn; - } - - // If we mucked up the solution unknowns because they were all - // zero to start with, set them back to zero here - if (modifiedSoln) { - for (size_t kspec = 0; kspec < m_nsp; ++kspec) { - m_molNumSpecies_old[kspec] = 0.0; - } - } - - // Initialize various arrays in the data to zero - m_feSpecies_old.assign(m_feSpecies_old.size(), 0.0); - m_feSpecies_new.assign(m_feSpecies_new.size(), 0.0); - m_molNumSpecies_new.assign(m_molNumSpecies_new.size(), 0.0); - m_deltaMolNumPhase.zero(); - m_phaseParticipation.zero(); - m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0); - m_tPhaseMoles_new.assign(m_tPhaseMoles_new.size(), 0.0); - - // Calculate the total number of moles in all phases. - vcs_tmoles(); - - // Check to see if the current problem is well posed. - double sum = 0.0; - for (size_t e = 0; e < m_mix->nElements(); e++) { - sum += m_mix->elementMoles(e); - } - if (sum < 1.0E-20) { - // Check to see if the current problem is well posed. - plogf("vcs has determined the problem is not well posed: Bailing\n"); - return VCS_PUB_BAD; - } - return VCS_SUCCESS; -} - -} diff --git a/src/equil/vcs_prob.cpp b/src/equil/vcs_prob.cpp deleted file mode 100644 index dd849da9ed..0000000000 --- a/src/equil/vcs_prob.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/** - * @file vcs_prob.cpp - * Implementation for the Interface class for the vcs thermo - * equilibrium solver package, - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_VolPhase.h" -#include "cantera/equil/vcs_species_thermo.h" -#include "cantera/equil/vcs_internal.h" -#include "cantera/equil/vcs_defs.h" -#include "cantera/equil/vcs_solve.h" -#include "cantera/thermo/MolalityVPSSTP.h" -#include "cantera/equil/MultiPhase.h" - -#include - -using namespace std; - -namespace Cantera -{ - -void VCS_SOLVE::prob_report(int print_lvl) -{ - m_printLvl = print_lvl; - - // Printout the species information: PhaseID's and mole nums - if (m_printLvl > 0) { - writeline('=', 80, true, true); - writeline('=', 20, false); - plogf(" VCS_PROB: PROBLEM STATEMENT "); - writeline('=', 31); - writeline('=', 80); - plogf("\n"); - plogf("\tSolve a constant T, P problem:\n"); - plogf("\t\tT = %g K\n", m_temperature); - double pres_atm = m_pressurePA / 1.01325E5; - - plogf("\t\tPres = %g atm\n", pres_atm); - plogf("\n"); - plogf(" Phase IDs of species\n"); - plogf(" species phaseID phaseName "); - plogf(" Initial_Estimated_Moles Species_Type\n"); - for (size_t i = 0; i < m_nsp; i++) { - vcs_VolPhase* Vphase = m_VolPhaseList[m_phaseID[i]].get(); - plogf("%16s %5d %16s", m_mix->speciesName(i), m_phaseID[i], - Vphase->PhaseName); - if (m_doEstimateEquil >= 0) { - plogf(" %-10.5g", m_molNumSpecies_old[i]); - } else { - plogf(" N/A"); - } - if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { - plogf(" Mol_Num"); - } else if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - plogf(" Voltage"); - } else { - plogf(" "); - } - plogf("\n"); - } - - // Printout of the Phase structure information - writeline('-', 80, true, true); - plogf(" Information about phases\n"); - plogf(" PhaseName PhaseNum SingSpec GasPhase " - " EqnState NumSpec"); - plogf(" TMolesInert TKmoles\n"); - - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); - plogf("%16s %5d %5d %8d ", Vphase->PhaseName, - Vphase->VP_ID_, Vphase->m_singleSpecies, Vphase->m_gasPhase); - plogf("%16s %8d %16e ", Vphase->eos_name(), - Vphase->nSpecies(), Vphase->totalMolesInert()); - if (m_doEstimateEquil >= 0) { - plogf("%16e\n", Vphase->totalMoles()); - } else { - plogf(" N/A\n"); - } - } - - plogf("\nElemental Abundances: "); - plogf(" Target_kmol ElemType ElActive\n"); - for (size_t i = 0; i < m_nelem; ++i) { - writeline(' ', 26, false); - plogf("%-2.2s", m_elementName[i]); - plogf("%20.12E ", m_elemAbundancesGoal[i]); - plogf("%3d %3d\n", m_elType[i], m_elementActive[i]); - } - - plogf("\nChemical Potentials: (J/kmol)\n"); - plogf(" Species (phase) " - " SS0ChemPot StarChemPot\n"); - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); - Vphase->setState_TP(m_temperature, m_pressurePA); - for (size_t kindex = 0; kindex < Vphase->nSpecies(); kindex++) { - size_t kglob = Vphase->spGlobalIndexVCS(kindex); - plogf("%16s ", m_mix->speciesName(kglob)); - if (kindex == 0) { - plogf("%16s", Vphase->PhaseName); - } else { - plogf(" "); - } - - plogf("%16g %16g\n", Vphase->G0_calc_one(kindex), - Vphase->GStar_calc_one(kindex)); - } - } - writeline('=', 80, true, true); - writeline('=', 20, false); - plogf(" VCS_PROB: END OF PROBLEM STATEMENT "); - writeline('=', 24); - writeline('=', 80); - plogf("\n"); - } -} - -void VCS_SOLVE::addPhaseElements(vcs_VolPhase* volPhase) -{ - size_t neVP = volPhase->nElemConstraints(); - // Loop through the elements in the vol phase object - for (size_t eVP = 0; eVP < neVP; eVP++) { - size_t foundPos = npos; - std::string enVP = volPhase->elementName(eVP); - - // Search for matches with the existing elements. If found, then fill in - // the entry in the global mapping array. - for (size_t e = 0; e < m_nelem; e++) { - std::string en = m_elementName[e]; - if (!strcmp(enVP.c_str(), en.c_str())) { - volPhase->setElemGlobalIndex(eVP, e); - foundPos = e; - } - } - if (foundPos == npos) { - int elType = volPhase->elementType(eVP); - int elactive = volPhase->elementActive(eVP); - size_t e = addElement(enVP.c_str(), elType, elactive); - volPhase->setElemGlobalIndex(eVP, e); - } - } -} - -size_t VCS_SOLVE::addElement(const char* elNameNew, int elType, int elactive) -{ - if (!elNameNew) { - throw CanteraError("VCS_SOLVE::addElement", - "error: element must have a name"); - } - m_nelem++; - m_numComponents++; - - m_formulaMatrix.resize(m_nsp, m_nelem, 0.0); - m_stoichCoeffRxnMatrix.resize(m_nelem, m_nsp, 0.0); - m_elType.push_back(elType); - m_elementActive.push_back(elactive); - m_elemAbundances.push_back(0.0); - m_elemAbundancesGoal.push_back(0.0); - m_elementMapIndex.push_back(0); - m_elementName.push_back(elNameNew); - return m_nelem - 1; -} - -size_t VCS_SOLVE::addOnePhaseSpecies(vcs_VolPhase* volPhase, size_t k, size_t kT) -{ - if (kT > m_nsp) { - // Need to expand the number of species here - throw CanteraError("VCS_SOLVE::addOnePhaseSpecies", "Shouldn't be here"); - } - const Array2D& fm = volPhase->getFormulaMatrix(); - for (size_t eVP = 0; eVP < volPhase->nElemConstraints(); eVP++) { - size_t e = volPhase->elemGlobalIndex(eVP); - AssertThrowMsg(e != npos, "VCS_PROB::addOnePhaseSpecies", - "element not found"); - m_formulaMatrix(kT,e) = fm(k,eVP); - } - - // Tell the phase object about the current position of the species within - // the global species vector - volPhase->setSpGlobalIndexVCS(k, kT); - return kT; -} - -} diff --git a/src/equil/vcs_report.cpp b/src/equil/vcs_report.cpp deleted file mode 100644 index 348ee7def3..0000000000 --- a/src/equil/vcs_report.cpp +++ /dev/null @@ -1,324 +0,0 @@ -//! @file vcs_report.cpp - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" -#include "cantera/base/ctexceptions.h" - -namespace Cantera -{ -int VCS_SOLVE::vcs_report(int iconv) -{ - bool inertYes = false; - - // SORT DEPENDENT SPECIES IN DECREASING ORDER OF MOLES - std::vector> x_order; - for (size_t i = 0; i < m_nsp; i++) { - x_order.push_back({-m_molNumSpecies_old[i], i}); - } - std::sort(x_order.begin() + m_numComponents, - x_order.begin() + m_numSpeciesRdc); - - vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD); - vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_nsp); - - // PRINT OUT RESULTS - plogf("\n\n\n\n"); - writeline('-', 80); - writeline('-', 80); - plogf("\t\t VCS_TP REPORT\n"); - writeline('-', 80); - writeline('-', 80); - if (iconv < 0) { - plogf(" ERROR: CONVERGENCE CRITERION NOT SATISFIED.\n"); - } else if (iconv == 1) { - plogf(" RANGE SPACE ERROR: Equilibrium Found but not all Element Abundances are Satisfied\n"); - } - - // Calculate some quantities that may need updating - vcs_tmoles(); - m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA, - &m_molNumSpecies_old[0], &m_PMVolumeSpecies[0]); - - plogf("\t\tTemperature = %15.2g Kelvin\n", m_temperature); - plogf("\t\tPressure = %15.5g Pa \n", m_pressurePA); - plogf("\t\ttotal Volume = %15.5g m**3\n", m_totalVol); - - // TABLE OF SPECIES IN DECREASING MOLE NUMBERS - plogf("\n\n"); - writeline('-', 80); - plogf(" Species Equilibrium kmoles "); - plogf("Mole Fraction ChemPot/RT SpecUnkType\n"); - writeline('-', 80); - for (size_t i = 0; i < m_numComponents; ++i) { - plogf(" %-12.12s", m_speciesName[i]); - writeline(' ', 13, false); - plogf("%14.7E %14.7E %12.4E", m_molNumSpecies_old[i], - m_molNumSpecies_new[i], m_feSpecies_old[i]); - plogf(" %3d", m_speciesUnknownType[i]); - plogf("\n"); - } - for (size_t i = m_numComponents; i < m_numSpeciesRdc; ++i) { - size_t j = x_order[i].second; - plogf(" %-12.12s", m_speciesName[j]); - writeline(' ', 13, false); - - if (m_speciesUnknownType[j] == VCS_SPECIES_TYPE_MOLNUM) { - plogf("%14.7E %14.7E %12.4E", m_molNumSpecies_old[j], - m_molNumSpecies_new[j], m_feSpecies_old[j]); - plogf(" KMolNum "); - } else if (m_speciesUnknownType[j] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - plogf(" NA %14.7E %12.4E", 1.0, m_feSpecies_old[j]); - plogf(" Voltage = %14.7E", m_molNumSpecies_old[j]); - } else { - throw CanteraError("VCS_SOLVE::vcs_report", "we have a problem"); - } - plogf("\n"); - } - for (size_t i = 0; i < m_numPhases; i++) { - if (TPhInertMoles[i] > 0.0) { - inertYes = true; - if (i == 0) { - plogf(" Inert Gas Species "); - } else { - plogf(" Inert Species in phase %16s ", - m_VolPhaseList[i]->PhaseName); - } - plogf("%14.7E %14.7E %12.4E\n", TPhInertMoles[i], - TPhInertMoles[i] / m_tPhaseMoles_old[i], 0.0); - } - } - if (m_numSpeciesRdc != m_nsp) { - plogf("\n SPECIES WITH LESS THAN 1.0E-32 KMOLES:\n\n"); - for (size_t kspec = m_numSpeciesRdc; kspec < m_nsp; ++kspec) { - plogf(" %-12.12s", m_speciesName[kspec]); - // Note m_deltaGRxn_new[] stores in kspec slot not irxn slot, after solve - plogf(" %14.7E %14.7E %12.4E", - m_molNumSpecies_old[kspec], - m_molNumSpecies_new[kspec], m_deltaGRxn_new[kspec]); - if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { - plogf(" KMol_Num"); - } else if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - plogf(" Voltage"); - } else { - plogf(" Unknown"); - } - plogf("\n"); - } - } - writeline('-', 80); - plogf("\n"); - - // TABLE OF SPECIES FORMATION REACTIONS - writeline('-', m_numComponents*10 + 45, true, true); - plogf(" |ComponentID|"); - for (size_t j = 0; j < m_numComponents; j++) { - plogf(" %3d", j); - } - plogf(" | |\n"); - plogf(" | Components|"); - for (size_t j = 0; j < m_numComponents; j++) { - plogf(" %10.10s", m_speciesName[j]); - } - plogf(" | |\n"); - plogf(" NonComponent | Moles |"); - for (size_t j = 0; j < m_numComponents; j++) { - plogf(" %10.3g", m_molNumSpecies_old[j]); - } - plogf(" | DG/RT Rxn |\n"); - writeline('-', m_numComponents*10 + 45); - for (size_t irxn = 0; irxn < m_numRxnTot; irxn++) { - size_t kspec = m_indexRxnToSpecies[irxn]; - plogf(" %3d ", kspec); - plogf("%-10.10s", m_speciesName[kspec]); - plogf("|%10.3g |", m_molNumSpecies_old[kspec]); - for (size_t j = 0; j < m_numComponents; j++) { - plogf(" %6.2f", m_stoichCoeffRxnMatrix(j,irxn)); - } - plogf(" |%10.3g |", m_deltaGRxn_new[irxn]); - plogf("\n"); - } - writeline('-', m_numComponents*10 + 45); - plogf("\n"); - - // TABLE OF PHASE INFORMATION - vector_fp gaPhase(m_nelem, 0.0); - vector_fp gaTPhase(m_nelem, 0.0); - double totalMoles = 0.0; - double gibbsPhase = 0.0; - double gibbsTotal = 0.0; - plogf("\n\n"); - plogf("\n"); - writeline('-', m_nelem*10 + 58); - plogf(" | ElementID |"); - for (size_t j = 0; j < m_nelem; j++) { - plogf(" %3d", j); - } - plogf(" | |\n"); - plogf(" | Element |"); - for (size_t j = 0; j < m_nelem; j++) { - plogf(" %10.10s", m_elementName[j]); - } - plogf(" | |\n"); - plogf(" PhaseName |KMolTarget |"); - for (size_t j = 0; j < m_nelem; j++) { - plogf(" %10.3g", m_elemAbundancesGoal[j]); - } - plogf(" | Gibbs Total |\n"); - writeline('-', m_nelem*10 + 58); - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - plogf(" %3d ", iphase); - vcs_VolPhase* VPhase = m_VolPhaseList[iphase].get(); - plogf("%-12.12s |",VPhase->PhaseName); - plogf("%10.3e |", m_tPhaseMoles_old[iphase]); - totalMoles += m_tPhaseMoles_old[iphase]; - if (m_tPhaseMoles_old[iphase] != VPhase->totalMoles() && - !vcs_doubleEqual(m_tPhaseMoles_old[iphase], VPhase->totalMoles())) { - throw CanteraError("VCS_SOLVE::vcs_report", "we have a problem"); - } - vcs_elabPhase(iphase, &gaPhase[0]); - for (size_t j = 0; j < m_nelem; j++) { - plogf(" %10.3g", gaPhase[j]); - gaTPhase[j] += gaPhase[j]; - } - gibbsPhase = vcs_GibbsPhase(iphase, &m_molNumSpecies_old[0], - &m_feSpecies_old[0]); - gibbsTotal += gibbsPhase; - plogf(" | %18.11E |\n", gibbsPhase); - } - writeline('-', m_nelem*10 + 58); - plogf(" TOTAL |%10.3e |", totalMoles); - for (size_t j = 0; j < m_nelem; j++) { - plogf(" %10.3g", gaTPhase[j]); - } - plogf(" | %18.11E |\n", gibbsTotal); - - writeline('-', m_nelem*10 + 58); - plogf("\n"); - - // GLOBAL SATISFACTION INFORMATION - - // Calculate the total dimensionless Gibbs Free Energy. Inert species are - // handled as if they had a standard free energy of zero - double g = vcs_Total_Gibbs(&m_molNumSpecies_old[0], &m_feSpecies_old[0], - &m_tPhaseMoles_old[0]); - plogf("\n\tTotal Dimensionless Gibbs Free Energy = G/RT = %15.7E\n", g); - if (inertYes) { - plogf("\t\t(Inert species have standard free energy of zero)\n"); - } - - plogf("\nElemental Abundances (kmol): "); - plogf(" Actual Target Type ElActive\n"); - for (size_t i = 0; i < m_nelem; ++i) { - writeline(' ', 26, false); - plogf("%-2.2s", m_elementName[i]); - plogf("%20.12E %20.12E", m_elemAbundances[i], m_elemAbundancesGoal[i]); - plogf(" %3d %3d\n", m_elType[i], m_elementActive[i]); - } - plogf("\n"); - - // TABLE OF SPECIES CHEM POTS - writeline('-', 93, true, true); - plogf("Chemical Potentials of the Species: (dimensionless)\n"); - - plogf("\t\t(RT = %g J/kmol)\n", GasConstant * m_temperature); - plogf(" Name TKMoles StandStateChemPot " - " ln(AC) ln(X_i) | F z_i phi | ChemPot | (-lnMnaught)"); - plogf("| (MolNum ChemPot)|"); - writeline('-', 147, true, true); - for (size_t i = 0; i < m_nsp; ++i) { - size_t j = x_order[i].second; - size_t pid = m_phaseID[j]; - plogf(" %-12.12s", m_speciesName[j]); - plogf(" %14.7E ", m_molNumSpecies_old[j]); - plogf("%14.7E ", m_SSfeSpecies[j]); - plogf("%14.7E ", log(m_actCoeffSpecies_old[j])); - double tpmoles = m_tPhaseMoles_old[pid]; - double phi = m_phasePhi[pid]; - double eContrib = phi * m_chargeSpecies[j] * m_Faraday_dim; - double lx = 0.0; - if (m_speciesUnknownType[j] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - lx = 0.0; - } else { - if (tpmoles > 0.0 && m_molNumSpecies_old[j] > 0.0) { - double tmp = std::max(VCS_DELETE_MINORSPECIES_CUTOFF, m_molNumSpecies_old[j]); - lx = log(tmp) - log(tpmoles); - } else { - lx = m_feSpecies_old[j] - m_SSfeSpecies[j] - - log(m_actCoeffSpecies_old[j]) + m_lnMnaughtSpecies[j]; - } - } - plogf("%14.7E |", lx); - plogf("%14.7E | ", eContrib); - double tmp = m_SSfeSpecies[j] + log(m_actCoeffSpecies_old[j]) - + lx - m_lnMnaughtSpecies[j] + eContrib; - if (fabs(m_feSpecies_old[j] - tmp) > 1.0E-7) { - throw CanteraError("VCS_SOLVE::vcs_report", - "we have a problem - doesn't add up"); - } - plogf(" %12.4E |", m_feSpecies_old[j]); - if (m_lnMnaughtSpecies[j] != 0.0) { - plogf("(%11.5E)", - m_lnMnaughtSpecies[j]); - } else { - plogf(" "); - } - - plogf("| %20.9E |", m_feSpecies_old[j] * m_molNumSpecies_old[j]); - plogf("\n"); - } - for (size_t i = 0; i < 125; i++) { - plogf(" "); - } - plogf(" %20.9E\n", g); - writeline('-', 147); - - // TABLE OF SOLUTION COUNTERS - plogf("\n"); - plogf("\nCounters: Iterations Time (seconds)\n"); - if (m_timing_print_lvl > 0) { - plogf(" vcs_basopt: %5d %11.5E\n", - m_VCount->Basis_Opts, m_VCount->Time_basopt); - plogf(" vcs_TP: %5d %11.5E\n", - m_VCount->Its, m_VCount->Time_vcs_TP); - } else { - plogf(" vcs_basopt: %5d %11s\n", - m_VCount->Basis_Opts," NA "); - plogf(" vcs_TP: %5d %11s\n", - m_VCount->Its," NA "); - } - writeline('-', 80); - writeline('-', 80); - - // Return a successful completion flag - return VCS_SUCCESS; -} - -void VCS_SOLVE::vcs_TCounters_report(int timing_print_lvl) -{ - plogf("\nTCounters: Num_Calls Total_Its Total_Time (seconds)\n"); - if (timing_print_lvl > 0) { - plogf(" vcs_basopt: %5d %5d %11.5E\n", - m_VCount->T_Basis_Opts, m_VCount->T_Basis_Opts, - m_VCount->T_Time_basopt); - plogf(" vcs_TP: %5d %5d %11.5E\n", - m_VCount->T_Calls_vcs_TP, m_VCount->T_Its, - m_VCount->T_Time_vcs_TP); - plogf(" vcs_inest: %5d %11.5E\n", - m_VCount->T_Calls_Inest, m_VCount->T_Time_inest); - plogf(" vcs_TotalTime: %11.5E\n", - m_VCount->T_Time_vcs); - } else { - plogf(" vcs_basopt: %5d %5d %11s\n", - m_VCount->T_Basis_Opts, m_VCount->T_Basis_Opts," NA "); - plogf(" vcs_TP: %5d %5d %11s\n", - m_VCount->T_Calls_vcs_TP, m_VCount->T_Its," NA "); - plogf(" vcs_inest: %5d %11s\n", - m_VCount->T_Calls_Inest, " NA "); - plogf(" vcs_TotalTime: %11s\n", - " NA "); - } -} - -} diff --git a/src/equil/vcs_rxnadj.cpp b/src/equil/vcs_rxnadj.cpp deleted file mode 100644 index 66328cb1ea..0000000000 --- a/src/equil/vcs_rxnadj.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/** - * @file vcs_rxnadj.cpp - * Routines for carrying out various adjustments to the reaction steps - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" -#include "cantera/equil/vcs_VolPhase.h" -#include "cantera/base/ctexceptions.h" - -#include - -namespace Cantera -{ - -size_t VCS_SOLVE::vcs_RxnStepSizes(int& forceComponentCalc, size_t& kSpecial) -{ - size_t iphDel = npos; - size_t k = 0; - std::string ANOTE; - if (m_debug_print_lvl >= 2) { - plogf(" "); - for (int j = 0; j < 82; j++) { - plogf("-"); - } - plogf("\n"); - plogf(" --- Subroutine vcs_RxnStepSizes called - Details:\n"); - plogf(" "); - for (int j = 0; j < 82; j++) { - plogf("-"); - } - plogf("\n"); - plogf(" --- Species KMoles Rxn_Adjustment DeltaG" - " | Comment\n"); - } - - // We update the matrix dlnActCoeffdmolNumber[][] at the top of the loop, - // when necessary - if (m_useActCoeffJac) { - vcs_CalcLnActCoeffJac(&m_molNumSpecies_old[0]); - } - - // LOOP OVER THE FORMATION REACTIONS - for (size_t irxn = 0; irxn < m_numRxnRdc; ++irxn) { - ANOTE = "Normal Calc"; - - size_t kspec = m_indexRxnToSpecies[irxn]; - if (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) { - m_deltaMolNumSpecies[kspec] = 0.0; - ANOTE = "ZeroedPhase: Phase is artificially zeroed"; - } else if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - if (m_molNumSpecies_old[kspec] == 0.0 && (!m_SSPhase[kspec])) { - // MULTISPECIES PHASE WITH total moles equal to zero - // - // If dg[irxn] is negative, then the multispecies phase should - // come alive again. Add a small positive step size to make it - // come alive. - if (m_deltaGRxn_new[irxn] < -1.0e-4) { - // First decide if this species is part of a multiphase that - // is nontrivial in size. - size_t iph = m_phaseID[kspec]; - double tphmoles = m_tPhaseMoles_old[iph]; - double trphmoles = tphmoles / m_totalMolNum; - vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); - if (Vphase->exists() && (trphmoles > VCS_DELETE_PHASE_CUTOFF)) { - m_deltaMolNumSpecies[kspec] = m_totalMolNum * VCS_SMALL_MULTIPHASE_SPECIES; - if (m_speciesStatus[kspec] == VCS_SPECIES_STOICHZERO) { - m_deltaMolNumSpecies[kspec] = 0.0; - ANOTE = fmt::sprintf("MultSpec (%s): Species not born due to STOICH/PHASEPOP even though DG = %11.3E", - vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); - } else { - m_deltaMolNumSpecies[kspec] = m_totalMolNum * VCS_SMALL_MULTIPHASE_SPECIES * 10.0; - ANOTE = fmt::sprintf("MultSpec (%s): small species born again DG = %11.3E", - vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); - } - } else { - ANOTE = fmt::sprintf("MultSpec (%s):still dead, no phase pop, even though DG = %11.3E", - vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); - m_deltaMolNumSpecies[kspec] = 0.0; - if (Vphase->exists() > 0 && trphmoles > 0.0) { - m_deltaMolNumSpecies[kspec] = m_totalMolNum * VCS_SMALL_MULTIPHASE_SPECIES * 10.; - ANOTE = fmt::sprintf("MultSpec (%s): birthed species because it was zero in a small existing phase with DG = %11.3E", - vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); - } - } - } else { - ANOTE = fmt::sprintf("MultSpec (%s): still dead DG = %11.3E", - vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); - m_deltaMolNumSpecies[kspec] = 0.0; - } - } else { - // REGULAR PROCESSING - // - // First take care of cases where we want to bail out. Don't - // bother if superconvergence has already been achieved in this - // mode. - if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) { - ANOTE = fmt::sprintf("Skipped: superconverged DG = %11.3E", m_deltaGRxn_new[irxn]); - if (m_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", m_speciesName[kspec]); - plogf(" %12.4E %12.4E %12.4E | %s\n", - m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], - m_deltaGRxn_new[irxn], ANOTE); - } - continue; - } - - // Don't calculate for minor or nonexistent species if their - // values are to be decreasing anyway. - if ((m_speciesStatus[kspec] != VCS_SPECIES_MAJOR) && (m_deltaGRxn_new[irxn] >= 0.0)) { - ANOTE = fmt::sprintf("Skipped: IC = %3d and DG >0: %11.3E", - m_speciesStatus[kspec], m_deltaGRxn_new[irxn]); - if (m_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", m_speciesName[kspec]); - plogf(" %12.4E %12.4E %12.4E | %s\n", - m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], - m_deltaGRxn_new[irxn], ANOTE); - } - continue; - } - - // Start of the regular processing - double s; - if (m_SSPhase[kspec]) { - s = 0.0; - } else { - s = 1.0 / m_molNumSpecies_old[kspec]; - } - for (size_t j = 0; j < m_numComponents; ++j) { - if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) { - s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j]; - } - } - for (size_t j = 0; j < m_numPhases; j++) { - vcs_VolPhase* Vphase = m_VolPhaseList[j].get(); - if (!Vphase->m_singleSpecies && m_tPhaseMoles_old[j] > 0.0) { - s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j]; - } - } - if (s != 0.0) { - // Take into account of the derivatives of the activity - // coefficients with respect to the mole numbers, even in - // our diagonal approximation. - if (m_useActCoeffJac) { - double s_old = s; - s = vcs_Hessian_diag_adj(irxn, s_old); - ANOTE = fmt::sprintf("Normal calc: diag adjusted from %g " - "to %g due to act coeff", s_old, s); - } - - m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s; - // New section to do damping of the m_deltaMolNumSpecies[] - for (size_t j = 0; j < m_numComponents; ++j) { - double stoicC = m_stoichCoeffRxnMatrix(j,irxn); - if (stoicC != 0.0) { - double negChangeComp = -stoicC * m_deltaMolNumSpecies[kspec]; - if (negChangeComp > m_molNumSpecies_old[j]) { - if (m_molNumSpecies_old[j] > 0.0) { - ANOTE = fmt::sprintf("Delta damped from %g " - "to %g due to component %d (%10s) going neg", m_deltaMolNumSpecies[kspec], - -m_molNumSpecies_old[j] / stoicC, j, m_speciesName[j]); - m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[j] / stoicC; - } else { - ANOTE = fmt::sprintf("Delta damped from %g " - "to %g due to component %d (%10s) zero", m_deltaMolNumSpecies[kspec], - -m_molNumSpecies_old[j] / stoicC, j, m_speciesName[j]); - m_deltaMolNumSpecies[kspec] = 0.0; - } - } - } - } - // Implement a damping term that limits m_deltaMolNumSpecies - // to the size of the mole number - if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) { - ANOTE = fmt::sprintf("Delta damped from %g " - "to %g due to %s going negative", m_deltaMolNumSpecies[kspec], -m_molNumSpecies_old[kspec], - m_speciesName[kspec]); - m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; - } - } else { - // REACTION IS ENTIRELY AMONGST SINGLE SPECIES PHASES. - // DELETE ONE OF THE PHASES AND RECOMPUTE BASIS. - // - // Either the species L will disappear or one of the - // component single species phases will disappear. The sign - // of DG(I) will indicate which way the reaction will go. - // Then, we need to follow the reaction to see which species - // will zero out first. The species to be zeroed out will be - // "k". - double dss; - if (m_deltaGRxn_new[irxn] > 0.0) { - dss = m_molNumSpecies_old[kspec]; - k = kspec; - for (size_t j = 0; j < m_numComponents; ++j) { - if (m_stoichCoeffRxnMatrix(j,irxn) > 0.0) { - double xx = m_molNumSpecies_old[j] / m_stoichCoeffRxnMatrix(j,irxn); - if (xx < dss) { - dss = xx; - k = j; - } - } - } - dss = -dss; - } else { - dss = 1.0e10; - for (size_t j = 0; j < m_numComponents; ++j) { - if (m_stoichCoeffRxnMatrix(j,irxn) < 0.0) { - double xx = -m_molNumSpecies_old[j] / m_stoichCoeffRxnMatrix(j,irxn); - if (xx < dss) { - dss = xx; - k = j; - } - } - } - } - - // Here we adjust the mole fractions according to DSS and - // the stoichiometric array to take into account that we are - // eliminating the kth species. DSS contains the amount of - // moles of the kth species that needs to be added back into - // the component species. - if (dss != 0.0) { - 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. - ANOTE = fmt::sprintf("Delta damped from %g to %g due to delete %s", m_deltaMolNumSpecies[kspec], - -m_molNumSpecies_old[kspec], m_speciesName[kspec]); - m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; - if (m_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", m_speciesName[kspec]); - plogf(" %12.4E %12.4E %12.4E | %s\n", - m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], - m_deltaGRxn_new[irxn], ANOTE); - } - continue; - } - - // Delete the single species phase - for (size_t j = 0; j < m_nsp; j++) { - m_deltaMolNumSpecies[j] = 0.0; - } - m_deltaMolNumSpecies[kspec] = dss; - for (size_t j = 0; j < m_numComponents; ++j) { - m_deltaMolNumSpecies[j] = dss * m_stoichCoeffRxnMatrix(j,irxn); - } - - iphDel = m_phaseID[k]; - kSpecial = k; - - if (k != kspec) { - ANOTE = fmt::sprintf("Delete component SS phase %d named %s - SS phases only", - iphDel, m_speciesName[k]); - } else { - ANOTE = fmt::sprintf("Delete this SS phase %d - SS components only", iphDel); - } - if (m_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", m_speciesName[kspec]); - 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\n", - m_speciesName[k]); - } - if (k != kspec) { - forceComponentCalc = 1; - debuglog(" --- Force a component recalculation\n\n", m_debug_print_lvl >= 2); - } - if (m_debug_print_lvl >= 2) { - plogf(" "); - writeline('-', 82); - } - return iphDel; - } - } - } // End of regular processing - if (m_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", m_speciesName[kspec]); - plogf(" %12.4E %12.4E %12.4E | %s\n", - m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], - m_deltaGRxn_new[irxn], ANOTE); - } - } // End of loop over m_speciesUnknownType - } // End of loop over non-component stoichiometric formation reactions - if (m_debug_print_lvl >= 2) { - plogf(" "); - writeline('-', 82); - } - return iphDel; -} - -double VCS_SOLVE::vcs_Hessian_diag_adj(size_t irxn, double hessianDiag_Ideal) -{ - double diag = hessianDiag_Ideal; - double hessActCoef = vcs_Hessian_actCoeff_diag(irxn); - if (hessianDiag_Ideal <= 0.0) { - throw CanteraError("VCS_SOLVE::vcs_Hessian_diag_adj", - "We shouldn't be here"); - } - if (hessActCoef >= 0.0) { - diag += hessActCoef; - } else if (fabs(hessActCoef) < 0.6666 * hessianDiag_Ideal) { - diag += hessActCoef; - } else { - diag -= 0.6666 * hessianDiag_Ideal; - } - return diag; -} - -double VCS_SOLVE::vcs_Hessian_actCoeff_diag(size_t irxn) -{ - size_t kspec = m_indexRxnToSpecies[irxn]; - size_t kph = m_phaseID[kspec]; - double np_kspec = std::max(m_tPhaseMoles_old[kph], 1e-13); - double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn); - - // First the diagonal term of the Jacobian - double s = m_np_dLnActCoeffdMolNum(kspec,kspec) / np_kspec; - - // Next, the other terms. Note this only a loop over the components So, it's - // not too expensive to calculate. - for (size_t j = 0; j < m_numComponents; j++) { - if (!m_SSPhase[j]) { - for (size_t k = 0; k < m_numComponents; ++k) { - if (m_phaseID[k] == m_phaseID[j]) { - double np = m_tPhaseMoles_old[m_phaseID[k]]; - if (np > 0.0) { - s += sc_irxn[k] * sc_irxn[j] * m_np_dLnActCoeffdMolNum(j,k) / np; - } - } - } - if (kph == m_phaseID[j]) { - s += sc_irxn[j] * (m_np_dLnActCoeffdMolNum(j,kspec) + m_np_dLnActCoeffdMolNum(kspec,j)) / np_kspec; - } - } - } - return s; -} - -void VCS_SOLVE::vcs_CalcLnActCoeffJac(const double* const moleSpeciesVCS) -{ - // Loop over all of the phases in the problem - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); - - // We don't need to call single species phases; - if (!Vphase->m_singleSpecies && !Vphase->isIdealSoln()) { - // update the mole numbers - Vphase->setMolesFromVCS(VCS_STATECALC_OLD, moleSpeciesVCS); - - // Download the resulting calculation into the full vector. This - // scatter calculation is carried out in the vcs_VolPhase object. - Vphase->sendToVCS_LnActCoeffJac(m_np_dLnActCoeffdMolNum); - } - } -} - -} diff --git a/src/equil/vcs_setMolesLinProg.cpp b/src/equil/vcs_setMolesLinProg.cpp deleted file mode 100644 index 72cecf0887..0000000000 --- a/src/equil/vcs_setMolesLinProg.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/*! - * @file vcs_setMolesLinProg.cpp - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_solve.h" - -using namespace std; - -namespace Cantera -{ - -static void printProgress(const vector &spName, - const vector_fp &soln, - const vector_fp &ff) -{ - double sum = 0.0; - plogf(" --- Summary of current progress:\n"); - plogf(" --- Name Moles - SSGibbs \n"); - plogf(" -------------------------------------------------------------------------------------\n"); - for (size_t k = 0; k < soln.size(); k++) { - plogf(" --- %20s %12.4g - %12.4g\n", spName[k], soln[k], ff[k]); - sum += soln[k] * ff[k]; - } - plogf(" --- Total sum to be minimized = %g\n", sum); -} - -int VCS_SOLVE::vcs_setMolesLinProg() -{ - double test = -1.0E-10; - - if (m_debug_print_lvl >= 2) { - plogf(" --- call setInitialMoles\n"); - } - - double dxi_min = 1.0e10; - int retn; - int iter = 0; - bool abundancesOK = true; - bool usedZeroedSpecies; - vector_fp sm(m_nelem * m_nelem, 0.0); - vector_fp ss(m_nelem, 0.0); - vector_fp sa(m_nelem, 0.0); - vector_fp wx(m_nelem, 0.0); - vector_fp aw(m_nsp, 0.0); - - for (size_t ik = 0; ik < m_nsp; ik++) { - if (m_speciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) { - m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]); - } - } - - if (m_debug_print_lvl >= 2) { - printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); - } - - bool redo = true; - while (redo) { - if (!vcs_elabcheck(0)) { - if (m_debug_print_lvl >= 2) { - plogf(" --- seMolesLinProg Mole numbers failing element abundances\n"); - plogf(" --- seMolesLinProg Call vcs_elcorr to attempt fix\n"); - } - retn = vcs_elcorr(&sm[0], &wx[0]); - if (retn >= 2) { - abundancesOK = false; - } else { - abundancesOK = true; - } - } else { - abundancesOK = true; - } - - // Now find the optimized basis that spans the stoichiometric - // coefficient matrix, based on the current composition, - // m_molNumSpecies_old[] We also calculate sc[][], the reaction matrix. - retn = vcs_basopt(false, &aw[0], &sa[0], &sm[0], &ss[0], - test, &usedZeroedSpecies); - if (retn != VCS_SUCCESS) { - return retn; - } - - if (m_debug_print_lvl >= 2) { - plogf("iteration %d\n", iter); - } - redo = false; - iter++; - if (iter > 15) { - break; - } - - // loop over all reactions - for (size_t irxn = 0; irxn < m_numRxnTot; irxn++) { - // dg_rt is the Delta_G / RT value for the reaction - size_t ik = m_numComponents + irxn; - double dg_rt = m_SSfeSpecies[ik]; - dxi_min = 1.0e10; - const double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn); - for (size_t jcomp = 0; jcomp < m_nelem; jcomp++) { - dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp]; - } - // fwd or rev direction. - // idir > 0 implies increasing the current species - // idir < 0 implies decreasing the current species - int idir = (dg_rt < 0.0 ? 1 : -1); - if (idir < 0) { - dxi_min = m_molNumSpecies_old[ik]; - } - - for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) { - double nu = sc_irxn[jcomp]; - // set max change in progress variable by - // non-negativity requirement - if (nu*idir < 0) { - double delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu); - // if a component has nearly zero moles, redo - // with a new set of components - if (!redo && delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) { - if (m_debug_print_lvl >= 2) { - plogf(" --- Component too small: %s\n", m_speciesName[jcomp]); - } - redo = true; - } - dxi_min = std::min(dxi_min, delta_xi); - } - } - - // step the composition by dxi_min, check against zero, since - // we are zeroing components and species on every step. - // Redo the iteration, if a component went from positive to zero on this step. - double dsLocal = idir*dxi_min; - m_molNumSpecies_old[ik] += dsLocal; - m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]); - for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) { - bool full = false; - if (m_molNumSpecies_old[jcomp] > 1.0E-15) { - full = true; - } - m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal; - m_molNumSpecies_old[jcomp] = max(0.0, m_molNumSpecies_old[jcomp]); - if (full && m_molNumSpecies_old[jcomp] < 1.0E-60) { - redo = true; - } - } - } - - if (m_debug_print_lvl >= 2) { - printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); - } - } - - if (m_debug_print_lvl == 1) { - printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); - plogf(" --- setInitialMoles end\n"); - } - retn = 0; - if (!abundancesOK) { - retn = -1; - } else if (iter > 15) { - retn = 1; - } - return retn; -} - -} diff --git a/src/equil/vcs_solve.cpp b/src/equil/vcs_solve.cpp index 526854d2f0..7975b16aa4 100644 --- a/src/equil/vcs_solve.cpp +++ b/src/equil/vcs_solve.cpp @@ -13,12 +13,31 @@ #include "cantera/equil/vcs_species_thermo.h" #include "cantera/base/clockWC.h" #include "cantera/equil/MultiPhase.h" +#include "cantera/thermo/speciesThermoTypes.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; namespace Cantera { +namespace { + +void printProgress(const vector& spName, const vector_fp& soln, const vector_fp& ff) +{ + double sum = 0.0; + plogf(" --- Summary of current progress:\n"); + plogf(" --- Name Moles - SSGibbs \n"); + plogf(" -------------------------------------------------------------------------------------\n"); + for (size_t k = 0; k < soln.size(); k++) { + plogf(" --- %20s %12.4g - %12.4g\n", spName[k], soln[k], ff[k]); + sum += soln[k] * ff[k]; + } + plogf(" --- Total sum to be minimized = %g\n", sum); +} + +} // anonymous namespace + int vcs_timing_print_lvl = 1; VCS_SOLVE::VCS_SOLVE(MultiPhase* mphase, int printLvl) : @@ -473,17 +492,6 @@ VCS_SOLVE::~VCS_SOLVE() vcs_delete_memory(); } -void VCS_SOLVE::vcs_delete_memory() -{ - delete m_VCount; - m_VCount = 0; - - m_nsp = 0; - m_nelem = 0; - m_numComponents = 0; - -} - int VCS_SOLVE::vcs(int ipr, int ip1, int maxit) { clockWC tickTock; @@ -536,138 +544,2926 @@ int VCS_SOLVE::vcs(int ipr, int ip1, int maxit) return iconv; } -void VCS_SOLVE::vcs_prob_specifyFully() +bool VCS_SOLVE::vcs_popPhasePossible(const size_t iphasePop) const { - // Whether we have an estimate or not gets overwritten on - // the call to the equilibrium solver. - m_temperature = m_mix->temperature(); - m_pressurePA = m_mix->pressure(); - m_Faraday_dim = Faraday / (m_temperature * GasConstant); - m_totalVol = m_mix->volume(); + vcs_VolPhase* Vphase = m_VolPhaseList[iphasePop].get(); + AssertThrowMsg(!Vphase->exists(), "VCS_SOLVE::vcs_popPhasePossible", + "called for a phase that exists!"); + + // Loop through all of the species in the phase. We say the phase can be + // popped, if there is one species in the phase that can be popped. This + // does not mean that the phase will be popped or that it leads to a lower + // Gibbs free energy. + for (size_t k = 0; k < Vphase->nSpecies(); k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + AssertThrowMsg(m_molNumSpecies_old[kspec] <= 0.0, + "VCS_SOLVE::vcs_popPhasePossible", + "we shouldn't be here {}: {} > 0.0", kspec, + m_molNumSpecies_old[kspec]); + size_t irxn = kspec - m_numComponents; + if (kspec >= m_numComponents) { + bool iPopPossible = true; + + // Note one case is if the component is a member of the popping + // phase. This component will be zeroed and the logic here will + // negate the current species from causing a positive if this + // component is consumed. + for (size_t j = 0; j < m_numComponents; ++j) { + if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + double stoicC = m_stoichCoeffRxnMatrix(j,irxn); + if (stoicC != 0.0) { + double negChangeComp = - stoicC; + if (negChangeComp > 0.0) { + // If there is no component to give, then the + // species can't be created + if (m_molNumSpecies_old[j] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + iPopPossible = false; + } + } + } + } + } + // We are here when the species can be popped because all its needed + // components have positive mole numbers + if (iPopPossible) { + return true; + } + } else { + // We are here when the species, k, 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. + for (size_t jrxn = 0; jrxn < m_numRxnRdc; jrxn++) { + bool foundJrxn = false; + // First, if the component is a product of the reaction + if (m_stoichCoeffRxnMatrix(kspec,jrxn) > 0.0) { + foundJrxn = true; + // We can do the reaction if all other reactant components + // have positive mole fractions + for (size_t kcomp = 0; kcomp < m_numComponents; kcomp++) { + if (m_stoichCoeffRxnMatrix(kcomp,jrxn) < 0.0 && m_molNumSpecies_old[kcomp] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + foundJrxn = false; + } + } + if (foundJrxn) { + return true; + } + } else if (m_stoichCoeffRxnMatrix(kspec,jrxn) < 0.0) { + // Second we are here if the component is a reactant in the + // reaction, and the reaction goes backwards. + foundJrxn = true; + size_t jspec = jrxn + m_numComponents; + if (m_molNumSpecies_old[jspec] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + foundJrxn = false; + continue; + } + // We can do the backwards reaction if all of the product + // components species are positive + for (size_t kcomp = 0; kcomp < m_numComponents; kcomp++) { + if (m_stoichCoeffRxnMatrix(kcomp,jrxn) > 0.0 && m_molNumSpecies_old[kcomp] <= VCS_DELETE_ELEMENTABS_CUTOFF*0.5) { + foundJrxn = false; + } + } + if (foundJrxn) { + return true; + } + } + } + } + } + return false; +} - vector invSpecies(m_nsp); - for (size_t k = 0; k < m_nsp; k++) { - invSpecies[m_speciesMapIndex[k]] = k; +size_t VCS_SOLVE::vcs_popPhaseID(std::vector & phasePopPhaseIDs) +{ + size_t iphasePop = npos; + double FephaseMax = -1.0E30; + double Fephase = -1.0E30; + + char anote[128]; + if (m_debug_print_lvl >= 2) { + plogf(" --- vcs_popPhaseID() called\n"); + plogf(" --- Phase Status F_e MoleNum\n"); + plogf(" --------------------------------------------------------------------------\n"); } + for (size_t iph = 0; iph < m_numPhases; iph++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); + int existence = Vphase->exists(); + strcpy(anote, ""); + if (existence > 0) { + if (m_debug_print_lvl >= 2) { + plogf(" --- %18s %5d NA %11.3e\n", + Vphase->PhaseName, existence, m_tPhaseMoles_old[iph]); + } + } else { + if (Vphase->m_singleSpecies) { + // Single Phase Stability Resolution + size_t kspec = Vphase->spGlobalIndexVCS(0); + size_t irxn = kspec - m_numComponents; + if (irxn > m_deltaGRxn_old.size()) { + throw CanteraError("VCS_SOLVE::vcs_popPhaseID", + "Index out of bounds due to logic error."); + } + double deltaGRxn = m_deltaGRxn_old[irxn]; + Fephase = exp(-deltaGRxn) - 1.0; + if (Fephase > 0.0) { + strcpy(anote," (ready to be birthed)"); + if (Fephase > FephaseMax) { + iphasePop = iph; + FephaseMax = Fephase; + strcpy(anote," (chosen to be birthed)"); + } + } + if (Fephase < 0.0) { + strcpy(anote," (not stable)"); + AssertThrowMsg(m_tPhaseMoles_old[iph] <= 0.0, + "VCS_SOLVE::vcs_popPhaseID", "shouldn't be here"); + } - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - ThermoPhase* tPhase = &m_mix->phase(iphase); - vcs_VolPhase* volPhase = m_VolPhaseList[iphase].get(); + if (m_debug_print_lvl >= 2) { + plogf(" --- %18s %5d %10.3g %10.3g %s\n", + Vphase->PhaseName, existence, Fephase, + m_tPhaseMoles_old[iph], anote); + } + } else { + // MultiSpecies Phase Stability Resolution + if (vcs_popPhasePossible(iph)) { + Fephase = vcs_phaseStabilityTest(iph); + if (Fephase > 0.0) { + if (Fephase > FephaseMax) { + iphasePop = iph; + FephaseMax = Fephase; + } + } else { + FephaseMax = std::max(FephaseMax, Fephase); + } + if (m_debug_print_lvl >= 2) { + plogf(" --- %18s %5d %11.3g %11.3g\n", + Vphase->PhaseName, existence, Fephase, + m_tPhaseMoles_old[iph]); + } + } else { + if (m_debug_print_lvl >= 2) { + plogf(" --- %18s %5d blocked %11.3g\n", + Vphase->PhaseName, + existence, m_tPhaseMoles_old[iph]); + } + } + } + } + } + phasePopPhaseIDs.resize(0); + if (iphasePop != npos) { + phasePopPhaseIDs.push_back(iphasePop); + } - volPhase->setState_TP(m_temperature, m_pressurePA); + // Insert logic here to figure out if phase pops are linked together. Only + // do one linked pop at a time. + if (m_debug_print_lvl >= 2) { + plogf(" ---------------------------------------------------------------------\n"); + } + return iphasePop; +} - // Loop through each species in the current phase - size_t nSpPhase = tPhase->nSpecies(); - if ((nSpPhase == 1) && (volPhase->phiVarIndex() == 0)) { - volPhase->setExistence(VCS_PHASE_EXIST_ALWAYS); - } else if (volPhase->totalMoles() > 0.0) { - volPhase->setExistence(VCS_PHASE_EXIST_YES); +int VCS_SOLVE::vcs_popPhaseRxnStepSizes(const size_t iphasePop) +{ + vcs_VolPhase* Vphase = m_VolPhaseList[iphasePop].get(); + // Identify the first species in the phase + size_t kspec = Vphase->spGlobalIndexVCS(0); + // Identify the formation reaction for that species + size_t irxn = kspec - m_numComponents; + std::vector creationGlobalRxnNumbers; + + // Calculate the initial moles of the phase being born. + // Here we set it to 10x of the value which would cause the phase to be + // zeroed out within the algorithm. We may later adjust the value. + double tPhaseMoles = 10. * m_totalMolNum * VCS_DELETE_PHASE_CUTOFF; + + AssertThrowMsg(!Vphase->exists(), "VCS_SOLVE::vcs_popPhaseRxnStepSizes", + "called for a phase that exists!"); + if (m_debug_print_lvl >= 2) { + plogf(" --- vcs_popPhaseRxnStepSizes() called to pop phase %s %d into existence\n", + Vphase->PhaseName, iphasePop); + } + // Section for a single-species phase + if (Vphase->m_singleSpecies) { + double s = 0.0; + for (size_t j = 0; j < m_numComponents; ++j) { + if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) { + s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j]; + } + } + for (size_t j = 0; j < m_numPhases; j++) { + Vphase = m_VolPhaseList[j].get(); + if (! Vphase->m_singleSpecies && m_tPhaseMoles_old[j] > 0.0) { + s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j]; + } + } + if (s != 0.0) { + double s_old = s; + s = vcs_Hessian_diag_adj(irxn, s_old); + m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s; } else { - volPhase->setExistence(VCS_PHASE_EXIST_NO); + // Ok, s is equal to zero. We can not apply a sophisticated theory + // to birth the phase. Just pick a small delta and go with it. + m_deltaMolNumSpecies[kspec] = tPhaseMoles; } - } - // Printout the species information: PhaseID's and mole nums - if (m_printLvl > 1) { - writeline('=', 80, true, true); - writeline('=', 20, false); - plogf(" Cantera_to_vprob: START OF PROBLEM STATEMENT "); - writeline('=', 20); - writeline('=', 80); - plogf("\n"); - plogf(" Phase IDs of species\n"); - plogf(" species phaseID phaseName "); - plogf(" Initial_Estimated_kMols\n"); - for (size_t i = 0; i < m_nsp; i++) { - size_t iphase = m_phaseID[i]; - vcs_VolPhase* VolPhase = m_VolPhaseList[iphase].get(); - plogf("%16s %5d %16s", m_speciesName[i].c_str(), iphase, - VolPhase->PhaseName.c_str()); - if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - plogf(" Volts = %-10.5g\n", m_molNumSpecies_old[i]); + // section to do damping of the m_deltaMolNumSpecies[] + for (size_t j = 0; j < m_numComponents; ++j) { + double stoicC = m_stoichCoeffRxnMatrix(j,irxn); + if (stoicC != 0.0 && m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + double negChangeComp = - stoicC * m_deltaMolNumSpecies[kspec]; + if (negChangeComp > m_molNumSpecies_old[j]) { + if (m_molNumSpecies_old[j] > 0.0) { + m_deltaMolNumSpecies[kspec] = - 0.5 * m_molNumSpecies_old[j] / stoicC; + } else { + m_deltaMolNumSpecies[kspec] = 0.0; + } + } + } + } + // Implement a damping term that limits m_deltaMolNumSpecies to the size + // of the mole number + if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) { + m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; + } + } else { + vector_fp fracDelta(Vphase->nSpecies()); + vector_fp X_est(Vphase->nSpecies()); + fracDelta = Vphase->creationMoleNumbers(creationGlobalRxnNumbers); + + double sumFrac = 0.0; + for (size_t k = 0; k < Vphase->nSpecies(); k++) { + sumFrac += fracDelta[k]; + } + for (size_t k = 0; k < Vphase->nSpecies(); k++) { + X_est[k] = fracDelta[k] / sumFrac; + } + + double deltaMolNumPhase = tPhaseMoles; + double damp = 1.0; + m_deltaGRxn_tmp = m_molNumSpecies_old; + double* molNumSpecies_tmp = m_deltaGRxn_tmp.data(); + + for (size_t k = 0; k < Vphase->nSpecies(); k++) { + kspec = Vphase->spGlobalIndexVCS(k); + double delmol = deltaMolNumPhase * X_est[k]; + if (kspec >= m_numComponents) { + irxn = kspec - m_numComponents; + if (irxn > m_stoichCoeffRxnMatrix.nColumns()) { + throw CanteraError("VCS_SOLVE::vcs_popPhaseRxnStepSizes", + "Index out of bounds due to logic error."); + } + for (size_t j = 0; j < m_numComponents; ++j) { + double stoicC = m_stoichCoeffRxnMatrix(j,irxn); + if (stoicC != 0.0 && m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + molNumSpecies_tmp[j] += stoicC * delmol; + } + } + } + } + + double ratioComp = 0.0; + for (size_t j = 0; j < m_numComponents; ++j) { + double deltaJ = m_molNumSpecies_old[j] - molNumSpecies_tmp[j]; + if (molNumSpecies_tmp[j] < 0.0) { + ratioComp = 1.0; + if (deltaJ > 0.0) { + double delta0 = m_molNumSpecies_old[j]; + damp = std::min(damp, delta0 / deltaJ * 0.9); + } } else { - plogf(" %-10.5g\n", m_molNumSpecies_old[i]); + if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + size_t jph = m_phaseID[j]; + if ((jph != iphasePop) && (!m_SSPhase[j])) { + double fdeltaJ = fabs(deltaJ); + if (m_molNumSpecies_old[j] > 0.0) { + ratioComp = std::max(ratioComp, fdeltaJ/ m_molNumSpecies_old[j]); + } + } + } } } - // Printout of the Phase structure information - writeline('-', 80, true, true); - plogf(" Information about phases\n"); - plogf(" PhaseName PhaseNum SingSpec GasPhase EqnState NumSpec"); - plogf(" TMolesInert Tmoles(kmol)\n"); + // We may have greatly underestimated the deltaMoles for the phase pop + // Here we create a damp > 1 to account for this possibility. We adjust + // upwards to make sure that a component in an existing multispecies + // phase is modified by a factor of 1/1000. + if (ratioComp > 1.0E-30 && ratioComp < 0.001) { + damp = 0.001 / ratioComp; + } + if (damp <= 1.0E-6) { + return 3; + } - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - vcs_VolPhase* VolPhase = m_VolPhaseList[iphase].get(); - plogf("%16s %5d %5d %8d %16s %8d %16e ", VolPhase->PhaseName.c_str(), - VolPhase->VP_ID_, VolPhase->m_singleSpecies, - VolPhase->m_gasPhase, VolPhase->eos_name(), - VolPhase->nSpecies(), VolPhase->totalMolesInert()); - plogf("%16e\n", VolPhase->totalMoles()); + for (size_t k = 0; k < Vphase->nSpecies(); k++) { + kspec = Vphase->spGlobalIndexVCS(k); + if (kspec < m_numComponents) { + m_speciesStatus[kspec] = VCS_SPECIES_COMPONENT; + } else { + m_deltaMolNumSpecies[kspec] = deltaMolNumPhase * X_est[k] * damp; + if (X_est[k] > 1.0E-3) { + m_speciesStatus[kspec] = VCS_SPECIES_MAJOR; + } else { + m_speciesStatus[kspec] = VCS_SPECIES_MINOR; + } + } } + } + return 0; +} - writeline('=', 80, true, true); - writeline('=', 20, false); - plogf(" Cantera_to_vprob: END OF PROBLEM STATEMENT "); - writeline('=', 20); - writeline('=', 80); +size_t VCS_SOLVE::vcs_RxnStepSizes(int& forceComponentCalc, size_t& kSpecial) +{ + size_t iphDel = npos; + size_t k = 0; + std::string ANOTE; + if (m_debug_print_lvl >= 2) { + plogf(" "); + for (int j = 0; j < 82; j++) { + plogf("-"); + } + plogf("\n"); + plogf(" --- Subroutine vcs_RxnStepSizes called - Details:\n"); + plogf(" "); + for (int j = 0; j < 82; j++) { + plogf("-"); + } plogf("\n"); + plogf(" --- Species KMoles Rxn_Adjustment DeltaG" + " | Comment\n"); } - // m_numRxnTot = number of noncomponents, also equal to the number of - // reactions. Note, it's possible that the number of elements is greater - // than the number of species. In that case set the number of reactions to - // zero. - if (m_nelem > m_nsp) { - m_numRxnTot = 0; - } else { - m_numRxnTot = m_nsp - m_nelem; + // We update the matrix dlnActCoeffdmolNumber[][] at the top of the loop, + // when necessary + if (m_useActCoeffJac) { + vcs_CalcLnActCoeffJac(&m_molNumSpecies_old[0]); } - m_numRxnRdc = m_numRxnTot; -} -void VCS_SOLVE::vcs_prob_update() -{ - // 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 zeroed out phases actually contain information - // about likely reemergent states. - m_mix->uploadMoleFractionsFromPhases(); - for (size_t ip = 0; ip < m_numPhases; ip++) { - m_mix->setPhaseMoles(ip, m_VolPhaseList[ip]->totalMoles()); + // LOOP OVER THE FORMATION REACTIONS + for (size_t irxn = 0; irxn < m_numRxnRdc; ++irxn) { + ANOTE = "Normal Calc"; + + size_t kspec = m_indexRxnToSpecies[irxn]; + if (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) { + m_deltaMolNumSpecies[kspec] = 0.0; + ANOTE = "ZeroedPhase: Phase is artificially zeroed"; + } else if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + if (m_molNumSpecies_old[kspec] == 0.0 && (!m_SSPhase[kspec])) { + // MULTISPECIES PHASE WITH total moles equal to zero + // + // If dg[irxn] is negative, then the multispecies phase should + // come alive again. Add a small positive step size to make it + // come alive. + if (m_deltaGRxn_new[irxn] < -1.0e-4) { + // First decide if this species is part of a multiphase that + // is nontrivial in size. + size_t iph = m_phaseID[kspec]; + double tphmoles = m_tPhaseMoles_old[iph]; + double trphmoles = tphmoles / m_totalMolNum; + vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); + if (Vphase->exists() && (trphmoles > VCS_DELETE_PHASE_CUTOFF)) { + m_deltaMolNumSpecies[kspec] = m_totalMolNum * VCS_SMALL_MULTIPHASE_SPECIES; + if (m_speciesStatus[kspec] == VCS_SPECIES_STOICHZERO) { + m_deltaMolNumSpecies[kspec] = 0.0; + ANOTE = fmt::sprintf("MultSpec (%s): Species not born due to STOICH/PHASEPOP even though DG = %11.3E", + vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); + } else { + m_deltaMolNumSpecies[kspec] = m_totalMolNum * VCS_SMALL_MULTIPHASE_SPECIES * 10.0; + ANOTE = fmt::sprintf("MultSpec (%s): small species born again DG = %11.3E", + vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); + } + } else { + ANOTE = fmt::sprintf("MultSpec (%s):still dead, no phase pop, even though DG = %11.3E", + vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); + m_deltaMolNumSpecies[kspec] = 0.0; + if (Vphase->exists() > 0 && trphmoles > 0.0) { + m_deltaMolNumSpecies[kspec] = m_totalMolNum * VCS_SMALL_MULTIPHASE_SPECIES * 10.; + ANOTE = fmt::sprintf("MultSpec (%s): birthed species because it was zero in a small existing phase with DG = %11.3E", + vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); + } + } + } else { + ANOTE = fmt::sprintf("MultSpec (%s): still dead DG = %11.3E", + vcs_speciesType_string(m_speciesStatus[kspec], 15), m_deltaGRxn_new[irxn]); + m_deltaMolNumSpecies[kspec] = 0.0; + } + } else { + // REGULAR PROCESSING + // + // First take care of cases where we want to bail out. Don't + // bother if superconvergence has already been achieved in this + // mode. + if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) { + ANOTE = fmt::sprintf("Skipped: superconverged DG = %11.3E", m_deltaGRxn_new[irxn]); + if (m_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", m_speciesName[kspec]); + plogf(" %12.4E %12.4E %12.4E | %s\n", + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], + m_deltaGRxn_new[irxn], ANOTE); + } + continue; + } + + // Don't calculate for minor or nonexistent species if their + // values are to be decreasing anyway. + if ((m_speciesStatus[kspec] != VCS_SPECIES_MAJOR) && (m_deltaGRxn_new[irxn] >= 0.0)) { + ANOTE = fmt::sprintf("Skipped: IC = %3d and DG >0: %11.3E", + m_speciesStatus[kspec], m_deltaGRxn_new[irxn]); + if (m_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", m_speciesName[kspec]); + plogf(" %12.4E %12.4E %12.4E | %s\n", + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], + m_deltaGRxn_new[irxn], ANOTE); + } + continue; + } + + // Start of the regular processing + double s; + if (m_SSPhase[kspec]) { + s = 0.0; + } else { + s = 1.0 / m_molNumSpecies_old[kspec]; + } + for (size_t j = 0; j < m_numComponents; ++j) { + if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) { + s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j]; + } + } + for (size_t j = 0; j < m_numPhases; j++) { + vcs_VolPhase* Vphase = m_VolPhaseList[j].get(); + if (!Vphase->m_singleSpecies && m_tPhaseMoles_old[j] > 0.0) { + s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j]; + } + } + if (s != 0.0) { + // Take into account of the derivatives of the activity + // coefficients with respect to the mole numbers, even in + // our diagonal approximation. + if (m_useActCoeffJac) { + double s_old = s; + s = vcs_Hessian_diag_adj(irxn, s_old); + ANOTE = fmt::sprintf("Normal calc: diag adjusted from %g " + "to %g due to act coeff", s_old, s); + } + + m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s; + // New section to do damping of the m_deltaMolNumSpecies[] + for (size_t j = 0; j < m_numComponents; ++j) { + double stoicC = m_stoichCoeffRxnMatrix(j,irxn); + if (stoicC != 0.0) { + double negChangeComp = -stoicC * m_deltaMolNumSpecies[kspec]; + if (negChangeComp > m_molNumSpecies_old[j]) { + if (m_molNumSpecies_old[j] > 0.0) { + ANOTE = fmt::sprintf("Delta damped from %g " + "to %g due to component %d (%10s) going neg", m_deltaMolNumSpecies[kspec], + -m_molNumSpecies_old[j] / stoicC, j, m_speciesName[j]); + m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[j] / stoicC; + } else { + ANOTE = fmt::sprintf("Delta damped from %g " + "to %g due to component %d (%10s) zero", m_deltaMolNumSpecies[kspec], + -m_molNumSpecies_old[j] / stoicC, j, m_speciesName[j]); + m_deltaMolNumSpecies[kspec] = 0.0; + } + } + } + } + // Implement a damping term that limits m_deltaMolNumSpecies + // to the size of the mole number + if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) { + ANOTE = fmt::sprintf("Delta damped from %g " + "to %g due to %s going negative", m_deltaMolNumSpecies[kspec], -m_molNumSpecies_old[kspec], + m_speciesName[kspec]); + m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; + } + } else { + // REACTION IS ENTIRELY AMONGST SINGLE SPECIES PHASES. + // DELETE ONE OF THE PHASES AND RECOMPUTE BASIS. + // + // Either the species L will disappear or one of the + // component single species phases will disappear. The sign + // of DG(I) will indicate which way the reaction will go. + // Then, we need to follow the reaction to see which species + // will zero out first. The species to be zeroed out will be + // "k". + double dss; + if (m_deltaGRxn_new[irxn] > 0.0) { + dss = m_molNumSpecies_old[kspec]; + k = kspec; + for (size_t j = 0; j < m_numComponents; ++j) { + if (m_stoichCoeffRxnMatrix(j,irxn) > 0.0) { + double xx = m_molNumSpecies_old[j] / m_stoichCoeffRxnMatrix(j,irxn); + if (xx < dss) { + dss = xx; + k = j; + } + } + } + dss = -dss; + } else { + dss = 1.0e10; + for (size_t j = 0; j < m_numComponents; ++j) { + if (m_stoichCoeffRxnMatrix(j,irxn) < 0.0) { + double xx = -m_molNumSpecies_old[j] / m_stoichCoeffRxnMatrix(j,irxn); + if (xx < dss) { + dss = xx; + k = j; + } + } + } + } + + // Here we adjust the mole fractions according to DSS and + // the stoichiometric array to take into account that we are + // eliminating the kth species. DSS contains the amount of + // moles of the kth species that needs to be added back into + // the component species. + if (dss != 0.0) { + 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. + ANOTE = fmt::sprintf("Delta damped from %g to %g due to delete %s", m_deltaMolNumSpecies[kspec], + -m_molNumSpecies_old[kspec], m_speciesName[kspec]); + m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec]; + if (m_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", m_speciesName[kspec]); + plogf(" %12.4E %12.4E %12.4E | %s\n", + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], + m_deltaGRxn_new[irxn], ANOTE); + } + continue; + } + + // Delete the single species phase + for (size_t j = 0; j < m_nsp; j++) { + m_deltaMolNumSpecies[j] = 0.0; + } + m_deltaMolNumSpecies[kspec] = dss; + for (size_t j = 0; j < m_numComponents; ++j) { + m_deltaMolNumSpecies[j] = dss * m_stoichCoeffRxnMatrix(j,irxn); + } + + iphDel = m_phaseID[k]; + kSpecial = k; + + if (k != kspec) { + ANOTE = fmt::sprintf("Delete component SS phase %d named %s - SS phases only", + iphDel, m_speciesName[k]); + } else { + ANOTE = fmt::sprintf("Delete this SS phase %d - SS components only", iphDel); + } + if (m_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", m_speciesName[kspec]); + 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\n", + m_speciesName[k]); + } + if (k != kspec) { + forceComponentCalc = 1; + debuglog(" --- Force a component recalculation\n\n", m_debug_print_lvl >= 2); + } + if (m_debug_print_lvl >= 2) { + plogf(" "); + writeline('-', 82); + } + return iphDel; + } + } + } // End of regular processing + if (m_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", m_speciesName[kspec]); + plogf(" %12.4E %12.4E %12.4E | %s\n", + m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec], + m_deltaGRxn_new[irxn], ANOTE); + } + } // End of loop over m_speciesUnknownType + } // End of loop over non-component stoichiometric formation reactions + if (m_debug_print_lvl >= 2) { + plogf(" "); + writeline('-', 82); } + return iphDel; } -void VCS_SOLVE::vcs_counters_init(int ifunc) +double VCS_SOLVE::vcs_phaseStabilityTest(const size_t iph) { - m_VCount->Its = 0; - m_VCount->Basis_Opts = 0; - m_VCount->Time_vcs_TP = 0.0; - m_VCount->Time_basopt = 0.0; - if (ifunc) { - m_VCount->T_Its = 0; - m_VCount->T_Basis_Opts = 0; - m_VCount->T_Calls_Inest = 0; - m_VCount->T_Calls_vcs_TP = 0; - m_VCount->T_Time_vcs_TP = 0.0; - m_VCount->T_Time_basopt = 0.0; - m_VCount->T_Time_inest = 0.0; - m_VCount->T_Time_vcs = 0.0; + // We will use the _new state calc here + vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); + const size_t nsp = Vphase->nSpecies(); + int minNumberIterations = 3; + if (nsp <= 1) { + minNumberIterations = 1; } -} -double VCS_SOLVE::vcs_VolTotal(const double tkelvin, const double pres, - const double w[], double volPM[]) -{ - double VolTot = 0.0; - for (size_t iphase = 0; iphase < m_numPhases; iphase++) { - vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); - Vphase->setState_TP(tkelvin, pres); - Vphase->setMolesFromVCS(VCS_STATECALC_OLD, w); - double Volp = Vphase->sendToVCS_VolPM(volPM); - VolTot += Volp; + // We will do a full Newton calculation later, but for now, ... + bool doSuccessiveSubstitution = true; + double funcPhaseStability; + vector_fp X_est(nsp, 0.0); + vector_fp delFrac(nsp, 0.0); + vector_fp E_phi(nsp, 0.0); + vector_fp fracDelta_old(nsp, 0.0); + vector_fp fracDelta_raw(nsp, 0.0); + vector creationGlobalRxnNumbers(nsp, npos); + m_deltaGRxn_Deficient = m_deltaGRxn_old; + vector_fp feSpecies_Deficient = m_feSpecies_old; + + // get the activity coefficients + Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, &m_actCoeffSpecies_new[0]); + + // Get the stored estimate for the composition of the phase if + // it gets created + vector_fp fracDelta_new = Vphase->creationMoleNumbers(creationGlobalRxnNumbers); + + std::vector componentList; + for (size_t k = 0; k < nsp; k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + if (kspec < m_numComponents) { + componentList.push_back(k); + } } - return VolTot; + + double normUpdate = 0.1 * vcs_l2norm(fracDelta_new); + double damp = 1.0E-2; + + if (doSuccessiveSubstitution) { + int KP = 0; + if (m_debug_print_lvl >= 2) { + plogf(" --- vcs_phaseStabilityTest() called\n"); + plogf(" --- Its X_old[%2d] FracDel_old[%2d] deltaF[%2d] FracDel_new[%2d]" + " normUpdate damp FuncPhaseStability\n", KP, KP, KP, KP); + plogf(" --------------------------------------------------------------" + "--------------------------------------------------------\n"); + } else if (m_debug_print_lvl == 1) { + plogf(" --- vcs_phaseStabilityTest() called for phase %d\n", iph); + } + + for (size_t k = 0; k < nsp; k++) { + if (fracDelta_new[k] < 1.0E-13) { + fracDelta_new[k] =1.0E-13; + } + } + bool converged = false; + double dirProd = 0.0; + for (int its = 0; its < 200 && (!converged); its++) { + double dampOld = damp; + double normUpdateOld = normUpdate; + fracDelta_old = fracDelta_new; + double dirProdOld = dirProd; + + // Given a set of fracDelta's, we calculate the fracDelta's + // for the component species, if any + for (size_t i = 0; i < componentList.size(); i++) { + size_t kc = componentList[i]; + size_t kc_spec = Vphase->spGlobalIndexVCS(kc); + fracDelta_old[kc] = 0.0; + for (size_t k = 0; k < nsp; k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + if (kspec >= m_numComponents) { + size_t irxn = kspec - m_numComponents; + fracDelta_old[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_old[k]; + } + } + } + + // Now, calculate the predicted mole fractions, X_est[k] + double sumFrac = 0.0; + for (size_t k = 0; k < nsp; 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 (size_t k = 0; k < nsp; k++) { + X_est[k] = fracDelta_old[k] / sumFrac; + if (Vphase->spGlobalIndexVCS(k) < m_numComponents) { + sum_Xcomp += X_est[k]; + } + } + + // Feed the newly formed estimate of the mole fractions back into the + // ThermoPhase object + Vphase->setMoleFractionsState(0.0, &X_est[0], VCS_STATECALC_PHASESTABILITY); + + // get the activity coefficients + Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, &m_actCoeffSpecies_new[0]); + + // First calculate altered chemical potentials for component species + // belonging to this phase. + for (size_t i = 0; i < componentList.size(); i++) { + size_t kc = componentList[i]; + size_t kc_spec = Vphase->spGlobalIndexVCS(kc); + if (X_est[kc] > VCS_DELETE_MINORSPECIES_CUTOFF) { + feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] + + log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]); + } else { + feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec] + + log(m_actCoeffSpecies_new[kc_spec] * VCS_DELETE_MINORSPECIES_CUTOFF); + } + } + + for (size_t i = 0; i < componentList.size(); i++) { + size_t kc_spec = Vphase->spGlobalIndexVCS(componentList[i]); + for (size_t k = 0; k < Vphase->nSpecies(); k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + if (kspec >= m_numComponents) { + size_t irxn = kspec - m_numComponents; + if (i == 0) { + m_deltaGRxn_Deficient[irxn] = m_deltaGRxn_old[irxn]; + } + if (m_stoichCoeffRxnMatrix(kc_spec,irxn) != 0.0) { + m_deltaGRxn_Deficient[irxn] += + m_stoichCoeffRxnMatrix(kc_spec,irxn) * (feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]); + } + } + } + } + + // Calculate the E_phi's + double sum = 0.0; + funcPhaseStability = sum_Xcomp - 1.0; + for (size_t k = 0; k < nsp; k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + if (kspec >= m_numComponents) { + size_t irxn = kspec - m_numComponents; + double deltaGRxn = clip(m_deltaGRxn_Deficient[irxn], -50.0, 50.0); + E_phi[k] = std::exp(-deltaGRxn) / m_actCoeffSpecies_new[kspec]; + sum += E_phi[k]; + funcPhaseStability += E_phi[k]; + } else { + E_phi[k] = 0.0; + } + } + + // Calculate the raw estimate of the new fracs + for (size_t k = 0; k < nsp; k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + double b = E_phi[k] / sum * (1.0 - sum_Xcomp); + if (kspec >= m_numComponents) { + fracDelta_raw[k] = b; + } + } + + // Given a set of fracDelta's, we calculate the fracDelta's + // for the component species, if any + for (size_t i = 0; i < componentList.size(); i++) { + size_t kc = componentList[i]; + size_t kc_spec = Vphase->spGlobalIndexVCS(kc); + fracDelta_raw[kc] = 0.0; + for (size_t k = 0; k < nsp; k++) { + size_t kspec = Vphase->spGlobalIndexVCS(k); + if (kspec >= m_numComponents) { + size_t irxn = kspec - m_numComponents; + fracDelta_raw[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_raw[k]; + } + } + } + + // Now possibly dampen the estimate. + double sumADel = 0.0; + for (size_t k = 0; k < nsp; k++) { + delFrac[k] = fracDelta_raw[k] - fracDelta_old[k]; + sumADel += fabs(delFrac[k]); + } + normUpdate = vcs_l2norm(delFrac); + + dirProd = 0.0; + for (size_t k = 0; k < nsp; k++) { + dirProd += fracDelta_old[k] * delFrac[k]; + } + bool crossedSign = false; + if (dirProd * dirProdOld < 0.0) { + crossedSign = true; + } + + damp = 0.5; + if (dampOld < 0.25) { + damp = 2.0 * dampOld; + } + if (crossedSign) { + if (normUpdate *1.5 > normUpdateOld) { + damp = 0.5 * dampOld; + } else if (normUpdate *2.0 > normUpdateOld) { + damp = 0.8 * dampOld; + } + } else { + if (normUpdate > normUpdateOld * 2.0) { + damp = 0.6 * dampOld; + } else if (normUpdate > normUpdateOld * 1.2) { + damp = 0.9 * dampOld; + } + } + + for (size_t k = 0; k < nsp; k++) { + if (fabs(damp * delFrac[k]) > 0.3*fabs(fracDelta_old[k])) { + damp = std::max(0.3*fabs(fracDelta_old[k]) / fabs(delFrac[k]), + 1.0E-8/fabs(delFrac[k])); + } + if (delFrac[k] < 0.0 && 2.0 * damp * (-delFrac[k]) > fracDelta_old[k]) { + damp = fracDelta_old[k] / (2.0 * -delFrac[k]); + } + if (delFrac[k] > 0.0 && 2.0 * damp * delFrac[k] > fracDelta_old[k]) { + damp = fracDelta_old[k] / (2.0 * delFrac[k]); + } + } + damp = std::max(damp, 0.000001); + for (size_t k = 0; k < nsp; k++) { + fracDelta_new[k] = fracDelta_old[k] + damp * delFrac[k]; + } + + if (m_debug_print_lvl >= 2) { + plogf(" --- %3d %12g %12g %12g %12g %12g %12g %12g\n", its, X_est[KP], fracDelta_old[KP], + delFrac[KP], fracDelta_new[KP], normUpdate, damp, funcPhaseStability); + } + + if (normUpdate < 1.0E-5 * damp) { + converged = true; + if (its < minNumberIterations) { + converged = false; + } + } + } + + if (converged) { + // Save the final optimized stated back into the VolPhase object for later use + Vphase->setMoleFractionsState(0.0, &X_est[0], VCS_STATECALC_PHASESTABILITY); + + // Save fracDelta for later use to initialize the problem better + // @TODO creationGlobalRxnNumbers needs to be calculated here and stored. + Vphase->setCreationMoleNumbers(&fracDelta_new[0], creationGlobalRxnNumbers); + } + } else { + throw CanteraError("VCS_SOLVE::vcs_phaseStabilityTest", "not done yet"); + } + if (m_debug_print_lvl >= 2) { + plogf(" ------------------------------------------------------------" + "-------------------------------------------------------------\n"); + } else if (m_debug_print_lvl == 1) { + if (funcPhaseStability > 0.0) { + plogf(" --- phase %d with func = %g is to be born\n", iph, funcPhaseStability); + } else { + plogf(" --- phase %d with func = %g stays dead\n", iph, funcPhaseStability); + } + } + return funcPhaseStability; +} + +int VCS_SOLVE::vcs_TP(int ipr, int ip1, int maxit, double T_arg, double pres_arg) +{ + // Store the temperature and pressure in the private global variables + m_temperature = T_arg; + m_pressurePA = pres_arg; + m_Faraday_dim = Faraday / (m_temperature * GasConstant); + + // Evaluate the standard state free energies + // at the current temperatures and pressures. + int iconv = vcs_evalSS_TP(ipr, ip1, m_temperature, pres_arg); + + // Prep the fe field + vcs_fePrep_TP(); + + // Decide whether we need an initial estimate of the solution If so, go get + // one. If not, then + if (m_doEstimateEquil) { + int retn = vcs_inest_TP(); + if (retn != VCS_SUCCESS) { + plogf("vcs_inest_TP returned a failure flag\n"); + } + } + + // Solve the problem at a fixed Temperature and Pressure (all information + // concerning Temperature and Pressure has already been derived. The free + // energies are now in dimensionless form.) + iconv = vcs_solve_TP(ipr, ip1, maxit); + + // Return the convergence success flag. + return iconv; +} + +int VCS_SOLVE::vcs_evalSS_TP(int ipr, int ip1, double Temp, double pres) +{ + for (size_t iph = 0; iph < m_numPhases; iph++) { + vcs_VolPhase* vph = m_VolPhaseList[iph].get(); + vph->setState_TP(m_temperature, m_pressurePA); + vph->sendToVCS_GStar(&m_SSfeSpecies[0]); + } + for (size_t k = 0; k < m_nsp; k++) { + m_SSfeSpecies[k] /= GasConstant * m_temperature; + } + + return VCS_SUCCESS; +} + +void VCS_SOLVE::vcs_fePrep_TP() +{ + for (size_t i = 0; i < m_nsp; ++i) { + // For single species phases, initialize the chemical potential with the + // value of the standard state chemical potential. This value doesn't + // change during the calculation + if (m_SSPhase[i]) { + m_feSpecies_old[i] = m_SSfeSpecies[i]; + m_feSpecies_new[i] = m_SSfeSpecies[i]; + } + } +} + +double VCS_SOLVE::vcs_VolTotal(const double tkelvin, const double pres, + const double w[], double volPM[]) +{ + double VolTot = 0.0; + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); + Vphase->setState_TP(tkelvin, pres); + Vphase->setMolesFromVCS(VCS_STATECALC_OLD, w); + double Volp = Vphase->sendToVCS_VolPM(volPM); + VolTot += Volp; + } + return VolTot; +} + +int VCS_SOLVE::vcs_prep(int printLvl) +{ + int retn = VCS_SUCCESS; + m_debug_print_lvl = printLvl; + + // Calculate the Single Species status of phases + // Also calculate the number of species per phase + vcs_SSPhase(); + + // Set an initial estimate for the number of noncomponent species equal to + // nspecies - nelements. This may be changed below + if (m_nelem > m_nsp) { + m_numRxnTot = 0; + } else { + m_numRxnTot = m_nsp - m_nelem; + } + m_numRxnRdc = m_numRxnTot; + m_numSpeciesRdc = m_nsp; + for (size_t i = 0; i < m_numRxnRdc; ++i) { + m_indexRxnToSpecies[i] = m_nelem + i; + } + + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + size_t pID = m_phaseID[kspec]; + size_t spPhIndex = m_speciesLocalPhaseIndex[kspec]; + vcs_VolPhase* vPhase = m_VolPhaseList[pID].get(); + vcs_SpeciesProperties* spProp = vPhase->speciesProperty(spPhIndex); + double sz = 0.0; + size_t eSize = spProp->FormulaMatrixCol.size(); + for (size_t e = 0; e < eSize; e++) { + sz += fabs(spProp->FormulaMatrixCol[e]); + } + if (sz > 0.0) { + m_spSize[kspec] = sz; + } else { + m_spSize[kspec] = 1.0; + } + } + + // DETERMINE THE NUMBER OF COMPONENTS + // + // Obtain a valid estimate of the mole fraction. This will be used as an + // initial ordering vector for prioritizing which species are defined as + // components. + // + // If a mole number estimate was supplied from the input file, use that mole + // number estimate. + // + // If a solution estimate wasn't supplied from the input file, supply an + // initial estimate for the mole fractions based on the relative reverse + // ordering of the chemical potentials. + // + // For voltage unknowns, set these to zero for the moment. + double test = -1.0e-10; + bool modifiedSoln = false; + if (m_doEstimateEquil < 0) { + double sum = 0.0; + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { + sum += fabs(m_molNumSpecies_old[kspec]); + } + } + if (fabs(sum) < 1.0E-6) { + modifiedSoln = true; + double pres = (m_pressurePA <= 0.0) ? 1.01325E5 : m_pressurePA; + retn = vcs_evalSS_TP(0, 0, m_temperature, pres); + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { + m_molNumSpecies_old[kspec] = - m_SSfeSpecies[kspec]; + } else { + m_molNumSpecies_old[kspec] = 0.0; + } + } + } + test = -1.0e20; + } + + // NC = number of components is in the vcs.h common block. This call to + // BASOPT doesn't calculate the stoichiometric reaction matrix. + vector_fp awSpace(m_nsp + (m_nelem + 2)*(m_nelem), 0.0); + double* aw = &awSpace[0]; + if (aw == NULL) { + plogf("vcs_prep_oneTime: failed to get memory: global bailout\n"); + return VCS_NOMEMORY; + } + double* sa = aw + m_nsp; + double* sm = sa + m_nelem; + double* ss = sm + m_nelem * m_nelem; + bool conv; + retn = vcs_basopt(true, aw, sa, sm, ss, test, &conv); + if (retn != VCS_SUCCESS) { + plogf("vcs_prep_oneTime:"); + plogf(" Determination of number of components failed: %d\n", + retn); + plogf(" Global Bailout!\n"); + return retn; + } + + if (m_nsp >= m_numComponents) { + m_numRxnTot = m_numRxnRdc = m_nsp - m_numComponents; + for (size_t i = 0; i < m_numRxnRdc; ++i) { + m_indexRxnToSpecies[i] = m_numComponents + i; + } + } else { + m_numRxnTot = m_numRxnRdc = 0; + } + + // The elements might need to be rearranged. + awSpace.resize(m_nelem + (m_nelem + 2)*m_nelem, 0.0); + aw = &awSpace[0]; + sa = aw + m_nelem; + sm = sa + m_nelem; + ss = sm + m_nelem * m_nelem; + retn = vcs_elem_rearrange(aw, sa, sm, ss); + if (retn != VCS_SUCCESS) { + plogf("vcs_prep_oneTime:"); + plogf(" Determination of element reordering failed: %d\n", + retn); + plogf(" Global Bailout!\n"); + return retn; + } + + // If we mucked up the solution unknowns because they were all + // zero to start with, set them back to zero here + if (modifiedSoln) { + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + m_molNumSpecies_old[kspec] = 0.0; + } + } + + // Initialize various arrays in the data to zero + m_feSpecies_old.assign(m_feSpecies_old.size(), 0.0); + m_feSpecies_new.assign(m_feSpecies_new.size(), 0.0); + m_molNumSpecies_new.assign(m_molNumSpecies_new.size(), 0.0); + m_deltaMolNumPhase.zero(); + m_phaseParticipation.zero(); + m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0); + m_tPhaseMoles_new.assign(m_tPhaseMoles_new.size(), 0.0); + + // Calculate the total number of moles in all phases. + vcs_tmoles(); + + // Check to see if the current problem is well posed. + double sum = 0.0; + for (size_t e = 0; e < m_mix->nElements(); e++) { + sum += m_mix->elementMoles(e); + } + if (sum < 1.0E-20) { + // Check to see if the current problem is well posed. + plogf("vcs has determined the problem is not well posed: Bailing\n"); + return VCS_PUB_BAD; + } + return VCS_SUCCESS; +} + +int VCS_SOLVE::vcs_elem_rearrange(double* const aw, double* const sa, + double* const sm, double* const ss) +{ + size_t ncomponents = m_numComponents; + if (m_debug_print_lvl >= 2) { + plogf(" "); + writeline('-', 77); + plogf(" --- Subroutine elem_rearrange() called to "); + plogf("check stoich. coefficient matrix\n"); + plogf(" --- and to rearrange the element ordering once\n"); + } + + // Use a temporary work array for the element numbers + // Also make sure the value of test is unique. + bool lindep = true; + double test = -1.0E10; + while (lindep) { + lindep = false; + for (size_t i = 0; i < m_nelem; ++i) { + test -= 1.0; + aw[i] = m_elemAbundancesGoal[i]; + if (test == aw[i]) { + lindep = true; + } + } + } + + // Top of a loop of some sort based on the index JR. JR is the current + // number independent elements found. + size_t jr = 0; + while (jr < ncomponents) { + size_t k; + + // Top of another loop point based on finding a linearly independent + // species + while (true) { + // Search the remaining part of the mole fraction vector, AW, for + // the largest remaining species. Return its identity in K. + k = m_nelem; + for (size_t ielem = jr; ielem < m_nelem; ielem++) { + if (m_elementActive[ielem] && aw[ielem] != test) { + k = ielem; + break; + } + } + if (k == m_nelem) { + throw CanteraError("VCS_SOLVE::vcs_elem_rearrange", + "Shouldn't be here. Algorithm misfired."); + } + + // Assign a large negative number to the element that we have just + // found, in order to take it out of further consideration. + aw[k] = test; + + // CHECK LINEAR INDEPENDENCE OF CURRENT FORMULA MATRIX LINE WITH + // PREVIOUS LINES OF THE FORMULA MATRIX + // + // Modified Gram-Schmidt Method, p. 202 Dalquist QR factorization of + // a matrix without row pivoting. + size_t jl = jr; + + // Fill in the row for the current element, k, under consideration + // The row will contain the Formula matrix value for that element + // from the current component. + for (size_t j = 0; j < ncomponents; ++j) { + sm[j + jr*ncomponents] = m_formulaMatrix(j,k); + } + if (jl > 0) { + // Compute the coefficients of JA column of the the upper + // triangular R matrix, SS(J) = R_J_JR (this is slightly + // different than Dalquist) R_JA_JA = 1 + for (size_t j = 0; j < jl; ++j) { + ss[j] = 0.0; + for (size_t i = 0; i < ncomponents; ++i) { + ss[j] += sm[i + jr*ncomponents] * sm[i + j*ncomponents]; + } + ss[j] /= sa[j]; + } + + // Now make the new column, (*,JR), orthogonal to the previous + // columns + for (size_t j = 0; j < jl; ++j) { + for (size_t i = 0; i < ncomponents; ++i) { + sm[i + jr*ncomponents] -= ss[j] * sm[i + j*ncomponents]; + } + } + } + + // Find the new length of the new column in Q. It will be used in + // the denominator in future row calcs. + sa[jr] = 0.0; + for (size_t ml = 0; ml < ncomponents; ++ml) { + sa[jr] += pow(sm[ml + jr*ncomponents], 2); + } + // IF NORM OF NEW ROW .LT. 1E-6 REJECT + if (sa[jr] > 1.0e-6) { + break; + } + } + // REARRANGE THE DATA + if (jr != k) { + if (m_debug_print_lvl >= 2) { + plogf(" --- %-2.2s(%9.2g) replaces %-2.2s(%9.2g) as element %3d\n", + m_elementName[k], m_elemAbundancesGoal[k], + m_elementName[jr], m_elemAbundancesGoal[jr], jr); + } + vcs_switch_elem_pos(jr, k); + std::swap(aw[jr], aw[k]); + } + + // If we haven't found enough components, go back and find some more. + jr++; + } + return VCS_SUCCESS; +} + +void VCS_SOLVE::vcs_switch_elem_pos(size_t ipos, size_t jpos) +{ + if (ipos == jpos) { + return; + } + AssertThrowMsg(ipos < m_nelem && jpos < m_nelem, + "vcs_switch_elem_pos", + "inappropriate args: {} {}", ipos, jpos); + + // Change the element Global Index list in each vcs_VolPhase object + // to reflect the switch in the element positions. + for (size_t iph = 0; iph < m_numPhases; iph++) { + vcs_VolPhase* volPhase = m_VolPhaseList[iph].get(); + for (size_t e = 0; e < volPhase->nElemConstraints(); e++) { + if (volPhase->elemGlobalIndex(e) == ipos) { + volPhase->setElemGlobalIndex(e, jpos); + } + if (volPhase->elemGlobalIndex(e) == jpos) { + volPhase->setElemGlobalIndex(e, ipos); + } + } + } + std::swap(m_elemAbundancesGoal[ipos], m_elemAbundancesGoal[jpos]); + std::swap(m_elemAbundances[ipos], m_elemAbundances[jpos]); + std::swap(m_elementMapIndex[ipos], m_elementMapIndex[jpos]); + std::swap(m_elType[ipos], m_elType[jpos]); + std::swap(m_elementActive[ipos], m_elementActive[jpos]); + for (size_t j = 0; j < m_nsp; ++j) { + std::swap(m_formulaMatrix(j,ipos), m_formulaMatrix(j,jpos)); + } + std::swap(m_elementName[ipos], m_elementName[jpos]); +} + +double VCS_SOLVE::vcs_Hessian_diag_adj(size_t irxn, double hessianDiag_Ideal) +{ + double diag = hessianDiag_Ideal; + double hessActCoef = vcs_Hessian_actCoeff_diag(irxn); + if (hessianDiag_Ideal <= 0.0) { + throw CanteraError("VCS_SOLVE::vcs_Hessian_diag_adj", + "We shouldn't be here"); + } + if (hessActCoef >= 0.0) { + diag += hessActCoef; + } else if (fabs(hessActCoef) < 0.6666 * hessianDiag_Ideal) { + diag += hessActCoef; + } else { + diag -= 0.6666 * hessianDiag_Ideal; + } + return diag; +} + +double VCS_SOLVE::vcs_Hessian_actCoeff_diag(size_t irxn) +{ + size_t kspec = m_indexRxnToSpecies[irxn]; + size_t kph = m_phaseID[kspec]; + double np_kspec = std::max(m_tPhaseMoles_old[kph], 1e-13); + double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn); + + // First the diagonal term of the Jacobian + double s = m_np_dLnActCoeffdMolNum(kspec,kspec) / np_kspec; + + // Next, the other terms. Note this only a loop over the components So, it's + // not too expensive to calculate. + for (size_t j = 0; j < m_numComponents; j++) { + if (!m_SSPhase[j]) { + for (size_t k = 0; k < m_numComponents; ++k) { + if (m_phaseID[k] == m_phaseID[j]) { + double np = m_tPhaseMoles_old[m_phaseID[k]]; + if (np > 0.0) { + s += sc_irxn[k] * sc_irxn[j] * m_np_dLnActCoeffdMolNum(j,k) / np; + } + } + } + if (kph == m_phaseID[j]) { + s += sc_irxn[j] * (m_np_dLnActCoeffdMolNum(j,kspec) + m_np_dLnActCoeffdMolNum(kspec,j)) / np_kspec; + } + } + } + return s; +} + +void VCS_SOLVE::vcs_CalcLnActCoeffJac(const double* const moleSpeciesVCS) +{ + // Loop over all of the phases in the problem + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); + + // We don't need to call single species phases; + if (!Vphase->m_singleSpecies && !Vphase->isIdealSoln()) { + // update the mole numbers + Vphase->setMolesFromVCS(VCS_STATECALC_OLD, moleSpeciesVCS); + + // Download the resulting calculation into the full vector. This + // scatter calculation is carried out in the vcs_VolPhase object. + Vphase->sendToVCS_LnActCoeffJac(m_np_dLnActCoeffdMolNum); + } + } +} + +int VCS_SOLVE::vcs_report(int iconv) +{ + bool inertYes = false; + + // SORT DEPENDENT SPECIES IN DECREASING ORDER OF MOLES + std::vector> x_order; + for (size_t i = 0; i < m_nsp; i++) { + x_order.push_back({-m_molNumSpecies_old[i], i}); + } + std::sort(x_order.begin() + m_numComponents, + x_order.begin() + m_numSpeciesRdc); + + vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD); + vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_nsp); + + // PRINT OUT RESULTS + plogf("\n\n\n\n"); + writeline('-', 80); + writeline('-', 80); + plogf("\t\t VCS_TP REPORT\n"); + writeline('-', 80); + writeline('-', 80); + if (iconv < 0) { + plogf(" ERROR: CONVERGENCE CRITERION NOT SATISFIED.\n"); + } else if (iconv == 1) { + plogf(" RANGE SPACE ERROR: Equilibrium Found but not all Element Abundances are Satisfied\n"); + } + + // Calculate some quantities that may need updating + vcs_tmoles(); + m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA, + &m_molNumSpecies_old[0], &m_PMVolumeSpecies[0]); + + plogf("\t\tTemperature = %15.2g Kelvin\n", m_temperature); + plogf("\t\tPressure = %15.5g Pa \n", m_pressurePA); + plogf("\t\ttotal Volume = %15.5g m**3\n", m_totalVol); + + // TABLE OF SPECIES IN DECREASING MOLE NUMBERS + plogf("\n\n"); + writeline('-', 80); + plogf(" Species Equilibrium kmoles "); + plogf("Mole Fraction ChemPot/RT SpecUnkType\n"); + writeline('-', 80); + for (size_t i = 0; i < m_numComponents; ++i) { + plogf(" %-12.12s", m_speciesName[i]); + writeline(' ', 13, false); + plogf("%14.7E %14.7E %12.4E", m_molNumSpecies_old[i], + m_molNumSpecies_new[i], m_feSpecies_old[i]); + plogf(" %3d", m_speciesUnknownType[i]); + plogf("\n"); + } + for (size_t i = m_numComponents; i < m_numSpeciesRdc; ++i) { + size_t j = x_order[i].second; + plogf(" %-12.12s", m_speciesName[j]); + writeline(' ', 13, false); + + if (m_speciesUnknownType[j] == VCS_SPECIES_TYPE_MOLNUM) { + plogf("%14.7E %14.7E %12.4E", m_molNumSpecies_old[j], + m_molNumSpecies_new[j], m_feSpecies_old[j]); + plogf(" KMolNum "); + } else if (m_speciesUnknownType[j] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf(" NA %14.7E %12.4E", 1.0, m_feSpecies_old[j]); + plogf(" Voltage = %14.7E", m_molNumSpecies_old[j]); + } else { + throw CanteraError("VCS_SOLVE::vcs_report", "we have a problem"); + } + plogf("\n"); + } + for (size_t i = 0; i < m_numPhases; i++) { + if (TPhInertMoles[i] > 0.0) { + inertYes = true; + if (i == 0) { + plogf(" Inert Gas Species "); + } else { + plogf(" Inert Species in phase %16s ", + m_VolPhaseList[i]->PhaseName); + } + plogf("%14.7E %14.7E %12.4E\n", TPhInertMoles[i], + TPhInertMoles[i] / m_tPhaseMoles_old[i], 0.0); + } + } + if (m_numSpeciesRdc != m_nsp) { + plogf("\n SPECIES WITH LESS THAN 1.0E-32 KMOLES:\n\n"); + for (size_t kspec = m_numSpeciesRdc; kspec < m_nsp; ++kspec) { + plogf(" %-12.12s", m_speciesName[kspec]); + // Note m_deltaGRxn_new[] stores in kspec slot not irxn slot, after solve + plogf(" %14.7E %14.7E %12.4E", + m_molNumSpecies_old[kspec], + m_molNumSpecies_new[kspec], m_deltaGRxn_new[kspec]); + if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { + plogf(" KMol_Num"); + } else if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf(" Voltage"); + } else { + plogf(" Unknown"); + } + plogf("\n"); + } + } + writeline('-', 80); + plogf("\n"); + + // TABLE OF SPECIES FORMATION REACTIONS + writeline('-', m_numComponents*10 + 45, true, true); + plogf(" |ComponentID|"); + for (size_t j = 0; j < m_numComponents; j++) { + plogf(" %3d", j); + } + plogf(" | |\n"); + plogf(" | Components|"); + for (size_t j = 0; j < m_numComponents; j++) { + plogf(" %10.10s", m_speciesName[j]); + } + plogf(" | |\n"); + plogf(" NonComponent | Moles |"); + for (size_t j = 0; j < m_numComponents; j++) { + plogf(" %10.3g", m_molNumSpecies_old[j]); + } + plogf(" | DG/RT Rxn |\n"); + writeline('-', m_numComponents*10 + 45); + for (size_t irxn = 0; irxn < m_numRxnTot; irxn++) { + size_t kspec = m_indexRxnToSpecies[irxn]; + plogf(" %3d ", kspec); + plogf("%-10.10s", m_speciesName[kspec]); + plogf("|%10.3g |", m_molNumSpecies_old[kspec]); + for (size_t j = 0; j < m_numComponents; j++) { + plogf(" %6.2f", m_stoichCoeffRxnMatrix(j,irxn)); + } + plogf(" |%10.3g |", m_deltaGRxn_new[irxn]); + plogf("\n"); + } + writeline('-', m_numComponents*10 + 45); + plogf("\n"); + + // TABLE OF PHASE INFORMATION + vector_fp gaPhase(m_nelem, 0.0); + vector_fp gaTPhase(m_nelem, 0.0); + double totalMoles = 0.0; + double gibbsPhase = 0.0; + double gibbsTotal = 0.0; + plogf("\n\n"); + plogf("\n"); + writeline('-', m_nelem*10 + 58); + plogf(" | ElementID |"); + for (size_t j = 0; j < m_nelem; j++) { + plogf(" %3d", j); + } + plogf(" | |\n"); + plogf(" | Element |"); + for (size_t j = 0; j < m_nelem; j++) { + plogf(" %10.10s", m_elementName[j]); + } + plogf(" | |\n"); + plogf(" PhaseName |KMolTarget |"); + for (size_t j = 0; j < m_nelem; j++) { + plogf(" %10.3g", m_elemAbundancesGoal[j]); + } + plogf(" | Gibbs Total |\n"); + writeline('-', m_nelem*10 + 58); + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + plogf(" %3d ", iphase); + vcs_VolPhase* VPhase = m_VolPhaseList[iphase].get(); + plogf("%-12.12s |",VPhase->PhaseName); + plogf("%10.3e |", m_tPhaseMoles_old[iphase]); + totalMoles += m_tPhaseMoles_old[iphase]; + if (m_tPhaseMoles_old[iphase] != VPhase->totalMoles() && + !vcs_doubleEqual(m_tPhaseMoles_old[iphase], VPhase->totalMoles())) { + throw CanteraError("VCS_SOLVE::vcs_report", "we have a problem"); + } + vcs_elabPhase(iphase, &gaPhase[0]); + for (size_t j = 0; j < m_nelem; j++) { + plogf(" %10.3g", gaPhase[j]); + gaTPhase[j] += gaPhase[j]; + } + gibbsPhase = vcs_GibbsPhase(iphase, &m_molNumSpecies_old[0], + &m_feSpecies_old[0]); + gibbsTotal += gibbsPhase; + plogf(" | %18.11E |\n", gibbsPhase); + } + writeline('-', m_nelem*10 + 58); + plogf(" TOTAL |%10.3e |", totalMoles); + for (size_t j = 0; j < m_nelem; j++) { + plogf(" %10.3g", gaTPhase[j]); + } + plogf(" | %18.11E |\n", gibbsTotal); + + writeline('-', m_nelem*10 + 58); + plogf("\n"); + + // GLOBAL SATISFACTION INFORMATION + + // Calculate the total dimensionless Gibbs Free Energy. Inert species are + // handled as if they had a standard free energy of zero + double g = vcs_Total_Gibbs(&m_molNumSpecies_old[0], &m_feSpecies_old[0], + &m_tPhaseMoles_old[0]); + plogf("\n\tTotal Dimensionless Gibbs Free Energy = G/RT = %15.7E\n", g); + if (inertYes) { + plogf("\t\t(Inert species have standard free energy of zero)\n"); + } + + plogf("\nElemental Abundances (kmol): "); + plogf(" Actual Target Type ElActive\n"); + for (size_t i = 0; i < m_nelem; ++i) { + writeline(' ', 26, false); + plogf("%-2.2s", m_elementName[i]); + plogf("%20.12E %20.12E", m_elemAbundances[i], m_elemAbundancesGoal[i]); + plogf(" %3d %3d\n", m_elType[i], m_elementActive[i]); + } + plogf("\n"); + + // TABLE OF SPECIES CHEM POTS + writeline('-', 93, true, true); + plogf("Chemical Potentials of the Species: (dimensionless)\n"); + + plogf("\t\t(RT = %g J/kmol)\n", GasConstant * m_temperature); + plogf(" Name TKMoles StandStateChemPot " + " ln(AC) ln(X_i) | F z_i phi | ChemPot | (-lnMnaught)"); + plogf("| (MolNum ChemPot)|"); + writeline('-', 147, true, true); + for (size_t i = 0; i < m_nsp; ++i) { + size_t j = x_order[i].second; + size_t pid = m_phaseID[j]; + plogf(" %-12.12s", m_speciesName[j]); + plogf(" %14.7E ", m_molNumSpecies_old[j]); + plogf("%14.7E ", m_SSfeSpecies[j]); + plogf("%14.7E ", log(m_actCoeffSpecies_old[j])); + double tpmoles = m_tPhaseMoles_old[pid]; + double phi = m_phasePhi[pid]; + double eContrib = phi * m_chargeSpecies[j] * m_Faraday_dim; + double lx = 0.0; + if (m_speciesUnknownType[j] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + lx = 0.0; + } else { + if (tpmoles > 0.0 && m_molNumSpecies_old[j] > 0.0) { + double tmp = std::max(VCS_DELETE_MINORSPECIES_CUTOFF, m_molNumSpecies_old[j]); + lx = log(tmp) - log(tpmoles); + } else { + lx = m_feSpecies_old[j] - m_SSfeSpecies[j] + - log(m_actCoeffSpecies_old[j]) + m_lnMnaughtSpecies[j]; + } + } + plogf("%14.7E |", lx); + plogf("%14.7E | ", eContrib); + double tmp = m_SSfeSpecies[j] + log(m_actCoeffSpecies_old[j]) + + lx - m_lnMnaughtSpecies[j] + eContrib; + if (fabs(m_feSpecies_old[j] - tmp) > 1.0E-7) { + throw CanteraError("VCS_SOLVE::vcs_report", + "we have a problem - doesn't add up"); + } + plogf(" %12.4E |", m_feSpecies_old[j]); + if (m_lnMnaughtSpecies[j] != 0.0) { + plogf("(%11.5E)", - m_lnMnaughtSpecies[j]); + } else { + plogf(" "); + } + + plogf("| %20.9E |", m_feSpecies_old[j] * m_molNumSpecies_old[j]); + plogf("\n"); + } + for (size_t i = 0; i < 125; i++) { + plogf(" "); + } + plogf(" %20.9E\n", g); + writeline('-', 147); + + // TABLE OF SOLUTION COUNTERS + plogf("\n"); + plogf("\nCounters: Iterations Time (seconds)\n"); + if (m_timing_print_lvl > 0) { + plogf(" vcs_basopt: %5d %11.5E\n", + m_VCount->Basis_Opts, m_VCount->Time_basopt); + plogf(" vcs_TP: %5d %11.5E\n", + m_VCount->Its, m_VCount->Time_vcs_TP); + } else { + plogf(" vcs_basopt: %5d %11s\n", + m_VCount->Basis_Opts," NA "); + plogf(" vcs_TP: %5d %11s\n", + m_VCount->Its," NA "); + } + writeline('-', 80); + writeline('-', 80); + + // Return a successful completion flag + return VCS_SUCCESS; +} + +void VCS_SOLVE::vcs_elab() +{ + for (size_t j = 0; j < m_nelem; ++j) { + m_elemAbundances[j] = 0.0; + for (size_t i = 0; i < m_nsp; ++i) { + if (m_speciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + m_elemAbundances[j] += m_formulaMatrix(i,j) * m_molNumSpecies_old[i]; + } + } + } +} + +bool VCS_SOLVE::vcs_elabcheck(int ibound) +{ + size_t top = m_numComponents; + if (ibound) { + top = m_nelem; + } + + for (size_t i = 0; i < top; ++i) { + // Require 12 digits of accuracy on non-zero constraints. + if (m_elementActive[i] && fabs(m_elemAbundances[i] - m_elemAbundancesGoal[i]) > fabs(m_elemAbundancesGoal[i]) * 1.0e-12) { + // This logic is for charge neutrality condition + if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY && + m_elemAbundancesGoal[i] != 0.0) { + throw CanteraError("VCS_SOLVE::vcs_elabcheck", + "Problem with charge neutrality condition"); + } + if (m_elemAbundancesGoal[i] == 0.0 || (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE)) { + double scale = VCS_DELETE_MINORSPECIES_CUTOFF; + + // Find out if the constraint is a multisign constraint. If it + // is, then we have to worry about roundoff error in the + // addition of terms. We are limited to 13 digits of finite + // arithmetic accuracy. + bool multisign = false; + for (size_t kspec = 0; kspec < m_nsp; kspec++) { + double eval = m_formulaMatrix(kspec,i); + if (eval < 0.0) { + multisign = true; + } + if (eval != 0.0) { + scale = std::max(scale, fabs(eval * m_molNumSpecies_old[kspec])); + } + } + if (multisign) { + if (fabs(m_elemAbundances[i] - m_elemAbundancesGoal[i]) > 1e-11 * scale) { + return false; + } + } else { + if (fabs(m_elemAbundances[i] - m_elemAbundancesGoal[i]) > VCS_DELETE_MINORSPECIES_CUTOFF) { + return false; + } + } + } else { + // For normal element balances, we require absolute compliance + // even for ridiculously small numbers. + if (m_elType[i] == VCS_ELEM_TYPE_ABSPOS) { + return false; + } else { + return false; + } + } + } + } + return true; +} + +void VCS_SOLVE::vcs_elabPhase(size_t iphase, double* const elemAbundPhase) +{ + for (size_t j = 0; j < m_nelem; ++j) { + elemAbundPhase[j] = 0.0; + for (size_t i = 0; i < m_nsp; ++i) { + if (m_speciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE && m_phaseID[i] == iphase) { + elemAbundPhase[j] += m_formulaMatrix(i,j) * m_molNumSpecies_old[i]; + } + } + } +} + +int VCS_SOLVE::vcs_elcorr(double aa[], double x[]) +{ + int retn = 0; + + vector_fp ga_save(m_elemAbundances); + if (m_debug_print_lvl >= 2) { + plogf(" --- vcsc_elcorr: Element abundances correction routine"); + if (m_nelem != m_numComponents) { + plogf(" (m_numComponents != m_nelem)"); + } + plogf("\n"); + } + + for (size_t i = 0; i < m_nelem; ++i) { + x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i]; + } + double l2before = 0.0; + for (size_t i = 0; i < m_nelem; ++i) { + l2before += x[i] * x[i]; + } + l2before = sqrt(l2before/m_nelem); + + // Special section to take out single species, single component, + // moles. These are species which have non-zero entries in the + // formula matrix, and no other species have zero values either. + bool changed = false; + for (size_t i = 0; i < m_nelem; ++i) { + int numNonZero = 0; + bool multisign = false; + for (size_t kspec = 0; kspec < m_nsp; kspec++) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + double eval = m_formulaMatrix(kspec,i); + if (eval < 0.0) { + multisign = true; + } + if (eval != 0.0) { + numNonZero++; + } + } + } + if (!multisign) { + if (numNonZero < 2) { + for (size_t kspec = 0; kspec < m_nsp; kspec++) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + double eval = m_formulaMatrix(kspec,i); + if (eval > 0.0) { + m_molNumSpecies_old[kspec] = m_elemAbundancesGoal[i] / eval; + changed = true; + } + } + } + } else { + int numCompNonZero = 0; + size_t compID = npos; + for (size_t kspec = 0; kspec < m_numComponents; kspec++) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + double eval = m_formulaMatrix(kspec,i); + if (eval > 0.0) { + compID = kspec; + numCompNonZero++; + } + } + } + if (numCompNonZero == 1) { + double diff = m_elemAbundancesGoal[i]; + for (size_t kspec = m_numComponents; kspec < m_nsp; kspec++) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + double eval = m_formulaMatrix(kspec,i); + diff -= eval * m_molNumSpecies_old[kspec]; + } + m_molNumSpecies_old[compID] = std::max(0.0,diff/m_formulaMatrix(compID,i)); + changed = true; + } + } + } + } + } + if (changed) { + vcs_elab(); + } + + // Section to check for maximum bounds errors on all species due to + // elements. This may only be tried on element types which are + // VCS_ELEM_TYPE_ABSPOS. This is because no other species may have a + // negative number of these. + // + // Note, also we can do this over ne, the number of elements, not just the + // number of components. + changed = false; + for (size_t i = 0; i < m_nelem; ++i) { + int elType = m_elType[i]; + if (elType == VCS_ELEM_TYPE_ABSPOS) { + for (size_t kspec = 0; kspec < m_nsp; kspec++) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + double atomComp = m_formulaMatrix(kspec,i); + if (atomComp > 0.0) { + double maxPermissible = m_elemAbundancesGoal[i] / atomComp; + if (m_molNumSpecies_old[kspec] > maxPermissible) { + if (m_debug_print_lvl >= 3) { + plogf(" --- vcs_elcorr: Reduced species %s from %g to %g " + "due to %s max bounds constraint\n", + m_speciesName[kspec], m_molNumSpecies_old[kspec], + maxPermissible, m_elementName[i]); + } + m_molNumSpecies_old[kspec] = maxPermissible; + changed = true; + if (m_molNumSpecies_old[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF) { + m_molNumSpecies_old[kspec] = 0.0; + if (m_SSPhase[kspec]) { + m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS; + } else { + m_speciesStatus[kspec] = VCS_SPECIES_ACTIVEBUTZERO; + } + if (m_debug_print_lvl >= 2) { + plogf(" --- vcs_elcorr: Zeroed species %s and changed " + "status to %d due to max bounds constraint\n", + m_speciesName[kspec], m_speciesStatus[kspec]); + } + } + } + } + } + } + } + } + + // Recalculate the element abundances if something has changed. + if (changed) { + vcs_elab(); + } + + // Ok, do the general case. Linear algebra problem is of length nc, not ne, + // as there may be degenerate rows when nc .ne. ne. + DenseMatrix A(m_numComponents, m_numComponents); + for (size_t i = 0; i < m_numComponents; ++i) { + x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i]; + if (fabs(x[i]) > 1.0E-13) { + retn = 1; + } + for (size_t j = 0; j < m_numComponents; ++j) { + A(j, i) = - m_formulaMatrix(i,j); + } + } + + solve(A, x, 1, m_nelem); + + // Now apply the new direction without creating negative species. + double par = 0.5; + for (size_t i = 0; i < m_numComponents; ++i) { + if (m_molNumSpecies_old[i] > 0.0) { + par = std::max(par, -x[i] / m_molNumSpecies_old[i]); + } + } + par = std::min(par, 100.0); + par = 1.0 / par; + if (par < 1.0 && par > 0.0) { + retn = 2; + par *= 0.9999; + for (size_t i = 0; i < m_numComponents; ++i) { + double tmp = m_molNumSpecies_old[i] + par * x[i]; + if (tmp > 0.0) { + m_molNumSpecies_old[i] = tmp; + } else { + if (m_SSPhase[i]) { + m_molNumSpecies_old[i] = 0.0; + } else { + m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001; + } + } + } + } else { + for (size_t i = 0; i < m_numComponents; ++i) { + double tmp = m_molNumSpecies_old[i] + x[i]; + if (tmp > 0.0) { + m_molNumSpecies_old[i] = tmp; + } else { + if (m_SSPhase[i]) { + m_molNumSpecies_old[i] = 0.0; + } else { + m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001; + } + } + } + } + + // We have changed the element abundances. Calculate them again + vcs_elab(); + + // We have changed the total moles in each phase. Calculate them again + vcs_tmoles(); + + // Try some ad hoc procedures for fixing the problem + if (retn >= 2) { + // First find a species whose adjustment is a win-win situation. + for (size_t kspec = 0; kspec < m_nsp; kspec++) { + if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + continue; + } + double saveDir = 0.0; + bool goodSpec = true; + for (size_t i = 0; i < m_numComponents; ++i) { + double dir = m_formulaMatrix(kspec,i) * (m_elemAbundancesGoal[i] - m_elemAbundances[i]); + if (fabs(dir) > 1.0E-10) { + if (dir > 0.0) { + if (saveDir < 0.0) { + goodSpec = false; + break; + } + } else { + if (saveDir > 0.0) { + goodSpec = false; + break; + } + } + saveDir = dir; + } else { + if (m_formulaMatrix(kspec,i) != 0.) { + goodSpec = false; + break; + } + } + } + if (goodSpec) { + int its = 0; + double xx = 0.0; + for (size_t i = 0; i < m_numComponents; ++i) { + if (m_formulaMatrix(kspec,i) != 0.0) { + xx += (m_elemAbundancesGoal[i] - m_elemAbundances[i]) / m_formulaMatrix(kspec,i); + its++; + } + } + if (its > 0) { + xx /= its; + } + m_molNumSpecies_old[kspec] += xx; + m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 1.0E-10); + + // If we are dealing with a deleted species, then we need to + // reinsert it into the active list. + if (kspec >= m_numSpeciesRdc) { + vcs_reinsert_deleted(kspec); + m_molNumSpecies_old[m_numSpeciesRdc - 1] = xx; + vcs_elab(); + goto L_CLEANUP; + } + vcs_elab(); + } + } + } + if (vcs_elabcheck(0)) { + retn = 1; + goto L_CLEANUP; + } + + for (size_t i = 0; i < m_nelem; ++i) { + if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY || + (m_elType[i] == VCS_ELEM_TYPE_ABSPOS && m_elemAbundancesGoal[i] == 0.0)) { + for (size_t kspec = 0; kspec < m_numSpeciesRdc; kspec++) { + if (m_elemAbundances[i] > 0.0 && m_formulaMatrix(kspec,i) < 0.0) { + m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix(kspec,i); + m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); + vcs_elab(); + break; + } + if (m_elemAbundances[i] < 0.0 && m_formulaMatrix(kspec,i) > 0.0) { + m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix(kspec,i); + m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); + vcs_elab(); + break; + } + } + } + } + if (vcs_elabcheck(1)) { + retn = 1; + goto L_CLEANUP; + } + + // For electron charges element types, we try positive deltas in the species + // concentrations to match the desired electron charge exactly. + for (size_t i = 0; i < m_nelem; ++i) { + double dev = m_elemAbundancesGoal[i] - m_elemAbundances[i]; + if (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE && (fabs(dev) > 1.0E-300)) { + bool useZeroed = true; + for (size_t kspec = 0; kspec < m_numSpeciesRdc; kspec++) { + if (dev < 0.0) { + if (m_formulaMatrix(kspec,i) < 0.0 && m_molNumSpecies_old[kspec] > 0.0) { + useZeroed = false; + } + } else { + if (m_formulaMatrix(kspec,i) > 0.0 && m_molNumSpecies_old[kspec] > 0.0) { + useZeroed = false; + } + } + } + for (size_t kspec = 0; kspec < m_numSpeciesRdc; kspec++) { + if (m_molNumSpecies_old[kspec] > 0.0 || useZeroed) { + if (dev < 0.0 && m_formulaMatrix(kspec,i) < 0.0) { + double delta = dev / m_formulaMatrix(kspec,i); + m_molNumSpecies_old[kspec] += delta; + m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); + vcs_elab(); + break; + } + if (dev > 0.0 && m_formulaMatrix(kspec,i) > 0.0) { + double delta = dev / m_formulaMatrix(kspec,i); + m_molNumSpecies_old[kspec] += delta; + m_molNumSpecies_old[kspec] = std::max(m_molNumSpecies_old[kspec], 0.0); + vcs_elab(); + break; + } + } + } + } + } + if (vcs_elabcheck(1)) { + retn = 1; + goto L_CLEANUP; + } + +L_CLEANUP: + ; + vcs_tmoles(); + double l2after = 0.0; + for (size_t i = 0; i < m_nelem; ++i) { + l2after += pow(m_elemAbundances[i] - m_elemAbundancesGoal[i], 2); + } + l2after = sqrt(l2after/m_nelem); + if (m_debug_print_lvl >= 2) { + plogf(" --- Elem_Abund: Correct Initial " + " Final\n"); + for (size_t i = 0; i < m_nelem; ++i) { + plogf(" --- "); + plogf("%-2.2s", m_elementName[i]); + plogf(" %20.12E %20.12E %20.12E\n", m_elemAbundancesGoal[i], ga_save[i], m_elemAbundances[i]); + } + plogf(" --- Diff_Norm: %20.12E %20.12E\n", + l2before, l2after); + } + return retn; +} + +int VCS_SOLVE::vcs_inest_TP() +{ + const char* pprefix = " --- vcs_inest: "; + int retn = 0; + clockWC tickTock; + if (m_doEstimateEquil > 0) { + // Calculate the elemental abundances + vcs_elab(); + if (vcs_elabcheck(0)) { + if (m_debug_print_lvl >= 2) { + plogf("%s Initial guess passed element abundances on input\n", pprefix); + plogf("%s m_doEstimateEquil = 1 so will use the input mole " + "numbers as estimates\n", pprefix); + } + return retn; + } else if (m_debug_print_lvl >= 2) { + plogf("%s Initial guess failed element abundances on input\n", pprefix); + plogf("%s m_doEstimateEquil = 1 so will discard input " + "mole numbers and find our own estimate\n", pprefix); + } + } + + // temporary space for usage in this routine and in subroutines + vector_fp sm(m_nelem*m_nelem, 0.0); + vector_fp ss(m_nelem, 0.0); + vector_fp sa(m_nelem, 0.0); + vector_fp aw(m_nsp + m_nelem, 0.0); + + // Go get the estimate of the solution + if (m_debug_print_lvl >= 2) { + plogf("%sGo find an initial estimate for the equilibrium problem\n", + pprefix); + } + double test = -1.0E20; + vcs_inest(&aw[0], &sa[0], &sm[0], &ss[0], test); + + // Calculate the elemental abundances + vcs_elab(); + + // If we still fail to achieve the correct elemental abundances, try to fix + // the problem again by calling the main elemental abundances fixer routine, + // used in the main program. This attempts to tweak the mole numbers of the + // component species to satisfy the element abundance constraints. + // + // Note: We won't do this unless we have to since it involves inverting a + // matrix. + bool rangeCheck = vcs_elabcheck(1); + if (!vcs_elabcheck(0)) { + if (m_debug_print_lvl >= 2) { + plogf("%sInitial guess failed element abundances\n", pprefix); + plogf("%sCall vcs_elcorr to attempt fix\n", pprefix); + } + vcs_elcorr(&sm[0], &aw[0]); + rangeCheck = vcs_elabcheck(1); + if (!vcs_elabcheck(0)) { + plogf("%sInitial guess still fails element abundance equations\n", + pprefix); + plogf("%s - Inability to ever satisfy element abundance " + "constraints is probable\n", pprefix); + retn = -1; + } else { + if (m_debug_print_lvl >= 2) { + if (rangeCheck) { + plogf("%sInitial guess now satisfies element abundances\n", pprefix); + } else { + plogf("%sElement Abundances RANGE ERROR\n", pprefix); + plogf("%s - Initial guess satisfies NC=%d element abundances, " + "BUT not NE=%d element abundances\n", pprefix, + m_numComponents, m_nelem); + } + } + } + } else { + if (m_debug_print_lvl >= 2) { + if (rangeCheck) { + plogf("%sInitial guess satisfies element abundances\n", pprefix); + } else { + plogf("%sElement Abundances RANGE ERROR\n", pprefix); + plogf("%s - Initial guess satisfies NC=%d element abundances, " + "BUT not NE=%d element abundances\n", pprefix, + m_numComponents, m_nelem); + } + } + } + + if (m_debug_print_lvl >= 2) { + plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E\n", pprefix, + vcs_Total_Gibbs(&m_molNumSpecies_old[0], &m_feSpecies_new[0], + &m_tPhaseMoles_old[0])); + } + + // Record time + m_VCount->T_Time_inest += tickTock.secondsWC(); + m_VCount->T_Calls_Inest++; + return retn; +} + +int VCS_SOLVE::vcs_setMolesLinProg() +{ + double test = -1.0E-10; + + if (m_debug_print_lvl >= 2) { + plogf(" --- call setInitialMoles\n"); + } + + double dxi_min = 1.0e10; + int retn; + int iter = 0; + bool abundancesOK = true; + bool usedZeroedSpecies; + vector_fp sm(m_nelem * m_nelem, 0.0); + vector_fp ss(m_nelem, 0.0); + vector_fp sa(m_nelem, 0.0); + vector_fp wx(m_nelem, 0.0); + vector_fp aw(m_nsp, 0.0); + + for (size_t ik = 0; ik < m_nsp; ik++) { + if (m_speciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) { + m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]); + } + } + + if (m_debug_print_lvl >= 2) { + printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); + } + + bool redo = true; + while (redo) { + if (!vcs_elabcheck(0)) { + if (m_debug_print_lvl >= 2) { + plogf(" --- seMolesLinProg Mole numbers failing element abundances\n"); + plogf(" --- seMolesLinProg Call vcs_elcorr to attempt fix\n"); + } + retn = vcs_elcorr(&sm[0], &wx[0]); + if (retn >= 2) { + abundancesOK = false; + } else { + abundancesOK = true; + } + } else { + abundancesOK = true; + } + + // Now find the optimized basis that spans the stoichiometric + // coefficient matrix, based on the current composition, + // m_molNumSpecies_old[] We also calculate sc[][], the reaction matrix. + retn = vcs_basopt(false, &aw[0], &sa[0], &sm[0], &ss[0], + test, &usedZeroedSpecies); + if (retn != VCS_SUCCESS) { + return retn; + } + + if (m_debug_print_lvl >= 2) { + plogf("iteration %d\n", iter); + } + redo = false; + iter++; + if (iter > 15) { + break; + } + + // loop over all reactions + for (size_t irxn = 0; irxn < m_numRxnTot; irxn++) { + // dg_rt is the Delta_G / RT value for the reaction + size_t ik = m_numComponents + irxn; + double dg_rt = m_SSfeSpecies[ik]; + dxi_min = 1.0e10; + const double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn); + for (size_t jcomp = 0; jcomp < m_nelem; jcomp++) { + dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp]; + } + // fwd or rev direction. + // idir > 0 implies increasing the current species + // idir < 0 implies decreasing the current species + int idir = (dg_rt < 0.0 ? 1 : -1); + if (idir < 0) { + dxi_min = m_molNumSpecies_old[ik]; + } + + for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) { + double nu = sc_irxn[jcomp]; + // set max change in progress variable by + // non-negativity requirement + if (nu*idir < 0) { + double delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu); + // if a component has nearly zero moles, redo + // with a new set of components + if (!redo && delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) { + if (m_debug_print_lvl >= 2) { + plogf(" --- Component too small: %s\n", m_speciesName[jcomp]); + } + redo = true; + } + dxi_min = std::min(dxi_min, delta_xi); + } + } + + // step the composition by dxi_min, check against zero, since + // we are zeroing components and species on every step. + // Redo the iteration, if a component went from positive to zero on this step. + double dsLocal = idir*dxi_min; + m_molNumSpecies_old[ik] += dsLocal; + m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]); + for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) { + bool full = false; + if (m_molNumSpecies_old[jcomp] > 1.0E-15) { + full = true; + } + m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal; + m_molNumSpecies_old[jcomp] = max(0.0, m_molNumSpecies_old[jcomp]); + if (full && m_molNumSpecies_old[jcomp] < 1.0E-60) { + redo = true; + } + } + } + + if (m_debug_print_lvl >= 2) { + printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); + } + } + + if (m_debug_print_lvl == 1) { + printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); + plogf(" --- setInitialMoles end\n"); + } + retn = 0; + if (!abundancesOK) { + retn = -1; + } else if (iter > 15) { + retn = 1; + } + return retn; +} + +double VCS_SOLVE::vcs_Total_Gibbs(double* molesSp, double* chemPot, + double* tPhMoles) +{ + double g = 0.0; + + for (size_t iph = 0; iph < m_numPhases; iph++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); + if ((TPhInertMoles[iph] > 0.0) && (tPhMoles[iph] > 0.0)) { + g += TPhInertMoles[iph] * + log(TPhInertMoles[iph] / tPhMoles[iph]); + if (Vphase->m_gasPhase) { + g += TPhInertMoles[iph] * log(m_pressurePA/(1.01325E5)); + } + } + } + + for (size_t kspec = 0; kspec < m_numSpeciesRdc; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + g += molesSp[kspec] * chemPot[kspec]; + } + } + + return g; +} + +double VCS_SOLVE::vcs_GibbsPhase(size_t iphase, const double* const w, + const double* const fe) +{ + double g = 0.0; + double phaseMols = 0.0; + for (size_t kspec = 0; kspec < m_numSpeciesRdc; ++kspec) { + if (m_phaseID[kspec] == iphase && m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + g += w[kspec] * fe[kspec]; + phaseMols += w[kspec]; + } + } + + if (TPhInertMoles[iphase] > 0.0) { + phaseMols += TPhInertMoles[iphase]; + g += TPhInertMoles[iphase] * log(TPhInertMoles[iphase] / phaseMols); + vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); + if (Vphase->m_gasPhase) { + g += TPhInertMoles[iphase] * log(m_pressurePA/1.01325E5); + } + } + + return g; +} + +void VCS_SOLVE::vcs_prob_update() +{ + // 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 zeroed out phases actually contain information + // about likely reemergent states. + m_mix->uploadMoleFractionsFromPhases(); + for (size_t ip = 0; ip < m_numPhases; ip++) { + m_mix->setPhaseMoles(ip, m_VolPhaseList[ip]->totalMoles()); + } +} + +void VCS_SOLVE::vcs_prob_specifyFully() +{ + // Whether we have an estimate or not gets overwritten on + // the call to the equilibrium solver. + m_temperature = m_mix->temperature(); + m_pressurePA = m_mix->pressure(); + m_Faraday_dim = Faraday / (m_temperature * GasConstant); + m_totalVol = m_mix->volume(); + + vector invSpecies(m_nsp); + for (size_t k = 0; k < m_nsp; k++) { + invSpecies[m_speciesMapIndex[k]] = k; + } + + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + ThermoPhase* tPhase = &m_mix->phase(iphase); + vcs_VolPhase* volPhase = m_VolPhaseList[iphase].get(); + + volPhase->setState_TP(m_temperature, m_pressurePA); + + // Loop through each species in the current phase + size_t nSpPhase = tPhase->nSpecies(); + if ((nSpPhase == 1) && (volPhase->phiVarIndex() == 0)) { + volPhase->setExistence(VCS_PHASE_EXIST_ALWAYS); + } else if (volPhase->totalMoles() > 0.0) { + volPhase->setExistence(VCS_PHASE_EXIST_YES); + } else { + volPhase->setExistence(VCS_PHASE_EXIST_NO); + } + } + + // Printout the species information: PhaseID's and mole nums + if (m_printLvl > 1) { + writeline('=', 80, true, true); + writeline('=', 20, false); + plogf(" Cantera_to_vprob: START OF PROBLEM STATEMENT "); + writeline('=', 20); + writeline('=', 80); + plogf("\n"); + plogf(" Phase IDs of species\n"); + plogf(" species phaseID phaseName "); + plogf(" Initial_Estimated_kMols\n"); + for (size_t i = 0; i < m_nsp; i++) { + size_t iphase = m_phaseID[i]; + vcs_VolPhase* VolPhase = m_VolPhaseList[iphase].get(); + plogf("%16s %5d %16s", m_speciesName[i].c_str(), iphase, + VolPhase->PhaseName.c_str()); + if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf(" Volts = %-10.5g\n", m_molNumSpecies_old[i]); + } else { + plogf(" %-10.5g\n", m_molNumSpecies_old[i]); + } + } + + // Printout of the Phase structure information + writeline('-', 80, true, true); + plogf(" Information about phases\n"); + plogf(" PhaseName PhaseNum SingSpec GasPhase EqnState NumSpec"); + plogf(" TMolesInert Tmoles(kmol)\n"); + + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + vcs_VolPhase* VolPhase = m_VolPhaseList[iphase].get(); + plogf("%16s %5d %5d %8d %16s %8d %16e ", VolPhase->PhaseName.c_str(), + VolPhase->VP_ID_, VolPhase->m_singleSpecies, + VolPhase->m_gasPhase, VolPhase->eos_name(), + VolPhase->nSpecies(), VolPhase->totalMolesInert()); + plogf("%16e\n", VolPhase->totalMoles()); + } + + writeline('=', 80, true, true); + writeline('=', 20, false); + plogf(" Cantera_to_vprob: END OF PROBLEM STATEMENT "); + writeline('=', 20); + writeline('=', 80); + plogf("\n"); + } + + // m_numRxnTot = number of noncomponents, also equal to the number of + // reactions. Note, it's possible that the number of elements is greater + // than the number of species. In that case set the number of reactions to + // zero. + if (m_nelem > m_nsp) { + m_numRxnTot = 0; + } else { + m_numRxnTot = m_nsp - m_nelem; + } + m_numRxnRdc = m_numRxnTot; +} + +void VCS_SOLVE::vcs_inest(double* const aw, double* const sa, double* const sm, + double* const ss, double test) +{ + const char* pprefix = " --- vcs_inest: "; + size_t nrxn = m_numRxnTot; + + // CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB AND + // molNum(I) .GE. 0.0. Note, both of these programs do this. + vcs_setMolesLinProg(); + + if (m_debug_print_lvl >= 2) { + plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n", + pprefix); + plogf("%s SPECIES MOLE_NUMBER -SS_ChemPotential\n", pprefix); + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + plogf("%s ", pprefix); + plogf("%-12.12s", m_speciesName[kspec]); + plogf(" %15.5g %12.3g\n", m_molNumSpecies_old[kspec], -m_SSfeSpecies[kspec]); + } + plogf("%s Element Abundance Agreement returned from linear " + "programming (vcs_inest initial guess):\n", pprefix); + plogf("%s Element Goal Actual\n", pprefix); + for (size_t j = 0; j < m_nelem; j++) { + if (m_elementActive[j]) { + double tmp = 0.0; + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + tmp += m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec]; + } + plogf("%s ", pprefix); + plogf(" %-9.9s", m_elementName[j]); + plogf(" %12.3g %12.3g\n", m_elemAbundancesGoal[j], tmp); + } + } + writelogendl(); + } + + // Make sure all species have positive definite mole numbers Set voltages to + // zero for now, until we figure out what to do + m_deltaMolNumSpecies.assign(m_deltaMolNumSpecies.size(), 0.0); + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + if (m_molNumSpecies_old[kspec] <= 0.0) { + // HKM Should eventually include logic here for non SS phases + if (!m_SSPhase[kspec]) { + m_molNumSpecies_old[kspec] = 1.0e-30; + } + } + } else { + m_molNumSpecies_old[kspec] = 0.0; + } + } + + // Now find the optimized basis that spans the stoichiometric coefficient + // matrix + bool conv; + vcs_basopt(false, aw, sa, sm, ss, test, &conv); + + // CALCULATE TOTAL MOLES, CHEMICAL POTENTIALS OF BASIS + + // Calculate TMoles and m_tPhaseMoles_old[] + vcs_tmoles(); + + // m_tPhaseMoles_new[] will consist of just the component moles + for (size_t iph = 0; iph < m_numPhases; iph++) { + m_tPhaseMoles_new[iph] = TPhInertMoles[iph] + 1.0E-20; + } + for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { + if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { + m_tPhaseMoles_new[m_phaseID[kspec]] += m_molNumSpecies_old[kspec]; + } + } + double TMolesMultiphase = 0.0; + for (size_t iph = 0; iph < m_numPhases; iph++) { + if (! m_VolPhaseList[iph]->m_singleSpecies) { + TMolesMultiphase += m_tPhaseMoles_new[iph]; + } + } + m_molNumSpecies_new = m_molNumSpecies_old; + for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_MOLNUM) { + m_molNumSpecies_new[kspec] = 0.0; + } + } + m_feSpecies_new = m_SSfeSpecies; + + for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { + if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) { + if (! m_SSPhase[kspec]) { + size_t iph = m_phaseID[kspec]; + m_feSpecies_new[kspec] += log(m_molNumSpecies_new[kspec] / m_tPhaseMoles_old[iph]); + } + } else { + m_molNumSpecies_new[kspec] = 0.0; + } + } + vcs_deltag(0, true, VCS_STATECALC_NEW); + if (m_debug_print_lvl >= 2) { + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + plogf("%s", pprefix); + plogf("%-12.12s", m_speciesName[kspec]); + if (kspec < m_numComponents) { + plogf("fe* = %15.5g ff = %15.5g\n", m_feSpecies_new[kspec], + m_SSfeSpecies[kspec]); + } else { + plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n", + m_feSpecies_new[kspec], m_SSfeSpecies[kspec], m_deltaGRxn_new[kspec-m_numComponents]); + } + } + } + + // ESTIMATE REACTION ADJUSTMENTS + vector_fp& xtphMax = m_TmpPhase; + vector_fp& xtphMin = m_TmpPhase2; + m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0); + for (size_t iph = 0; iph < m_numPhases; iph++) { + xtphMax[iph] = log(m_tPhaseMoles_new[iph] * 1.0E32); + xtphMin[iph] = log(m_tPhaseMoles_new[iph] * 1.0E-32); + } + for (size_t irxn = 0; irxn < nrxn; ++irxn) { + size_t kspec = m_indexRxnToSpecies[irxn]; + + // For single species phases, we will not estimate the mole numbers. If + // the phase exists, it stays. If it doesn't exist in the estimate, it + // doesn't come into existence here. + if (! m_SSPhase[kspec]) { + size_t iph = m_phaseID[kspec]; + if (m_deltaGRxn_new[irxn] > xtphMax[iph]) { + m_deltaGRxn_new[irxn] = 0.8 * xtphMax[iph]; + } + if (m_deltaGRxn_new[irxn] < xtphMin[iph]) { + m_deltaGRxn_new[irxn] = 0.8 * xtphMin[iph]; + } + + // HKM -> The TMolesMultiphase is a change of mine. It more evenly + // distributes the initial moles amongst multiple multispecies + // phases according to the relative values of the standard state + // free energies. There is no change for problems with one + // multispecies phase. It cut diamond4.vin iterations down from 62 + // to 14. + m_deltaMolNumSpecies[kspec] = 0.5 * (m_tPhaseMoles_new[iph] + TMolesMultiphase) + * exp(-m_deltaGRxn_new[irxn]); + + for (size_t k = 0; k < m_numComponents; ++k) { + m_deltaMolNumSpecies[k] += m_stoichCoeffRxnMatrix(k,irxn) * m_deltaMolNumSpecies[kspec]; + } + + for (iph = 0; iph < m_numPhases; iph++) { + m_deltaPhaseMoles[iph] += m_deltaMolNumPhase(iph,irxn) * m_deltaMolNumSpecies[kspec]; + } + } + } + if (m_debug_print_lvl >= 2) { + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf("%sdirection (", pprefix); + plogf("%-12.12s", m_speciesName[kspec]); + plogf(") = %g", m_deltaMolNumSpecies[kspec]); + if (m_SSPhase[kspec]) { + if (m_molNumSpecies_old[kspec] > 0.0) { + plogf(" (ssPhase exists at w = %g moles)", m_molNumSpecies_old[kspec]); + } else { + plogf(" (ssPhase doesn't exist -> stability not checked)"); + } + } + writelogendl(); + } + } + } + + // KEEP COMPONENT SPECIES POSITIVE + double par = 0.5; + for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE && + par < -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]) { + par = -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]; + } + } + par = 1. / par; + if (par <= 1.0 && par > 0.0) { + par *= 0.8; + } else { + par = 1.0; + } + + // CALCULATE NEW MOLE NUMBERS + size_t lt = 0; + size_t ikl = 0; + double s1 = 0.0; + while (true) { + for (size_t kspec = 0; kspec < m_numComponents; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + m_molNumSpecies_old[kspec] = m_molNumSpecies_new[kspec] + par * m_deltaMolNumSpecies[kspec]; + } else { + m_deltaMolNumSpecies[kspec] = 0.0; + } + } + for (size_t kspec = m_numComponents; kspec < m_nsp; ++kspec) { + if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE && + m_deltaMolNumSpecies[kspec] != 0.0) { + m_molNumSpecies_old[kspec] = m_deltaMolNumSpecies[kspec] * par; + } + } + + // We have a new w[] estimate, go get the TMoles and m_tPhaseMoles_old[] + // values + vcs_tmoles(); + if (lt > 0) { + break; + } + + // CONVERGENCE FORCING SECTION + vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD); + vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_nsp); + double s = 0.0; + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + s += m_deltaMolNumSpecies[kspec] * m_feSpecies_old[kspec]; + } + if (s == 0.0) { + break; + } + if (s < 0.0 && ikl == 0) { + break; + } + + // TRY HALF STEP SIZE + if (ikl == 0) { + s1 = s; + par *= 0.5; + ikl = 1; + continue; + } + + // FIT PARABOLA THROUGH HALF AND FULL STEPS + double xl = (1.0 - s / (s1 - s)) * 0.5; + if (xl < 0.0) { + // POOR DIRECTION, REDUCE STEP SIZE TO 0.2 + par *= 0.2; + } else { + if (xl > 1.0) { + // TOO BIG A STEP, TAKE ORIGINAL FULL STEP + par *= 2.0; + } else { + // ACCEPT RESULTS OF FORCER + par = par * 2.0 * xl; + } + } + lt = 1; + } + + if (m_debug_print_lvl >= 2) { + plogf("%s Final Mole Numbers produced by inest:\n", + pprefix); + plogf("%s SPECIES MOLE_NUMBER\n", pprefix); + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + plogf("%s %-12.12s %g\n", + pprefix, m_speciesName[kspec], m_molNumSpecies_old[kspec]); + } + } +} + +void VCS_SOLVE::vcs_SSPhase() +{ + vector_int numPhSpecies(m_numPhases, 0); + for (size_t kspec = 0; kspec < m_nsp; ++kspec) { + numPhSpecies[m_phaseID[kspec]]++; + } + + // Handle the special case of a single species in a phase that has been + // earmarked as a multispecies phase. Treat that species as a single-species + // phase + for (size_t iph = 0; iph < m_numPhases; iph++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); + Vphase->m_singleSpecies = false; + if (TPhInertMoles[iph] > 0.0) { + Vphase->setExistence(2); + } + if (numPhSpecies[iph] <= 1 && TPhInertMoles[iph] == 0.0) { + Vphase->m_singleSpecies = true; + } + } + + // Fill in some useful arrays here that have to do with the static + // information concerning the phase ID of species. SSPhase = Boolean + // indicating whether a species is in a single species phase or not. + for (size_t kspec = 0; kspec < m_nsp; kspec++) { + size_t iph = m_phaseID[kspec]; + vcs_VolPhase* Vphase = m_VolPhaseList[iph].get(); + if (Vphase->m_singleSpecies) { + m_SSPhase[kspec] = true; + } else { + m_SSPhase[kspec] = false; + } + } +} + +void VCS_SOLVE::vcs_delete_memory() +{ + delete m_VCount; + m_VCount = 0; + + m_nsp = 0; + m_nelem = 0; + m_numComponents = 0; + +} + +void VCS_SOLVE::vcs_counters_init(int ifunc) +{ + m_VCount->Its = 0; + m_VCount->Basis_Opts = 0; + m_VCount->Time_vcs_TP = 0.0; + m_VCount->Time_basopt = 0.0; + if (ifunc) { + m_VCount->T_Its = 0; + m_VCount->T_Basis_Opts = 0; + m_VCount->T_Calls_Inest = 0; + m_VCount->T_Calls_vcs_TP = 0; + m_VCount->T_Time_vcs_TP = 0.0; + m_VCount->T_Time_basopt = 0.0; + m_VCount->T_Time_inest = 0.0; + m_VCount->T_Time_vcs = 0.0; + } +} + +void VCS_SOLVE::vcs_TCounters_report(int timing_print_lvl) +{ + plogf("\nTCounters: Num_Calls Total_Its Total_Time (seconds)\n"); + if (timing_print_lvl > 0) { + plogf(" vcs_basopt: %5d %5d %11.5E\n", + m_VCount->T_Basis_Opts, m_VCount->T_Basis_Opts, + m_VCount->T_Time_basopt); + plogf(" vcs_TP: %5d %5d %11.5E\n", + m_VCount->T_Calls_vcs_TP, m_VCount->T_Its, + m_VCount->T_Time_vcs_TP); + plogf(" vcs_inest: %5d %11.5E\n", + m_VCount->T_Calls_Inest, m_VCount->T_Time_inest); + plogf(" vcs_TotalTime: %11.5E\n", + m_VCount->T_Time_vcs); + } else { + plogf(" vcs_basopt: %5d %5d %11s\n", + m_VCount->T_Basis_Opts, m_VCount->T_Basis_Opts," NA "); + plogf(" vcs_TP: %5d %5d %11s\n", + m_VCount->T_Calls_vcs_TP, m_VCount->T_Its," NA "); + plogf(" vcs_inest: %5d %11s\n", + m_VCount->T_Calls_Inest, " NA "); + plogf(" vcs_TotalTime: %11s\n", + " NA "); + } +} + +void VCS_SOLVE::prob_report(int print_lvl) +{ + m_printLvl = print_lvl; + + // Printout the species information: PhaseID's and mole nums + if (m_printLvl > 0) { + writeline('=', 80, true, true); + writeline('=', 20, false); + plogf(" VCS_PROB: PROBLEM STATEMENT "); + writeline('=', 31); + writeline('=', 80); + plogf("\n"); + plogf("\tSolve a constant T, P problem:\n"); + plogf("\t\tT = %g K\n", m_temperature); + double pres_atm = m_pressurePA / 1.01325E5; + + plogf("\t\tPres = %g atm\n", pres_atm); + plogf("\n"); + plogf(" Phase IDs of species\n"); + plogf(" species phaseID phaseName "); + plogf(" Initial_Estimated_Moles Species_Type\n"); + for (size_t i = 0; i < m_nsp; i++) { + vcs_VolPhase* Vphase = m_VolPhaseList[m_phaseID[i]].get(); + plogf("%16s %5d %16s", m_mix->speciesName(i), m_phaseID[i], + Vphase->PhaseName); + if (m_doEstimateEquil >= 0) { + plogf(" %-10.5g", m_molNumSpecies_old[i]); + } else { + plogf(" N/A"); + } + if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { + plogf(" Mol_Num"); + } else if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf(" Voltage"); + } else { + plogf(" "); + } + plogf("\n"); + } + + // Printout of the Phase structure information + writeline('-', 80, true, true); + plogf(" Information about phases\n"); + plogf(" PhaseName PhaseNum SingSpec GasPhase " + " EqnState NumSpec"); + plogf(" TMolesInert TKmoles\n"); + + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); + plogf("%16s %5d %5d %8d ", Vphase->PhaseName, + Vphase->VP_ID_, Vphase->m_singleSpecies, Vphase->m_gasPhase); + plogf("%16s %8d %16e ", Vphase->eos_name(), + Vphase->nSpecies(), Vphase->totalMolesInert()); + if (m_doEstimateEquil >= 0) { + plogf("%16e\n", Vphase->totalMoles()); + } else { + plogf(" N/A\n"); + } + } + + plogf("\nElemental Abundances: "); + plogf(" Target_kmol ElemType ElActive\n"); + for (size_t i = 0; i < m_nelem; ++i) { + writeline(' ', 26, false); + plogf("%-2.2s", m_elementName[i]); + plogf("%20.12E ", m_elemAbundancesGoal[i]); + plogf("%3d %3d\n", m_elType[i], m_elementActive[i]); + } + + plogf("\nChemical Potentials: (J/kmol)\n"); + plogf(" Species (phase) " + " SS0ChemPot StarChemPot\n"); + for (size_t iphase = 0; iphase < m_numPhases; iphase++) { + vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get(); + Vphase->setState_TP(m_temperature, m_pressurePA); + for (size_t kindex = 0; kindex < Vphase->nSpecies(); kindex++) { + size_t kglob = Vphase->spGlobalIndexVCS(kindex); + plogf("%16s ", m_mix->speciesName(kglob)); + if (kindex == 0) { + plogf("%16s", Vphase->PhaseName); + } else { + plogf(" "); + } + + plogf("%16g %16g\n", Vphase->G0_calc_one(kindex), + Vphase->GStar_calc_one(kindex)); + } + } + writeline('=', 80, true, true); + writeline('=', 20, false); + plogf(" VCS_PROB: END OF PROBLEM STATEMENT "); + writeline('=', 24); + writeline('=', 80); + plogf("\n"); + } +} + +void VCS_SOLVE::addPhaseElements(vcs_VolPhase* volPhase) +{ + size_t neVP = volPhase->nElemConstraints(); + // Loop through the elements in the vol phase object + for (size_t eVP = 0; eVP < neVP; eVP++) { + size_t foundPos = npos; + std::string enVP = volPhase->elementName(eVP); + + // Search for matches with the existing elements. If found, then fill in + // the entry in the global mapping array. + for (size_t e = 0; e < m_nelem; e++) { + std::string en = m_elementName[e]; + if (!strcmp(enVP.c_str(), en.c_str())) { + volPhase->setElemGlobalIndex(eVP, e); + foundPos = e; + } + } + if (foundPos == npos) { + int elType = volPhase->elementType(eVP); + int elactive = volPhase->elementActive(eVP); + size_t e = addElement(enVP.c_str(), elType, elactive); + volPhase->setElemGlobalIndex(eVP, e); + } + } +} + +size_t VCS_SOLVE::addOnePhaseSpecies(vcs_VolPhase* volPhase, size_t k, size_t kT) +{ + if (kT > m_nsp) { + // Need to expand the number of species here + throw CanteraError("VCS_SOLVE::addOnePhaseSpecies", "Shouldn't be here"); + } + const Array2D& fm = volPhase->getFormulaMatrix(); + for (size_t eVP = 0; eVP < volPhase->nElemConstraints(); eVP++) { + size_t e = volPhase->elemGlobalIndex(eVP); + AssertThrowMsg(e != npos, "VCS_PROB::addOnePhaseSpecies", + "element not found"); + m_formulaMatrix(kT,e) = fm(k,eVP); + } + + // Tell the phase object about the current position of the species within + // the global species vector + volPhase->setSpGlobalIndexVCS(k, kT); + return kT; +} + +size_t VCS_SOLVE::addElement(const char* elNameNew, int elType, int elactive) +{ + if (!elNameNew) { + throw CanteraError("VCS_SOLVE::addElement", + "error: element must have a name"); + } + m_nelem++; + m_numComponents++; + + m_formulaMatrix.resize(m_nsp, m_nelem, 0.0); + m_stoichCoeffRxnMatrix.resize(m_nelem, m_nsp, 0.0); + m_elType.push_back(elType); + m_elementActive.push_back(elactive); + m_elemAbundances.push_back(0.0); + m_elemAbundancesGoal.push_back(0.0); + m_elementMapIndex.push_back(0); + m_elementName.push_back(elNameNew); + return m_nelem - 1; } void VCS_SOLVE::disableTiming() { diff --git a/src/equil/vcs_species_thermo.cpp b/src/equil/vcs_species_thermo.cpp deleted file mode 100644 index a78657f312..0000000000 --- a/src/equil/vcs_species_thermo.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file vcs_species_thermo.cpp Implementation for the VCS_SPECIES_THERMO - * object. - */ - -// This file is part of Cantera. See License.txt in the top-level directory or -// at https://cantera.org/license.txt for license and copyright information. - -#include "cantera/equil/vcs_species_thermo.h" -#include "cantera/equil/vcs_defs.h" -#include "cantera/equil/vcs_VolPhase.h" - -#include "cantera/base/ctexceptions.h" -#include "cantera/equil/vcs_internal.h" - -using namespace std; -namespace Cantera -{ -VCS_SPECIES_THERMO::VCS_SPECIES_THERMO() : - IndexPhase(0), - IndexSpeciesPhase(0), - OwningPhase(0), - SS0_Model(VCS_SS0_CONSTANT), - SS0_feSave(0.0), - SS0_TSave(-90.0), - SS0_T0(273.15), - SS0_H0(0.0), - SS0_S0(0.0), - SS0_Cp0(0.0), - SS0_Pref(1.01325E5), - SSStar_Model(VCS_SSSTAR_CONSTANT), - SSStar_Vol_Model(VCS_SSVOL_IDEALGAS), - SSStar_Vol0(-1.0) -{ -} - -} diff --git a/src/fortran/fct.cpp b/src/fortran/fct.cpp index 7f3bd4f44a..489ade07d1 100644 --- a/src/fortran/fct.cpp +++ b/src/fortran/fct.cpp @@ -15,6 +15,7 @@ #include "cantera/transport/TransportFactory.h" #include "cantera/thermo/ThermoFactory.h" #include "cantera/base/ctml.h" +#include "cantera/base/stringUtils.h" #include "cantera/kinetics/importKinetics.h" #include "clib/Cabinet.h" #include "cantera/kinetics/InterfaceKinetics.h" @@ -359,7 +360,7 @@ extern "C" { integer th_newfromfile_(char* filename, char* phasename, ftnlen lenf, ftnlen lenp) { try { - thermo_t* th = newPhase(f2string(filename, lenf), + ThermoPhase* th = newPhase(f2string(filename, lenf), f2string(phasename, lenp)); return ThermoCabinet::add(th); } catch (...) { @@ -371,7 +372,7 @@ extern "C" { { try { XML_Node* x = _xml(mxml); - thermo_t* th = newPhase(*x); + ThermoPhase* th = newPhase(*x); return ThermoCabinet::add(th); } catch (...) { return handleAllExceptions(-1, ERR); @@ -507,7 +508,7 @@ extern "C" { status_t th_chempotentials_(const integer* n, doublereal* murt) { try { - thermo_t* thrm = _fth(n); + ThermoPhase* thrm = _fth(n); thrm->getChemPotentials(murt); } catch (...) { return handleAllExceptions(-1, ERR); @@ -605,7 +606,7 @@ extern "C" { status_t th_getenthalpies_rt_(const integer* n, doublereal* h_rt) { try { - thermo_t* thrm = _fth(n); + ThermoPhase* thrm = _fth(n); thrm->getEnthalpy_RT(h_rt); } catch (...) { return handleAllExceptions(-1, ERR); @@ -616,7 +617,7 @@ extern "C" { status_t th_getentropies_r_(const integer* n, doublereal* s_r) { try { - thermo_t* thrm = _fth(n); + ThermoPhase* thrm = _fth(n); thrm->getEntropy_R(s_r); } catch (...) { return handleAllExceptions(-1, ERR); @@ -627,7 +628,7 @@ extern "C" { status_t th_getcp_r_(const integer* n, integer* lenm, doublereal* cp_r) { try { - thermo_t* thrm = _fth(n); + ThermoPhase* thrm = _fth(n); thrm->getCp_R(cp_r); } catch (...) { return handleAllExceptions(-1, ERR); @@ -638,7 +639,7 @@ extern "C" { status_t th_getpartialmolarintenergies_r_(const integer* n, doublereal* ie) { try { - thermo_t* thrm = _fth(n); + ThermoPhase* thrm = _fth(n); thrm->getPartialMolarIntEnergies(ie); } catch (...) { return handleAllExceptions(-1, ERR); @@ -654,7 +655,7 @@ extern "C" { const integer* neighbor4, ftnlen nlen, ftnlen plen) { try { - std::vector phases; + std::vector phases; phases.push_back(_fth(reactingPhase)); if (*neighbor1 >= 0) { phases.push_back(_fth(neighbor1)); @@ -682,7 +683,7 @@ extern "C" { { try { XML_Node* x = _xml(mxml); - std::vector phases; + std::vector phases; phases.push_back(_fth(iphase)); if (*neighbor1 >= 0) { phases.push_back(_fth(neighbor1)); @@ -946,7 +947,7 @@ extern "C" { { try { std::string mstr = f2string(model, lenmodel); - thermo_t* t = _fth(ith); + ThermoPhase* t = _fth(ith); Transport* tr = newTransportMgr(mstr, t, *loglevel); return TransportCabinet::add(tr); } catch (...) { @@ -957,7 +958,7 @@ extern "C" { integer trans_newdefault_(integer* ith, integer* loglevel, ftnlen lenmodel) { try { - thermo_t* t = _fth(ith); + ThermoPhase* t = _fth(ith); Transport* tr = newDefaultTransportMgr(t, *loglevel); return TransportCabinet::add(tr); } catch (...) { @@ -1118,7 +1119,7 @@ extern "C" { root = _xml(ixml); } - thermo_t* t = _fth(ith); + ThermoPhase* t = _fth(ith); Kinetics* k = _fkin(ikin); XML_Node* x, *r=0; diff --git a/src/fortran/fctxml.cpp b/src/fortran/fctxml.cpp index 007bddad44..7d7da9940e 100644 --- a/src/fortran/fctxml.cpp +++ b/src/fortran/fctxml.cpp @@ -8,6 +8,7 @@ #include "clib/clib_utils.h" #include "cantera/base/ctml.h" +#include "cantera/base/global.h" #include #include diff --git a/src/kinetics/BulkKinetics.cpp b/src/kinetics/BulkKinetics.cpp index d2084f45bc..7791ebe772 100644 --- a/src/kinetics/BulkKinetics.cpp +++ b/src/kinetics/BulkKinetics.cpp @@ -3,11 +3,12 @@ #include "cantera/kinetics/BulkKinetics.h" #include "cantera/kinetics/Reaction.h" +#include "cantera/thermo/ThermoPhase.h" namespace Cantera { -BulkKinetics::BulkKinetics(thermo_t* thermo) : +BulkKinetics::BulkKinetics(ThermoPhase* thermo) : m_ROP_ok(false), m_temp(0.0) { diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index 154fc1aafc..152e1f0253 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -6,12 +6,13 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/kinetics/GasKinetics.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; namespace Cantera { -GasKinetics::GasKinetics(thermo_t* thermo) : +GasKinetics::GasKinetics(ThermoPhase* thermo) : BulkKinetics(thermo), m_logp_ref(0.0), m_logc_ref(0.0), diff --git a/src/kinetics/InterfaceKinetics.cpp b/src/kinetics/InterfaceKinetics.cpp index 09cacb1987..a1834b7efd 100644 --- a/src/kinetics/InterfaceKinetics.cpp +++ b/src/kinetics/InterfaceKinetics.cpp @@ -8,16 +8,16 @@ #include "cantera/kinetics/InterfaceKinetics.h" #include "cantera/kinetics/RateCoeffMgr.h" #include "cantera/kinetics/ImplicitSurfChem.h" +#include "cantera/kinetics/Reaction.h" #include "cantera/thermo/SurfPhase.h" - -#include +#include "cantera/base/utilities.h" using namespace std; namespace Cantera { -InterfaceKinetics::InterfaceKinetics(thermo_t* thermo) : +InterfaceKinetics::InterfaceKinetics(ThermoPhase* thermo) : m_redo_rates(false), m_surf(0), m_integrator(0), @@ -664,7 +664,7 @@ void InterfaceKinetics::setIOFlag(int ioFlag) } } -void InterfaceKinetics::addPhase(thermo_t& thermo) +void InterfaceKinetics::addPhase(ThermoPhase& thermo) { Kinetics::addPhase(thermo); m_phaseExists.push_back(true); diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index a9f04c7d12..42ab44e038 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -11,7 +11,9 @@ #include "cantera/kinetics/Kinetics.h" #include "cantera/kinetics/Reaction.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/utilities.h" #include using namespace std; @@ -267,8 +269,8 @@ void Kinetics::checkReactionBalance(const Reaction& R) } } -void Kinetics::selectPhase(const doublereal* data, const thermo_t* phase, - doublereal* phase_data) +void Kinetics::selectPhase(const double* data, const ThermoPhase* phase, + double* phase_data) { for (size_t n = 0; n < nPhases(); n++) { if (phase == m_thermo[n]) { @@ -323,7 +325,7 @@ size_t Kinetics::kineticsSpeciesIndex(const std::string& nm, return npos; } -thermo_t& Kinetics::speciesPhase(const std::string& nm) +ThermoPhase& Kinetics::speciesPhase(const std::string& nm) { for (size_t n = 0; n < m_thermo.size(); n++) { size_t k = thermo(n).speciesIndex(nm); @@ -334,7 +336,7 @@ thermo_t& Kinetics::speciesPhase(const std::string& nm) throw CanteraError("Kinetics::speciesPhase", "unknown species '{}'", nm); } -const thermo_t& Kinetics::speciesPhase(const std::string& nm) const +const ThermoPhase& Kinetics::speciesPhase(const std::string& nm) const { for (const auto thermo : m_thermo) { if (thermo->speciesIndex(nm) != npos) { @@ -367,6 +369,28 @@ double Kinetics::productStoichCoeff(size_t kSpec, size_t irxn) const 0.0); } +int Kinetics::reactionType(size_t i) const { + return m_reactions[i]->reaction_type; +} + + +std::string Kinetics::reactionString(size_t i) const +{ + return m_reactions[i]->equation(); +} + +//! Returns a string containing the reactants side of the reaction equation. +std::string Kinetics::reactantString(size_t i) const +{ + return m_reactions[i]->reactantString(); +} + +//! Returns a string containing the products side of the reaction equation. +std::string Kinetics::productString(size_t i) const +{ + return m_reactions[i]->productString(); +} + void Kinetics::getFwdRatesOfProgress(doublereal* fwdROP) { updateROP(); @@ -442,7 +466,7 @@ void Kinetics::getNetProductionRates(doublereal* net) m_reactantStoich.decrementSpecies(m_ropnet.data(), net); } -void Kinetics::addPhase(thermo_t& thermo) +void Kinetics::addPhase(ThermoPhase& thermo) { // the phase with lowest dimensionality is assumed to be the // phase/interface at which reactions take place diff --git a/src/kinetics/KineticsFactory.cpp b/src/kinetics/KineticsFactory.cpp index 0f6e589a42..e45b887fff 100644 --- a/src/kinetics/KineticsFactory.cpp +++ b/src/kinetics/KineticsFactory.cpp @@ -11,6 +11,7 @@ #include "cantera/kinetics/EdgeKinetics.h" #include "cantera/kinetics/importKinetics.h" #include "cantera/base/xml.h" +#include "cantera/base/stringUtils.h" using namespace std; diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index 66c5c0fdee..c5f82e8c59 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -8,9 +8,12 @@ #include "cantera/kinetics/Reaction.h" #include "cantera/kinetics/FalloffFactory.h" #include "cantera/kinetics/Kinetics.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/base/ctml.h" #include "cantera/base/Array.h" #include "cantera/base/AnyMap.h" +#include "cantera/base/utilities.h" +#include "cantera/base/stringUtils.h" #include #include @@ -133,6 +136,11 @@ ThirdBody::ThirdBody(double default_eff) { } +double ThirdBody::efficiency(const std::string& k) const +{ + return getValue(efficiencies, k, default_efficiency); +} + ThreeBodyReaction::ThreeBodyReaction() { reaction_type = THREE_BODY_RXN; diff --git a/src/kinetics/ReactionPath.cpp b/src/kinetics/ReactionPath.cpp index 72d9d7969e..7be482fdb9 100644 --- a/src/kinetics/ReactionPath.cpp +++ b/src/kinetics/ReactionPath.cpp @@ -8,6 +8,7 @@ #include "cantera/kinetics/ReactionPath.h" #include "cantera/kinetics/reaction_defs.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; diff --git a/src/numerics/DenseMatrix.cpp b/src/numerics/DenseMatrix.cpp index bac88fda7a..2d5b014e01 100644 --- a/src/numerics/DenseMatrix.cpp +++ b/src/numerics/DenseMatrix.cpp @@ -7,6 +7,7 @@ #include "cantera/numerics/DenseMatrix.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/global.h" #if CT_USE_LAPACK #include "cantera/numerics/ctlapack.h" #else diff --git a/src/numerics/ResidJacEval.cpp b/src/numerics/ResidJacEval.cpp index f4f9e1364f..25cbb952e3 100644 --- a/src/numerics/ResidJacEval.cpp +++ b/src/numerics/ResidJacEval.cpp @@ -3,8 +3,8 @@ // This file is part of Cantera. See License.txt in the top-level directory or // at https://cantera.org/license.txt for license and copyright information. -#include "cantera/base/ct_defs.h" #include "cantera/numerics/ResidJacEval.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/oneD/Boundary1D.cpp b/src/oneD/Boundary1D.cpp index 170956a885..2b2645596a 100644 --- a/src/oneD/Boundary1D.cpp +++ b/src/oneD/Boundary1D.cpp @@ -590,6 +590,11 @@ void Surf1D::showSolution_s(std::ostream& s, const double* x) s << " temperature: " << m_temp << " K" << std::endl; } +void Surf1D::showSolution(const double* x) +{ + writelog(" Temperature: {:10.4g} K \n\n", m_temp); +} + // -------- ReactingSurf1D -------- ReactingSurf1D::ReactingSurf1D() diff --git a/src/oneD/Domain1D.cpp b/src/oneD/Domain1D.cpp index 01f8d93965..254aff5499 100644 --- a/src/oneD/Domain1D.cpp +++ b/src/oneD/Domain1D.cpp @@ -7,6 +7,7 @@ #include "cantera/oneD/Domain1D.h" #include "cantera/oneD/MultiJac.h" +#include "cantera/oneD/refine.h" #include "cantera/base/ctml.h" using namespace std; @@ -30,6 +31,10 @@ Domain1D::Domain1D(size_t nv, size_t points, double time) : resize(nv, points); } +Domain1D::~Domain1D() +{ +} + void Domain1D::resize(size_t nv, size_t np) { // if the number of components is being changed, then a diff --git a/src/oneD/IonFlow.cpp b/src/oneD/IonFlow.cpp index 0f894eb17c..4c36ef2f04 100644 --- a/src/oneD/IonFlow.cpp +++ b/src/oneD/IonFlow.cpp @@ -5,10 +5,12 @@ #include "cantera/oneD/IonFlow.h" #include "cantera/oneD/StFlow.h" +#include "cantera/oneD/refine.h" #include "cantera/base/ctml.h" #include "cantera/transport/TransportBase.h" #include "cantera/numerics/funcs.h" #include "cantera/numerics/polyfit.h" +#include "cantera/base/utilities.h" using namespace std; diff --git a/src/oneD/Sim1D.cpp b/src/oneD/Sim1D.cpp index ba92d7b91d..abe2dc5c17 100644 --- a/src/oneD/Sim1D.cpp +++ b/src/oneD/Sim1D.cpp @@ -9,8 +9,10 @@ #include "cantera/oneD/MultiJac.h" #include "cantera/oneD/StFlow.h" #include "cantera/oneD/MultiNewton.h" +#include "cantera/oneD/refine.h" #include "cantera/numerics/funcs.h" #include "cantera/base/xml.h" +#include "cantera/base/stringUtils.h" #include "cantera/numerics/Func1.h" #include diff --git a/src/oneD/StFlow.cpp b/src/oneD/StFlow.cpp index b81595113e..69bf51985c 100644 --- a/src/oneD/StFlow.cpp +++ b/src/oneD/StFlow.cpp @@ -4,9 +4,11 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/oneD/StFlow.h" +#include "cantera/oneD/refine.h" #include "cantera/base/ctml.h" #include "cantera/transport/TransportBase.h" #include "cantera/numerics/funcs.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/oneD/refine.cpp b/src/oneD/refine.cpp index d3276639df..d91a301ad2 100644 --- a/src/oneD/refine.cpp +++ b/src/oneD/refine.cpp @@ -5,6 +5,7 @@ #include "cantera/oneD/refine.h" #include "cantera/oneD/StFlow.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/pch/system.h b/src/pch/system.h index 9294e92329..868ecdcaf6 100644 --- a/src/pch/system.h +++ b/src/pch/system.h @@ -3,7 +3,6 @@ // commonly-included system headers #include -#include #include #include #include diff --git a/src/thermo/BinarySolutionTabulatedThermo.cpp b/src/thermo/BinarySolutionTabulatedThermo.cpp index aa7da5af5c..1312a1dfdd 100644 --- a/src/thermo/BinarySolutionTabulatedThermo.cpp +++ b/src/thermo/BinarySolutionTabulatedThermo.cpp @@ -19,12 +19,6 @@ namespace Cantera { -BinarySolutionTabulatedThermo::BinarySolutionTabulatedThermo() - : m_kk_tab(npos) - , m_xlast(-1) -{ -} - BinarySolutionTabulatedThermo::BinarySolutionTabulatedThermo(const std::string& inputFile, const std::string& id_) : m_kk_tab(npos) diff --git a/src/thermo/DebyeHuckel.cpp b/src/thermo/DebyeHuckel.cpp index bbfb3efe4f..b3a610ac0e 100644 --- a/src/thermo/DebyeHuckel.cpp +++ b/src/thermo/DebyeHuckel.cpp @@ -13,6 +13,7 @@ #include "cantera/thermo/DebyeHuckel.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/PDSS_Water.h" #include "cantera/thermo/PDSS_ConstVol.h" #include "cantera/thermo/electrolytes.h" @@ -26,20 +27,6 @@ using namespace std; namespace Cantera { -DebyeHuckel::DebyeHuckel() : - m_formDH(DHFORM_DILUTE_LIMIT), - m_IionicMolality(0.0), - m_maxIionicStrength(30.0), - m_useHelgesonFixedForm(false), - m_IionicMolalityStoich(0.0), - m_form_A_Debye(A_DEBYE_CONST), - m_A_Debye(1.172576), // units = sqrt(kg/gmol) - m_B_Debye(3.28640E9), // units = sqrt(kg/gmol) / m - m_waterSS(0), - m_densWaterSS(1000.) -{ -} - DebyeHuckel::DebyeHuckel(const std::string& inputFile, const std::string& id_) : m_formDH(DHFORM_DILUTE_LIMIT), diff --git a/src/thermo/Elements.cpp b/src/thermo/Elements.cpp index 90588d4a38..a46612a3ed 100644 --- a/src/thermo/Elements.cpp +++ b/src/thermo/Elements.cpp @@ -7,8 +7,8 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/thermo/Elements.h" -#include "cantera/base/ctml.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/ctexceptions.h" using namespace std; diff --git a/src/thermo/GibbsExcessVPSSTP.cpp b/src/thermo/GibbsExcessVPSSTP.cpp index ef8c538cff..634dccb535 100644 --- a/src/thermo/GibbsExcessVPSSTP.cpp +++ b/src/thermo/GibbsExcessVPSSTP.cpp @@ -15,6 +15,7 @@ #include "cantera/thermo/GibbsExcessVPSSTP.h" #include "cantera/base/stringUtils.h" +#include using namespace std; diff --git a/src/thermo/HMWSoln.cpp b/src/thermo/HMWSoln.cpp index fb5d992542..a3bb53b57e 100644 --- a/src/thermo/HMWSoln.cpp +++ b/src/thermo/HMWSoln.cpp @@ -27,40 +27,6 @@ using namespace std; namespace Cantera { -HMWSoln::HMWSoln() : - m_formPitzerTemp(PITZER_TEMP_CONSTANT), - m_IionicMolality(0.0), - m_maxIionicStrength(100.0), - m_TempPitzerRef(298.15), - m_form_A_Debye(A_DEBYE_CONST), - m_A_Debye(1.172576), // units = sqrt(kg/gmol) - m_waterSS(0), - m_molalitiesAreCropped(false), - IMS_X_o_cutoff_(0.2), - IMS_cCut_(0.05), - IMS_slopegCut_(0.0), - IMS_dfCut_(0.0), - IMS_efCut_(0.0), - IMS_afCut_(0.0), - IMS_bfCut_(0.0), - IMS_dgCut_(0.0), - IMS_egCut_(0.0), - IMS_agCut_(0.0), - IMS_bgCut_(0.0), - MC_X_o_cutoff_(0.0), - MC_dpCut_(0.0), - MC_epCut_(0.0), - MC_apCut_(0.0), - MC_bpCut_(0.0), - MC_cpCut_(0.0), - CROP_ln_gamma_o_min(-6.0), - CROP_ln_gamma_o_max(3.0), - CROP_ln_gamma_k_min(-5.0), - CROP_ln_gamma_k_max(15.0), - m_last_is(-1.0) -{ -} - HMWSoln::~HMWSoln() { } diff --git a/src/thermo/IdealGasPhase.cpp b/src/thermo/IdealGasPhase.cpp index 3ea372821e..bbc18f746e 100644 --- a/src/thermo/IdealGasPhase.cpp +++ b/src/thermo/IdealGasPhase.cpp @@ -17,11 +17,6 @@ using namespace std; namespace Cantera { -IdealGasPhase::IdealGasPhase() : - m_p0(-1.0) -{ -} - IdealGasPhase::IdealGasPhase(const std::string& inputFile, const std::string& id_) : m_p0(-1.0) { diff --git a/src/thermo/IdealMolalSoln.cpp b/src/thermo/IdealMolalSoln.cpp index 2144eecf1f..d601632289 100644 --- a/src/thermo/IdealMolalSoln.cpp +++ b/src/thermo/IdealMolalSoln.cpp @@ -17,34 +17,13 @@ #include "cantera/thermo/IdealMolalSoln.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/PDSS.h" #include "cantera/base/ctml.h" #include "cantera/base/stringUtils.h" -#include - namespace Cantera { -IdealMolalSoln::IdealMolalSoln() : - m_formGC(2), - IMS_typeCutoff_(0), - IMS_X_o_cutoff_(0.20), - IMS_gamma_o_min_(0.00001), - IMS_gamma_k_min_(10.0), - IMS_slopefCut_(0.6), - IMS_slopegCut_(0.0), - IMS_cCut_(.05), - IMS_dfCut_(0.0), - IMS_efCut_(0.0), - IMS_afCut_(0.0), - IMS_bfCut_(0.0), - IMS_dgCut_(0.0), - IMS_egCut_(0.0), - IMS_agCut_(0.0), - IMS_bgCut_(0.0) -{ -} - IdealMolalSoln::IdealMolalSoln(const std::string& inputFile, const std::string& id_) : MolalityVPSSTP(), diff --git a/src/thermo/IdealSolidSolnPhase.cpp b/src/thermo/IdealSolidSolnPhase.cpp index baa05c250d..79ccb7fc68 100644 --- a/src/thermo/IdealSolidSolnPhase.cpp +++ b/src/thermo/IdealSolidSolnPhase.cpp @@ -10,6 +10,7 @@ #include "cantera/thermo/IdealSolidSolnPhase.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctml.h" #include "cantera/base/utilities.h" @@ -24,6 +25,18 @@ IdealSolidSolnPhase::IdealSolidSolnPhase(int formGC) : m_Pref(OneAtm), m_Pcurrent(OneAtm) { + // @TODO: After Cantera 2.6, this constructor can be deleted and the default + // construction option can be provided by adding "" as the default argument + // to the constructor from input file name and phase id. + if (formGC == -1) { + formGC = 0; + } else { + warn_deprecated("IdealSolidSolnPhase(int formGC)", + "The formGC constructor argument is deprecated and will be removed" + " after Cantera 2.6. Use the setStandardConcentrationModel" + " method instead."); + } + m_formGC = formGC; if (formGC < 0 || formGC > 2) { throw CanteraError("IdealSolidSolnPhase::IdealSolidSolnPhase", "Illegal value of formGC"); @@ -36,6 +49,15 @@ IdealSolidSolnPhase::IdealSolidSolnPhase(const std::string& inputFile, m_Pref(OneAtm), m_Pcurrent(OneAtm) { + if (formGC == -1) { + formGC = 0; + } else { + warn_deprecated("IdealSolidSolnPhase(string inputFile, string id_, int formGC)", + "The formGC constructor argument is deprecated and will be removed" + " after Cantera 2.6. Use the setStandardConcentrationModel" + " method instead."); + } + m_formGC = formGC; if (formGC < 0 || formGC > 2) { throw CanteraError("IdealSolidSolnPhase::IdealSolidSolnPhase", "Illegal value of formGC"); @@ -49,6 +71,15 @@ IdealSolidSolnPhase::IdealSolidSolnPhase(XML_Node& root, const std::string& id_, m_Pref(OneAtm), m_Pcurrent(OneAtm) { + if (formGC == -1) { + formGC = 0; + } else { + warn_deprecated("IdealSolidSolnPhase(XML_Node root, string id_, int formGC)", + "The formGC constructor argument is deprecated and will be removed" + " after Cantera 2.6. Use the setStandardConcentrationModel" + " method instead."); + } + m_formGC = formGC; if (formGC < 0 || formGC > 2) { throw CanteraError("IdealSolidSolnPhase::IdealSolidSolnPhase", "Illegal value of formGC"); diff --git a/src/thermo/IdealSolnGasVPSS.cpp b/src/thermo/IdealSolnGasVPSS.cpp index 141da4fde3..f73f21e5e6 100644 --- a/src/thermo/IdealSolnGasVPSS.cpp +++ b/src/thermo/IdealSolnGasVPSS.cpp @@ -12,34 +12,19 @@ #include "cantera/thermo/IdealSolnGasVPSS.h" #include "cantera/thermo/PDSS.h" -#include "cantera/thermo/ThermoFactory.h" #include "cantera/base/stringUtils.h" #include "cantera/base/utilities.h" +#include "cantera/base/xml.h" using namespace std; namespace Cantera { -IdealSolnGasVPSS::IdealSolnGasVPSS() : - m_formGC(0) -{ -} - IdealSolnGasVPSS::IdealSolnGasVPSS(const std::string& infile, std::string id_) : m_formGC(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("IdealSolnGasVPSS::IdealSolnGasVPSS", - "Couldn't find phase named '{} in file '{}'", - id_, infile); - } - importPhase(*xphase, this); + initThermoFile(infile, id_); } void IdealSolnGasVPSS::setStandardConcentrationModel(const std::string& model) diff --git a/src/thermo/IonsFromNeutralVPSSTP.cpp b/src/thermo/IonsFromNeutralVPSSTP.cpp index 8ba070c805..93220c2370 100644 --- a/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -16,6 +16,7 @@ #include "cantera/thermo/IonsFromNeutralVPSSTP.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/PDSS_IonsFromNeutral.h" #include "cantera/base/stringUtils.h" @@ -26,15 +27,6 @@ using namespace std; namespace Cantera { -IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP() : - ionSolnType_(cIonSolnType_SINGLEANION), - numNeutralMoleculeSpecies_(0), - indexSpecialSpecies_(npos), - neutralMoleculePhase_(0), - geThermo(0) -{ -} - IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP(const std::string& inputFile, const std::string& id_) : ionSolnType_(cIonSolnType_SINGLEANION), diff --git a/src/thermo/LatticePhase.cpp b/src/thermo/LatticePhase.cpp index 7e5983fbef..ee81249eca 100644 --- a/src/thermo/LatticePhase.cpp +++ b/src/thermo/LatticePhase.cpp @@ -11,6 +11,7 @@ #include "cantera/thermo/LatticePhase.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctml.h" #include "cantera/base/utilities.h" @@ -18,15 +19,10 @@ namespace Cantera { -LatticePhase::LatticePhase() : - m_Pref(OneAtm), - m_Pcurrent(OneAtm), - m_speciesMolarVolume(0), - m_site_density(0.0) -{ -} - LatticePhase::LatticePhase(const std::string& inputFile, const std::string& id_) + : m_Pref(OneAtm) + , m_Pcurrent(OneAtm) + , m_site_density(0.0) { initThermoFile(inputFile, id_); } diff --git a/src/thermo/MargulesVPSSTP.cpp b/src/thermo/MargulesVPSSTP.cpp index f1ddfbabb8..b86ed83d08 100644 --- a/src/thermo/MargulesVPSSTP.cpp +++ b/src/thermo/MargulesVPSSTP.cpp @@ -18,13 +18,6 @@ using namespace std; namespace Cantera { -MargulesVPSSTP::MargulesVPSSTP() : - numBinaryInteractions_(0), - formMargules_(0), - formTempModel_(0) -{ -} - MargulesVPSSTP::MargulesVPSSTP(const std::string& inputFile, const std::string& id_) : numBinaryInteractions_(0), formMargules_(0), diff --git a/src/thermo/Nasa9PolyMultiTempRegion.cpp b/src/thermo/Nasa9PolyMultiTempRegion.cpp index bf60fa84c2..9f46954ebb 100644 --- a/src/thermo/Nasa9PolyMultiTempRegion.cpp +++ b/src/thermo/Nasa9PolyMultiTempRegion.cpp @@ -16,6 +16,7 @@ #include "cantera/base/ctexceptions.h" #include "cantera/thermo/Nasa9PolyMultiTempRegion.h" +#include "cantera/thermo/speciesThermoTypes.h" using namespace std; diff --git a/src/thermo/PDSS_HKFT.cpp b/src/thermo/PDSS_HKFT.cpp index 34a80af09e..3a8d04cf0d 100644 --- a/src/thermo/PDSS_HKFT.cpp +++ b/src/thermo/PDSS_HKFT.cpp @@ -14,6 +14,7 @@ #include "cantera/thermo/PDSS_Water.h" #include "cantera/thermo/VPStandardStateTP.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index b36033bb35..2ee9f98e57 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -10,6 +10,7 @@ #include "cantera/base/utilities.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctml.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/ThermoFactory.h" using namespace std; @@ -999,6 +1000,10 @@ void Phase::compositionChanged() { m_stateNum++; } +void Phase::setRoot(std::shared_ptr root) { + m_root = root; +} + vector_fp Phase::getCompositionFromMap(const compositionMap& comp) const { vector_fp X(m_kk); diff --git a/src/thermo/PureFluidPhase.cpp b/src/thermo/PureFluidPhase.cpp index 7d4a9ea79c..a12412de15 100644 --- a/src/thermo/PureFluidPhase.cpp +++ b/src/thermo/PureFluidPhase.cpp @@ -14,8 +14,7 @@ #include "cantera/tpx/Sub.h" #include "cantera/tpx/utils.h" #include "cantera/base/stringUtils.h" - -#include +#include "cantera/base/global.h" using std::string; diff --git a/src/thermo/RedlichKisterVPSSTP.cpp b/src/thermo/RedlichKisterVPSSTP.cpp index 5c1c8fa1a9..de093c7d0a 100644 --- a/src/thermo/RedlichKisterVPSSTP.cpp +++ b/src/thermo/RedlichKisterVPSSTP.cpp @@ -18,13 +18,6 @@ using namespace std; namespace Cantera { -RedlichKisterVPSSTP::RedlichKisterVPSSTP() : - numBinaryInteractions_(0), - formRedlichKister_(0), - formTempModel_(0) -{ -} - RedlichKisterVPSSTP::RedlichKisterVPSSTP(const std::string& inputFile, const std::string& id_) : numBinaryInteractions_(0), diff --git a/src/thermo/RedlichKwongMFTP.cpp b/src/thermo/RedlichKwongMFTP.cpp index 7ce8021fb7..50ca199855 100644 --- a/src/thermo/RedlichKwongMFTP.cpp +++ b/src/thermo/RedlichKwongMFTP.cpp @@ -5,6 +5,7 @@ #include "cantera/thermo/RedlichKwongMFTP.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctml.h" @@ -22,17 +23,6 @@ const doublereal RedlichKwongMFTP::omega_a = 4.27480233540E-01; const doublereal RedlichKwongMFTP::omega_b = 8.66403499650E-02; const doublereal RedlichKwongMFTP::omega_vc = 3.33333333333333E-01; -RedlichKwongMFTP::RedlichKwongMFTP() : - m_formTempParam(0), - m_b_current(0.0), - m_a_current(0.0), - NSolns_(0), - dpdV_(0.0), - dpdT_(0.0) -{ - fill_n(Vroot_, 3, 0.0); -} - RedlichKwongMFTP::RedlichKwongMFTP(const std::string& infile, const std::string& id_) : m_formTempParam(0), m_b_current(0.0), diff --git a/src/thermo/StoichSubstance.cpp b/src/thermo/StoichSubstance.cpp index e6892a510a..35a48caeec 100644 --- a/src/thermo/StoichSubstance.cpp +++ b/src/thermo/StoichSubstance.cpp @@ -10,6 +10,7 @@ #include "cantera/thermo/StoichSubstance.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/base/ctml.h" namespace Cantera diff --git a/src/thermo/SurfPhase.cpp b/src/thermo/SurfPhase.cpp index ebfa7d19d9..8bbb30ee50 100644 --- a/src/thermo/SurfPhase.cpp +++ b/src/thermo/SurfPhase.cpp @@ -12,6 +12,7 @@ #include "cantera/thermo/SurfPhase.h" #include "cantera/thermo/EdgePhase.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/base/stringUtils.h" #include "cantera/base/ctml.h" #include "cantera/base/utilities.h" @@ -23,6 +24,16 @@ namespace Cantera SurfPhase::SurfPhase(doublereal n0): m_press(OneAtm) { + // @TODO After Cantera 2.6, this constructor can be deleted and a + // default value of "" can be added to for the infile argument of + // the other constructor to make this class default constructible. + if (n0 != -1.0) { + warn_deprecated("SurfPhase(double)", "The 'n0' argument to the " + "SurfPhase constructor is deprecated and will be removed after " + "Cantera 2.6. Use the 'setSiteDensity' method instead."); + } else { + n0 = 1.0; + } setSiteDensity(n0); setNDim(2); } @@ -345,8 +356,16 @@ void SurfPhase::setStateFromXML(const XML_Node& state) } } -EdgePhase::EdgePhase(doublereal n0) : SurfPhase(n0) +EdgePhase::EdgePhase(doublereal n0) { + if (n0 != -1.0) { + warn_deprecated("EdgePhase(double)", "The 'n0' argument to the " + "EdgePhase constructor is deprecated and will be removed after " + "Cantera 2.6. Use the 'setSiteDensity' method instead."); + } else { + n0 = 1.0; + } + setSiteDensity(n0); setNDim(1); } diff --git a/src/thermo/ThermoPhase.cpp b/src/thermo/ThermoPhase.cpp index 33aed0ad12..614b7ec789 100644 --- a/src/thermo/ThermoPhase.cpp +++ b/src/thermo/ThermoPhase.cpp @@ -11,6 +11,7 @@ #include "cantera/thermo/ThermoPhase.h" #include "cantera/base/stringUtils.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/SpeciesThermoInterpType.h" #include "cantera/equil/ChemEquil.h" #include "cantera/equil/MultiPhase.h" @@ -18,6 +19,7 @@ #include #include +#include using namespace std; @@ -1064,6 +1066,10 @@ const MultiSpeciesThermo& ThermoPhase::speciesThermo(int k) const void ThermoPhase::initThermoFile(const std::string& inputFile, const std::string& id) { + if (inputFile.empty()) { + // No input file specified - nothing to set up + return; + } size_t dot = inputFile.find_last_of("."); string extension; if (dot != npos) { diff --git a/src/thermo/VPStandardStateTP.cpp b/src/thermo/VPStandardStateTP.cpp index 7a2e1c0f47..f0f05a77ba 100644 --- a/src/thermo/VPStandardStateTP.cpp +++ b/src/thermo/VPStandardStateTP.cpp @@ -11,12 +11,8 @@ #include "cantera/thermo/VPStandardStateTP.h" #include "cantera/thermo/PDSS.h" -#include "cantera/thermo/PDSS_Water.h" -#include "cantera/thermo/IonsFromNeutralVPSSTP.h" -#include "cantera/thermo/SpeciesThermoFactory.h" -#include "cantera/thermo/PDSSFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/base/utilities.h" -#include "cantera/base/ctml.h" using namespace std; @@ -32,6 +28,10 @@ VPStandardStateTP::VPStandardStateTP() : { } +VPStandardStateTP::~VPStandardStateTP() +{ +} + int VPStandardStateTP::standardStateConvention() const { return cSS_CONVENTION_VPSS; diff --git a/src/thermo/WaterSSTP.cpp b/src/thermo/WaterSSTP.cpp index 85926fcfd3..689a9175a5 100644 --- a/src/thermo/WaterSSTP.cpp +++ b/src/thermo/WaterSSTP.cpp @@ -15,15 +15,6 @@ using namespace std; namespace Cantera { -WaterSSTP::WaterSSTP() : - m_mw(0.0), - EW_Offset(0.0), - SW_Offset(0.0), - m_ready(false), - m_allowGasPhase(false) -{ -} - WaterSSTP::WaterSSTP(const std::string& inputFile, const std::string& id) : m_mw(0.0), EW_Offset(0.0), diff --git a/src/transport/DustyGasTransport.cpp b/src/transport/DustyGasTransport.cpp index 9675984e94..17152460fa 100644 --- a/src/transport/DustyGasTransport.cpp +++ b/src/transport/DustyGasTransport.cpp @@ -7,13 +7,15 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/transport/DustyGasTransport.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/utilities.h" using namespace std; namespace Cantera { -DustyGasTransport::DustyGasTransport(thermo_t* thermo) : +DustyGasTransport::DustyGasTransport(ThermoPhase* thermo) : Transport(thermo), m_temp(-1.0), m_gradP(0.0), @@ -27,7 +29,7 @@ DustyGasTransport::DustyGasTransport(thermo_t* thermo) : { } -void DustyGasTransport::setThermo(thermo_t& thermo) +void DustyGasTransport::setThermo(ThermoPhase& thermo) { Transport::setThermo(thermo); m_gastran->setThermo(thermo); diff --git a/src/transport/GasTransport.cpp b/src/transport/GasTransport.cpp index 8df592ecb6..0afb448392 100644 --- a/src/transport/GasTransport.cpp +++ b/src/transport/GasTransport.cpp @@ -8,6 +8,10 @@ #include "cantera/base/stringUtils.h" #include "cantera/numerics/polyfit.h" #include "cantera/transport/TransportData.h" +#include "cantera/thermo/ThermoPhase.h" +#include "cantera/thermo/Species.h" +#include "cantera/base/utilities.h" +#include "cantera/base/global.h" namespace Cantera { @@ -271,7 +275,7 @@ void GasTransport::getMixDiffCoeffsMass(doublereal* const d) } } -void GasTransport::init(thermo_t* thermo, int mode, int log_level) +void GasTransport::init(ThermoPhase* thermo, int mode, int log_level) { m_thermo = thermo; m_nsp = m_thermo->nSpecies(); diff --git a/src/transport/HighPressureGasTransport.cpp b/src/transport/HighPressureGasTransport.cpp index 71d11b332e..c502a1c104 100644 --- a/src/transport/HighPressureGasTransport.cpp +++ b/src/transport/HighPressureGasTransport.cpp @@ -26,7 +26,7 @@ using namespace std; namespace Cantera { -HighPressureGasTransport::HighPressureGasTransport(thermo_t* thermo) +HighPressureGasTransport::HighPressureGasTransport(ThermoPhase* thermo) : MultiTransport(thermo) { } diff --git a/src/transport/IonGasTransport.cpp b/src/transport/IonGasTransport.cpp index 48dbe5479d..fac84d70b0 100644 --- a/src/transport/IonGasTransport.cpp +++ b/src/transport/IonGasTransport.cpp @@ -4,8 +4,11 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/transport/IonGasTransport.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/numerics/polyfit.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/utilities.h" +#include "cantera/base/global.h" #include "MMCollisionInt.h" namespace Cantera @@ -15,7 +18,7 @@ IonGasTransport::IonGasTransport() : { } -void IonGasTransport::init(thermo_t* thermo, int mode, int log_level) +void IonGasTransport::init(ThermoPhase* thermo, int mode, int log_level) { m_thermo = thermo; m_nsp = m_thermo->nSpecies(); diff --git a/src/transport/MMCollisionInt.cpp b/src/transport/MMCollisionInt.cpp index d285c8154f..58558bf761 100644 --- a/src/transport/MMCollisionInt.cpp +++ b/src/transport/MMCollisionInt.cpp @@ -9,6 +9,7 @@ #include "cantera/base/utilities.h" #include "cantera/numerics/polyfit.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/global.h" using namespace std; diff --git a/src/transport/MixTransport.cpp b/src/transport/MixTransport.cpp index 9765da2c1f..9cbd5d407d 100644 --- a/src/transport/MixTransport.cpp +++ b/src/transport/MixTransport.cpp @@ -8,6 +8,8 @@ #include "cantera/transport/MixTransport.h" #include "cantera/base/stringUtils.h" +#include "cantera/thermo/ThermoPhase.h" +#include "cantera/base/utilities.h" using namespace std; diff --git a/src/transport/MultiTransport.cpp b/src/transport/MultiTransport.cpp index dd7f72e29e..39c3d9227d 100644 --- a/src/transport/MultiTransport.cpp +++ b/src/transport/MultiTransport.cpp @@ -9,6 +9,7 @@ #include "cantera/transport/MultiTransport.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/base/stringUtils.h" +#include "cantera/base/utilities.h" using namespace std; @@ -33,7 +34,7 @@ doublereal Frot(doublereal tr, doublereal sqtr) //////////////////// class MultiTransport methods ////////////// -MultiTransport::MultiTransport(thermo_t* thermo) +MultiTransport::MultiTransport(ThermoPhase* thermo) : GasTransport(thermo) { } @@ -106,6 +107,11 @@ void MultiTransport::getThermalDiffCoeffs(doublereal* const dt) } } +double MultiTransport::pressure_ig() +{ + return m_thermo->molarDensity() * GasConstant * m_thermo->temperature(); +} + void MultiTransport::solveLMatrixEquation() { // if T has changed, update the temperature-dependent properties. diff --git a/src/transport/TransportBase.cpp b/src/transport/TransportBase.cpp index 7529c59278..ee9ca950c7 100644 --- a/src/transport/TransportBase.cpp +++ b/src/transport/TransportBase.cpp @@ -7,12 +7,13 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/transport/TransportBase.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; namespace Cantera { -Transport::Transport(thermo_t* thermo, size_t ndim) : +Transport::Transport(ThermoPhase* thermo, size_t ndim) : m_thermo(thermo), m_ready(false), m_nsp(0), @@ -51,7 +52,7 @@ void Transport::setParameters(const int type, const int k, throw NotImplementedError("Transport::setParameters"); } -void Transport::setThermo(thermo_t& thermo) +void Transport::setThermo(ThermoPhase& thermo) { if (!ready()) { m_thermo = &thermo; @@ -77,6 +78,11 @@ void Transport::setThermo(thermo_t& thermo) } } +void Transport::setRoot(std::shared_ptr root) +{ + m_root = root; +} + void Transport::finalize() { if (!ready()) { diff --git a/src/transport/TransportFactory.cpp b/src/transport/TransportFactory.cpp index 93d3e7cb4f..7d8f70e618 100644 --- a/src/transport/TransportFactory.cpp +++ b/src/transport/TransportFactory.cpp @@ -59,7 +59,7 @@ void TransportFactory::deleteFactory() } Transport* TransportFactory::newTransport(const std::string& transportModel, - thermo_t* phase, int log_level) + ThermoPhase* phase, int log_level) { vector_fp state; Transport* tr = 0; @@ -80,7 +80,7 @@ Transport* TransportFactory::newTransport(const std::string& transportModel, return tr; } -Transport* TransportFactory::newTransport(thermo_t* phase, int log_level) +Transport* TransportFactory::newTransport(ThermoPhase* phase, int log_level) { std::string transportModel = "None"; XML_Node& phaseNode = phase->xml(); @@ -93,13 +93,13 @@ Transport* TransportFactory::newTransport(thermo_t* phase, int log_level) return newTransport(transportModel, phase,log_level); } -Transport* newTransportMgr(const std::string& transportModel, thermo_t* thermo, int loglevel) +Transport* newTransportMgr(const std::string& transportModel, ThermoPhase* thermo, int loglevel) { TransportFactory* f = TransportFactory::factory(); return f->newTransport(transportModel, thermo, loglevel); } -Transport* newDefaultTransportMgr(thermo_t* thermo, int loglevel) +Transport* newDefaultTransportMgr(ThermoPhase* thermo, int loglevel) { return TransportFactory::factory()->newTransport(thermo, loglevel); } diff --git a/src/transport/WaterTransport.cpp b/src/transport/WaterTransport.cpp index 0c43d5e3f8..4e1b083bf5 100644 --- a/src/transport/WaterTransport.cpp +++ b/src/transport/WaterTransport.cpp @@ -32,7 +32,7 @@ const double Hij[6][7] = { namespace Cantera { -WaterTransport::WaterTransport(thermo_t* thermo, int ndim) : +WaterTransport::WaterTransport(ThermoPhase* thermo, int ndim) : Transport(thermo, ndim) { if (thermo) { @@ -40,7 +40,7 @@ WaterTransport::WaterTransport(thermo_t* thermo, int ndim) : } } -void WaterTransport::init(thermo_t* thermo, int mode, int log_level) +void WaterTransport::init(ThermoPhase* thermo, int mode, int log_level) { m_thermo = thermo; } diff --git a/src/zeroD/ConstPressureReactor.cpp b/src/zeroD/ConstPressureReactor.cpp index b2ea8806ce..44a9d90993 100644 --- a/src/zeroD/ConstPressureReactor.cpp +++ b/src/zeroD/ConstPressureReactor.cpp @@ -6,6 +6,7 @@ #include "cantera/zeroD/ConstPressureReactor.h" #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/Wall.h" +#include "cantera/kinetics/Kinetics.h" #include "cantera/thermo/SurfPhase.h" using namespace std; diff --git a/src/zeroD/FlowDevice.cpp b/src/zeroD/FlowDevice.cpp index 662e6d22f4..729c9b7cd7 100644 --- a/src/zeroD/FlowDevice.cpp +++ b/src/zeroD/FlowDevice.cpp @@ -5,6 +5,7 @@ #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/ReactorBase.h" +#include "cantera/thermo/ThermoPhase.h" #include "cantera/numerics/Func1.h" namespace Cantera diff --git a/src/zeroD/FlowReactor.cpp b/src/zeroD/FlowReactor.cpp index 75458ec613..3db5edc5da 100644 --- a/src/zeroD/FlowReactor.cpp +++ b/src/zeroD/FlowReactor.cpp @@ -5,6 +5,8 @@ #include "cantera/zeroD/FlowReactor.h" #include "cantera/base/global.h" +#include "cantera/kinetics/Kinetics.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; @@ -66,6 +68,16 @@ void FlowReactor::updateState(doublereal* y) m_thermo->saveState(m_state); } +void FlowReactor::setMassFlowRate(double mdot) +{ + m_rho0 = m_thermo->density(); + m_speed = mdot/m_rho0; + m_speed0 = m_speed; + m_T = m_thermo->temperature(); + m_P0 = m_thermo->pressure() + m_rho0*m_speed*m_speed; + m_h0 = m_thermo->enthalpy_mass() + 0.5*m_speed*m_speed; +} + void FlowReactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { diff --git a/src/zeroD/IdealGasConstPressureReactor.cpp b/src/zeroD/IdealGasConstPressureReactor.cpp index 05db78ac40..4f330f4299 100644 --- a/src/zeroD/IdealGasConstPressureReactor.cpp +++ b/src/zeroD/IdealGasConstPressureReactor.cpp @@ -6,6 +6,8 @@ #include "cantera/zeroD/IdealGasConstPressureReactor.h" #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/ReactorNet.h" +#include "cantera/kinetics/Kinetics.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; diff --git a/src/zeroD/IdealGasReactor.cpp b/src/zeroD/IdealGasReactor.cpp index 93553b0bc2..bc5b5485a0 100644 --- a/src/zeroD/IdealGasReactor.cpp +++ b/src/zeroD/IdealGasReactor.cpp @@ -6,6 +6,8 @@ #include "cantera/zeroD/IdealGasReactor.h" #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/Wall.h" +#include "cantera/kinetics/Kinetics.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; diff --git a/src/zeroD/Reactor.cpp b/src/zeroD/Reactor.cpp index da3f985312..5badb54e57 100644 --- a/src/zeroD/Reactor.cpp +++ b/src/zeroD/Reactor.cpp @@ -9,6 +9,8 @@ #include "cantera/thermo/SurfPhase.h" #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/ReactorSurface.h" +#include "cantera/kinetics/Kinetics.h" +#include "cantera/base/Solution.h" #include @@ -27,6 +29,11 @@ Reactor::Reactor() : m_nv(0) {} +void Reactor::insert(shared_ptr sol) { + setThermoMgr(*sol->thermo()); + setKineticsMgr(*sol->kinetics()); +} + void Reactor::setKineticsMgr(Kinetics& kin) { m_kin = &kin; diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index edcb7e1532..94eca5f85c 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -7,6 +7,7 @@ #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/ReactorSurface.h" +#include "cantera/thermo/ThermoPhase.h" using namespace std; namespace Cantera @@ -23,7 +24,7 @@ ReactorBase::ReactorBase(const string& name) : m_nsp(0), m_name = name; } -void ReactorBase::setThermoMgr(thermo_t& thermo) +void ReactorBase::setThermoMgr(ThermoPhase& thermo) { m_thermo = &thermo; m_nsp = m_thermo->nSpecies(); @@ -82,6 +83,13 @@ ReactorSurface* ReactorBase::surface(size_t n) return m_surfaces[n]; } +void ReactorBase::restoreState() { + if (!m_thermo) { + throw CanteraError("ReactorBase::restoreState", "No phase defined."); + } + m_thermo->restoreState(m_state); +} + ReactorNet& ReactorBase::network() { if (m_net) { diff --git a/src/zeroD/ReactorNet.cpp b/src/zeroD/ReactorNet.cpp index d48a156234..c4c6b3ce38 100644 --- a/src/zeroD/ReactorNet.cpp +++ b/src/zeroD/ReactorNet.cpp @@ -6,8 +6,9 @@ #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/Wall.h" - -#include +#include "cantera/base/utilities.h" +#include "cantera/base/Array.h" +#include "cantera/numerics/Integrator.h" using namespace std; @@ -30,6 +31,10 @@ ReactorNet::ReactorNet() : m_integ->setProblemType(DENSE + NOJAC); } +ReactorNet::~ReactorNet() +{ +} + void ReactorNet::setInitialTime(double time) { m_time = time; @@ -125,6 +130,16 @@ void ReactorNet::reinitialize() } } +void ReactorNet::setMaxSteps(int nmax) +{ + m_integ->setMaxSteps(nmax); +} + +int ReactorNet::maxSteps() +{ + return m_integ->maxSteps(); +} + void ReactorNet::advance(doublereal time) { if (!m_init) { @@ -224,6 +239,11 @@ void ReactorNet::getEstimate(double time, int k, double* yest) } } +int ReactorNet::lastOrder() +{ + return m_integ->lastOrder(); +} + void ReactorNet::addReactor(Reactor& r) { r.setNetwork(this); diff --git a/test/equil/equil_gas.cpp b/test/equil/equil_gas.cpp index f3db8191c9..d11b5d6041 100644 --- a/test/equil/equil_gas.cpp +++ b/test/equil/equil_gas.cpp @@ -2,6 +2,7 @@ #include "cantera/thermo/ThermoFactory.h" #include "cantera/thermo/IdealGasPhase.h" +#include "cantera/thermo/Species.h" #include "cantera/equil/MultiPhase.h" #include "cantera/base/global.h" #include "cantera/base/utilities.h" diff --git a/test/kinetics/kineticsFromScratch.cpp b/test/kinetics/kineticsFromScratch.cpp index acc71bb472..58c3ea1479 100644 --- a/test/kinetics/kineticsFromScratch.cpp +++ b/test/kinetics/kineticsFromScratch.cpp @@ -2,9 +2,12 @@ #include "cantera/kinetics/importKinetics.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/thermo/SurfPhase.h" +#include "cantera/thermo/Species.h" #include "cantera/kinetics/GasKinetics.h" #include "cantera/kinetics/InterfaceKinetics.h" +#include "cantera/kinetics/FalloffFactory.h" #include "cantera/base/Array.h" +#include "cantera/base/stringUtils.h" using namespace Cantera; diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index 884d210190..352fb5ff6d 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -1,5 +1,6 @@ #include "gtest/gtest.h" #include "cantera/base/Units.h" +#include "cantera/base/Solution.h" #include "cantera/kinetics/GasKinetics.h" #include "cantera/thermo/SurfPhase.h" #include "cantera/kinetics/KineticsFactory.h" diff --git a/test/kinetics/pdep.cpp b/test/kinetics/pdep.cpp index 1f1317a6aa..9ce017eade 100644 --- a/test/kinetics/pdep.cpp +++ b/test/kinetics/pdep.cpp @@ -2,6 +2,7 @@ #include "cantera/kinetics/importKinetics.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/kinetics/GasKinetics.h" +#include "cantera/base/global.h" namespace Cantera { diff --git a/test/thermo/MaskellSolidSolnPhase_Test.cpp b/test/thermo/MaskellSolidSolnPhase_Test.cpp index b1363d2221..12e4f38ded 100644 --- a/test/thermo/MaskellSolidSolnPhase_Test.cpp +++ b/test/thermo/MaskellSolidSolnPhase_Test.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "cantera/thermo/MaskellSolidSolnPhase.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/PDSS_ConstVol.h" #include "cantera/thermo/ConstCpPoly.h" #include "cantera/base/stringUtils.h" diff --git a/test/thermo/RedlichKisterTest.cpp b/test/thermo/RedlichKisterTest.cpp index b5778e7e94..85000c1073 100644 --- a/test/thermo/RedlichKisterTest.cpp +++ b/test/thermo/RedlichKisterTest.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "cantera/thermo/RedlichKisterVPSSTP.h" #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/ConstCpPoly.h" #include "cantera/base/stringUtils.h" #include "cantera/thermo/PDSS_IdealGas.h" diff --git a/test/thermo/ThermoPhase_Test.cpp b/test/thermo/ThermoPhase_Test.cpp index 0709c8ecc3..27d798595d 100644 --- a/test/thermo/ThermoPhase_Test.cpp +++ b/test/thermo/ThermoPhase_Test.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "cantera/thermo/ThermoPhase.h" #include "cantera/thermo/ThermoFactory.h" -#include +#include "cantera/base/Solution.h" namespace Cantera { diff --git a/test/thermo/nasapoly.cpp b/test/thermo/nasapoly.cpp index 119ebe5967..4e6be00463 100644 --- a/test/thermo/nasapoly.cpp +++ b/test/thermo/nasapoly.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "cantera/thermo/NasaPoly1.h" #include "cantera/thermo/IdealGasPhase.h" +#include "cantera/base/global.h" namespace Cantera { diff --git a/test/thermo/phaseConstructors.cpp b/test/thermo/phaseConstructors.cpp index 19e0c21bbe..b1ed87a424 100644 --- a/test/thermo/phaseConstructors.cpp +++ b/test/thermo/phaseConstructors.cpp @@ -1,4 +1,5 @@ #include "gtest/gtest.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/ThermoFactory.h" #include "cantera/thermo/PDSSFactory.h" #include "cantera/thermo/PDSS_ConstVol.h" diff --git a/test/thermo/thermoFromYaml.cpp b/test/thermo/thermoFromYaml.cpp index 77c2260df8..abdda8a3b4 100644 --- a/test/thermo/thermoFromYaml.cpp +++ b/test/thermo/thermoFromYaml.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "cantera/thermo/ThermoFactory.h" #include "cantera/thermo/Elements.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/MolalityVPSSTP.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/thermo/SurfPhase.h" diff --git a/test/thermo/thermoParameterizations.cpp b/test/thermo/thermoParameterizations.cpp index dc6bfd8a72..5049ad3128 100644 --- a/test/thermo/thermoParameterizations.cpp +++ b/test/thermo/thermoParameterizations.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "cantera/thermo/speciesThermoTypes.h" #include "cantera/thermo/SpeciesThermoFactory.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/thermo/ConstCpPoly.h" #include "cantera/thermo/NasaPoly2.h" diff --git a/test/transport/transportFromScratch.cpp b/test/transport/transportFromScratch.cpp index 92458f3ee4..e579c8015b 100644 --- a/test/transport/transportFromScratch.cpp +++ b/test/transport/transportFromScratch.cpp @@ -6,6 +6,7 @@ #include "cantera/transport/TransportFactory.h" #include "cantera/thermo/ThermoFactory.h" #include "cantera/thermo/IdealGasPhase.h" +#include "cantera/thermo/Species.h" #include "cantera/thermo/NasaPoly2.h" #include "cantera/base/global.h" #include "cantera/base/stringUtils.h" diff --git a/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp b/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp index 71523e6048..bf0354df2b 100644 --- a/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp +++ b/test_problems/ChemEquil_ionizedGas/ionizedGasEquil.cpp @@ -2,6 +2,7 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/thermo/IdealGasPhase.h" +#include "cantera/base/Solution.h" #include diff --git a/test_problems/SConscript b/test_problems/SConscript index 4167135386..60871520a0 100644 --- a/test_problems/SConscript +++ b/test_problems/SConscript @@ -221,7 +221,7 @@ Test('VCS-LiSi-verbose', 'VCSnonideal/LatticeSolid_LiSi', vcs_LiSi.program, artifacts=['vcs_equilibrate_res.csv']) CompileAndTest('clib', 'clib_test', 'clib_test', - extensions=['^clib_test.c'], libs=['cantera_shared']) + extensions=['^clib_test.c'], libs=localenv['cantera_shared_libs']) # C++ Samples Test('cxx-bvp', 'cxx_samples', '#build/samples/cxx/bvp/blasius', None, diff --git a/test_problems/cathermo/DH_graph_1/DH_graph_1.cpp b/test_problems/cathermo/DH_graph_1/DH_graph_1.cpp index 827996413c..1bc4ee4bfc 100644 --- a/test_problems/cathermo/DH_graph_1/DH_graph_1.cpp +++ b/test_problems/cathermo/DH_graph_1/DH_graph_1.cpp @@ -4,6 +4,7 @@ #include "fileLog.h" #include "cantera/thermo/DebyeHuckel.h" +#include "cantera/base/global.h" #include diff --git a/test_problems/cathermo/HMW_graph_GvI/HMW_graph_GvI.cpp b/test_problems/cathermo/HMW_graph_GvI/HMW_graph_GvI.cpp index a7cf23c0ba..3bdf10195b 100644 --- a/test_problems/cathermo/HMW_graph_GvI/HMW_graph_GvI.cpp +++ b/test_problems/cathermo/HMW_graph_GvI/HMW_graph_GvI.cpp @@ -4,6 +4,7 @@ #include "cantera/base/logger.h" #include "cantera/thermo/HMWSoln.h" +#include "cantera/base/global.h" #include diff --git a/test_problems/cathermo/HMW_test_1/HMW_test_1.cpp b/test_problems/cathermo/HMW_test_1/HMW_test_1.cpp index b4e0c828c8..3b0a249a32 100644 --- a/test_problems/cathermo/HMW_test_1/HMW_test_1.cpp +++ b/test_problems/cathermo/HMW_test_1/HMW_test_1.cpp @@ -1,4 +1,5 @@ #include "cantera/thermo/HMWSoln.h" +#include "cantera/base/global.h" #include diff --git a/test_problems/cathermo/HMW_test_3/HMW_test_3.cpp b/test_problems/cathermo/HMW_test_3/HMW_test_3.cpp index f4d1661080..dd5dedb827 100644 --- a/test_problems/cathermo/HMW_test_3/HMW_test_3.cpp +++ b/test_problems/cathermo/HMW_test_3/HMW_test_3.cpp @@ -1,4 +1,5 @@ #include "cantera/thermo/HMWSoln.h" +#include "cantera/base/global.h" #include diff --git a/test_problems/cathermo/stoichSub/stoichSub.cpp b/test_problems/cathermo/stoichSub/stoichSub.cpp index e69e0032d6..97d50ca0bd 100644 --- a/test_problems/cathermo/stoichSub/stoichSub.cpp +++ b/test_problems/cathermo/stoichSub/stoichSub.cpp @@ -4,6 +4,7 @@ */ #include "cantera/thermo/StoichSubstance.h" +#include "cantera/base/global.h" #include "TemperatureTable.h" #include diff --git a/test_problems/diamondSurf/runDiamond.cpp b/test_problems/diamondSurf/runDiamond.cpp index c10b0f07cc..31c86a6fb0 100644 --- a/test_problems/diamondSurf/runDiamond.cpp +++ b/test_problems/diamondSurf/runDiamond.cpp @@ -13,6 +13,7 @@ #include "cantera/thermo.h" #include "cantera/kinetics.h" #include "cantera/kinetics/InterfaceKinetics.h" +#include using namespace std; using namespace Cantera; diff --git a/test_problems/dustyGasTransport/dustyGasTransportTest.cpp b/test_problems/dustyGasTransport/dustyGasTransportTest.cpp index c967304979..5e5b68550f 100644 --- a/test_problems/dustyGasTransport/dustyGasTransportTest.cpp +++ b/test_problems/dustyGasTransport/dustyGasTransportTest.cpp @@ -1,7 +1,7 @@ #include "cantera/thermo.h" #include "cantera/transport.h" #include "cantera/transport/DustyGasTransport.h" - +#include "cantera/base/utilities.h" #include using namespace std; diff --git a/test_problems/mixGasTransport/mixGasTransport.cpp b/test_problems/mixGasTransport/mixGasTransport.cpp index ea8a663982..d851483b25 100644 --- a/test_problems/mixGasTransport/mixGasTransport.cpp +++ b/test_problems/mixGasTransport/mixGasTransport.cpp @@ -22,6 +22,7 @@ #include "cantera/thermo/IdealGasPhase.h" #include "cantera/transport/MixTransport.h" +#include "cantera/base/Solution.h" #include diff --git a/test_problems/multiGasTransport/multiGasTransport.cpp b/test_problems/multiGasTransport/multiGasTransport.cpp index 1c19cecba2..d3f6fd9af1 100644 --- a/test_problems/multiGasTransport/multiGasTransport.cpp +++ b/test_problems/multiGasTransport/multiGasTransport.cpp @@ -22,6 +22,7 @@ #include "cantera/thermo/IdealGasPhase.h" #include "cantera/transport/MultiTransport.h" +#include "cantera/base/Solution.h" #include diff --git a/test_problems/silane_equil/silane_equil.cpp b/test_problems/silane_equil/silane_equil.cpp index 5106e544e2..8a016b1bd1 100644 --- a/test_problems/silane_equil/silane_equil.cpp +++ b/test_problems/silane_equil/silane_equil.cpp @@ -2,6 +2,7 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/thermo/IdealGasPhase.h" +#include "cantera/base/Solution.h" #include diff --git a/test_problems/stoichSolidKinetics/stoichSolidKinetics.cpp b/test_problems/stoichSolidKinetics/stoichSolidKinetics.cpp index 8443a5cce0..7679f60978 100644 --- a/test_problems/stoichSolidKinetics/stoichSolidKinetics.cpp +++ b/test_problems/stoichSolidKinetics/stoichSolidKinetics.cpp @@ -4,6 +4,7 @@ #include #include +#include using namespace Cantera; using namespace std; diff --git a/test_problems/surfkin/surfdemo.cpp b/test_problems/surfkin/surfdemo.cpp index de69f79d02..1d958e2e36 100644 --- a/test_problems/surfkin/surfdemo.cpp +++ b/test_problems/surfkin/surfdemo.cpp @@ -9,6 +9,7 @@ #include "cantera/thermo/IdealGasPhase.h" #include "cantera/thermo/SurfPhase.h" #include "cantera/kinetics/InterfaceKinetics.h" +#include "cantera/base/Solution.h" #include