def test_get_dimensional_expr_with_function(): v_w1 = Quantity('v_w1') v_w2 = Quantity('v_w2') v_w1.set_dimension(length/time) v_w2.set_dimension(length/time) v_w1.set_scale_factor(meter/second) v_w2.set_scale_factor(meter/second) assert Quantity.get_dimensional_expr(sin(v_w1)) == \ sin(Quantity.get_dimensional_expr(v_w1)) assert Quantity.get_dimensional_expr(sin(v_w1/v_w2)) == 1
def test_dimensional_expr_of_derivative(): l = Quantity('l', length, 36 * km) t = Quantity('t', time, hour) t1 = Quantity('t1', time, second) x = Symbol('x') y = Symbol('y') f = Function('f') dfdx = f(x, y).diff(x, y) dl_dt = dfdx.subs({f(x, y): l, x: t, y: t1}) assert Quantity.get_dimensional_expr(dl_dt) ==\ Quantity.get_dimensional_expr(l / t / t1) ==\ Symbol("length")/Symbol("time")**2 assert Quantity._collect_factor_and_dimension(dl_dt) ==\ Quantity._collect_factor_and_dimension(l / t / t1) ==\ (10, length/time**2)
def __add__(self, other): from sympy.physics.units.quantities import Quantity other = sympify(other) if isinstance(other, Basic): if other.has(Quantity): other = Dimension(Quantity.get_dimensional_expr(other)) if isinstance(other, Dimension) and self == other: return self return super(Dimension, self).__add__(other) return self
def _get_conversion_matrix_for_expr(expr, target_units): from sympy import Matrix expr_dim = Dimension(Quantity.get_dimensional_expr(expr)) dim_dependencies = expr_dim.get_dimensional_dependencies(mark_dimensionless=True) target_dims = [Dimension(Quantity.get_dimensional_expr(x)) for x in target_units] canon_dim_units = {i for x in target_dims for i in x.get_dimensional_dependencies(mark_dimensionless=True)} canon_expr_units = {i for i in dim_dependencies} if not canon_expr_units.issubset(canon_dim_units): return None canon_dim_units = sorted(canon_dim_units) camat = Matrix([[i.get_dimensional_dependencies(mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units]) exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units]) res_exponents = camat.solve_least_squares(exprmat, method=None) return res_exponents
def __mul__(self, other): from sympy.physics.units.quantities import Quantity if isinstance(other, Basic): if other.has(Quantity): other = Dimension(Quantity.get_dimensional_expr(other)) if isinstance(other, Dimension): return Dimension(self.name*other.name) if not other.free_symbols: return self return super(Dimension, self).__mul__(other) return self
def __mul__(self, other): from sympy.physics.units.quantities import Quantity if isinstance(other, Basic): if other.has(Quantity): other = Dimension(Quantity.get_dimensional_expr(other)) if isinstance(other, Dimension): return Dimension(self.name*other.name) if not other.free_symbols: # other.is_number cannot be used return self return super(Dimension, self).__mul__(other) return self
def test_quantity_abs(): v_w1 = Quantity('v_w1', length/time, meter/second) v_w2 = Quantity('v_w2', length/time, meter/second) v_w3 = Quantity('v_w3', length/time, meter/second) expr = v_w3 - Abs(v_w1 - v_w2) Dq = Dimension(Quantity.get_dimensional_expr(expr)) assert dimsys_default.get_dimensional_dependencies(Dq) == { 'length': 1, 'time': -1, } assert meter == sqrt(meter**2)
def test_dimensional_expr_of_derivative(): l = Quantity('l') t = Quantity('t') t1 = Quantity('t1') l.set_dimension(length) t.set_dimension(time) t1.set_dimension(time) l.set_scale_factor(36*km) t.set_scale_factor(hour) t1.set_scale_factor(second) x = Symbol('x') y = Symbol('y') f = Function('f') dfdx = f(x, y).diff(x, y) dl_dt = dfdx.subs({f(x, y): l, x: t, y: t1}) assert Quantity.get_dimensional_expr(dl_dt) ==\ Quantity.get_dimensional_expr(l / t / t1) ==\ Symbol("length")/Symbol("time")**2 assert Quantity._collect_factor_and_dimension(dl_dt) ==\ Quantity._collect_factor_and_dimension(l / t / t1) ==\ (10, length/time**2)
def test_quantity_postprocessing(): q1 = Quantity('q1', length*pressure**2*temperature/time) q2 = Quantity('q2', energy*pressure*temperature/(length**2*time)) assert q1 + q2 q = q1 + q2 Dq = Dimension(Quantity.get_dimensional_expr(q)) assert dimsys_default.get_dimensional_dependencies(Dq) == { 'length': -1, 'mass': 2, 'temperature': 1, 'time': -5, }
def _convert_to(expr, quantity): if isinstance(expr, Add): return Add(*[_convert_to(i, quantity) for i in expr.args]) elif isinstance(expr, Mul): new_args = [_convert_to(i, quantity) for i in expr.args] edim = Dimension(Quantity.get_dimensional_expr(expr)) if edim == quantity.dimension: scale_factor_old = get_total_scale_factor(expr) return expr / get_units( expr) * scale_factor_old / quantity.scale_factor * quantity return Mul(*new_args) elif isinstance(expr, Pow): base = _convert_to(expr.base, quantity) edim = Dimension(Quantity.get_dimensional_expr(base))**expr.exp if edim == quantity.dimension: scale_factor_old = get_total_scale_factor(expr) return expr / get_units( expr) * scale_factor_old / quantity.scale_factor * quantity return base**expr.exp elif isinstance(expr, Quantity): edim = Dimension(Quantity.get_dimensional_expr(expr)) edep1 = edim.get_dimensional_dependencies() edep2 = quantity.dimension.get_dimensional_dependencies() if edim == quantity.dimension: return expr.scale_factor / quantity.scale_factor * quantity if set(edep1.keys()) == set(edep2.keys()): fracs = [ Rational(v1, v2) for v1, v2 in zip(edep1.values(), edep2.values()) ] powers = list(set(fracs)) if len(powers) == 1: return expr.scale_factor / quantity.scale_factor**powers[ 0] * quantity**powers[0] else: return expr return expr
def _get_conversion_matrix_for_expr(expr, target_units): from sympy import Matrix expr_dim = Dimension(Quantity.get_dimensional_expr(expr)) dim_dependencies = expr_dim.get_dimensional_dependencies(mark_dimensionless=True) target_dims = [Dimension(_get_dimension_of_expr(x)) for x in target_units] canon_dim_units = {i for x in target_dims for i in x.get_dimensional_dependencies(mark_dimensionless=True)} canon_expr_units = {i for i in dim_dependencies} if not canon_expr_units.issubset(canon_dim_units): return None canon_dim_units = sorted(canon_dim_units) camat = Matrix([[i.get_dimensional_dependencies(mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units]) exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units]) res_exponents = camat.solve_least_squares(exprmat, method=None) return res_exponents
def check_dimensions(expr): """Return expr if there are not unitless values added to dimensional quantities, else raise a ValueError.""" from sympy.solvers.solveset import _term_factors # the case of adding a number to a dimensional quantity # is ignored for the sake of SymPy core routines, so this # function will raise an error now if such an addend is # found. # Also, when doing substitutions, multiplicative constants # might be introduced, so remove those now adds = expr.atoms(Add) DIM_OF = dimsys_default.get_dimensional_dependencies for a in adds: deset = set() for ai in a.args: if ai.is_number: deset.add(()) continue dims = [] skip = False for i in Mul.make_args(ai): if i.has(Quantity): i = Dimension(Quantity.get_dimensional_expr(i)) if i.has(Dimension): dims.extend(DIM_OF(i).items()) elif i.free_symbols: skip = True break if not skip: deset.add(tuple(sorted(dims))) if len(deset) > 1: raise ValueError( "addends have incompatible dimensions") # clear multiplicative constants on Dimensions which may be # left after substitution reps = {} for m in expr.atoms(Mul): if any(isinstance(i, Dimension) for i in m.args): reps[m] = m.func(*[ i for i in m.args if not i.is_number]) return expr.xreplace(reps)
def check_dimensions(expr): """Return expr if there are not unitless values added to dimensional quantities, else raise a ValueError.""" from sympy.solvers.solveset import _term_factors # the case of adding a number to a dimensional quantity # is ignored for the sake of SymPy core routines, so this # function will raise an error now if such an addend is # found. # Also, when doing substitutions, multiplicative constants # might be introduced, so remove those now adds = expr.atoms(Add) DIM_OF = dimsys_default.get_dimensional_dependencies for a in adds: deset = set() for ai in a.args: if ai.is_number: deset.add(()) continue dims = [] skip = False for i in Mul.make_args(ai): if i.has(Quantity): i = Dimension(Quantity.get_dimensional_expr(i)) if i.has(Dimension): dims.extend(DIM_OF(i).items()) elif i.free_symbols: skip = True break if not skip: deset.add(tuple(sorted(dims))) if len(deset) > 1: raise ValueError( "addends have incompatible dimensions") # clear multiplicative constants on Dimensions which may be # left after substitution reps = {} for m in expr.atoms(Mul): if any(isinstance(i, Dimension) for i in m.args): reps[m] = m.func(*[ i for i in m.args if not i.is_number]) return expr.xreplace(reps)
def test_quantity_abs(): v_w1 = Quantity('v_w1') v_w2 = Quantity('v_w2') v_w3 = Quantity('v_w3') v_w1.set_global_relative_scale_factor(1, meter / second) v_w2.set_global_relative_scale_factor(1, meter / second) v_w3.set_global_relative_scale_factor(1, meter / second) expr = v_w3 - Abs(v_w1 - v_w2) assert SI.get_dimensional_expr(v_w1) == (length / time).name Dq = Dimension(SI.get_dimensional_expr(expr)) with warns_deprecated_sympy(): Dq1 = Dimension(Quantity.get_dimensional_expr(expr)) assert Dq == Dq1 assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == { 'length': 1, 'time': -1, } assert meter == sqrt(meter**2)
mebibyte = mebibytes = Quantity("mebibyte") mebibyte.set_dimension(information) mebibyte.set_scale_factor(mebi * byte) gibibyte = gibibytes = Quantity("gibibyte") gibibyte.set_dimension(information) gibibyte.set_scale_factor(gibi * byte) tebibyte = tebibytes = Quantity("tebibyte") tebibyte.set_dimension(information) tebibyte.set_scale_factor(tebi * byte) pebibyte = pebibytes = Quantity("pebibyte") pebibyte.set_dimension(information) pebibyte.set_scale_factor(pebi * byte) exbibyte = exbibytes = Quantity("exbibyte") exbibyte.set_dimension(information) exbibyte.set_scale_factor(exbi * byte) # check that scale factors are the right SI dimensions: for _scale_factor, _dimension in zip( Quantity.SI_quantity_scale_factors.values(), Quantity.SI_quantity_dimension_map.values()): dimex = Quantity.get_dimensional_expr(_scale_factor) if dimex != 1: if not dimsys_default.equivalent_dims(_dimension, Dimension(dimex)): raise ValueError("quantity value and dimension mismatch") del _scale_factor, _dimension
mebibyte = mebibytes = Quantity("mebibyte") mebibyte.set_dimension(information) mebibyte.set_scale_factor(mebi*byte) gibibyte = gibibytes = Quantity("gibibyte") gibibyte.set_dimension(information) gibibyte.set_scale_factor(gibi*byte) tebibyte = tebibytes = Quantity("tebibyte") tebibyte.set_dimension(information) tebibyte.set_scale_factor(tebi*byte) pebibyte = pebibytes = Quantity("pebibyte") pebibyte.set_dimension(information) pebibyte.set_scale_factor(pebi*byte) exbibyte = exbibytes = Quantity("exbibyte") exbibyte.set_dimension(information) exbibyte.set_scale_factor(exbi*byte) # check that scale factors are the right SI dimensions: for _scale_factor, _dimension in zip( Quantity.SI_quantity_scale_factors.values(), Quantity.SI_quantity_dimension_map.values()): dimex = Quantity.get_dimensional_expr(_scale_factor) if dimex != 1: if not dimsys_default.equivalent_dims(_dimension, Dimension(dimex)): raise ValueError("quantity value and dimension mismatch") del _scale_factor, _dimension
def convert_to(expr, quantity): """ Convert `expr` to the same expression with all of its units and quantities represented as factors of `quantity`, whenever the dimension is compatible. Examples ======== >>> from sympy.physics.units import speed_of_light, meter, gram, \ second, day, mile, newton, kilogram, inch, centimeter, atomic_mass_constant >>> from sympy.physics.units.definitions import kilometer >>> from sympy.physics.units import convert_to >>> convert_to(mile, kilometer) 25146*kilometer/15625 >>> convert_to(mile, kilometer).n() 1.609344*kilometer >>> convert_to(speed_of_light, meter/second) 299792458*meter/second >>> convert_to(day, second) 86400*second >>> 3*newton 3*newton >>> convert_to(3*newton, kilogram*meter/second**2) 3*kilogram*meter/second**2 >>> convert_to(atomic_mass_constant, gram) 1.66053904e-24*gram """ def get_total_scale_factor(expr): if isinstance(expr, Mul): return reduce(lambda x, y: x * y, [get_total_scale_factor(i) for i in expr.args]) elif isinstance(expr, Pow): return get_total_scale_factor(expr.base)**expr.exp elif isinstance(expr, Quantity): return expr.scale_factor return 1 def get_units(expr): if isinstance(expr, Mul): return reduce(lambda x, y: x * y, [get_units(i) for i in expr.args]) elif isinstance(expr, Pow): return get_units(expr.base)**expr.exp elif isinstance(expr, Quantity): return expr return 1 if isinstance(quantity, Quantity): backup_quantity = None else: backup_quantity = quantity quantity = Quantity("_temp", Dimension(Quantity.get_dimensional_expr(quantity)), get_total_scale_factor(quantity)) def _convert_to(expr, quantity): if isinstance(expr, Add): return Add(*[_convert_to(i, quantity) for i in expr.args]) elif isinstance(expr, Mul): new_args = [_convert_to(i, quantity) for i in expr.args] edim = Dimension(Quantity.get_dimensional_expr(expr)) if edim == quantity.dimension: scale_factor_old = get_total_scale_factor(expr) return expr / get_units( expr) * scale_factor_old / quantity.scale_factor * quantity return Mul(*new_args) elif isinstance(expr, Pow): base = _convert_to(expr.base, quantity) edim = Dimension(Quantity.get_dimensional_expr(base))**expr.exp if edim == quantity.dimension: scale_factor_old = get_total_scale_factor(expr) return expr / get_units( expr) * scale_factor_old / quantity.scale_factor * quantity return base**expr.exp elif isinstance(expr, Quantity): edim = Dimension(Quantity.get_dimensional_expr(expr)) edep1 = edim.get_dimensional_dependencies() edep2 = quantity.dimension.get_dimensional_dependencies() if edim == quantity.dimension: return expr.scale_factor / quantity.scale_factor * quantity if set(edep1.keys()) == set(edep2.keys()): fracs = [ Rational(v1, v2) for v1, v2 in zip(edep1.values(), edep2.values()) ] powers = list(set(fracs)) if len(powers) == 1: return expr.scale_factor / quantity.scale_factor**powers[ 0] * quantity**powers[0] else: return expr return expr res = _convert_to(expr, quantity) if backup_quantity: res = res.subs(quantity, backup_quantity) return res
def test_get_dimensional_expr_with_function_1(): v_w1 = Quantity('v_w1', length / time, meter / second) v_w2 = Quantity('v_w2', length / time, meter / second) assert Quantity.get_dimensional_expr(sin(v_w1/v_w2)) == 1
def test_get_dimensional_expr_with_function(): v_w1 = Quantity('v_w1', length / time, meter / second) assert Quantity.get_dimensional_expr(sin(v_w1)) == \ sin(Quantity.get_dimensional_expr(v_w1))