[Python] Basic implementation of class Quantity

This commit is contained in:
Ray Speth 2015-08-05 14:40:39 -04:00
parent 6e138d0ae4
commit 94f94dd0e6
3 changed files with 174 additions and 0 deletions

View file

@ -1,5 +1,6 @@
from ._cantera import *
from ._cantera import __version__, __sundials_version__
from .composite import *
from .liquidvapor import *
from .onedim import *
from .utils import *

View file

@ -0,0 +1,104 @@
from ._cantera import *
class Quantity(object):
"""
A class representing a specific quantity of a `Solution`.
"""
def __init__(self, phase, mass=None, moles=None, constant='UV'):
self.state = phase.TDY
self._phase = phase
if mass is not None:
self.mass = mass
elif moles is not None:
self.moles = moles
else:
self.mass = 1.0
assert constant in ('TP','TV','HP','SP','SV','UV')
self.constant = constant
@property
def phase(self):
self._phase.TDY = self.state
return self._phase
@property
def moles(self):
return self.mass / self.phase.mean_molecular_weight
@moles.setter
def moles(self, n):
self.mass = n * self.phase.mean_molecular_weight
@property
def volume(self):
return self.mass * self.phase.volume_mass
@property
def int_energy(self):
return self.mass * self.phase.int_energy_mass
@property
def enthalpy(self):
return self.mass * self.phase.enthalpy_mass
@property
def entropy(self):
return self.mass * self.phase.entropy_mass
@property
def gibbs(self):
return self.mass * self.phase.gibbs_mass
def __imul__(self, other):
self.mass *= other
return self
def __mul__(self, other):
return Quantity(self.phase, mass=self.mass * other)
def __rmul__(self, other):
return Quantity(self.phase, mass=self.mass * other)
def __iadd__(self, other):
assert(self.constant == other.constant)
a1,b1 = getattr(self.phase, self.constant)
a2,b2 = getattr(other.phase, self.constant)
m = self.mass + other.mass
a = (a1 * self.mass + a2 * other.mass) / m
b = (b1 * self.mass + b2 * other.mass) / m
self._phase.Y = (self.Y * self.mass + other.Y * other.mass) / m
setattr(self._phase, self.constant, (a,b))
self.state = self._phase.TDY
self.mass = m
return self
def __add__(self, other):
newquantity = Quantity(self.phase, mass=self.mass, constant=self.constant)
newquantity += other
return newquantity
# Synonyms for total properties
Quantity.V = Quantity.volume
Quantity.U = Quantity.int_energy
Quantity.H = Quantity.enthalpy
Quantity.S = Quantity.entropy
Quantity.G = Quantity.gibbs
# Add properties to act as pass-throughs for attributes of class Solution
def _prop(attr):
def getter(self):
return getattr(self.phase, attr)
def setter(self, value):
setattr(self.phase, attr, value)
self.state = self._phase.TDY
return property(getter, setter, doc=getattr(Solution, attr).__doc__)
for _attr in dir(Solution):
if _attr.startswith('_') or _attr in Quantity.__dict__:
continue
else:
setattr(Quantity, _attr, _prop(_attr))

View file

@ -910,3 +910,72 @@ class TestSpeciesThermo(utilities.CanteraTest):
self.assertEqual(st.max_temp, 3500)
self.assertEqual(st.reference_pressure, 101325)
self.assertArrayNear(self.h2o_coeffs, st.coeffs)
class TestQuantity(utilities.CanteraTest):
@classmethod
def setUpClass(cls):
cls.gas = ct.Solution('gri30.xml')
def setUp(self):
self.gas.TPX = 300, 101325, 'O2:1.0, N2:3.76'
def test_mass_moles(self):
q1 = ct.Quantity(self.gas, mass=5)
self.assertNear(q1.mass, 5)
self.assertNear(q1.moles, 5 / q1.mean_molecular_weight)
q1.mass = 7
self.assertNear(q1.moles, 7 / q1.mean_molecular_weight)
q1.moles = 9
self.assertNear(q1.moles, 9)
self.assertNear(q1.mass, 9 * q1.mean_molecular_weight)
def test_extensive(self):
q1 = ct.Quantity(self.gas, mass=5)
self.assertNear(q1.mass, 5)
self.assertNear(q1.volume * q1.density, q1.mass)
self.assertNear(q1.V * q1.density, q1.mass)
self.assertNear(q1.int_energy, q1.moles * q1.int_energy_mole)
self.assertNear(q1.enthalpy, q1.moles * q1.enthalpy_mole)
self.assertNear(q1.entropy, q1.moles * q1.entropy_mole)
self.assertNear(q1.gibbs, q1.moles * q1.gibbs_mole)
self.assertNear(q1.int_energy, q1.U)
self.assertNear(q1.enthalpy, q1.H)
self.assertNear(q1.entropy, q1.S)
self.assertNear(q1.gibbs, q1.G)
def test_multiply(self):
q1 = ct.Quantity(self.gas, mass=5)
q2 = q1 * 2.5
self.assertNear(q1.mass * 2.5, q2.mass)
self.assertNear(q1.moles * 2.5, q2.moles)
self.assertNear(q1.entropy * 2.5, q2.entropy)
self.assertArrayNear(q1.X, q2.X)
def test_iadd(self):
q0 = ct.Quantity(self.gas, mass=5)
q1 = ct.Quantity(self.gas, mass=5)
q2 = ct.Quantity(self.gas, mass=5)
q2.TPX = 500, 101325, 'CH4:1.0'
q1 += q2
self.assertNear(q0.mass + q2.mass, q1.mass)
# addition is at constant UV
self.assertNear(q0.U + q2.U, q1.U)
self.assertNear(q0.V + q2.V, q1.V)
self.assertArrayNear(q0.X*q0.moles + q2.X*q2.moles, q1.X*q1.moles)
def test_add(self):
q1 = ct.Quantity(self.gas, mass=5)
q2 = ct.Quantity(self.gas, mass=5)
q2.TPX = 500, 101325, 'CH4:1.0'
q3 = q1 + q2
self.assertNear(q1.mass + q2.mass, q3.mass)
# addition is at constant UV
self.assertNear(q1.U + q2.U, q3.U)
self.assertNear(q1.V + q2.V, q3.V)
self.assertArrayNear(q1.X*q1.moles + q2.X*q2.moles, q3.X*q3.moles)