Clean up comments in other equilibrium-related classes
This commit is contained in:
parent
618c485c55
commit
5bf3b0fc67
6 changed files with 434 additions and 628 deletions
|
|
@ -48,10 +48,9 @@ public:
|
|||
int propertyPair;
|
||||
|
||||
/**
|
||||
* Continuation flag. Set true if the calculation should be
|
||||
* initialized from the last calculation. Otherwise, the
|
||||
* calculation will be started from scratch and the initial
|
||||
* composition and element potentials estimated.
|
||||
* Continuation flag. Set true if the calculation should be initialized from
|
||||
* the last calculation. Otherwise, the calculation will be started from
|
||||
* scratch and the initial composition and element potentials estimated.
|
||||
*/
|
||||
bool contin;
|
||||
};
|
||||
|
|
@ -64,26 +63,22 @@ class PropertyCalculator;
|
|||
*/
|
||||
|
||||
/**
|
||||
* Class ChemEquil implements a chemical equilibrium solver for
|
||||
* single-phase solutions. It is a "non-stoichiometric" solver in
|
||||
* the terminology of Smith and Missen, meaning that every
|
||||
* intermediate state is a valid chemical equilibrium state, but
|
||||
* does not necessarily satisfy the element constraints. In
|
||||
* contrast, the solver implemented in class MultiPhaseEquil uses
|
||||
* a "stoichiometric" algorithm, in which each intermediate state
|
||||
* satisfies the element constraints but is not a state of
|
||||
* chemical equilibrium. Non-stoichiometric methods are faster
|
||||
* when they converge, but stoichiometric ones tend to be more
|
||||
* robust and can be used also for problems with multiple
|
||||
* condensed phases. As expected, the ChemEquil solver is faster
|
||||
* than MultiPhaseEquil for many single-phase equilibrium
|
||||
* problems (particularly if there are only a few elements but
|
||||
* very many species), but can be less stable. Problem
|
||||
* situations include low temperatures where only a few species
|
||||
* have non-zero mole fractions, precisely stoichiometric
|
||||
* compositions (e.g. 2 H2 + O2). In general, if speed is
|
||||
* important, this solver should be tried first, and if it fails
|
||||
* then use MultiPhaseEquil.
|
||||
* Class ChemEquil implements a chemical equilibrium solver for single-phase
|
||||
* solutions. It is a "non-stoichiometric" solver in the terminology of Smith
|
||||
* and Missen, meaning that every intermediate state is a valid chemical
|
||||
* equilibrium state, but does not necessarily satisfy the element constraints.
|
||||
* In contrast, the solver implemented in class MultiPhaseEquil uses a
|
||||
* "stoichiometric" algorithm, in which each intermediate state satisfies the
|
||||
* element constraints but is not a state of chemical equilibrium. Non-
|
||||
* stoichiometric methods are faster when they converge, but stoichiometric ones
|
||||
* tend to be more robust and can be used also for problems with multiple
|
||||
* condensed phases. As expected, the ChemEquil solver is faster than
|
||||
* MultiPhaseEquil for many single-phase equilibrium problems (particularly if
|
||||
* there are only a few elements but very many species), but can be less stable.
|
||||
* Problem situations include low temperatures where only a few species have
|
||||
* non-zero mole fractions, precisely stoichiometric compositions (e.g. 2 H2 +
|
||||
* O2). In general, if speed is important, this solver should be tried first,
|
||||
* and if it fails then use MultiPhaseEquil.
|
||||
* @ingroup equil
|
||||
*/
|
||||
class ChemEquil
|
||||
|
|
@ -93,32 +88,33 @@ public:
|
|||
|
||||
//! Constructor combined with the initialization function
|
||||
/*!
|
||||
* This constructor initializes the ChemEquil object with everything it
|
||||
* needs to start solving equilibrium problems.
|
||||
* @param s ThermoPhase object that will be used in the equilibrium calls.
|
||||
* This constructor initializes the ChemEquil object with everything it
|
||||
* needs to start solving equilibrium problems.
|
||||
*
|
||||
* @param s ThermoPhase object that will be used in the equilibrium calls.
|
||||
*/
|
||||
ChemEquil(thermo_t& s);
|
||||
|
||||
virtual ~ChemEquil();
|
||||
|
||||
/*!
|
||||
* Equilibrate a phase, holding the elemental composition fixed
|
||||
* at the initial value found within the ThermoPhase object *s*.
|
||||
* Equilibrate a phase, holding the elemental composition fixed at the
|
||||
* initial value found within the ThermoPhase object *s*.
|
||||
*
|
||||
* The value of 2 specified properties are obtained by querying the
|
||||
* ThermoPhase object. The properties must be already contained
|
||||
* within the current thermodynamic state of the system.
|
||||
* The value of two specified properties are obtained by querying the
|
||||
* ThermoPhase object. The properties must be already contained within the
|
||||
* current thermodynamic state of the system.
|
||||
*/
|
||||
int equilibrate(thermo_t& s, const char* XY,
|
||||
bool useThermoPhaseElementPotentials = false, int loglevel = 0);
|
||||
|
||||
/*!
|
||||
* Compute the equilibrium composition for 2 specified
|
||||
* properties and the specified element moles.
|
||||
* Compute the equilibrium composition for two specified properties and the
|
||||
* specified element moles.
|
||||
*
|
||||
* The 2 specified properties are obtained by querying the
|
||||
* ThermoPhase object. The properties must be already contained
|
||||
* within the current thermodynamic state of the system.
|
||||
* The two specified properties are obtained by querying the ThermoPhase
|
||||
* object. The properties must be already contained within the current
|
||||
* thermodynamic state of the system.
|
||||
*
|
||||
* @param s phase object to be equilibrated
|
||||
* @param XY property pair to hold constant
|
||||
|
|
@ -146,10 +142,9 @@ public:
|
|||
protected:
|
||||
//! Pointer to the ThermoPhase object used to initialize this object.
|
||||
/*!
|
||||
* This ThermoPhase object must be compatible with the ThermoPhase
|
||||
* objects input from the equilibrate function. Currently, this
|
||||
* means that the 2 ThermoPhases have to have consist of the same
|
||||
* species and elements.
|
||||
* This ThermoPhase object must be compatible with the ThermoPhase objects
|
||||
* 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;
|
||||
|
||||
|
|
@ -159,14 +154,14 @@ protected:
|
|||
}
|
||||
|
||||
/*!
|
||||
* Prepare for equilibrium calculations.
|
||||
* @param s object representing the solution phase.
|
||||
* Prepare for equilibrium calculations.
|
||||
* @param s object representing the solution phase.
|
||||
*/
|
||||
void initialize(thermo_t& s);
|
||||
|
||||
/*!
|
||||
* Set mixture to an equilibrium state consistent with specified
|
||||
* element potentials and temperature.
|
||||
* Set mixture to an equilibrium state consistent with specified element
|
||||
* potentials and temperature.
|
||||
*
|
||||
* @param s mixture to be updated
|
||||
* @param x vector of non-dimensional element potentials
|
||||
|
|
@ -267,51 +262,36 @@ protected:
|
|||
size_t m_kk; //!< number of species in the phase
|
||||
size_t m_skip;
|
||||
|
||||
/**
|
||||
* This is equal to the rank of the stoichiometric coefficient
|
||||
* matrix when it is computed. It's initialized to #m_mm.
|
||||
*/
|
||||
//! This is equal to the rank of the stoichiometric coefficient matrix when
|
||||
//! it is computed. It's initialized to #m_mm.
|
||||
size_t m_nComponents;
|
||||
|
||||
std::unique_ptr<PropertyCalculator<thermo_t> > m_p1, m_p2;
|
||||
|
||||
/**
|
||||
* Current value of the mole fractions in the single phase.
|
||||
* -> length = #m_kk.
|
||||
*/
|
||||
//! Current value of the mole fractions in the single phase. length = #m_kk.
|
||||
vector_fp m_molefractions;
|
||||
/**
|
||||
* Current value of the dimensional element potentials
|
||||
* -> length = #m_mm
|
||||
*/
|
||||
|
||||
//! Current value of the dimensional element potentials. length = #m_mm
|
||||
vector_fp m_lambda;
|
||||
|
||||
/*
|
||||
* Current value of the sum of the element abundances given the
|
||||
* current element potentials.
|
||||
*/
|
||||
//! Current value of the sum of the element abundances given the current
|
||||
//! element potentials.
|
||||
doublereal m_elementTotalSum;
|
||||
/*
|
||||
* Current value of the element mole fractions. Note these aren't
|
||||
* the goal element mole fractions.
|
||||
*/
|
||||
|
||||
//! Current value of the element mole fractions. Note these aren't the goal
|
||||
//! element mole fractions.
|
||||
vector_fp m_elementmolefracs;
|
||||
vector_fp m_reswork;
|
||||
vector_fp m_jwork1;
|
||||
vector_fp m_jwork2;
|
||||
|
||||
/*
|
||||
* Storage of the element compositions
|
||||
* natom(k,m) = m_comp[k*m_mm+ m];
|
||||
*/
|
||||
//! Storage of the element compositions. natom(k,m) = m_comp[k*m_mm+ m];
|
||||
vector_fp m_comp;
|
||||
doublereal m_temp, m_dens;
|
||||
doublereal m_p0;
|
||||
|
||||
/**
|
||||
* Index of the element id corresponding to the electric charge of each
|
||||
* species. Equal to -1 if there is no such element id.
|
||||
*/
|
||||
//! Index of the element id corresponding to the electric charge of each
|
||||
//! species. Equal to -1 if there is no such element id.
|
||||
size_t m_eloc;
|
||||
|
||||
vector_fp m_startSoln;
|
||||
|
|
@ -319,11 +299,9 @@ protected:
|
|||
vector_fp m_grt;
|
||||
vector_fp m_mu_RT;
|
||||
|
||||
/**
|
||||
* Dimensionless values of the Gibbs free energy for the
|
||||
* standard state of each species, at the temperature and
|
||||
* pressure of the solution (the star standard state).
|
||||
*/
|
||||
//! Dimensionless values of the Gibbs free energy for the standard state of
|
||||
//! each species, at the temperature and pressure of the solution (the star
|
||||
//! standard state).
|
||||
vector_fp m_muSS_RT;
|
||||
std::vector<size_t> m_component;
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ public:
|
|||
/*!
|
||||
* @param kGlob global species index
|
||||
* @param mGlob global element index
|
||||
* @return returns the number of atoms.
|
||||
* @returns the number of atoms.
|
||||
*/
|
||||
doublereal nAtoms(const size_t kGlob, const size_t mGlob) const;
|
||||
|
||||
|
|
@ -176,9 +176,7 @@ public:
|
|||
//! Returns the index, given the phase name
|
||||
/*!
|
||||
* @param pName Name of the phase
|
||||
*
|
||||
* @return returns the index. A value of -1 means
|
||||
* the phase isn't in the object.
|
||||
* @returns the index. A value of -1 means the phase isn't in the object.
|
||||
*/
|
||||
int phaseIndex(const std::string& pName) const;
|
||||
|
||||
|
|
@ -236,9 +234,10 @@ public:
|
|||
* @param speciesName Species Name
|
||||
* @param phaseName Phase Name
|
||||
*
|
||||
* @return returns the global index
|
||||
* If the species or phase name is not recognized, this routine throws
|
||||
* a CanteraError.
|
||||
* @returns the global index
|
||||
*
|
||||
* If the species or phase name is not recognized, this routine throws a
|
||||
* CanteraError.
|
||||
*/
|
||||
size_t speciesIndex(const std::string& speciesName, const std::string& phaseName);
|
||||
|
||||
|
|
@ -273,14 +272,14 @@ public:
|
|||
*/
|
||||
doublereal elementMoles(size_t m) const;
|
||||
|
||||
//! Returns a vector of Chemical potentials.
|
||||
//! Returns a vector of Chemical potentials.
|
||||
/*!
|
||||
* Write into array \a mu the chemical potentials of all species
|
||||
* [J/kmol]. The chemical potentials are related to the activities by
|
||||
* Write into array \a mu the chemical potentials of all species
|
||||
* [J/kmol]. The chemical potentials are related to the activities by
|
||||
*
|
||||
* \f$
|
||||
* \f$
|
||||
* \mu_k = \mu_k^0(T, P) + RT \ln a_k.
|
||||
* \f$.
|
||||
* \f$.
|
||||
*
|
||||
* @param mu Chemical potential vector. Length = num global species. Units
|
||||
* = J/kmol.
|
||||
|
|
@ -372,17 +371,17 @@ public:
|
|||
|
||||
//! Set the state of the underlying ThermoPhase objects in one call
|
||||
/*!
|
||||
* @param T Temperature of the system (kelvin)
|
||||
* @param Pres pressure of the system (pascal)
|
||||
* @param T Temperature of the system (kelvin)
|
||||
* @param Pres pressure of the system (pascal)
|
||||
*/
|
||||
void setState_TP(const doublereal T, const doublereal Pres);
|
||||
|
||||
//! Set the state of the underlying ThermoPhase objects in one call
|
||||
/*!
|
||||
* @param T Temperature of the system (kelvin)
|
||||
* @param Pres pressure of the system (pascal)
|
||||
* @param Moles Vector of mole numbers of all the species in all the phases
|
||||
* (kmol)
|
||||
* @param T Temperature of the system (kelvin)
|
||||
* @param Pres pressure of the system (pascal)
|
||||
* @param Moles Vector of mole numbers of all the species in all the phases
|
||||
* (kmol)
|
||||
*/
|
||||
void setState_TPMoles(const doublereal T, const doublereal Pres, const doublereal* Moles);
|
||||
|
||||
|
|
@ -393,8 +392,8 @@ public:
|
|||
|
||||
/// The total mixture volume [m^3].
|
||||
/*!
|
||||
* Returns the cumulative sum of the volumes of all the
|
||||
* phases in the mixture.
|
||||
* Returns the cumulative sum of the volumes of all the phases in the
|
||||
* mixture.
|
||||
*/
|
||||
doublereal volume() const;
|
||||
|
||||
|
|
@ -428,8 +427,8 @@ public:
|
|||
return m_np;
|
||||
}
|
||||
|
||||
//! Return true is species \a kGlob is a species in a
|
||||
//! multicomponent solution phase.
|
||||
//! Return true is species \a kGlob is a species in a multicomponent
|
||||
//! solution phase.
|
||||
/*!
|
||||
* @param kGlob index of the global species
|
||||
*/
|
||||
|
|
@ -438,7 +437,7 @@ public:
|
|||
//! Returns the phase index of the Kth "global" species
|
||||
/*!
|
||||
* @param kGlob Global species index.
|
||||
* @return Returns the index of the owning phase.
|
||||
* @returns the index of the owning phase.
|
||||
*/
|
||||
size_t speciesPhaseIndex(const size_t kGlob) const;
|
||||
|
||||
|
|
@ -495,8 +494,8 @@ public:
|
|||
|
||||
//! Adds moles of a certain species to the mixture
|
||||
/*!
|
||||
* @param indexS Index of the species in the MultiPhase object
|
||||
* @param addedMoles Value of the moles that are added to the species.
|
||||
* @param indexS Index of the species in the MultiPhase object
|
||||
* @param addedMoles Value of the moles that are added to the species.
|
||||
*/
|
||||
void addSpeciesMoles(const int indexS, const doublereal addedMoles);
|
||||
|
||||
|
|
@ -508,8 +507,8 @@ public:
|
|||
*/
|
||||
void getElemAbundances(doublereal* elemAbundances) const;
|
||||
|
||||
//! Return true if the phase \a p has valid thermo data for
|
||||
//! the current temperature.
|
||||
//! Return true if the phase \a p has valid thermo data for the current
|
||||
//! temperature.
|
||||
/*!
|
||||
* @param p Index of the phase.
|
||||
*/
|
||||
|
|
@ -517,31 +516,30 @@ public:
|
|||
|
||||
// These methods are meant for internal use.
|
||||
|
||||
//! Update the locally-stored composition within this object
|
||||
//! to match the current compositions of the phase objects.
|
||||
//! Update the locally-stored composition within this object to match the
|
||||
//! current compositions of the phase objects.
|
||||
/*!
|
||||
* Query the underlying ThermoPhase objects for their mole fractions and
|
||||
* fill in the mole fraction vector of this current object. Adjust
|
||||
* element compositions within this object to match.
|
||||
* Query the underlying ThermoPhase objects for their mole fractions and
|
||||
* fill in the mole fraction vector of this current object. Adjust element
|
||||
* compositions within this object to match.
|
||||
*
|
||||
* This is an upload operation in the sense that we are taking downstream
|
||||
* information (ThermoPhase object info) and applying it to an upstream
|
||||
* object (MultiPhase object).
|
||||
* This is an upload operation in the sense that we are taking downstream
|
||||
* information (ThermoPhase object info) and applying it to an upstream
|
||||
* object (MultiPhase object).
|
||||
*/
|
||||
void uploadMoleFractionsFromPhases();
|
||||
|
||||
//! Set the states of the phase objects to the locally-stored
|
||||
//! state within this MultiPhase object.
|
||||
/*!
|
||||
* This method sets each phase to the mixture temperature and pressure,
|
||||
* and sets the phase mole fractions based on the mixture mole numbers.
|
||||
* This method sets each phase to the mixture temperature and pressure,
|
||||
* and sets the phase mole fractions based on the mixture mole numbers.
|
||||
*
|
||||
* This is an download operation in the sense that we are taking
|
||||
* upstream object information (MultiPhase object) and
|
||||
* applying it to downstream objects (ThermoPhase object information)
|
||||
* This is an download operation in the sense that we are taking upstream
|
||||
* object information (MultiPhase object) and applying it to downstream
|
||||
* objects (ThermoPhase object information)
|
||||
*
|
||||
* Therefore, the term, "update", is appropriate for a downstream
|
||||
* operation.
|
||||
* Therefore, the term, "update", is appropriate for a downstream operation.
|
||||
*/
|
||||
void updatePhases() const;
|
||||
|
||||
|
|
@ -552,15 +550,14 @@ private:
|
|||
//! Set the mixture to a state of chemical equilibrium using the
|
||||
//! MultiPhaseEquil solver.
|
||||
/*!
|
||||
* @param XY Integer flag specifying properties to hold fixed.
|
||||
* @param err Error tolerance for \f$\Delta \mu/RT \f$ for all reactions.
|
||||
* Also used as the relative error tolerance for the outer
|
||||
* loop.
|
||||
* @param maxsteps Maximum number of steps to take in solving the fixed
|
||||
* TP problem.
|
||||
* @param maxiter Maximum number of "outer" iterations for problems holding
|
||||
* fixed something other than (T,P).
|
||||
* @param loglevel Level of diagnostic output
|
||||
* @param XY Integer flag specifying properties to hold fixed.
|
||||
* @param err Error tolerance for \f$\Delta \mu/RT \f$ for all reactions.
|
||||
* Also used as the relative error tolerance for the outer loop.
|
||||
* @param maxsteps Maximum number of steps to take in solving the fixed TP
|
||||
* problem.
|
||||
* @param maxiter Maximum number of "outer" iterations for problems holding
|
||||
* fixed something other than (T,P).
|
||||
* @param loglevel Level of diagnostic output
|
||||
*/
|
||||
double equilibrate_MultiPhaseEquil(int XY, doublereal err, int maxsteps,
|
||||
int maxiter, int loglevel);
|
||||
|
|
@ -576,16 +573,14 @@ private:
|
|||
|
||||
//! Global Stoichiometric Coefficient array
|
||||
/*!
|
||||
* This is a two dimensional array m_atoms(m, k). The first index is the
|
||||
* global element index. The second index, k, is the global species
|
||||
* index. The value is the number of atoms of type m in species k.
|
||||
* This is a two dimensional array m_atoms(m, k). The first index is the
|
||||
* global element index. The second index, k, is the global species index.
|
||||
* The value is the number of atoms of type m in species k.
|
||||
*/
|
||||
DenseMatrix m_atoms;
|
||||
|
||||
/**
|
||||
* Locally stored vector of mole fractions of all species
|
||||
* comprising the MultiPhase object.
|
||||
*/
|
||||
//! Locally stored vector of mole fractions of all species comprising the
|
||||
//! MultiPhase object.
|
||||
vector_fp m_moleFractions;
|
||||
|
||||
//! Mapping between the global species number and the phase ID
|
||||
|
|
@ -603,23 +598,15 @@ private:
|
|||
*/
|
||||
std::vector<size_t> m_spstart;
|
||||
|
||||
//! String names of the global elements
|
||||
/*!
|
||||
* This has a length equal to the number of global elements.
|
||||
*/
|
||||
//! String names of the global elements. This has a length equal to the
|
||||
//! number of global elements.
|
||||
std::vector<std::string> m_enames;
|
||||
|
||||
//! Atomic number of each element
|
||||
/*!
|
||||
* This is the atomic number of each global element.
|
||||
*/
|
||||
//! Atomic number of each global element.
|
||||
vector_int m_atomicNumber;
|
||||
|
||||
//! Vector of species names in the problem
|
||||
/*!
|
||||
* Vector is over all species defined in the object,
|
||||
* the global species index.
|
||||
*/
|
||||
//! Vector of species names in the problem. Vector is over all species
|
||||
//! defined in the object, the global species index.
|
||||
std::vector<std::string> m_snames;
|
||||
|
||||
//! Returns the global element index, given the element string name
|
||||
|
|
@ -646,10 +633,8 @@ private:
|
|||
//! True if the init() routine has been called, and the MultiPhase frozen
|
||||
bool m_init;
|
||||
|
||||
//! Global ID of the element corresponding to the electronic charge.
|
||||
/*!
|
||||
* If there is none, then this is equal to -1
|
||||
*/
|
||||
//! Global ID of the element corresponding to the electronic charge. If
|
||||
//! there is none, then this is equal to -1
|
||||
size_t m_eloc;
|
||||
|
||||
//! Vector of bools indicating whether temperatures are ok for phases.
|
||||
|
|
@ -659,17 +644,12 @@ private:
|
|||
*/
|
||||
mutable std::vector<bool> m_temp_OK;
|
||||
|
||||
//! Minimum temperature for which thermo parameterizations are valid
|
||||
/*!
|
||||
* Stoichiometric phases are ignored in this determination.
|
||||
* units Kelvin
|
||||
*/
|
||||
//! Minimum temperature for which thermo parameterizations are valid.
|
||||
//! Stoichiometric phases are ignored in this determination. units Kelvin
|
||||
doublereal m_Tmin;
|
||||
|
||||
//! Minimum temperature for which thermo parameterizations are valid
|
||||
/*!
|
||||
* Stoichiometric phases are ignored in this determination. units Kelvin
|
||||
*/
|
||||
//! Minimum temperature for which thermo parameterizations are valid.
|
||||
//! Stoichiometric phases are ignored in this determination. units Kelvin
|
||||
doublereal m_Tmax;
|
||||
|
||||
//! Vector of element abundances
|
||||
|
|
@ -711,9 +691,8 @@ inline std::ostream& operator<<(std::ostream& s, MultiPhase& x)
|
|||
* currently a linear combination of the previous components. Then, calculate
|
||||
* the stoichiometric coefficient matrix for that basis.
|
||||
*
|
||||
* Calculates the identity of the component species in the mechanism.
|
||||
* Rearranges the solution data to put the component data at the
|
||||
* front of the species list.
|
||||
* Calculates the identity of the component species in the mechanism. Rearranges
|
||||
* the solution data to put the component data at the front of the species list.
|
||||
*
|
||||
* Then, calculates SC(J,I) the formation reactions for all noncomponent
|
||||
* species in the mechanism.
|
||||
|
|
|
|||
|
|
@ -31,20 +31,16 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
size_t j, jj, k=0, kk, l, i, jl, ml;
|
||||
std::string ename;
|
||||
std::string sname;
|
||||
/*
|
||||
* Get the total number of elements defined in the multiphase object
|
||||
*/
|
||||
|
||||
// Get the total number of elements defined in the multiphase object
|
||||
size_t ne = mphase->nElements();
|
||||
/*
|
||||
* Get the total number of species in the multiphase object
|
||||
*/
|
||||
|
||||
// Get the total number of species in the multiphase object
|
||||
size_t nspecies = mphase->nSpecies();
|
||||
doublereal tmp;
|
||||
doublereal const USEDBEFORE = -1;
|
||||
|
||||
/*
|
||||
* Perhaps, initialize the element ordering
|
||||
*/
|
||||
// Perhaps, initialize the element ordering
|
||||
if (orderVectorElements.size() < ne) {
|
||||
orderVectorElements.resize(ne);
|
||||
for (j = 0; j < ne; j++) {
|
||||
|
|
@ -52,9 +48,7 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perhaps, initialize the species ordering
|
||||
*/
|
||||
// Perhaps, initialize the species ordering
|
||||
if (orderVectorSpecies.size() != nspecies) {
|
||||
orderVectorSpecies.resize(nspecies);
|
||||
for (k = 0; k < nspecies; k++) {
|
||||
|
|
@ -101,27 +95,20 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the maximum value of the number of components possible
|
||||
* It's equal to the minimum of the number of elements and the
|
||||
* number of total species.
|
||||
*/
|
||||
// Calculate the maximum value of the number of components possible. It's
|
||||
// equal to the minimum of the number of elements and the number of total
|
||||
// species.
|
||||
size_t nComponents = std::min(ne, nspecies);
|
||||
size_t nNonComponents = nspecies - nComponents;
|
||||
/*
|
||||
* Set this return variable to false
|
||||
*/
|
||||
|
||||
// Set this return variable to false
|
||||
*usedZeroedSpecies = false;
|
||||
|
||||
/*
|
||||
* Create an array of mole numbers
|
||||
*/
|
||||
// Create an array of mole numbers
|
||||
vector_fp molNum(nspecies,0.0);
|
||||
mphase->getMoles(molNum.data());
|
||||
|
||||
/*
|
||||
* Other workspace
|
||||
*/
|
||||
// Other workspace
|
||||
vector_fp sm(ne*ne, 0.0);
|
||||
vector_fp ss(ne, 0.0);
|
||||
vector_fp sa(ne, 0.0);
|
||||
|
|
@ -129,9 +116,7 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
formRxnMatrix.resize(nspecies*ne, 0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* For debugging purposes keep an unmodified copy of the array.
|
||||
*/
|
||||
// For debugging purposes keep an unmodified copy of the array.
|
||||
vector_fp molNumBase;
|
||||
if (DEBUG_MODE_ENABLED) {
|
||||
molNumBase = molNum;
|
||||
|
|
@ -139,19 +124,16 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
double molSave = 0.0;
|
||||
|
||||
size_t jr = 0;
|
||||
/*
|
||||
* Top of a loop of some sort based on the index JR. JR is the
|
||||
* current number of component species found.
|
||||
*/
|
||||
|
||||
// Top of a loop of some sort based on the index JR. JR is the current
|
||||
// number of component species found.
|
||||
while (jr < nComponents) {
|
||||
// Top of another loop point based on finding a linearly independent
|
||||
// species
|
||||
while (true) {
|
||||
/*
|
||||
* Search the remaining part of the mole number vector, molNum
|
||||
* for the largest remaining species. Return its identity.
|
||||
* kk is the raw number. k is the orderVectorSpecies index.
|
||||
*/
|
||||
// Search the remaining part of the mole number vector, molNum for
|
||||
// the largest remaining species. Return its identity. kk is the raw
|
||||
// number. k is the orderVectorSpecies index.
|
||||
kk = max_element(molNum.begin(), molNum.end()) - molNum.begin();
|
||||
for (j = 0; j < nspecies; j++) {
|
||||
if (orderVectorSpecies[j] == kk) {
|
||||
|
|
@ -166,40 +148,33 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
if (molNum[kk] == 0.0) {
|
||||
*usedZeroedSpecies = true;
|
||||
}
|
||||
/*
|
||||
* If the largest molNum is negative, then we are done.
|
||||
*/
|
||||
// If the largest molNum is negative, then we are done.
|
||||
if (molNum[kk] == USEDBEFORE) {
|
||||
nComponents = jr;
|
||||
nNonComponents = nspecies - nComponents;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Assign a small negative number to the component that we have
|
||||
* just found, in order to take it out of further consideration.
|
||||
*/
|
||||
|
||||
// Assign a small negative number to the component that we have
|
||||
// just found, in order to take it out of further consideration.
|
||||
#ifdef DEBUG_MODE
|
||||
molSave = molNum[kk];
|
||||
#endif
|
||||
molNum[kk] = USEDBEFORE;
|
||||
|
||||
// **** CHECK LINEAR INDEPENDENCE WITH PREVIOUS SPECIES ******
|
||||
/*
|
||||
* Modified Gram-Schmidt Method, p. 202 Dalquist
|
||||
* QR factorization of a matrix without row pivoting.
|
||||
*/
|
||||
// CHECK LINEAR INDEPENDENCE WITH PREVIOUS SPECIES
|
||||
|
||||
// Modified Gram-Schmidt Method, p. 202 Dalquist
|
||||
// QR factorization of a matrix without row pivoting.
|
||||
jl = jr;
|
||||
for (j = 0; j < ne; ++j) {
|
||||
jj = orderVectorElements[j];
|
||||
sm[j + jr*ne] = mphase->nAtoms(kk,jj);
|
||||
}
|
||||
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
|
||||
*/
|
||||
// Compute the coefficients of JA column of the the upper
|
||||
// triangular R matrix, SS(J) = R_J_JR (this is slightly
|
||||
// different than Dalquist) R_JA_JA = 1
|
||||
for (j = 0; j < jl; ++j) {
|
||||
ss[j] = 0.0;
|
||||
for (i = 0; i < ne; ++i) {
|
||||
|
|
@ -207,31 +182,31 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
}
|
||||
ss[j] /= sa[j];
|
||||
}
|
||||
/*
|
||||
* Now make the new column, (*,JR), orthogonal to the
|
||||
* previous columns
|
||||
*/
|
||||
|
||||
// Now make the new column, (*,JR), orthogonal to the previous
|
||||
// columns
|
||||
for (j = 0; j < jl; ++j) {
|
||||
for (l = 0; l < ne; ++l) {
|
||||
sm[l + jr*ne] -= ss[j] * sm[l + j*ne];
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Find the new length of the new column in Q.
|
||||
* It will be used in the denominator in future row calcs.
|
||||
*/
|
||||
|
||||
// Find the new length of the new column in Q.
|
||||
// It will be used in the denominator in future row calcs.
|
||||
sa[jr] = 0.0;
|
||||
for (ml = 0; ml < ne; ++ml) {
|
||||
tmp = sm[ml + jr*ne];
|
||||
sa[jr] += tmp * tmp;
|
||||
}
|
||||
// **** IF NORM OF NEW ROW .LT. 1E-3 REJECT **********
|
||||
|
||||
// IF NORM OF NEW ROW .LT. 1E-3 REJECT
|
||||
if (sa[jr] > 1.0e-6) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// **** REARRANGE THE DATA ******************
|
||||
|
||||
// REARRANGE THE DATA
|
||||
if (jr != k) {
|
||||
if (DEBUG_MODE_ENABLED && BasisOptimize_print_lvl >= 1) {
|
||||
kk = orderVectorSpecies[k];
|
||||
|
|
@ -252,38 +227,36 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
return nComponents;
|
||||
}
|
||||
|
||||
// **** EVALUATE THE STOICHIOMETRY **********************
|
||||
/*
|
||||
* Formulate the matrix problem for the stoichiometric
|
||||
* coefficients. CX + B = 0
|
||||
* C will be an nc x nc matrix made up of the formula
|
||||
* vectors for the components. Each component's formula
|
||||
* vector is a column. The rows are the elements.
|
||||
* n RHS's will be solved for. Thus, B is an nc x n
|
||||
* matrix.
|
||||
*
|
||||
* BIG PROBLEM 1/21/99:
|
||||
*
|
||||
* This algorithm makes the assumption that the
|
||||
* first nc rows of the formula matrix aren't rank deficient.
|
||||
* However, this might not be the case. For example, assume
|
||||
* that the first element in FormulaMatrix[] is argon. Assume that
|
||||
* no species in the matrix problem actually includes argon.
|
||||
* Then, the first row in sm[], below will be identically
|
||||
* zero. bleh.
|
||||
* What needs to be done is to perform a rearrangement
|
||||
* of the ELEMENTS -> i.e. rearrange, FormulaMatrix, sp, and gai, such
|
||||
* that the first nc elements form in combination with the
|
||||
* nc components create an invertible sm[]. not a small
|
||||
* project, but very doable.
|
||||
* An alternative would be to turn the matrix problem
|
||||
* below into an ne x nc problem, and do QR elimination instead
|
||||
* of Gauss-Jordan elimination.
|
||||
* Note the rearrangement of elements need only be done once
|
||||
* in the problem. It's actually very similar to the top of
|
||||
* this program with ne being the species and nc being the
|
||||
* elements!!
|
||||
*/
|
||||
// EVALUATE THE STOICHIOMETRY
|
||||
//
|
||||
// Formulate the matrix problem for the stoichiometric
|
||||
// coefficients. CX + B = 0
|
||||
//
|
||||
// C will be an nc x nc matrix made up of the formula vectors for the
|
||||
// components. Each component's formula vector is a column. The rows are the
|
||||
// elements.
|
||||
//
|
||||
// n RHS's will be solved for. Thus, B is an nc x n matrix.
|
||||
//
|
||||
// BIG PROBLEM 1/21/99:
|
||||
//
|
||||
// This algorithm makes the assumption that the first nc rows of the formula
|
||||
// matrix aren't rank deficient. However, this might not be the case. For
|
||||
// example, assume that the first element in FormulaMatrix[] is argon.
|
||||
// Assume that no species in the matrix problem actually includes argon.
|
||||
// Then, the first row in sm[], below will be identically zero. bleh.
|
||||
//
|
||||
// What needs to be done is to perform a rearrangement of the ELEMENTS ->
|
||||
// i.e. rearrange, FormulaMatrix, sp, and gai, such that the first nc
|
||||
// elements form in combination with the nc components create an invertible
|
||||
// sm[]. not a small project, but very doable.
|
||||
//
|
||||
// An alternative would be to turn the matrix problem below into an ne x nc
|
||||
// problem, and do QR elimination instead of Gauss-Jordan elimination.
|
||||
//
|
||||
// Note the rearrangement of elements need only be done once in the problem.
|
||||
// It's actually very similar to the top of this program with ne being the
|
||||
// species and nc being the elements!!
|
||||
for (k = 0; k < nComponents; ++k) {
|
||||
kk = orderVectorSpecies[k];
|
||||
for (j = 0; j < nComponents; ++j) {
|
||||
|
|
@ -337,9 +310,7 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
writelogf(" --- %3d (%3d) ", k, kk);
|
||||
writelogf("%-10.10s", mphase->speciesName(kk));
|
||||
writelogf("|%10.3g|", molNumBase[kk]);
|
||||
/*
|
||||
* Print the negative of formRxnMatrix[]; it's easier to interpret.
|
||||
*/
|
||||
// Print the negative of formRxnMatrix[]; it's easier to interpret.
|
||||
for (j = 0; j < nComponents; j++) {
|
||||
writelogf(" %6.2f", - formRxnMatrix[j + i * ne]);
|
||||
}
|
||||
|
|
@ -355,21 +326,17 @@ size_t BasisOptimize(int* usedZeroedSpecies, bool doFormRxn, MultiPhase* mphase,
|
|||
return nComponents;
|
||||
} // basopt()
|
||||
|
||||
/**
|
||||
* Print a string within a given space limit. This routine limits the amount of
|
||||
* the string that will be printed to a maximum of "space" characters.
|
||||
*
|
||||
* str = String -> must be null terminated.
|
||||
* space = space limit for the printing.
|
||||
* alignment = 0 centered
|
||||
* 1 right aligned
|
||||
* 2 left aligned
|
||||
*/
|
||||
static void print_stringTrunc(const char* str, int space, int alignment)
|
||||
|
||||
/***********************************************************************
|
||||
* vcs_print_stringTrunc():
|
||||
*
|
||||
* Print a string within a given space limit. This routine
|
||||
* limits the amount of the string that will be printed to a
|
||||
* maximum of "space" characters.
|
||||
*
|
||||
* str = String -> must be null terminated.
|
||||
* space = space limit for the printing.
|
||||
* alignment = 0 centered
|
||||
* 1 right aligned
|
||||
* 2 left aligned
|
||||
***********************************************************************/
|
||||
{
|
||||
int i, ls=0, rs=0;
|
||||
int len = static_cast<int>(strlen(str));
|
||||
|
|
@ -408,9 +375,7 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
size_t j, k, l, i, jl, ml, jr, ielem, jj, kk=0;
|
||||
size_t nelements = mphase->nElements();
|
||||
std::string ename;
|
||||
/*
|
||||
* Get the total number of species in the multiphase object
|
||||
*/
|
||||
// Get the total number of species in the multiphase object
|
||||
size_t nspecies = mphase->nSpecies();
|
||||
|
||||
double test = -1.0E10;
|
||||
|
|
@ -425,9 +390,7 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
writelog(" --- and to rearrange the element ordering once\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Perhaps, initialize the element ordering
|
||||
*/
|
||||
// Perhaps, initialize the element ordering
|
||||
if (orderVectorElements.size() < nelements) {
|
||||
orderVectorElements.resize(nelements);
|
||||
for (j = 0; j < nelements; j++) {
|
||||
|
|
@ -435,11 +398,8 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perhaps, initialize the species ordering. However, this is
|
||||
* dangerous, as this ordering is assumed to yield the
|
||||
* component species for the problem
|
||||
*/
|
||||
// Perhaps, initialize the species ordering. However, this is dangerous, as
|
||||
// this ordering is assumed to yield the component species for the problem
|
||||
if (orderVectorSpecies.size() != nspecies) {
|
||||
orderVectorSpecies.resize(nspecies);
|
||||
for (k = 0; k < nspecies; k++) {
|
||||
|
|
@ -447,12 +407,9 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the elementAbundances aren't input, just create a fake one
|
||||
* based on summing the column of the stoich matrix.
|
||||
* This will force elements with zero species to the
|
||||
* end of the element ordering.
|
||||
*/
|
||||
// If the elementAbundances aren't input, just create a fake one based on
|
||||
// summing the column of the stoich matrix. This will force elements with
|
||||
// zero species to the end of the element ordering.
|
||||
vector_fp eAbund(nelements,0.0);
|
||||
if (elementAbundances.size() != nelements) {
|
||||
for (j = 0; j < nelements; j++) {
|
||||
|
|
@ -470,23 +427,16 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
vector_fp ss(nelements,0.0);
|
||||
vector_fp sm(nelements*nelements,0.0);
|
||||
|
||||
/*
|
||||
* Top of a loop of some sort based on the index JR. JR is the
|
||||
* current number independent elements found.
|
||||
*/
|
||||
// Top of a loop of some sort based on the index JR. JR is the current
|
||||
// number independent elements found.
|
||||
jr = 0;
|
||||
while (jr < nComponents) {
|
||||
/*
|
||||
* Top of another loop point based on finding a linearly
|
||||
* independent element
|
||||
*/
|
||||
// Top of another loop point based on finding a linearly independent
|
||||
// element
|
||||
while (true) {
|
||||
/*
|
||||
* Search the element vector. We first locate elements that
|
||||
* are present in any amount. Then, we locate elements that
|
||||
* are not present in any amount.
|
||||
* Return its identity in K.
|
||||
*/
|
||||
// Search the element vector. We first locate elements that are
|
||||
// present in any amount. Then, we locate elements that are not
|
||||
// present in any amount. Return its identity in K.
|
||||
k = nelements;
|
||||
for (ielem = jr; ielem < nelements; ielem++) {
|
||||
kk = orderVectorElements[ielem];
|
||||
|
|
@ -512,37 +462,30 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
throw CanteraError("ElemRearrange", "Required number of elements not found.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign a large negative number to the element that we have
|
||||
* just found, in order to take it out of further consideration.
|
||||
*/
|
||||
// Assign a large negative number to the element that we have
|
||||
// just found, in order to take it out of further consideration.
|
||||
eAbund[kk] = 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.
|
||||
*/
|
||||
// CHECK LINEAR INDEPENDENCE OF CURRENT FORMULA MATRIX
|
||||
// LINE WITH PREVIOUS LINES OF THE FORMULA MATRIX
|
||||
|
||||
// Modified Gram-Schmidt Method, p. 202 Dalquist
|
||||
// QR factorization of a matrix without row pivoting.
|
||||
jl = jr;
|
||||
/*
|
||||
* Fill in the row for the current element, k, under consideration
|
||||
* The row will contain the Formula matrix value for that element
|
||||
* with respect to the vector of component species.
|
||||
* (note j and k indices are flipped compared to the previous routine)
|
||||
*/
|
||||
|
||||
// Fill in the row for the current element, k, under consideration
|
||||
// The row will contain the Formula matrix value for that element
|
||||
// with respect to the vector of component species. (note j and k
|
||||
// indices are flipped compared to the previous routine)
|
||||
for (j = 0; j < nComponents; ++j) {
|
||||
jj = orderVectorSpecies[j];
|
||||
kk = orderVectorElements[k];
|
||||
sm[j + jr*nComponents] = mphase->nAtoms(jj,kk);
|
||||
}
|
||||
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
|
||||
*/
|
||||
// Compute the coefficients of JA column of the the upper
|
||||
// triangular R matrix, SS(J) = R_J_JR (this is slightly
|
||||
// different than Dalquist) R_JA_JA = 1
|
||||
for (j = 0; j < jl; ++j) {
|
||||
ss[j] = 0.0;
|
||||
for (i = 0; i < nComponents; ++i) {
|
||||
|
|
@ -550,10 +493,9 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
}
|
||||
ss[j] /= sa[j];
|
||||
}
|
||||
/*
|
||||
* Now make the new column, (*,JR), orthogonal to the
|
||||
* previous columns
|
||||
*/
|
||||
|
||||
// Now make the new column, (*,JR), orthogonal to the
|
||||
// previous columns
|
||||
for (j = 0; j < jl; ++j) {
|
||||
for (l = 0; l < nComponents; ++l) {
|
||||
sm[l + jr*nComponents] -= ss[j] * sm[l + j*nComponents];
|
||||
|
|
@ -561,21 +503,19 @@ void ElemRearrange(size_t nComponents, const vector_fp& elementAbundances,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the new length of the new column in Q.
|
||||
* It will be used in the denominator in future row calcs.
|
||||
*/
|
||||
// Find the new length of the new column in Q.
|
||||
// It will be used in the denominator in future row calcs.
|
||||
sa[jr] = 0.0;
|
||||
for (ml = 0; ml < nComponents; ++ml) {
|
||||
double tmp = sm[ml + jr*nComponents];
|
||||
sa[jr] += tmp * tmp;
|
||||
}
|
||||
// **** IF NORM OF NEW ROW .LT. 1E-6 REJECT **********
|
||||
// IF NORM OF NEW ROW .LT. 1E-6 REJECT
|
||||
if (sa[jr] > 1.0e-6) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// **** REARRANGE THE DATA ******************
|
||||
// REARRANGE THE DATA
|
||||
if (jr != k) {
|
||||
if (DEBUG_MODE_ENABLED && BasisOptimize_print_lvl > 0) {
|
||||
kk = orderVectorElements[k];
|
||||
|
|
|
|||
|
|
@ -201,11 +201,9 @@ int ChemEquil::setInitialMoles(thermo_t& s, vector_fp& elMoleGoal,
|
|||
for (size_t m = 0; m < m_nComponents; m++) {
|
||||
m_component[m] = e.componentIndex(m);
|
||||
}
|
||||
/*
|
||||
* Update the current values of the temp, density, and
|
||||
* mole fraction, and element abundance vectors kept
|
||||
* within the ChemEquil object.
|
||||
*/
|
||||
|
||||
// Update the current values of the temp, density, and mole fraction,
|
||||
// and element abundance vectors kept within the ChemEquil object.
|
||||
update(s);
|
||||
|
||||
if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
|
||||
|
|
@ -347,9 +345,7 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
vector_fp state;
|
||||
s.saveState(state);
|
||||
|
||||
/*
|
||||
* Check Compatibility
|
||||
*/
|
||||
// Check Compatibility
|
||||
if (m_mm != s.nElements() || m_kk != s.nSpecies()) {
|
||||
throw CanteraError("ChemEquil::equilibrate ERROR",
|
||||
"Input ThermoPhase is incompatible with initialization");
|
||||
|
|
@ -406,11 +402,8 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Before we do anything to change the ThermoPhase object,
|
||||
* we calculate and store the two specified thermodynamic
|
||||
* properties that we are after.
|
||||
*/
|
||||
// Before we do anything to change the ThermoPhase object, we calculate and
|
||||
// store the two specified thermodynamic properties that we are after.
|
||||
xval = m_p1->value(s);
|
||||
yval = m_p2->value(s);
|
||||
|
||||
|
|
@ -420,13 +413,10 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
vector_fp x(nvar, -102.0); // solution vector
|
||||
vector_fp res_trial(nvar, 0.0); // residual
|
||||
|
||||
/*
|
||||
* Replace one of the element abundance fraction equations
|
||||
* with the specified property calculation.
|
||||
*
|
||||
* We choose the equation of the element with the highest element
|
||||
* abundance.
|
||||
*/
|
||||
// Replace one of the element abundance fraction equations with the
|
||||
// specified property calculation.
|
||||
//
|
||||
// We choose the equation of the element with the highest element abundance.
|
||||
size_t m;
|
||||
tmp = -1.0;
|
||||
for (size_t im = 0; im < m_nComponents; im++) {
|
||||
|
|
@ -441,20 +431,17 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
"Element Abundance Vector is zeroed");
|
||||
}
|
||||
|
||||
// start with a composition with everything non-zero. Note
|
||||
// that since we have already save the target element moles,
|
||||
// changing the composition at this point only affects the
|
||||
// starting point, not the final solution.
|
||||
// start with a composition with everything non-zero. Note that since we
|
||||
// have already save the target element moles, changing the composition at
|
||||
// this point only affects the starting point, not the final solution.
|
||||
vector_fp xmm(m_kk, 0.0);
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
xmm[k] = s.moleFraction(k) + 1.0E-32;
|
||||
}
|
||||
s.setMoleFractions(xmm.data());
|
||||
|
||||
/*
|
||||
* Update the internally stored values of m_temp,
|
||||
* m_dens, and the element mole fractions.
|
||||
*/
|
||||
// Update the internally stored values of m_temp, m_dens, and the element
|
||||
// mole fractions.
|
||||
update(s);
|
||||
|
||||
doublereal tmaxPhase = s.maxTemp();
|
||||
|
|
@ -472,10 +459,9 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
|
||||
doublereal slope, phigh, plow, pval, dt;
|
||||
|
||||
// first get the property values at the upper and lower
|
||||
// temperature limits. Since p1 (h, s, or u) is monotonic
|
||||
// in T, these values determine the upper and lower
|
||||
// bounnds (phigh, plow) for p1.
|
||||
// first get the property values at the upper and lower temperature
|
||||
// limits. Since p1 (h, s, or u) is monotonic in T, these values
|
||||
// determine the upper and lower bounnds (phigh, plow) for p1.
|
||||
|
||||
s.setTemperature(tmax);
|
||||
setInitialMoles(s, elMolesGoal, loglevel - 1);
|
||||
|
|
@ -495,10 +481,10 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
setInitialMoles(s, elMolesGoal, loglevel - 1);
|
||||
pval = m_p1->value(s);
|
||||
|
||||
// If this value of p1 is greater than the specified
|
||||
// property value, then the current temperature is too
|
||||
// high. Use it as the new upper bound. Otherwise, it
|
||||
// is too low, so use it as the new lower bound.
|
||||
// If this value of p1 is greater than the specified property value,
|
||||
// then the current temperature is too high. Use it as the new upper
|
||||
// bound. Otherwise, it is too low, so use it as the new lower
|
||||
// bound.
|
||||
if (pval > xval) {
|
||||
tmax = t0;
|
||||
phigh = pval;
|
||||
|
|
@ -534,11 +520,8 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
|
||||
setInitialMoles(s, elMolesGoal,loglevel);
|
||||
|
||||
/*
|
||||
* If requested, get the initial estimate for the
|
||||
* chemical potentials from the ThermoPhase object
|
||||
* itself. Or else, create our own estimate.
|
||||
*/
|
||||
// If requested, get the initial estimate for the chemical potentials from
|
||||
// the ThermoPhase object itself. Or else, create our own estimate.
|
||||
if (useThermoPhaseElementPotentials) {
|
||||
bool haveEm = s.getElementPotentials(x.data());
|
||||
if (haveEm) {
|
||||
|
|
@ -552,44 +535,32 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
estimateElementPotentials(s, x, elMolesGoal);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Calculate initial estimates of the element potentials.
|
||||
* This algorithm uese the MultiPhaseEquil object's
|
||||
* initialization capabilities to calculate an initial
|
||||
* estimate of the mole fractions for a set of linearly
|
||||
* independent component species. Then, the element
|
||||
* potentials are solved for based on the chemical
|
||||
* potentials of the component species.
|
||||
*/
|
||||
// Calculate initial estimates of the element potentials. This algorithm
|
||||
// uese the MultiPhaseEquil object's initialization capabilities to
|
||||
// calculate an initial estimate of the mole fractions for a set of
|
||||
// linearly independent component species. Then, the element potentials
|
||||
// are solved for based on the chemical potentials of the component
|
||||
// species.
|
||||
estimateElementPotentials(s, x, elMolesGoal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do a better estimate of the element potentials.
|
||||
* We have found that the current estimate may not be good
|
||||
* enough to avoid drastic numerical issues associated with
|
||||
* the use of a numerically generated Jacobian.
|
||||
*
|
||||
* The Brinkley algorithm assumes a constant T, P system
|
||||
* and uses a linearized analytical Jacobian that turns out
|
||||
* to be very stable.
|
||||
*/
|
||||
// Do a better estimate of the element potentials. We have found that the
|
||||
// current estimate may not be good enough to avoid drastic numerical issues
|
||||
// associated with the use of a numerically generated Jacobian.
|
||||
//
|
||||
// The Brinkley algorithm assumes a constant T, P system and uses a
|
||||
// linearized analytical Jacobian that turns out to be very stable.
|
||||
int info = estimateEP_Brinkley(s, x, elMolesGoal);
|
||||
if (info == 0) {
|
||||
setToEquilState(s, x, s.temperature());
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the log(temp) into the last solution unknown
|
||||
* slot.
|
||||
*/
|
||||
// Install the log(temp) into the last solution unknown slot.
|
||||
x[m_mm] = log(s.temperature());
|
||||
|
||||
/*
|
||||
* Setting the max and min values for x[]. Also, if element
|
||||
* abundance vector is zero, setting x[] to -1000. This
|
||||
* effectively zeroes out all species containing that element.
|
||||
*/
|
||||
// Setting the max and min values for x[]. Also, if element abundance vector
|
||||
// is zero, setting x[] to -1000. This effectively zeroes out all species
|
||||
// containing that element.
|
||||
vector_fp above(nvar);
|
||||
vector_fp below(nvar);
|
||||
for (m = 0; m < mm; m++) {
|
||||
|
|
@ -599,10 +570,9 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
x[m] = -1000.0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Set the temperature bounds to be 25 degrees different than the max and min
|
||||
* temperatures.
|
||||
*/
|
||||
|
||||
// Set the temperature bounds to be 25 degrees different than the max and
|
||||
// min temperatures.
|
||||
above[mm] = log(s.maxTemp() + 25.0);
|
||||
below[mm] = log(s.minTemp() - 25.0);
|
||||
|
||||
|
|
@ -625,19 +595,17 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
for (m = 0; m < nvar; m++) {
|
||||
double tval = options.relTolerance;
|
||||
if (m < mm) {
|
||||
/*
|
||||
* Special case convergence requirements for electron element.
|
||||
* This is a special case because the element coefficients may
|
||||
* be both positive and negative. And, typically they sum to 0.0.
|
||||
* Therefore, there is no natural absolute value for this quantity.
|
||||
* We supply the absolute value tolerance here. Note, this is
|
||||
* made easier since the element abundances are normalized to one
|
||||
* within this routine.
|
||||
*
|
||||
* Note, the 1.0E-13 value was recently relaxed from 1.0E-15, because
|
||||
* convergence failures were found to occur for the lower value
|
||||
* at small pressure (0.01 pascal).
|
||||
*/
|
||||
// Special case convergence requirements for electron element.
|
||||
// This is a special case because the element coefficients may
|
||||
// be both positive and negative. And, typically they sum to
|
||||
// 0.0. Therefore, there is no natural absolute value for this
|
||||
// quantity. We supply the absolute value tolerance here. Note,
|
||||
// this is made easier since the element abundances are
|
||||
// normalized to one within this routine.
|
||||
//
|
||||
// Note, the 1.0E-13 value was recently relaxed from 1.0E-15,
|
||||
// because convergence failures were found to occur for the
|
||||
// lower value at small pressure (0.01 pascal).
|
||||
if (m == m_eloc) {
|
||||
tval = elMolesGoal[m] * options.relTolerance + options.absElemTol
|
||||
+ 1.0E-13;
|
||||
|
|
@ -659,10 +627,9 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
if (m_eloc != npos) {
|
||||
adjustEloc(s, elMolesGoal);
|
||||
}
|
||||
/*
|
||||
* Save the calculated and converged element potentials
|
||||
* to the original ThermoPhase object.
|
||||
*/
|
||||
|
||||
// Save the calculated and converged element potentials to the
|
||||
// original ThermoPhase object.
|
||||
s.setElementPotentials(m_lambda);
|
||||
if (s.temperature() > s.maxTemp() + 1.0 ||
|
||||
s.temperature() < s.minTemp() - 1.0) {
|
||||
|
|
@ -705,9 +672,7 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
|||
oldf = f;
|
||||
scale(res_trial.begin(), res_trial.end(), res_trial.begin(), -1.0);
|
||||
|
||||
/*
|
||||
* Solve the system
|
||||
*/
|
||||
// Solve the system
|
||||
try {
|
||||
info = solve(jac, res_trial.data());
|
||||
} catch (CanteraError& err) {
|
||||
|
|
@ -776,9 +741,8 @@ int ChemEquil::dampStep(thermo_t& mix, vector_fp& oldx,
|
|||
{
|
||||
double damp;
|
||||
|
||||
/*
|
||||
* Carry out a delta damping approach on the dimensionless element potentials.
|
||||
*/
|
||||
// Carry out a delta damping approach on the dimensionless element
|
||||
// potentials.
|
||||
damp = 1.0;
|
||||
for (size_t m = 0; m < m_mm; m++) {
|
||||
if (m == m_eloc) {
|
||||
|
|
@ -798,9 +762,7 @@ int ChemEquil::dampStep(thermo_t& mix, vector_fp& oldx,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the solution unknown
|
||||
*/
|
||||
// Update the solution unknown
|
||||
for (size_t m = 0; m < x.size(); m++) {
|
||||
x[m] = oldx[m] + damp * step[m];
|
||||
}
|
||||
|
|
@ -832,11 +794,8 @@ void ChemEquil::equilResidual(thermo_t& s, const vector_fp& x,
|
|||
} else if (n >= m_nComponents) {
|
||||
resid[m] = x[m];
|
||||
} else {
|
||||
/*
|
||||
* Change the calculation for small element number, using
|
||||
* L'Hopital's rule.
|
||||
* The log formulation is unstable.
|
||||
*/
|
||||
// Change the calculation for small element number, using
|
||||
// L'Hopital's rule. The log formulation is unstable.
|
||||
if (elmFracGoal[m] < 1.0E-10 || elmFrac[m] < 1.0E-10 || m == m_eloc) {
|
||||
resid[m] = elmFracGoal[m] - elmFrac[m];
|
||||
} else {
|
||||
|
|
@ -907,10 +866,9 @@ double ChemEquil::calcEmoles(thermo_t& s, vector_fp& x, const double& n_t,
|
|||
{
|
||||
double n_t_calc = 0.0;
|
||||
double tmp;
|
||||
/*
|
||||
* Calculate the activity coefficients of the solution, at the
|
||||
* previous solution state.
|
||||
*/
|
||||
|
||||
// Calculate the activity coefficients of the solution, at the previous
|
||||
// solution state.
|
||||
vector_fp actCoeff(m_kk, 1.0);
|
||||
s.setMoleFractions(Xmol_i_calc.data());
|
||||
s.setPressure(pressureConst);
|
||||
|
|
@ -941,11 +899,8 @@ double ChemEquil::calcEmoles(thermo_t& s, vector_fp& x, const double& n_t,
|
|||
int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
||||
vector_fp& elMoles)
|
||||
{
|
||||
/*
|
||||
* Before we do anything, we will save the state of the solution.
|
||||
* Then, if things go drastically wrong, we will restore the
|
||||
* saved state.
|
||||
*/
|
||||
// Before we do anything, we will save the state of the solution. Then, if
|
||||
// things go drastically wrong, we will restore the saved state.
|
||||
vector_fp state;
|
||||
s.saveState(state);
|
||||
double tmp, sum;
|
||||
|
|
@ -969,11 +924,8 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
vector_fp resid(m_mm+1, 0.0);
|
||||
vector_int lumpSum(m_mm+1, 0);
|
||||
|
||||
/*
|
||||
* Get the nondimensional Gibbs functions for the species
|
||||
* at their standard states of solution at the current T and P
|
||||
* of the solution.
|
||||
*/
|
||||
// Get the nondimensional Gibbs functions for the species at their standard
|
||||
// states of solution at the current T and P of the solution.
|
||||
s.getGibbs_RT(m_muSS_RT.data());
|
||||
|
||||
vector_fp eMolesCalc(m_mm, 0.0);
|
||||
|
|
@ -1042,27 +994,18 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* -------------------------------------------------------------------
|
||||
* Main Loop.
|
||||
*/
|
||||
// Main Loop.
|
||||
for (int iter = 0; iter < 20* options.maxIterations; iter++) {
|
||||
/*
|
||||
* Save the old solution
|
||||
*/
|
||||
// Save the old solution
|
||||
for (m = 0; m < m_mm; m++) {
|
||||
x_old[m] = x[m];
|
||||
}
|
||||
x_old[m_mm] = n_t;
|
||||
/*
|
||||
* Calculate the mole numbers of species
|
||||
*/
|
||||
// Calculate the mole numbers of species
|
||||
if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
|
||||
writelogf("START ITERATION %d:\n", iter);
|
||||
}
|
||||
/*
|
||||
* Calculate the mole numbers of species and elements.
|
||||
*/
|
||||
// Calculate the mole numbers of species and elements.
|
||||
double n_t_calc = calcEmoles(s, x, n_t, Xmol_i_calc, eMolesCalc, n_i_calc,
|
||||
pressureConst);
|
||||
|
||||
|
|
@ -1086,9 +1029,7 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
|
||||
double nCutoff;
|
||||
bool normalStep = true;
|
||||
/*
|
||||
* Decide if we are to do a normal step or a modified step
|
||||
*/
|
||||
// Decide if we are to do a normal step or a modified step
|
||||
size_t iM = npos;
|
||||
for (m = 0; m < m_mm; m++) {
|
||||
if (elMoles[m] > 0.001 * elMolesTotal) {
|
||||
|
|
@ -1130,30 +1071,28 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
resid[m_mm] = std::min(resid[m_mm], 0.0);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Determine whether the matrix should be dumbed down because
|
||||
* the coefficient matrix of species (with significant concentrations)
|
||||
* is rank deficient.
|
||||
*
|
||||
* The basic idea is that at any time during the calculation only a
|
||||
* small subset of species with sufficient concentration matters.
|
||||
* If the rank of the element coefficient matrix for that subset of species
|
||||
* is less than the number of elements, then the matrix created by
|
||||
* the Brinkley method below may become singular.
|
||||
*
|
||||
* The logic below looks for obvious cases where the current element
|
||||
* coefficient matrix is rank deficient.
|
||||
*
|
||||
* The way around rank-deficiency is to lump-sum the corresponding row
|
||||
* of the matrix. Note, lump-summing seems to work very well in terms of
|
||||
* its stability properties, i.e., it heads in the right direction,
|
||||
* albeit with lousy convergence rates.
|
||||
*
|
||||
* NOTE: This probably should be extended to a full blown Gauss-Jordan
|
||||
* factorization scheme in the future. For Example
|
||||
* the scheme below would fail for the set: HCl NH4Cl, NH3.
|
||||
* Hopefully, it's caught by the equal rows logic below.
|
||||
*/
|
||||
// Determine whether the matrix should be dumbed down because the
|
||||
// coefficient matrix of species (with significant concentrations)
|
||||
// is rank deficient.
|
||||
//
|
||||
// The basic idea is that at any time during the calculation only a
|
||||
// small subset of species with sufficient concentration matters. If
|
||||
// the rank of the element coefficient matrix for that subset of
|
||||
// species is less than the number of elements, then the matrix
|
||||
// created by the Brinkley method below may become singular.
|
||||
//
|
||||
// The logic below looks for obvious cases where the current element
|
||||
// coefficient matrix is rank deficient.
|
||||
//
|
||||
// The way around rank-deficiency is to lump-sum the corresponding
|
||||
// row of the matrix. Note, lump-summing seems to work very well in
|
||||
// terms of its stability properties, i.e., it heads in the right
|
||||
// direction, albeit with lousy convergence rates.
|
||||
//
|
||||
// NOTE: This probably should be extended to a full blown Gauss-
|
||||
// Jordan factorization scheme in the future. For Example the scheme
|
||||
// below would fail for the set: HCl NH4Cl, NH3. Hopefully, it's
|
||||
// caught by the equal rows logic below.
|
||||
for (m = 0; m < m_mm; m++) {
|
||||
lumpSum[m] = 1;
|
||||
}
|
||||
|
|
@ -1189,9 +1128,7 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Formulate the matrix.
|
||||
*/
|
||||
// Formulate the matrix.
|
||||
for (im = 0; im < m_mm; im++) {
|
||||
m = m_orderVectorElements[im];
|
||||
if (im < m_nComponents) {
|
||||
|
|
@ -1212,9 +1149,8 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
}
|
||||
a1(m_mm, m_mm) = 0.0;
|
||||
|
||||
/*
|
||||
* Formulate the residual, resid, and the estimate for the convergence criteria, sum
|
||||
*/
|
||||
// Formulate the residual, resid, and the estimate for the
|
||||
// convergence criteria, sum
|
||||
sum = 0.0;
|
||||
for (im = 0; im < m_mm; im++) {
|
||||
m = m_orderVectorElements[im];
|
||||
|
|
@ -1223,12 +1159,12 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
} else {
|
||||
resid[m] = 0.0;
|
||||
}
|
||||
/*
|
||||
* For equations with positive and negative coefficients, (electronic charge),
|
||||
* we must mitigate the convergence criteria by a condition limited by
|
||||
* finite precision of inverting a matrix.
|
||||
* Other equations with just positive coefficients aren't limited by this.
|
||||
*/
|
||||
|
||||
// For equations with positive and negative coefficients,
|
||||
// (electronic charge), we must mitigate the convergence
|
||||
// criteria by a condition limited by finite precision of
|
||||
// inverting a matrix. Other equations with just positive
|
||||
// coefficients aren't limited by this.
|
||||
if (m == m_eloc) {
|
||||
tmp = resid[m] / (elMoles[m] + elMolesTotal*1.0E-6 + options.absElemTol);
|
||||
} else {
|
||||
|
|
@ -1274,21 +1210,17 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
|
||||
writelogf("(it %d) Convergence = %g\n", iter, sum);
|
||||
}
|
||||
/*
|
||||
* Insist on 20x accuracy compared to the top routine.
|
||||
* There are instances, for ill-conditioned or
|
||||
* singular matrices where this is needed to move
|
||||
* the system to a point where the matrices aren't
|
||||
* singular.
|
||||
*/
|
||||
|
||||
// Insist on 20x accuracy compared to the top routine. There are
|
||||
// instances, for ill-conditioned or singular matrices where this is
|
||||
// needed to move the system to a point where the matrices aren't
|
||||
// singular.
|
||||
if (sum < 0.05 * options.relTolerance) {
|
||||
retn = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Row Sum scaling
|
||||
*/
|
||||
// Row Sum scaling
|
||||
for (m = 0; m <= m_mm; m++) {
|
||||
tmp = 0.0;
|
||||
for (n = 0; n <= m_mm; n++) {
|
||||
|
|
@ -1322,27 +1254,26 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
writelogf("] = %10.5g\n", resid[m]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Next Step: We have row-summed the equations.
|
||||
* However, there are some degenerate cases where two
|
||||
* rows will be multiplies of each other in terms of
|
||||
* 0 < m, 0 < m part of the matrix. This occurs on a case
|
||||
* by case basis, and depends upon the current state of the
|
||||
* element potential values, which affect the concentrations
|
||||
* of species.
|
||||
* So, the way we have found to eliminate this problem is to
|
||||
* lump-sum one of the rows of the matrix, except for the
|
||||
* last column, and stick it all on the diagonal.
|
||||
* Then, we at least have a non-singular matrix, and the
|
||||
* modified equation moves the corresponding unknown in the
|
||||
* correct direction.
|
||||
* The previous row-sum operation has made the identification
|
||||
* of identical rows much simpler.
|
||||
*
|
||||
* Note at least 6E-4 is necessary for the comparison.
|
||||
* I'm guessing 1.0E-3. If two rows are anywhere close to being
|
||||
* equivalent, the algorithm can get stuck in an oscillatory mode.
|
||||
*/
|
||||
|
||||
// Next Step: We have row-summed the equations. However, there are
|
||||
// some degenerate cases where two rows will be multiplies of each
|
||||
// other in terms of 0 < m, 0 < m part of the matrix. This occurs on
|
||||
// a case by case basis, and depends upon the current state of the
|
||||
// element potential values, which affect the concentrations of
|
||||
// species.
|
||||
//
|
||||
// So, the way we have found to eliminate this problem is to lump-
|
||||
// sum one of the rows of the matrix, except for the last column,
|
||||
// and stick it all on the diagonal. Then, we at least have a non-
|
||||
// singular matrix, and the modified equation moves the
|
||||
// corresponding unknown in the correct direction.
|
||||
//
|
||||
// The previous row-sum operation has made the identification of
|
||||
// identical rows much simpler.
|
||||
//
|
||||
// Note at least 6E-4 is necessary for the comparison. I'm guessing
|
||||
// 1.0E-3. If two rows are anywhere close to being equivalent, the
|
||||
// algorithm can get stuck in an oscillatory mode.
|
||||
modifiedMatrix = false;
|
||||
for (m = 0; m < m_mm; m++) {
|
||||
size_t sameAsRow = npos;
|
||||
|
|
@ -1401,11 +1332,8 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
"unused elements.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out the damping coefficient: Use a delta damping
|
||||
* coefficient formulation: magnitude of change is capped
|
||||
* to exp(1).
|
||||
*/
|
||||
// Figure out the damping coefficient: Use a delta damping
|
||||
// coefficient formulation: magnitude of change is capped to exp(1).
|
||||
beta = 1.0;
|
||||
for (m = 0; m < m_mm; m++) {
|
||||
if (resid[m] > 1.0) {
|
||||
|
|
@ -1419,9 +1347,7 @@ int ChemEquil::estimateEP_Brinkley(thermo_t& s, vector_fp& x,
|
|||
writelogf("(it %d) Beta = %g\n", iter, beta);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Update the solution vector
|
||||
*/
|
||||
// Update the solution vector
|
||||
for (m = 0; m < m_mm; m++) {
|
||||
x[m] += beta * resid[m];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,9 +107,8 @@ void MultiPhase::addPhase(ThermoPhase* p, doublereal moles)
|
|||
m_np = m_phase.size();
|
||||
m_nsp += p->nSpecies();
|
||||
|
||||
// determine if this phase has new elements
|
||||
// for each new element, add an entry in the map
|
||||
// from names to index number + 1:
|
||||
// determine if this phase has new elements for each new element, add an
|
||||
// entry in the map from names to index number + 1:
|
||||
|
||||
string ename;
|
||||
// iterate over the elements in this phase
|
||||
|
|
@ -117,10 +116,9 @@ void MultiPhase::addPhase(ThermoPhase* p, doublereal moles)
|
|||
for (m = 0; m < nel; m++) {
|
||||
ename = p->elementName(m);
|
||||
|
||||
// if no entry is found for this element name, then
|
||||
// it is a new element. In this case, add the name
|
||||
// to the list of names, increment the element count,
|
||||
// and add an entry to the name->(index+1) map.
|
||||
// if no entry is found for this element name, then it is a new element.
|
||||
// In this case, add the name to the list of names, increment the
|
||||
// element count, and add an entry to the name->(index+1) map.
|
||||
if (m_enamemap.find(ename) == m_enamemap.end()) {
|
||||
m_enamemap[ename] = m_nel + 1;
|
||||
m_enames.push_back(ename);
|
||||
|
|
@ -135,22 +133,21 @@ void MultiPhase::addPhase(ThermoPhase* p, doublereal moles)
|
|||
}
|
||||
}
|
||||
|
||||
// If the mixture temperature hasn't been set, then set the
|
||||
// temperature and pressure to the values for the phase being
|
||||
// added. There is no good way to do this. However, this will be overridden later.
|
||||
// If the mixture temperature hasn't been set, then set the temperature and
|
||||
// pressure to the values for the phase being added. There is no good way to
|
||||
// do this. However, this will be overridden later.
|
||||
if (m_temp == 298.15 && p->temperature() > 2.0E-3) {
|
||||
m_temp = p->temperature();
|
||||
m_press = p->pressure();
|
||||
}
|
||||
|
||||
// If this is a solution phase, update the minimum and maximum
|
||||
// mixture temperatures. Stoichiometric phases are excluded,
|
||||
// since a mixture may define multiple stoichiometric phases,
|
||||
// each of which has thermo data valid only over a limited
|
||||
// range. For example, a mixture might be defined to contain a
|
||||
// phase representing water ice and one representing liquid
|
||||
// water, only one of which should be present if the mixture
|
||||
// represents an equilibrium state.
|
||||
// If this is a solution phase, update the minimum and maximum mixture
|
||||
// temperatures. Stoichiometric phases are excluded, since a mixture may
|
||||
// define multiple stoichiometric phases, each of which has thermo data
|
||||
// valid only over a limited range. For example, a mixture might be defined
|
||||
// to contain a phase representing water ice and one representing liquid
|
||||
// water, only one of which should be present if the mixture represents an
|
||||
// equilibrium state.
|
||||
if (p->nSpecies() > 1) {
|
||||
m_Tmin = std::max(p->minTemp(), m_Tmin);
|
||||
m_Tmax = std::min(p->maxTemp(), m_Tmax);
|
||||
|
|
@ -172,8 +169,7 @@ void MultiPhase::init()
|
|||
m_elemAbundances.resize(m_nel, 0.0);
|
||||
|
||||
// iterate over the elements
|
||||
// -> fill in m_atoms(m,k), m_snames(k), m_spphase(k),
|
||||
// m_sptart(ip)
|
||||
// -> fill in m_atoms(m,k), m_snames(k), m_spphase(k), m_spstart(ip)
|
||||
for (m = 0; m < m_nel; m++) {
|
||||
sym = m_enames[m];
|
||||
k = 0;
|
||||
|
|
@ -210,8 +206,8 @@ void MultiPhase::init()
|
|||
}
|
||||
}
|
||||
|
||||
/// set the initial composition within each phase to the
|
||||
/// mole fractions stored in the phase objects
|
||||
// set the initial composition within each phase to the
|
||||
// mole fractions stored in the phase objects
|
||||
m_init = true;
|
||||
uploadMoleFractionsFromPhases();
|
||||
updatePhases();
|
||||
|
|
@ -437,9 +433,7 @@ void MultiPhase::setMolesByName(const std::string& x)
|
|||
|
||||
void MultiPhase::getMoles(doublereal* molNum) const
|
||||
{
|
||||
/*
|
||||
* First copy in the mole fractions
|
||||
*/
|
||||
// First copy in the mole fractions
|
||||
copy(m_moleFractions.begin(), m_moleFractions.end(), molNum);
|
||||
size_t ik;
|
||||
doublereal* dtmp = molNum;
|
||||
|
|
@ -605,8 +599,8 @@ double MultiPhase::equilibrate_MultiPhaseEquil(int XY, doublereal err,
|
|||
Hlow = hnow;
|
||||
}
|
||||
} else {
|
||||
// the current enthalpy is greater than the target; therefore the
|
||||
// current temperature is too high.
|
||||
// the current enthalpy is greater than the target;
|
||||
// therefore the current temperature is too high.
|
||||
if (m_temp < Thigh) {
|
||||
Thigh = m_temp;
|
||||
Hhigh = hnow;
|
||||
|
|
|
|||
|
|
@ -30,17 +30,15 @@ MultiPhaseEquil::MultiPhaseEquil(MultiPhase* mix, bool start, int loglevel) : m_
|
|||
m_incl_element.resize(m_nel_mix,1);
|
||||
for (m = 0; m < m_nel_mix; m++) {
|
||||
string enm = mix->elementName(m);
|
||||
// element 'E' or 'e' represents an electron; this
|
||||
// requires special handling, so save its index
|
||||
// for later use
|
||||
// element 'E' or 'e' represents an electron; this requires special
|
||||
// handling, so save its index for later use
|
||||
if (enm == "E" || enm == "e") {
|
||||
m_eloc = m;
|
||||
}
|
||||
// if an element other than electrons is not present in
|
||||
// the mixture, then exclude it and all species containing
|
||||
// it from the calculation. Electrons are a special case,
|
||||
// since a species can have a negative number of 'atoms'
|
||||
// of electrons (positive ions).
|
||||
// if an element other than electrons is not present in the mixture,
|
||||
// then exclude it and all species containing it from the calculation.
|
||||
// Electrons are a special case, since a species can have a negative
|
||||
// number of 'atoms' of electrons (positive ions).
|
||||
if (m_mix->elementMoles(m) <= 0.0 && m != m_eloc) {
|
||||
m_incl_element[m] = 0;
|
||||
for (k = 0; k < m_nsp_mix; k++) {
|
||||
|
|
@ -65,17 +63,15 @@ MultiPhaseEquil::MultiPhaseEquil(MultiPhase* mix, bool start, int loglevel) : m_
|
|||
}
|
||||
}
|
||||
|
||||
// include pure single-constituent phases only if their thermo
|
||||
// data are valid for this temperature. This is necessary,
|
||||
// since some thermo polynomial fits are done only for a
|
||||
// limited temperature range. For example, using the NASA
|
||||
// polynomial fits for solid ice and liquid water, if this
|
||||
// were not done the calculation would predict solid ice to be
|
||||
// present far above its melting point, since the thermo
|
||||
// polynomial fits only extend to 273.15 K, and give
|
||||
// unphysical results above this temperature, leading
|
||||
// (incorrectly) to Gibbs free energies at high temperature
|
||||
// lower than for liquid water.
|
||||
// include pure single-constituent phases only if their thermo data are
|
||||
// valid for this temperature. This is necessary, since some thermo
|
||||
// polynomial fits are done only for a limited temperature range. For
|
||||
// example, using the NASA polynomial fits for solid ice and liquid water,
|
||||
// if this were not done the calculation would predict solid ice to be
|
||||
// present far above its melting point, since the thermo polynomial fits
|
||||
// only extend to 273.15 K, and give unphysical results above this
|
||||
// temperature, leading (incorrectly) to Gibbs free energies at high
|
||||
// temperature lower than for liquid water.
|
||||
size_t ip;
|
||||
for (k = 0; k < m_nsp_mix; k++) {
|
||||
ip = m_mix->speciesPhaseIndex(k);
|
||||
|
|
@ -92,8 +88,7 @@ MultiPhaseEquil::MultiPhaseEquil(MultiPhase* mix, bool start, int loglevel) : m_
|
|||
}
|
||||
}
|
||||
|
||||
// Now build the list of all species to be included in the
|
||||
// calculation.
|
||||
// Now build the list of all species to be included in the calculation.
|
||||
for (k = 0; k < m_nsp_mix; k++) {
|
||||
if (m_incl_species[k] ==1) {
|
||||
m_nsp++;
|
||||
|
|
@ -131,10 +126,9 @@ MultiPhaseEquil::MultiPhaseEquil(MultiPhase* mix, bool start, int loglevel) : m_
|
|||
m_order[k] = k;
|
||||
}
|
||||
|
||||
// if the 'start' flag is set, estimate the initial mole
|
||||
// numbers by doing a linear Gibbs minimization. In this case,
|
||||
// only the elemental composition of the initial mixture state
|
||||
// matters.
|
||||
// if the 'start' flag is set, estimate the initial mole numbers by doing a
|
||||
// linear Gibbs minimization. In this case, only the elemental composition
|
||||
// of the initial mixture state matters.
|
||||
if (start) {
|
||||
setInitialMoles(loglevel-1);
|
||||
}
|
||||
|
|
@ -160,10 +154,9 @@ MultiPhaseEquil::MultiPhaseEquil(MultiPhase* mix, bool start, int loglevel) : m_
|
|||
m_force = false;
|
||||
updateMixMoles();
|
||||
|
||||
// At this point, the instance has been created, the species
|
||||
// to be included have been determined, and an initial
|
||||
// composition has been selected that has all non-zero mole
|
||||
// numbers for the included species.
|
||||
// At this point, the instance has been created, the species to be included
|
||||
// have been determined, and an initial composition has been selected that
|
||||
// has all non-zero mole numbers for the included species.
|
||||
}
|
||||
|
||||
doublereal MultiPhaseEquil::equilibrate(int XY, doublereal err,
|
||||
|
|
@ -219,8 +212,7 @@ int MultiPhaseEquil::setInitialMoles(int loglevel)
|
|||
int iter = 0;
|
||||
|
||||
while (redo) {
|
||||
// choose a set of components based on the current
|
||||
// composition
|
||||
// choose a set of components based on the current composition
|
||||
computeN();
|
||||
redo = false;
|
||||
iter++;
|
||||
|
|
@ -331,18 +323,16 @@ void MultiPhaseEquil::getComponents(const std::vector<size_t>& order)
|
|||
}
|
||||
}
|
||||
|
||||
// If a pivot is zero, exchange columns. This occurs when
|
||||
// a species has an elemental composition that is not
|
||||
// linearly independent of the component species that have
|
||||
// already been assigned
|
||||
// If a pivot is zero, exchange columns. This occurs when a species has
|
||||
// an elemental composition that is not linearly independent of the
|
||||
// component species that have already been assigned
|
||||
if (m < nColumns && m_A(m,m) == 0.0) {
|
||||
// First, we need to find a good candidate for a
|
||||
// component species to swap in for the one that has
|
||||
// zero pivot. It must contain element m, be linearly
|
||||
// independent of the components processed so far
|
||||
// (m_A(m,k) != 0), and should be a major species if
|
||||
// possible. We'll choose the species with greatest
|
||||
// mole fraction that satisfies these criteria.
|
||||
// First, we need to find a good candidate for a component species
|
||||
// to swap in for the one that has zero pivot. It must contain
|
||||
// element m, be linearly independent of the components processed so
|
||||
// far (m_A(m,k) != 0), and should be a major species if possible.
|
||||
// We'll choose the species with greatest mole fraction that
|
||||
// satisfies these criteria.
|
||||
doublereal maxmoles = -999.0;
|
||||
size_t kmax = 0;
|
||||
for (k = m+1; k < nColumns; k++) {
|
||||
|
|
@ -480,10 +470,9 @@ doublereal MultiPhaseEquil::stepComposition(int loglevel)
|
|||
} else {
|
||||
FCTR = 0.9;
|
||||
}
|
||||
// if species k is in a multi-species solution phase, then its
|
||||
// mole number must remain positive, unless the entire phase
|
||||
// goes away. First we'll determine an upper bound on omega,
|
||||
// such that all
|
||||
// if species k is in a multi-species solution phase, then its mole
|
||||
// number must remain positive, unless the entire phase goes away. First
|
||||
// we'll determine an upper bound on omega, such that all
|
||||
if (m_dsoln[k] == 1) {
|
||||
if ((m_moles[k] > MAJOR_THRESHOLD) || (ik < m_nel)) {
|
||||
if (m_moles[k] < MAJOR_THRESHOLD) {
|
||||
|
|
@ -516,9 +505,9 @@ doublereal MultiPhaseEquil::stepComposition(int loglevel)
|
|||
|
||||
// now take a step with this scaled omega
|
||||
step(omegamax, m_work);
|
||||
// compute the gradient of G at this new position in the
|
||||
// current direction. If it is positive, then we have overshot
|
||||
// the minimum. In this case, interpolate back.
|
||||
// compute the gradient of G at this new position in the current direction.
|
||||
// If it is positive, then we have overshot the minimum. In this case,
|
||||
// interpolate back.
|
||||
doublereal not_mu = 1.0e12;
|
||||
m_mix->getValidChemPotentials(not_mu, m_mu.data());
|
||||
doublereal grad1 = 0.0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue