Fix definition of elemental mole fraction

The elemental mole fractions should be invariant under composition changes which
conserve atoms.
This commit is contained in:
Ray Speth 2015-07-15 15:02:26 -04:00
parent 97b32069cf
commit e8292d387e
4 changed files with 42 additions and 16 deletions

View file

@ -541,12 +541,16 @@ public:
//! Elemental mole fraction of element m
/*!
* The elemental mole fraction \f$Z_{\mathrm{mole},m}\f$ of element \f$m\f$
* is defined as
* is the number of atoms of element *m* divided by the total number of
* atoms. It is defined as:
*
* \f[
* Z_{\mathrm{mole},m} = \sum_k \frac{a_{m,k}}{\sum_j a_{j,k}} X_k
* Z_{\mathrm{mole},m} = \frac{\sum_k a_{m,k} X_k}
* {\sum_k \sum_j a_{j,k} X_k}
* \f]
* with \f$a_{m,k}\f$ being the number of atoms of element \f$m\f$ in
* species \f$k\f$and \f$X_k\f$ the mole fraction of species \f$k\f$.
* species \f$k\f$, \f$\sum_j\f$ being a sum over all elements, and
* \f$X_k\f$ being the mole fraction of species \f$k\f$.
*
* @param[in] m Index of the element within the phase. If m is outside the
* valid range, an exception will be thrown.

View file

@ -65,8 +65,8 @@ class TestThermoPhase(utilities.CanteraTest):
mO = self.phase.element_index('O')
self.assertEqual(Zo, self.phase.elemental_mole_fraction(mO))
self.assertNear(Zo, 0.5/3 + 0.5)
self.assertNear(Zh, 0.5*2/3)
self.assertNear(Zo, (0.5 + 1) / (0.5*3 + 0.5*2))
self.assertNear(Zh, (2*0.5) / (0.5*3 + 0.5*2))
self.assertEqual(Zar, 0.0)
with self.assertRaises(ValueError):
@ -74,6 +74,22 @@ class TestThermoPhase(utilities.CanteraTest):
with self.assertRaises(ValueError):
self.phase.elemental_mole_fraction(5)
def test_elemental_mass_mole_fraction(self):
# expected relationship between elmental mass and mole fractions
comps = ['H2O:0.5, O2:0.5', 'H2:0.1, O2:0.4, H2O2:0.3, AR:0.2',
'O2:0.1, H2:0.9']
for comp in comps:
self.phase.X = comp
denom = sum(self.phase.elemental_mole_fraction(i)
* self.phase.atomic_weight(i)
for i in range(self.phase.n_elements))
for i in range(self.phase.n_elements):
self.assertNear(self.phase.elemental_mass_fraction(i),
self.phase.elemental_mole_fraction(i)
* self.phase.atomic_weight(i) / denom)
def test_weights(self):
atomic_weights = self.phase.atomic_weights
molecular_weights = self.phase.molecular_weights

View file

@ -542,13 +542,15 @@ cdef class ThermoPhase(_SolutionBase):
def elemental_mole_fraction(self, m):
r"""
Get the elemental mole fraction :math:`Z_{\mathrm{mole},m}` of element
:math:`m` as defined by:
:math:`m` (the number of atoms of element m divided by the total number
of atoms) as defined by:
.. math:: Z_{\mathrm{mole},m} = \sum_k \frac{a_{m,k}}{\sum_j a_{j,k}} X_k
.. math:: Z_{\mathrm{mole},m} = \frac{\sum_k a_{m,k} X_k}
{\sum_k \sum_j a_{j,k} X_k}
with :math:`a_{m,k}` being the number of atoms of element :math:`m` in
species :math:`k` and :math:`X_k` the mole fraction of species
:math:`k`.
species :math:`k`, :math:`\sum_j` being a sum over all elements, and
:math:`X_k` being the mole fraction of species :math:`k`.
:param m:
Base element, may be specified by name or by index.

View file

@ -643,15 +643,19 @@ doublereal Phase::elementalMassFraction(const size_t m) const
doublereal Phase::elementalMoleFraction(const size_t m) const
{
checkElementIndex(m);
doublereal Z_n = 0.0;
for (size_t k = 0; k != m_kk; ++k) {
double nTotalAtoms = 0;
for (size_t l = 0; l != m_mm; ++l) {
nTotalAtoms += nAtoms(k, l);
double denom = 0;
for (size_t k = 0; k < m_kk; k++) {
double atoms = 0;
for (size_t j = 0; j < nElements(); j++) {
atoms += nAtoms(k, j);
}
Z_n += nAtoms(k, m) / nTotalAtoms * moleFraction(k);
denom += atoms * moleFraction(k);
}
return Z_n;
doublereal numerator = 0.0;
for (size_t k = 0; k != m_kk; ++k) {
numerator += nAtoms(k, m) * moleFraction(k);
}
return numerator / denom;
}
doublereal Phase::molarDensity() const