823 lines
31 KiB
C++
Executable file
823 lines
31 KiB
C++
Executable file
/**
|
|
* @file StoichManager.h
|
|
*
|
|
* $Author$
|
|
* $Revision$
|
|
* $Date$
|
|
*/
|
|
|
|
// Copyright 2001 California Institute of Technology
|
|
|
|
|
|
#ifndef CT_STOICH_MGR_H
|
|
#define CT_STOICH_MGR_H
|
|
|
|
#include "stringUtils.h"
|
|
|
|
namespace Cantera {
|
|
|
|
/**
|
|
* @defgroup Stoichiometry Stoichiometry
|
|
*
|
|
* Note: these classes are designed for internal use in class
|
|
* ReactionStoichManager.
|
|
*
|
|
* The classes defined here implement simple operations that are
|
|
* used by class ReactionStoichManager to compute things like
|
|
* rates of progress, species production rates, etc. In general, a
|
|
* reaction mechanism may involve many species and many reactions,
|
|
* but any given reaction typically only involves a few species as
|
|
* reactants, and a few as products. Therefore, the matrix of
|
|
* stoichiometric coefficients is very sparse. Not only is it
|
|
* sparse, but the non-zero matrix elements often have the value
|
|
* 1, and in many cases no more than three coefficients are
|
|
* non-zero for the reactants and/or the products.
|
|
*
|
|
|
|
* For the present purposes, we will consider each direction of a
|
|
* reversible reaction to be a separate reaction. We often need to
|
|
* compute quantities that can formally be written as a matrix
|
|
* product of a stoichiometric coefficient matrix and a vector of
|
|
* reaction rates. For example, the species creation rates are
|
|
* given by
|
|
* \f[
|
|
* \dot C_k = \sum_k \nu^{(p)}_{k,i} R_i
|
|
* \f]
|
|
* where \f$ \nu^{(p)_{k,i}}$ is the product-side stoichiometric
|
|
* coefficient of species \a k in reaction \a i.
|
|
* This could be done be straightforward matrix multiplication, but would be inefficient, since most of the matrix elements of \f$ \nu^{(p)}_{k,i} \f$ are zero. We could do better by using sparse-matrix algorithms to compute this product.
|
|
|
|
If the reactions are general ones, with non-integral stoichiometric
|
|
coefficients, this is about as good as we can do. But we are
|
|
particularly concerned here with the performance for very large
|
|
reaction mechanisms, which are usually composed of elementary
|
|
reactions, which have integral stoichiometric
|
|
coefficients. Furthermore, very few elementary reactions involve more
|
|
than 3 product or reactant molecules. This means that instead of
|
|
|
|
|
|
But we can do even better if we take account of the special structure
|
|
of this matrix for elementary reactions.
|
|
|
|
involve three or fewer product molecules (or reactant molecules).
|
|
|
|
* To take advantage of this structure, reactions are divided int
|
|
These classes are
|
|
* designed to take advantage of this sparse structure when
|
|
* computing quantities that can be written as matrix multiplies
|
|
|
|
They are designed to explicitly unroll loops over species or reactions for
|
|
|
|
* Operations on reactions that require knowing the reaction
|
|
* stoichiometry.
|
|
* This module consists of class StoichManager, and
|
|
* classes C1, C2, and C3. Classes C1, C2, and C3 handle operations
|
|
* involving one, two, or three species, respectively, in a
|
|
* reaction. Instances are instantiated with a reaction number, and n
|
|
* species numbers (n = 1 for C1, etc.). All three classes have the
|
|
* same interface.
|
|
*
|
|
* These classes are designed for use by StoichManager, and the
|
|
* operations implemented are those needed to efficiently compute
|
|
* quantities such as rates of progress, species production rates,
|
|
* reaction thermochemistry, etc. The compiler will inline these
|
|
* methods into the body of the corresponding StoichManager method,
|
|
* and so there is no performance penalty (unless inlining is turned
|
|
* off).
|
|
*
|
|
* To describe the methods, consider class C3 and suppose an instance
|
|
* is created with reaction number irxn and species numbers k0, k1,
|
|
* and k2.
|
|
*
|
|
* - multiply(in, out) : out[irxn] is multiplied by
|
|
* in[k0] * in[k1] * in[k2]
|
|
*
|
|
* - power(in, out) : out[irxn] is multiplied by
|
|
* (in[k0]^order0) * (in[k1]^order1) * (in[k2]^order2)
|
|
*
|
|
* - incrementReaction(in, out) : out[irxn] is incremented by
|
|
* in[k0] + in[k1] + in[k2]
|
|
*
|
|
* - decrementReaction(in, out) : out[irxn] is decremented by
|
|
* in[k0] + in[k1] + in[k2]
|
|
*
|
|
* - incrementSpecies(in, out) : out[k0], out[k1], and out[k2]
|
|
* are all incremented by in[irxn]
|
|
*
|
|
* - decrementSpecies(in, out) : out[k0], out[k1], and out[k2]
|
|
* are all decremented by in[irxn]
|
|
*
|
|
* The function multiply() is usually used when evaluating the
|
|
* forward and reverse rates of progress of reactions.
|
|
* The rate constants are usually loaded into out[]. Then
|
|
* multply() is called to add in the dependence of the
|
|
* species concentrations to yield a forward and reverse rop.
|
|
*
|
|
* The function incrementSpecies() and its cousin decrementSpecies()
|
|
* is used to translate from rates of progress to species production
|
|
* rates. The vector in[] is preloaed with the rates of progess of
|
|
* all reactions. Then incrementSpecies() is called to
|
|
* increment the species production vector, out[], with the rates
|
|
* of progress.
|
|
*
|
|
* The functions incrementReaction() and decrementReaction() are
|
|
* used to find the standard state equilibrium constant for
|
|
* a reaction. Here, output[] is a vector of length
|
|
* number of reactions, usually the standard gibbs free energies
|
|
* of reaction, while input, usually the standard state
|
|
* gibbs free energies of species, is a vector of length number of
|
|
* species.
|
|
*
|
|
* Note the stoichiometric coefficient for a species in a reaction
|
|
* is handled by always assuming it is equal to one and then
|
|
* treating reactants and products for a reaction separately.
|
|
* Bimolecular reactions involving the identical species are
|
|
* treated as involving separate species.
|
|
*
|
|
* @internal This class should be upgraded to include cases where
|
|
* real stoichiometric coefficients are used. Shouldn't be that
|
|
* hard to do, and they occur in engineering simulations with some
|
|
* regularity.
|
|
*
|
|
*/
|
|
|
|
static doublereal ppow(doublereal x, doublereal order) {
|
|
if (x > 0.0)
|
|
return pow(x, order);
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
inline static string fmt(string r, int n) { return r + "[" + int2str(n) + "]"; }
|
|
|
|
|
|
/**
|
|
* Handles one species in a reaction.
|
|
* @ingroup Stoichiometry
|
|
* @internal
|
|
*/
|
|
class C1 {
|
|
|
|
public:
|
|
|
|
C1( int rxn = 0, int ic0 = 0)
|
|
: m_rxn (rxn), m_ic0 (ic0) {}
|
|
|
|
int data(vector<int>& ic) {
|
|
ic.resize(1);
|
|
ic[0] = m_ic0;
|
|
return m_rxn;
|
|
}
|
|
|
|
void incrementSpecies(const doublereal* R, doublereal* S) const {
|
|
S[m_ic0] += R[m_rxn];
|
|
}
|
|
|
|
void decrementSpecies(const doublereal* R, doublereal* S) const {
|
|
S[m_ic0] -= R[m_rxn];
|
|
}
|
|
|
|
void multiply(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] *= S[m_ic0];
|
|
}
|
|
|
|
void incrementReaction(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] += S[m_ic0];
|
|
}
|
|
|
|
void decrementReaction(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] -= S[m_ic0];
|
|
}
|
|
|
|
int rxnNumber() const { return m_rxn; }
|
|
int speciesIndex(int n) const { return m_ic0; }
|
|
int nSpecies() { return 1;}
|
|
|
|
void writeMultiply(string r, map<int, string>& out) {
|
|
out[m_rxn] = fmt(r, m_ic0);
|
|
}
|
|
|
|
void writeIncrementReaction(string r, map<int, string>& out) {
|
|
out[m_rxn] += " + "+fmt(r, m_ic0);
|
|
}
|
|
void writeDecrementReaction(string r, map<int, string>& out) {
|
|
out[m_rxn] += " - "+fmt(r, m_ic0);
|
|
}
|
|
|
|
void writeIncrementSpecies(string r, map<int, string>& out) {
|
|
out[m_ic0] += " + "+fmt(r, m_rxn);
|
|
}
|
|
void writeDecrementSpecies(string r, map<int, string>& out) {
|
|
out[m_ic0] += " - "+fmt(r, m_rxn);
|
|
}
|
|
|
|
private:
|
|
int m_rxn, m_ic0;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Handles two species in a single reaction.
|
|
* @ingroup Stoichiometry
|
|
*/
|
|
class C2 {
|
|
public:
|
|
C2( int rxn = 0, int ic0 = 0, int ic1 = 0)
|
|
: m_rxn (rxn), m_ic0 (ic0), m_ic1 (ic1) {}
|
|
|
|
int data(vector<int>& ic) {
|
|
ic.resize(2);
|
|
ic[0] = m_ic0;
|
|
ic[1] = m_ic1;
|
|
return m_rxn;
|
|
}
|
|
|
|
void incrementSpecies(const doublereal* R, doublereal* S) const {
|
|
S[m_ic0] += R[m_rxn];
|
|
S[m_ic1] += R[m_rxn];
|
|
}
|
|
|
|
void decrementSpecies(const doublereal* R, doublereal* S) const {
|
|
S[m_ic0] -= R[m_rxn];
|
|
S[m_ic1] -= R[m_rxn];
|
|
}
|
|
|
|
void multiply(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] *= S[m_ic0] * S[m_ic1];
|
|
}
|
|
|
|
void incrementReaction(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] += S[m_ic0] + S[m_ic1];
|
|
}
|
|
|
|
void decrementReaction(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] -= (S[m_ic0] + S[m_ic1]);
|
|
}
|
|
|
|
int rxnNumber() const { return m_rxn; }
|
|
int speciesIndex(int n) const { return (n == 0 ? m_ic0 : m_ic1); }
|
|
int nSpecies() { return 2;}
|
|
|
|
void writeMultiply(string r, map<int, string>& out) {
|
|
out[m_rxn] = fmt(r, m_ic0) + " * " + fmt(r, m_ic1);
|
|
}
|
|
void writeIncrementReaction(string r, map<int, string>& out) {
|
|
out[m_rxn] += " + "+fmt(r, m_ic0)+" + "+fmt(r, m_ic1);
|
|
}
|
|
void writeDecrementReaction(string r, map<int, string>& out) {
|
|
out[m_rxn] += " - "+fmt(r, m_ic0)+" - "+fmt(r, m_ic1);
|
|
}
|
|
|
|
void writeIncrementSpecies(string r, map<int, string>& out) {
|
|
string s = " + "+fmt(r, m_rxn);
|
|
out[m_ic0] += s;
|
|
out[m_ic1] += s;
|
|
}
|
|
void writeDecrementSpecies(string r, map<int, string>& out) {
|
|
string s = " - "+fmt(r, m_rxn);
|
|
out[m_ic0] += s;
|
|
out[m_ic1] += s;
|
|
}
|
|
|
|
private:
|
|
|
|
/**
|
|
* Reaction index -> index into the ROP vector
|
|
*/
|
|
int m_rxn;
|
|
|
|
/**
|
|
* Species indecise -> index into the species vector for the
|
|
* two species.
|
|
*/
|
|
int m_ic0, m_ic1;
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles three species in a reaction.
|
|
* @ingroup Stoichiometry
|
|
*/
|
|
class C3 {
|
|
public:
|
|
C3( int rxn = 0, int ic0 = 0, int ic1 = 0, int ic2 = 0)
|
|
: m_rxn (rxn), m_ic0 (ic0), m_ic1 (ic1), m_ic2 (ic2) {}
|
|
|
|
int data(vector<int>& ic) {
|
|
ic.resize(3);
|
|
ic[0] = m_ic0;
|
|
ic[1] = m_ic1;
|
|
ic[2] = m_ic2;
|
|
return m_rxn;
|
|
}
|
|
|
|
void incrementSpecies(const doublereal* R, doublereal* S) const {
|
|
S[m_ic0] += R[m_rxn];
|
|
S[m_ic1] += R[m_rxn];
|
|
S[m_ic2] += R[m_rxn];
|
|
}
|
|
|
|
void decrementSpecies(const doublereal* R, doublereal* S) const {
|
|
S[m_ic0] -= R[m_rxn];
|
|
S[m_ic1] -= R[m_rxn];
|
|
S[m_ic2] -= R[m_rxn];
|
|
}
|
|
|
|
void multiply(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] *= S[m_ic0] * S[m_ic1] * S[m_ic2];
|
|
}
|
|
|
|
void incrementReaction(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] += S[m_ic0] + S[m_ic1] + S[m_ic2];
|
|
}
|
|
|
|
void decrementReaction(const doublereal* S, doublereal* R) const {
|
|
R[m_rxn] -= (S[m_ic0] + S[m_ic1] + S[m_ic2]);
|
|
}
|
|
|
|
int rxnNumber() const { return m_rxn; }
|
|
int speciesIndex(int n) const { return (n == 0 ? m_ic0 : (n == 1 ? m_ic1 : m_ic2)); }
|
|
int nSpecies() { return 3;}
|
|
|
|
void writeMultiply(string r, map<int, string>& out) {
|
|
out[m_rxn] = fmt(r, m_ic0) + " * " + fmt(r, m_ic1) + " * " + fmt(r, m_ic2);
|
|
}
|
|
void writeIncrementReaction(string r, map<int, string>& out) {
|
|
out[m_rxn] += " + "+fmt(r, m_ic0)+" + "+fmt(r, m_ic1)+" + "+fmt(r, m_ic2);
|
|
}
|
|
void writeDecrementReaction(string r, map<int, string>& out) {
|
|
out[m_rxn] += " - "+fmt(r, m_ic0)+" - "+fmt(r, m_ic1)+" - "+fmt(r, m_ic2);
|
|
}
|
|
void writeIncrementSpecies(string r, map<int, string>& out) {
|
|
string s = " + "+fmt(r, m_rxn);
|
|
out[m_ic0] += s;
|
|
out[m_ic1] += s;
|
|
out[m_ic2] += s;
|
|
}
|
|
void writeDecrementSpecies(string r, map<int, string>& out) {
|
|
string s = " - "+fmt(r, m_rxn);
|
|
out[m_ic0] += s;
|
|
out[m_ic1] += s;
|
|
out[m_ic2] += s;
|
|
}
|
|
private:
|
|
int m_rxn, m_ic0, m_ic1, m_ic2;
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles any number of species in a reaction, including fractional
|
|
* stoichiometric coefficients, and arbitrary reaction orders.
|
|
* @ingroup Stoichiometry
|
|
*/
|
|
class C_AnyN {
|
|
public:
|
|
C_AnyN() : m_rxn (-1) {}
|
|
|
|
C_AnyN( int rxn, const vector_int& ic, const vector_fp& order,
|
|
const vector_fp& stoich)
|
|
: m_rxn (rxn) {
|
|
m_n = ic.size();
|
|
m_ic.resize(m_n);
|
|
m_order.resize(m_n);
|
|
m_stoich.resize(m_n);
|
|
for (int n = 0; n < m_n; n++) {
|
|
m_ic[n] = ic[n];
|
|
m_order[n] = order[n];
|
|
m_stoich[n] = stoich[n];
|
|
}
|
|
}
|
|
|
|
int data(vector<int>& ic) {
|
|
ic.resize(m_n);
|
|
int n;
|
|
for (n = 0; n < m_n; n++) ic[n] = m_ic[n];
|
|
return m_rxn;
|
|
}
|
|
|
|
doublereal order(int n) const {return m_order[n];}
|
|
doublereal stoich(int n) const {return m_stoich[n];}
|
|
int speciesIndex(int n) const {return m_ic[n];}
|
|
|
|
void multiply(const doublereal* input, doublereal* output) const {
|
|
for (int n = 0; n < m_n; n++) output[m_rxn] *=
|
|
ppow(input[m_ic[n]],m_order[n]);
|
|
}
|
|
|
|
void incrementSpecies(const doublereal* input,
|
|
doublereal* output) const {
|
|
doublereal x = input[m_rxn];
|
|
for (int n = 0; n < m_n; n++) output[m_ic[n]] += m_stoich[n]*x;
|
|
}
|
|
|
|
void decrementSpecies(const doublereal* input,
|
|
doublereal* output) const {
|
|
doublereal x = input[m_rxn];
|
|
for (int n = 0; n < m_n; n++) output[m_ic[n]] -= m_stoich[n]*x;
|
|
}
|
|
|
|
void incrementReaction(const doublereal* input,
|
|
doublereal* output) const {
|
|
for (int n = 0; n < m_n; n++) output[m_rxn]
|
|
+= m_stoich[n]*input[m_ic[n]];
|
|
}
|
|
|
|
void decrementReaction(const doublereal* input,
|
|
doublereal* output) const {
|
|
for (int n = 0; n < m_n; n++) output[m_rxn]
|
|
-= m_stoich[n]*input[m_ic[n]];
|
|
}
|
|
|
|
void writeMultiply(string r, map<int, string>& out) {
|
|
int n;
|
|
out[m_rxn] = "";
|
|
for (n = 0; n < m_n; n++) {
|
|
if (m_order[n] == 1.0)
|
|
out[m_rxn] += fmt(r, m_ic[n]);
|
|
else
|
|
out[m_rxn] += "pow("+fmt(r, m_ic[n])+","+fp2str(m_order[n])+")";
|
|
if (n < m_n-1)
|
|
out[m_rxn] += " * ";
|
|
}
|
|
}
|
|
void writeIncrementReaction(string r, map<int, string>& out) {
|
|
int n;
|
|
for (n = 0; n < m_n; n++) {
|
|
out[m_rxn] += " + "+fp2str(m_stoich[n]) + "*" + fmt(r, m_ic[n]);
|
|
}
|
|
}
|
|
void writeDecrementReaction(string r, map<int, string>& out) {
|
|
int n;
|
|
for (n = 0; n < m_n; n++) {
|
|
out[m_rxn] += " - "+fp2str(m_stoich[n]) + "*" + fmt(r, m_ic[n]);
|
|
}
|
|
}
|
|
void writeIncrementSpecies(string r, map<int, string>& out) {
|
|
string s = fmt(r, m_rxn);
|
|
int n;
|
|
for (n = 0; n < m_n; n++) {
|
|
out[m_ic[n]] += " + "+fp2str(m_stoich[n]) + "*" + s;
|
|
}
|
|
}
|
|
|
|
void writeDecrementSpecies(string r, map<int, string>& out) {
|
|
string s = fmt(r, m_rxn);
|
|
int n;
|
|
for (n = 0; n < m_n; n++) {
|
|
out[m_ic[n]] += " - "+fp2str(m_stoich[n]) + "*" + s;
|
|
}
|
|
}
|
|
|
|
private:
|
|
int m_n, m_rxn;
|
|
vector_int m_ic;
|
|
vector_fp m_order;
|
|
vector_fp m_stoich;
|
|
};
|
|
|
|
|
|
template<class InputIter, class Vec1, class Vec2>
|
|
inline static void _multiply(InputIter begin, InputIter end,
|
|
const Vec1& input, Vec2& output) {
|
|
for (; begin != end; ++begin)
|
|
begin->multiply(input, output);
|
|
}
|
|
|
|
template<class InputIter, class Vec1, class Vec2>
|
|
inline static void _incrementSpecies(InputIter begin,
|
|
InputIter end, const Vec1& input, Vec2& output) {
|
|
for (; begin != end; ++begin)
|
|
begin->incrementSpecies(input, output);
|
|
}
|
|
|
|
template<class InputIter, class Vec1, class Vec2>
|
|
inline static void _decrementSpecies(InputIter begin,
|
|
InputIter end, const Vec1& input, Vec2& output) {
|
|
for (; begin != end; ++begin)
|
|
begin->decrementSpecies(input, output);
|
|
}
|
|
|
|
template<class InputIter, class Vec1, class Vec2>
|
|
inline static void _incrementReactions(InputIter begin,
|
|
InputIter end, const Vec1& input, Vec2& output) {
|
|
for (; begin != end; ++begin)
|
|
begin->incrementReaction(input, output);
|
|
}
|
|
|
|
template<class InputIter, class Vec1, class Vec2>
|
|
inline static void _decrementReactions(InputIter begin,
|
|
InputIter end, const Vec1& input, Vec2& output) {
|
|
for (; begin != end; ++begin)
|
|
begin->decrementReaction(input, output);
|
|
}
|
|
|
|
|
|
template<class InputIter>
|
|
inline static void _writeIncrementSpecies(InputIter begin, InputIter end, string r,
|
|
map<int, string>& out) {
|
|
for (; begin != end; ++begin) begin->writeIncrementSpecies(r, out);
|
|
}
|
|
|
|
template<class InputIter>
|
|
inline static void _writeDecrementSpecies(InputIter begin, InputIter end, string r,
|
|
map<int, string>& out) {
|
|
for (; begin != end; ++begin) begin->writeDecrementSpecies(r, out);
|
|
}
|
|
|
|
template<class InputIter>
|
|
inline static void _writeIncrementReaction(InputIter begin, InputIter end, string r,
|
|
map<int, string>& out) {
|
|
for (; begin != end; ++begin) begin->writeIncrementReaction(r, out);
|
|
}
|
|
|
|
template<class InputIter>
|
|
inline static void _writeDecrementReaction(InputIter begin, InputIter end, string r,
|
|
map<int, string>& out) {
|
|
for (; begin != end; ++begin) begin->writeDecrementReaction(r, out);
|
|
}
|
|
|
|
template<class InputIter>
|
|
inline static void _writeMultiply(InputIter begin, InputIter end, string r,
|
|
map<int, string>& out) {
|
|
for (; begin != end; ++begin) begin->writeMultiply(r, out);
|
|
}
|
|
|
|
/*
|
|
* This class handles operations involving the stoichiometric
|
|
* coefficients on one side of a reaction (reactant or product) for
|
|
* a set of reactions comprising a reaction mechanism. This class is
|
|
* used by class ReactionStoichMgr, which contains three instances
|
|
* of this class (one to handle operations on the reactions, one for
|
|
* the products of reversible reactions, and one for the products of
|
|
* irreversible reactions).
|
|
*
|
|
* This class is designed for use with elementary reactions, or at
|
|
* least ones with integral stoichiometric coefficients. Let \f$ M(i) \f$
|
|
* be the number of molecules on the product or reactant side of
|
|
* reaction number i.
|
|
* \f[
|
|
* r_i = \sum_m^{M_i} s_{k_{m,i}}
|
|
* \f]
|
|
* To understand the operations performed by this class, let
|
|
* \f$ N_{k,i}\f$ denote the stoichiometric coefficient of species k on
|
|
* one side (reactant or product) in reaction i. Then \b N is a sparse
|
|
* K by I matrix of stoichiometric coefficients.
|
|
*
|
|
* The following matrix operations may be carried out with a vector
|
|
* S of length K, and a vector R of length I:
|
|
*
|
|
* - \f$ S = S + N R\f$ (incrementSpecies)
|
|
* - \f$ S = S - N R\f$ (decrementSpecies)
|
|
* - \f$ R = R + N^T S \f$ (incrementReaction)
|
|
* - \f$ R = R - N^T S \f$ (deccrementReaction)
|
|
*
|
|
* The actual implementation, however, does not compute these
|
|
* quantities by matrix multiplication. A faster algorithm is used
|
|
* that makes use of the fact that the \b integer-valued N matrix is
|
|
* very sparse, and the non-zero terms are small positive integers.
|
|
* \f[
|
|
* S_k = R_{i1} + \dots + R_{iM}
|
|
* \f]
|
|
* where M is the number of molecules, and $\f i(m) \f$ is the
|
|
* @ingroup Stoichiometry
|
|
*/
|
|
class StoichManagerN {
|
|
public:
|
|
|
|
/**
|
|
* Constructor for the StoichManagerN class.
|
|
*
|
|
* @internal Consider adding defaulted entries here that supply
|
|
* the total number of reactions in the mechanism and the total
|
|
* number of species in the species list. Then, we could use those
|
|
* numbers to provide error checks during the construction of the
|
|
* object. Those numbers would also provide some clarity to the
|
|
* purpose and utility of this class.
|
|
*
|
|
* DGG - the problem is that the number of reactions and species
|
|
* are not known initially.
|
|
*/
|
|
StoichManagerN() {}
|
|
|
|
/**
|
|
* Add a single reaction to the list of reactions that this
|
|
* stoichiometric manager object handles.
|
|
*
|
|
* This function is the same as the add() function below. However,
|
|
* the order of each species in the power list expression is
|
|
* set to one automatically.
|
|
*/
|
|
void add(int rxn, const vector_int& k) {
|
|
vector_fp order(k.size(), 1.0);
|
|
vector_fp stoich(k.size(), 1.0);
|
|
add(rxn, k, order, stoich);
|
|
}
|
|
|
|
void add(int rxn, const vector_int& k, const vector_fp& order) {
|
|
vector_fp stoich(k.size(), 1.0);
|
|
add(rxn, k, order, stoich);
|
|
}
|
|
|
|
/**
|
|
* Add a single reaction to the list of reactions that this
|
|
* stoichiometric manager object handles.
|
|
*
|
|
* @param rxn Reaction index of the current reaction. This is used
|
|
* as an index into vectors which have length n_total_rxn.
|
|
* @param k This is a vector of integer values specifying the
|
|
* species indecises. The length of this vector species
|
|
* the number of different species in the description.
|
|
* The value of the entries are the species indices.
|
|
* These are used as indexes into vectors which have
|
|
* length n_total_species.
|
|
* @param order This is a vector of the same length as vector k.
|
|
* The order is used for the routine power(), which produces
|
|
* a power law expression involving the species vector.
|
|
* @param stoich This is used to handle fractional stoichiometric coefficients
|
|
* on the product side of irreversible reactions.
|
|
*/
|
|
void add(int rxn, const vector_int& k, const vector_fp& order,
|
|
const vector_fp& stoich) {
|
|
m_n[rxn] = static_cast<int>(k.size());
|
|
int ns = stoich.size();
|
|
int n;
|
|
bool frac = false;
|
|
for (n = 0; n < ns; n++) {
|
|
if (stoich[n] != 1.0) frac = true;
|
|
}
|
|
if (frac) {
|
|
m_loc[rxn] = static_cast<int>(m_cn_list.size());
|
|
m_cn_list.push_back(C_AnyN(rxn, k, order, stoich));
|
|
}
|
|
else {
|
|
switch (k.size()) {
|
|
case 1:
|
|
m_loc[rxn] = static_cast<int>(m_c1_list.size());
|
|
m_c1_list.push_back(C1(rxn, k[0]));
|
|
break;
|
|
case 2:
|
|
m_loc[rxn] = static_cast<int>(m_c2_list.size());
|
|
m_c2_list.push_back(C2(rxn, k[0], k[1]));
|
|
break;
|
|
case 3:
|
|
m_loc[rxn] = static_cast<int>(m_c3_list.size());
|
|
m_c3_list.push_back(C3(rxn, k[0], k[1], k[2]));
|
|
break;
|
|
default:
|
|
m_loc[rxn] = static_cast<int>(m_cn_list.size());
|
|
m_cn_list.push_back(C_AnyN(rxn, k, order, stoich));
|
|
}
|
|
}
|
|
}
|
|
|
|
void multiply(const doublereal* input, doublereal* output) const {
|
|
_multiply(m_c1_list.begin(), m_c1_list.end(), input, output);
|
|
_multiply(m_c2_list.begin(), m_c2_list.end(), input, output);
|
|
_multiply(m_c3_list.begin(), m_c3_list.end(), input, output);
|
|
_multiply(m_cn_list.begin(), m_cn_list.end(), input, output);
|
|
}
|
|
|
|
void incrementSpecies(const doublereal* input, doublereal* output) const {
|
|
_incrementSpecies(m_c1_list.begin(), m_c1_list.end(), input, output);
|
|
_incrementSpecies(m_c2_list.begin(), m_c2_list.end(), input, output);
|
|
_incrementSpecies(m_c3_list.begin(), m_c3_list.end(), input, output);
|
|
_incrementSpecies(m_cn_list.begin(), m_cn_list.end(), input, output);
|
|
}
|
|
|
|
void decrementSpecies(const doublereal* input, doublereal* output) const {
|
|
_decrementSpecies(m_c1_list.begin(), m_c1_list.end(), input, output);
|
|
_decrementSpecies(m_c2_list.begin(), m_c2_list.end(), input, output);
|
|
_decrementSpecies(m_c3_list.begin(), m_c3_list.end(), input, output);
|
|
_decrementSpecies(m_cn_list.begin(), m_cn_list.end(), input, output);
|
|
}
|
|
|
|
void incrementReactions(const doublereal* input, doublereal* output) const {
|
|
_incrementReactions(m_c1_list.begin(), m_c1_list.end(), input, output);
|
|
_incrementReactions(m_c2_list.begin(), m_c2_list.end(), input, output);
|
|
_incrementReactions(m_c3_list.begin(), m_c3_list.end(), input, output);
|
|
_incrementReactions(m_cn_list.begin(), m_cn_list.end(), input, output);
|
|
}
|
|
|
|
void decrementReactions(const doublereal* input, doublereal* output) const {
|
|
_decrementReactions(m_c1_list.begin(), m_c1_list.end(), input, output);
|
|
_decrementReactions(m_c2_list.begin(), m_c2_list.end(), input, output);
|
|
_decrementReactions(m_c3_list.begin(), m_c3_list.end(), input, output);
|
|
_decrementReactions(m_cn_list.begin(), m_cn_list.end(), input, output);
|
|
}
|
|
|
|
void writeIncrementSpecies(string r, map<int, string>& out) {
|
|
_writeIncrementSpecies(m_c1_list.begin(), m_c1_list.end(), r, out);
|
|
_writeIncrementSpecies(m_c2_list.begin(), m_c2_list.end(), r, out);
|
|
_writeIncrementSpecies(m_c3_list.begin(), m_c3_list.end(), r, out);
|
|
_writeIncrementSpecies(m_cn_list.begin(), m_cn_list.end(), r, out);
|
|
}
|
|
|
|
void writeDecrementSpecies(string r, map<int, string>& out) {
|
|
_writeDecrementSpecies(m_c1_list.begin(), m_c1_list.end(), r, out);
|
|
_writeDecrementSpecies(m_c2_list.begin(), m_c2_list.end(), r, out);
|
|
_writeDecrementSpecies(m_c3_list.begin(), m_c3_list.end(), r, out);
|
|
_writeDecrementSpecies(m_cn_list.begin(), m_cn_list.end(), r, out);
|
|
}
|
|
|
|
void writeIncrementReaction(string r, map<int, string>& out) {
|
|
_writeIncrementReaction(m_c1_list.begin(), m_c1_list.end(), r, out);
|
|
_writeIncrementReaction(m_c2_list.begin(), m_c2_list.end(), r, out);
|
|
_writeIncrementReaction(m_c3_list.begin(), m_c3_list.end(), r, out);
|
|
_writeIncrementReaction(m_cn_list.begin(), m_cn_list.end(), r, out);
|
|
}
|
|
|
|
void writeDecrementReaction(string r, map<int, string>& out) {
|
|
_writeDecrementReaction(m_c1_list.begin(), m_c1_list.end(), r, out);
|
|
_writeDecrementReaction(m_c2_list.begin(), m_c2_list.end(), r, out);
|
|
_writeDecrementReaction(m_c3_list.begin(), m_c3_list.end(), r, out);
|
|
_writeDecrementReaction(m_cn_list.begin(), m_cn_list.end(), r, out);
|
|
}
|
|
|
|
void writeMultiply(string r, map<int, string>& out) {
|
|
_writeMultiply(m_c1_list.begin(), m_c1_list.end(), r, out);
|
|
_writeMultiply(m_c2_list.begin(), m_c2_list.end(), r, out);
|
|
_writeMultiply(m_c3_list.begin(), m_c3_list.end(), r, out);
|
|
_writeMultiply(m_cn_list.begin(), m_cn_list.end(), r, out);
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
vector<C1> m_c1_list;
|
|
vector<C2> m_c2_list;
|
|
vector<C3> m_c3_list;
|
|
vector<C_AnyN> m_cn_list;
|
|
/**
|
|
* Mapping with the Reaction Number as key and the Number of species
|
|
* as the value.
|
|
*/
|
|
map<int, int> m_n;
|
|
/**
|
|
* Mapping with the Reaction Number as key and the placement in the
|
|
* vector of reactions list( i.e., m_c1_list[]) as key
|
|
*/
|
|
map<int, int> m_loc;
|
|
};
|
|
|
|
#undef INCL_STOICH_WRITER
|
|
#ifdef INCL_STOICH_WRITER
|
|
|
|
class StoichWriter {
|
|
public:
|
|
|
|
StoichWriter() {}
|
|
|
|
void add(int rxn, const vector_int& k) {
|
|
int n, nn = k.size();
|
|
for (n = 0; n < nn; n++) {
|
|
if (m_mult[rxn] != "") m_mult[rxn] += " * ";
|
|
m_mult[rxn] += "c[" + int2str(k[n]) + "]";
|
|
m_is[k[n]] += " + rop[" + int2str(rxn) + "]";
|
|
m_ds[k[n]] += " - rop[" + int2str(rxn) + "]";
|
|
m_ir[rxn] += " + grt[" + int2str(k[n]) + "]";
|
|
m_dr[rxn] += " - grt[" + int2str(k[n]) + "]";
|
|
}
|
|
}
|
|
|
|
void add(int rxn, const vector_int& k, const vector_fp& order,
|
|
const vector_fp& stoich) {
|
|
int n, nn = k.size();
|
|
string s;
|
|
for (n = 0; n < nn; n++) {
|
|
if (order[n] == 1.0)
|
|
m_mult[rxn] += "*c[" + int2str(k[n]) + "]";
|
|
else
|
|
m_mult[rxn] += "*pow(c[" _ int2str(k[n]) + "],"+fp2str(order[n])+")";
|
|
if (stoich[n] == 1.0) {
|
|
m_is[k[n]] += " + r[" + int2str(rxn) + "]";
|
|
m_ds[k[n]] += " - r[" + int2str(rxn) + "]";
|
|
m_ir[rxn] += " + g[" + int2str(k[n]) + "]";
|
|
m_dr[rxn] += " - g[" + int2str(k[n]) + "]";
|
|
}
|
|
else {
|
|
s = fp2str(stoich[n]);
|
|
m_is[k[n]] += " + "+s+"*r[" + int2str(rxn) + "]";
|
|
m_ds[k[n]] += " - "+s+"*r[" + int2str(rxn) + "]";
|
|
m_ir[rxn] += " + "+s+"*g[" + int2str(k[n]) + "]";
|
|
m_dr[rxn] += " - "+s+"*g[" + int2str(k[n]) + "]";
|
|
}
|
|
}
|
|
}
|
|
|
|
string mult(int rxn) { return m_mult[rxn]; }
|
|
string incrSpec(int k, string) { return m_is[k]; }
|
|
string decrSpec(int k) { return m_ds[k]; }
|
|
string incrRxn(int rxn) { return m_ir[rxn]; }
|
|
string decrRxn(int rxn) { return m_dr[rxn]; }
|
|
|
|
private:
|
|
map<int, string> m_mult, m_ir, m_dr, m_is, m_ds;
|
|
};
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|