# Source code for sympy.physics.unitsystems.quantities

# -*- coding: utf-8 -*-

"""
Physical quantities.
"""

from __future__ import division
import numbers

from sympy import sympify, Expr, Number, Mul, Pow
from .units import Unit

#TODO: in operations, interpret a Unit as a quantity with factor 1

[docs]class Quantity(Expr): """ Physical quantity. A quantity is defined from a factor and a unit. """ is_commutative = True def __new__(cls, factor=1, unit=None, **assumptions): if not isinstance(factor, str): factor = sympify(factor) # if the given unit is a number (because of some operations) and # the factor is represented as a number, then return a number if ((unit is None or isinstance(unit, (Number, numbers.Real))) and isinstance(factor, (Number, numbers.Real))): return factor * (unit or 1) #TODO: if factor is of the form "1 m", parse the factor and the unit if isinstance(factor, (Number, numbers.Real)): if not isinstance(unit, Unit): raise TypeError("'unit' should be a Unit instance; %s found" % type(unit)) else: raise NotImplementedError obj = Expr.__new__(cls, factor, unit, **assumptions) obj.factor, obj.unit = factor, unit return obj def __str__(self): return "%g %s" % (self.factor, self.unit) def __repr__(self): return "%g %s" % (self.factor, repr(self.unit)) def __neg__(self): return Quantity(-self.factor, self.unit)
[docs] def add(self, other): """ Add two quantities. If the other object is not a quantity, raise an error. Two quantities can be added only if they have the same unit: so we convert first the other quantity to the same unit and, if it succedded, then we add the factors. """ if isinstance(other, Quantity): return Quantity(self.factor + other.convert_to(self.unit).factor, self.unit) else: raise TypeError("Only quantities can be added")
def sub(self, other): if isinstance(other, Quantity): return Quantity(self.factor - other.convert_to(self.unit).factor, self.unit) else: raise TypeError("Only quantities can be subtracted") def mul(self, other): other = sympify(other) if isinstance(other, Quantity): return Quantity(self.factor * other.factor, self.unit.mul(other.unit)) elif isinstance(other, (Number, numbers.Real)): return Quantity(self.factor * other, self.unit) else: return Mul(self, other) def div(self, other): other = sympify(other) if isinstance(other, Quantity): return Quantity(self.factor / other.factor, self.unit.div(other.unit)) elif isinstance(other, (Number, numbers.Real)): return Quantity(self.factor / other, self.unit) else: return Mul(self, Pow(other, -1)) def rdiv(self, other): other = sympify(other) if isinstance(other, Quantity): return Quantity(other.factor / self.factor, other.unit.div(self.unit)) elif isinstance(other, (Number, numbers.Real)): return Quantity(other / self.factor, self.unit.pow(-1)) else: return Mul(self**-1, other) def pow(self, other): other = sympify(other) if isinstance(other, (Number, numbers.Real)): f = self.factor**other # without evalf a Pow instance is returned, and it can not be # handled by Quantity.__new__ return Quantity(f.evalf(), self.unit.pow(other)) else: return Pow(self, other) @property
[docs] def as_unit(self): """ Convert the quantity to a unit. """ from .units import Unit return Unit(self.unit, factor=self.factor)
[docs] def convert_to(self, unit): """ Convert the quantity to another (compatible) unit. """ if self.unit.is_compatible(unit) is False: raise ValueError("Only compatible units can be converted; " "'%s' found" % unit.dim) return Quantity(self.factor * self.unit.factor / unit.factor, unit)