SfePy NTC

Source code for sfepy.mechanics.units

"""
Some utilities for work with units of physical quantities.
"""
try:
    import sympy as sm
except ImportError:
    sm = None

import numpy as nm

from sfepy.base.base import get_default, invert_dict, Struct

default_units_of_basic_quantities = {
    'length' : 'm',
    'time' : 's',
    'mass' : 'kg',
    'temperature' : 'C',
}

# Cannot use N for Newton as it is a sympy function...
derived_units = {
    'Newton' : '(kg * m) / s**2',
    'Pa' : 'kg / (m * s**2)', # N / m**2
    'J' : '(kg * m**2) / s**2', # N m
}

units_of_quantities = {
    'density' : 'g / m**3',
    'force' : 'Newton',
    'stress' : 'Pa',
    'energy' : 'J',
    'thermal_expandability' : 'Pa / C',
}

prefixes = {
    'p'  : 1e-12,
    'n'  : 1e-9,
    'mu' : 1e-6,
    'm'  : 1e-3,
    'c'  : 1e-2,
    ''   : 1e0,
    'd'  : 1e1,
    'k'  : 1e3,
    'M'  : 1e6,
    'G'  : 1e9,
    'T'  : 1e12,
}

inv_prefixes = invert_dict(prefixes)

[docs]class Unit(Struct): """ A unit of a physical quantity. The prefix and coefficient of the unit are determined from to its name. Examples -------- Construct some units: >>> from sfepy.mechanics.units import Unit >>> unit = Unit('mm') >>> print unit Unit:mm coef: 0.001 name: mm prefix: m prefix_length: 1 unit: m >>> unit = Unit('kg') >>> print unit Unit:kg coef: 1000.0 name: kg prefix: k prefix_length: 1 unit: g Get prefixes for a coefficient: >>> Unit.get_prefix(100.0) ('d', 10.0) >>> Unit.get_prefix(100.0, omit=('d',)) ('k', 0.10000000000000001) """ @staticmethod
[docs] def get_prefix(coef, bias=0.1, omit=()): """ Get the prefix and numerical multiplier corresponding to a numerical coefficient, omitting prefixes in omit tuple. """ values = [val for key, val in prefixes.iteritems() if key not in omit] coefs = nm.array(values, dtype=nm.float64) coefs.sort() ii = nm.searchsorted(coefs, bias*coef, side='left') cc = coefs[ii] prefix = inv_prefixes[cc] mul = coef / cc return prefix, mul
def __init__(self, name): self.name = name aux = sorted(prefixes.keys(), reverse=True) for prefix in aux: lp = len(prefix) if (prefix == name[:lp]) and (lp < len(name)): break self.prefix = prefix self.prefix_length = len(prefix) self.unit = name[self.prefix_length:] self.coef = prefixes[self.prefix]
[docs]class Quantity(Struct): """ A physical quantity in a given set of basic units. Examples -------- Construct the stress quantity: >>> from sfepy.mechanics.units import Unit, Quantity >>> units = ['m', 's', 'kg', 'C'] >>> unit_set = [Unit(key) for key in units] >>> q1 = Quantity('stress', unit_set) >>> q1() '1.0 Pa' Show its unit using various prefixes: >>> q1('m') '1000.0 mPa' >>> q1('') '1.0 Pa' >>> q1('k') '0.001 kPa' >>> q1('M') '1e-06 MPa' Construct the stress quantity in another unit set: >>> units = ['mm', 's', 'kg', 'C'] >>> unit_set = [Unit(key) for key in units] >>> q2 = Quantity('stress', unit_set) >>> q2() '1.0 kPa' Show its unit using various prefixes: >>> q2('m') '1000000.0 mPa' >>> q2('') '1000.0 Pa' >>> q2('k') '1.0 kPa' >>> q2('M') '0.001 MPa' """ def __init__(self, name, unit_set): """ Create a quantity in the given unit set. The name must be listed in the units_of_quantities dictionary.""" self.name = name self.unit_set = unit_set self.unit_name = units_of_quantities[self.name] unit_expr = sm.sympify(self.unit_name) unit_expr = unit_expr.subs(derived_units) self.symbolic_value = sm.sympify(unit_expr) atoms = self.symbolic_value.atoms(sm.Symbol) self.def_units = [Unit(atom.name) for atom in atoms] self.def_names, self.def_units = self._get_dicts(self.def_units) self.names, self.units = self._get_dicts(self.unit_set) self.def_coef = float(self.symbolic_value.subs(self.def_names)) coef_dict = {} for key, val in self.def_units.iteritems(): coef_dict[val.name] = self.units[key].coef self.coef_dict = coef_dict self.raw_coef = float(self.symbolic_value.subs(self.coef_dict)) self.coef = self.raw_coef / self.def_coef def _get_dicts(self, unit_set): """Get auxiliary dictionaries for a unit set.""" name_dict = {} unit_dict = {} for unit in unit_set: name_dict[unit.name] = unit.coef unit_dict[unit.unit] = unit return name_dict, unit_dict def __call__(self, prefix=None, omit=('c', 'd')): """Get the quantity units.""" if prefix is None: prefix, mul = Unit.get_prefix(self.coef, omit=omit) else: coef = prefixes[prefix] mul = self.coef / coef return '%s %s%s' % (mul, prefix, self.unit_name)
[docs]def get_consistent_unit_set(length=None, time=None, mass=None, temperature=None): """Given a set of basic units, return a consistent set of derived units for quantities listed in the units_of_quantities dictionary.""" defaults = default_units_of_basic_quantities length = get_default(length, defaults['length']) time = get_default(time, defaults['time']) mass = get_default(mass, defaults['mass']) temperature = get_default(temperature, defaults['temperature']) unit_set = [Unit(length), Unit(time), Unit(mass), Unit(temperature)] derived_units = {} for quantity_name in units_of_quantities.keys(): quantity = Quantity(quantity_name, unit_set) derived_units[quantity_name] = quantity() return derived_units