mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
325 lines
11 KiB
Python
325 lines
11 KiB
Python
import numpy as np
|
|
import pytest
|
|
from pytest import approx
|
|
|
|
import cantera as ct
|
|
from . import utilities
|
|
|
|
from cantera._utils import _py_to_any_to_py, _py_to_anymap_to_py
|
|
|
|
|
|
class TestUnitSystem(utilities.CanteraTest):
|
|
|
|
def test_default(self):
|
|
units = ct.UnitSystem().units
|
|
checks = {
|
|
"activation-energy": "J / kmol",
|
|
"current": "A",
|
|
"energy": "J",
|
|
"length": "m",
|
|
"mass": "kg",
|
|
"pressure": "Pa",
|
|
"quantity": "kmol",
|
|
"temperature": "K",
|
|
"time": "s",
|
|
}
|
|
for dim, unit in units.items():
|
|
self.assertIn(dim, checks)
|
|
self.assertEqual(checks[dim], unit)
|
|
|
|
def test_cgs(self):
|
|
system = ct.UnitSystem({
|
|
"length": "cm", "mass": "g", "time": "s",
|
|
"quantity": "mol", "pressure": "dyn / cm^2", "energy": "erg",
|
|
"activation-energy": "cal / mol"})
|
|
units = system.units
|
|
checks = {
|
|
"activation-energy": "cal / mol",
|
|
"current": "A",
|
|
"energy": "erg",
|
|
"length": "cm",
|
|
"mass": "g",
|
|
"pressure": "dyn / cm^2",
|
|
"quantity": "mol",
|
|
"temperature": "K",
|
|
"time": "s",
|
|
}
|
|
for dim, unit in units.items():
|
|
self.assertIn(dim, checks)
|
|
self.assertEqual(checks[dim], unit)
|
|
|
|
def test_activation_energy(self):
|
|
system = ct.UnitSystem({"activation-energy": "eV"})
|
|
units = system.units
|
|
self.assertEqual(units["activation-energy"], "eV")
|
|
|
|
system = ct.UnitSystem({"activation-energy": "K"})
|
|
units = system.units
|
|
self.assertEqual(units["activation-energy"], "K")
|
|
|
|
def test_raises(self):
|
|
with self.assertRaisesRegex(ct.CanteraError, "non-unity conversion factor"):
|
|
ct.UnitSystem({"temperature": "2 K"})
|
|
with self.assertRaisesRegex(ct.CanteraError, "non-unity conversion factor"):
|
|
ct.UnitSystem({"current": "2 A"})
|
|
|
|
def test_convert_to_default(self):
|
|
system = ct.UnitSystem()
|
|
assert system.convert_to("3 cm", "m") == 0.03
|
|
assert system.convert_to(4, "mm") == 4000.0
|
|
assert system.convert_to("3 cm", ct.Units("m")) == 0.03
|
|
assert system.convert_to(4, ct.Units("m")) == 4
|
|
|
|
def test_convert_activation_energy(self):
|
|
system = ct.UnitSystem()
|
|
assert system.convert_activation_energy_to("3 J/mol", "J/kmol") == 3000
|
|
assert system.convert_activation_energy_to(4, "J/mol") == 0.004
|
|
|
|
def test_convert_rate_coeff(self):
|
|
system = ct.UnitSystem({"length": "cm"})
|
|
assert system.convert_rate_coeff_to(11, ct.Units("m^3/kmol/s")) == approx(11e-6)
|
|
assert system.convert_rate_coeff_to("22 m^3/mol/s", "m^3/kmol/s") == approx(22e3)
|
|
|
|
def test_convert_to_custom(self):
|
|
system = ct.UnitSystem({"length": "cm", "mass": "g"})
|
|
assert system.convert_to(10000, "m^2") == 1.0
|
|
assert system.convert_to(500, "kg") == 0.5
|
|
|
|
def test_convert_to_array(self):
|
|
system = ct.UnitSystem({"length": "km"})
|
|
x = np.array(((3, 4), (0.5, 2.0), (1.0, 0.0)))
|
|
self.assertArrayNear(system.convert_to(x, "m"), 1000 * x)
|
|
|
|
def test_convert_activation_energy_to_array(self):
|
|
system = ct.UnitSystem({"activation-energy": "J/mol"})
|
|
x = np.array(((3, 4), (0.5, 2.0), (1.0, 0.0)))
|
|
self.assertArrayNear(system.convert_activation_energy_to(x, "J/kmol"), 1000 * x)
|
|
|
|
def test_convert_rate_coeff_to_array(self):
|
|
system = ct.UnitSystem({"length": "cm"})
|
|
x = np.array(((3, 4), (0.5, 2.0), (1.0, 0.0)))
|
|
self.assertArrayNear(system.convert_rate_coeff_to(x, "m^2/kmol/s"), 0.0001 * x)
|
|
|
|
def test_convert_to_sequence(self):
|
|
system = ct.UnitSystem({"length": "km"})
|
|
x = [("3000 mm", 4), (0.5, 2.0), 1.0]
|
|
x_m = system.convert_to(x, "m")
|
|
assert x_m[0][0] == 3.0
|
|
assert x_m[1][1] == 2000.0
|
|
assert x_m[2] == 1000.0
|
|
|
|
def test_convert_activation_energy_to_sequence(self):
|
|
system = ct.UnitSystem({"activation-energy": "J/mol"})
|
|
x = [("3000 K", 4), (0.5, 2.0), 1.0]
|
|
x_m = system.convert_activation_energy_to(x, "J/kmol")
|
|
assert x_m[0][0] == approx(3000 * ct.gas_constant)
|
|
assert x_m[1][1] == 2000.0
|
|
assert x_m[2] == 1000.0
|
|
|
|
def test_convert_rate_coeff_to_sequence(self):
|
|
system = ct.UnitSystem({"length": "cm"})
|
|
x = [("3000 mm^3/kmol/s", 4), (0.5, 2.0), 1.0]
|
|
x_m = system.convert_rate_coeff_to(x, ct.Units("m^3/kmol/s"))
|
|
assert x_m[0][0] == approx(3000 / 1e9)
|
|
assert x_m[1][1] == approx(2 / 1e6)
|
|
assert x_m[2] == approx(1e-6)
|
|
|
|
def test_convert_errors(self):
|
|
system = ct.UnitSystem()
|
|
with pytest.raises(ct.CanteraError):
|
|
system.convert_to("eggs", "J/kmol")
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_to("5 cm", True)
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_to(None, "J/kmol")
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_to(5, 6)
|
|
|
|
with pytest.raises(ct.CanteraError):
|
|
system.convert_activation_energy_to(4, "m^3/s")
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_activation_energy_to(5, True)
|
|
|
|
with pytest.raises(ct.CanteraError):
|
|
system.convert_activation_energy_to("spam spam eggs", "K")
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_activation_energy_to({"spam": 5}, "K")
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_rate_coeff_to(11, ["m^3"])
|
|
|
|
with pytest.raises(TypeError):
|
|
system.convert_rate_coeff_to({"spam": 13}, "m^6/kmol^2/s")
|
|
|
|
class TestPyToAnyValue(utilities.CanteraTest):
|
|
|
|
def check_conversion(self, value, check_type=None):
|
|
out, held_type = _py_to_any_to_py(value)
|
|
self.assertEqual(out, value)
|
|
if check_type is not None:
|
|
self.assertEqual(held_type, check_type)
|
|
|
|
def check_inexact_conversion(self, value, check_type=None):
|
|
out, held_type = _py_to_any_to_py(value)
|
|
if isinstance(value, np.ndarray):
|
|
self.assertEqual(out, value.tolist())
|
|
else:
|
|
self.assertEqual(out, list(value))
|
|
if check_type is not None:
|
|
self.assertEqual(held_type, check_type)
|
|
|
|
def check_raises(self, value, ee, regex):
|
|
with self.assertRaisesRegex(ee, regex):
|
|
_py_to_any_to_py(value)
|
|
|
|
def test_none(self):
|
|
self.check_conversion(None, "void")
|
|
|
|
def test_set(self):
|
|
# Sets are converted to lists
|
|
self.check_inexact_conversion({"a", "b"}, "vector<string>")
|
|
|
|
def test_empty_list(self):
|
|
self.check_conversion([])
|
|
|
|
def test_empty_ndarray(self):
|
|
self.check_inexact_conversion(np.ndarray((0,)))
|
|
|
|
def test_empty_dict(self):
|
|
self.check_conversion({})
|
|
|
|
def test_scalar_string(self):
|
|
self.check_conversion("spam", "string")
|
|
|
|
def test_scalar_int(self):
|
|
self.check_conversion(3, "long int")
|
|
|
|
def test_scalar_float(self):
|
|
self.check_conversion(3.1415, "double")
|
|
|
|
def test_scalar_bool(self):
|
|
self.check_conversion(True, "bool")
|
|
|
|
def test_list_string(self):
|
|
self.check_conversion(["spam", "eggs"], "vector<string>")
|
|
|
|
def test_list_int(self):
|
|
self.check_conversion([1, 2, 3], "vector<long int>")
|
|
|
|
def test_list_float(self):
|
|
self.check_conversion([1., 2., 3.], "vector<double>")
|
|
|
|
def test_list_bool(self):
|
|
self.check_conversion([True, False], "vector<bool>")
|
|
|
|
def test_list_various(self):
|
|
self.check_conversion([True, "spam", 3, 4., {"foo": "bar"}],
|
|
"vector<AnyValue>")
|
|
|
|
def test_tuple(self):
|
|
self.check_inexact_conversion((True, "spam", 3, 4.), "vector<AnyValue>")
|
|
|
|
def test_ndarray1(self):
|
|
self.check_inexact_conversion(np.random.randn(10), "vector<double>")
|
|
|
|
def test_ndarray2(self):
|
|
self.check_inexact_conversion(np.random.randn(3, 2), "vector<vector<double>>")
|
|
|
|
def test_ndarray3(self):
|
|
# Each inner AnyValue holds a vector<vector<double>>
|
|
self.check_inexact_conversion(np.random.randn(3, 2, 4), "vector<AnyValue>")
|
|
|
|
def test_nested_string(self):
|
|
self.check_conversion([["spam", "eggs"], ["foo", "bar"]],
|
|
"vector<vector<string>>")
|
|
|
|
def test_nested_int(self):
|
|
self.check_conversion([[1, 2, 3], [4, 5, 6]], "vector<vector<long int>>")
|
|
|
|
def test_nested_float(self):
|
|
self.check_conversion([[1., 2., 3.], [4., 5., 6.]], "vector<vector<double>>")
|
|
|
|
def test_nested_bool(self):
|
|
self.check_conversion([[True, False], [False, True]], "vector<vector<bool>>")
|
|
|
|
def test_multi_dict(self):
|
|
vv = [{"a": [["spam", "eggs"], ["foo", "bar"]], "b": {"c": 4}}, {"d": 3}]
|
|
self.check_conversion(vv, "vector<AnyMap>")
|
|
|
|
def test_dict(self):
|
|
self.check_conversion({"a": 1, "b": 2., "c": "eggs", "d": True}, "AnyMap")
|
|
|
|
def test_nested_dict(self):
|
|
self.check_conversion({"a": 1, "b": 2., "c": {"d": "eggs"}}, "AnyMap")
|
|
|
|
def test_unconvertible(self):
|
|
self.check_raises(object(), ct.CanteraError, "Unable to convert")
|
|
|
|
def test_unconvertible2(self):
|
|
self.check_raises([3+4j, 1-2j], ct.CanteraError, "Unable to convert")
|
|
|
|
|
|
class TestAnyMap(utilities.CanteraTest):
|
|
@classmethod
|
|
def setup_class(cls):
|
|
data = {
|
|
"units": {"length": "mm", "energy": "kJ"},
|
|
"group1": {
|
|
"a": 5000,
|
|
"b": "12 MJ",
|
|
"c": "8000 K",
|
|
"d": [16, "10 cm^2"]
|
|
},
|
|
"group2": {
|
|
"units": {"mass": "g"},
|
|
"x": 1300
|
|
}
|
|
}
|
|
cls.data = _py_to_anymap_to_py(data)
|
|
|
|
def test_units_simple(self):
|
|
assert self.data['group1'].convert('a', 'm') == 5.0
|
|
assert self.data['group1'].convert('b', 'J') == 12e6
|
|
assert self.data['group1'].convert('d', 'm^2') == [16e-6, 10e-4]
|
|
|
|
def test_units_activation_energy(self):
|
|
assert self.data['group1'].convert_activation_energy('a', 'J/kmol') == 5e6
|
|
assert (self.data['group1'].convert_activation_energy('c', 'J/kmol')
|
|
== pytest.approx(8000 * ct.gas_constant))
|
|
|
|
def test_units_nested(self):
|
|
assert self.data['group2'].convert('x', 'J/kg') == 1300 * 1e6
|
|
|
|
def test_set_quantity(self):
|
|
params = ct.AnyMap()
|
|
params.set_quantity('spam', [2, 3, 4], 'Gg')
|
|
params.set_quantity('eggs', 10, ct.Units('kg/m^3'))
|
|
params.set_activation_energy('beans', 5, 'K')
|
|
|
|
converted = _py_to_anymap_to_py(params)
|
|
assert converted['spam'] == [2e6, 3e6, 4e6]
|
|
assert converted['eggs'] == pytest.approx(10)
|
|
assert converted['beans'] == pytest.approx(5 * ct.gas_constant)
|
|
|
|
# Unit conversions are deferred
|
|
outer = ct.AnyMap()
|
|
outer['units'] = {'mass': 'g', 'activation-energy': 'K'}
|
|
outer['inner'] = params
|
|
converted = _py_to_anymap_to_py(outer)
|
|
assert converted['inner']['spam'] == pytest.approx([2e9, 3e9, 4e9])
|
|
assert converted['inner']['eggs'] == pytest.approx(10e3)
|
|
assert converted['inner']['beans'] == pytest.approx(5)
|
|
|
|
outer.set_quantity('cheese', {'gouda': 5.5}, 'J/kg')
|
|
with pytest.raises(ct.CanteraError):
|
|
_py_to_anymap_to_py(outer)
|
|
|
|
outer.set_activation_energy('cheese', 12, 'V/m')
|
|
with pytest.raises(ct.CanteraError):
|
|
_py_to_anymap_to_py(outer)
|