# -*- coding: utf-8 -*-
#
# This file is part of essm.
# Copyright (C) 2017 ETH Zurich, Swiss Data Science Center.
#
# essm is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# essm is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with essm; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
"""Define unit symbols."""
import functools
import operator
import sympy.physics.units as u
from sympy import Symbol
from sympy.physics.units import Dimension, Quantity, find_unit
from sympy.physics.units.definitions.dimension_definitions import (
amount_of_substance, capacitance,
charge, conductance,
energy, force, frequency,
inductance, luminous_intensity,
magnetic_density, magnetic_flux,
power, pressure, temperature, time,
voltage)
from sympy.physics.units.systems.si import dimsys_SI, SI
candela = u.candela
coulomb = u.coulomb
farad = u.farad
gray = u.gray
henry = u.henry
joule = u.joule
katal = u.katal
kelvin = u.kelvin
kilogram = u.kilogram
lux = u.lux
meter = u.meter
mol = mole = u.mol
newton = u.newton
ohm = u.ohm
pascal = u.pascal
second = u.second
siemens = u.siemens
tesla = u.tesla
volt = u.volt
watt = u.watt
weber = u.weber
SI_BASE_DIMENSIONS = {
SI.get_dimensional_expr(d): d
for d in SI._base_units
}
SI_EXTENDED_UNITS = list(SI._base_units) + [
kelvin, candela, lux, mol, newton, pascal, joule, watt, coulomb, volt,
farad, ohm, siemens, weber, tesla, henry
]
SI_EXTENDED_DIMENSIONS = {
SI.get_dimensional_expr(d): d
for d in SI_EXTENDED_UNITS
}
[docs]def markdown(unit):
"""Return markdown representation of a unit."""
from operator import itemgetter
if unit.is_Pow:
item = unit.args
base1 = item[0]
if hasattr(base1, 'abbrev'):
base1 = base1.abbrev
exp1 = item[1]
if hasattr(exp1, 'abbrev'):
exp1 = exp1.abbrev
return '{0}$^{{{1}}}$'.format(base1, exp1)
if unit.is_Mul:
str1 = ''
tuples = []
allargs = unit.args
for arg in allargs:
if arg.is_Pow:
args = arg.args
args0 = args[0]
if isinstance(args0, Quantity):
args0 = args0.abbrev
args1 = args[1]
if isinstance(args1, Quantity):
args1 = args1.abbrev
tuples.append((str(args0), args1))
if isinstance(arg, Quantity):
tuples.append((str(arg.abbrev), 1))
tuples.sort(key=itemgetter(1), reverse=True)
for item in tuples:
if item[1] == 1:
str1 = str1 + ' ' + item[0]
else:
base1 = item[0]
if hasattr(base1, 'abbrev'):
base1 = base1.abbrev
exp1 = item[1]
if hasattr(exp1, 'abbrev'):
exp1 = exp1.abbrev
str1 = str1 + ' {0}$^{{{1}}}$'.format(base1, exp1)
return str1.strip()
else:
if isinstance(unit, Quantity):
unit = unit.abbrev
return str(unit)
[docs]def derive_unit(expr, name=None):
"""Derive SI unit from an expression, omitting scale factors."""
from essm.variables import Variable
from essm.variables.utils import extract_variables
dim = Variable.get_dimensional_expr(expr)
return dim.subs(SI_EXTENDED_DIMENSIONS)
[docs]def derive_baseunit(expr, name=None):
"""Derive SI base unit from an expression, omitting scale factors."""
from essm.variables import Variable
from essm.variables.utils import extract_variables
from sympy.physics.units import Dimension
from sympy.physics.units.systems.si import dimsys_SI
Variable.check_unit(expr) # check for dimensional consistency
variables = extract_variables(expr)
for var1 in variables:
q1 = Quantity('q_' + str(var1))
SI.set_quantity_dimension(
q1, Dimension(SI.get_dimensional_expr(
derive_baseunit(var1.definition.unit)))
)
SI.set_quantity_scale_factor(q1, var1.definition.unit)
expr = expr.xreplace({var1: q1})
dim = Dimension(Variable.get_dimensional_expr(expr))
return functools.reduce(
operator.mul, (
SI_BASE_DIMENSIONS[Symbol(d)] ** p
for d, p in dimsys_SI.get_dimensional_dependencies(dim).items()
), 1
)
def derive_base_dimension(dim):
"""Derive base dimension of dimension."""
return functools.reduce(
operator.mul, (
Dimension(d) ** p
for d, p in dimsys_SI.get_dimensional_dependencies(dim).items()
), Dimension(1)
)
__all__ = (
'derive_baseunit', 'derive_unit', 'markdown',
'joule', 'kelvin', 'kilogram', 'meter', 'mole',
'pascal', 'second', 'watt'
)