Skip to content

Commit

Permalink
Fix collect_factor_and_basedimension and undo previous changes
Browse files Browse the repository at this point in the history
  • Loading branch information
schymans committed Oct 20, 2020
1 parent 2a6c8ee commit bf2a9df
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 76 deletions.
84 changes: 9 additions & 75 deletions essm/variables/_core.py
Expand Up @@ -155,84 +155,14 @@ def get_dimensional_expr(expr):
return Variable.get_dimensional_expr(expr.definition.unit)
return S.One

@staticmethod
def check_dimensions(expr, unit_system="SI"):
"""Return expr if units in addends have the same
base dimensions, else raise a ValueError."""
# 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

import functools
import operator
from sympy.physics.units import UnitSystem
unit_system = UnitSystem.get_unit_system(unit_system)

def addDict(dict1, dict2):
"""Merge dictionaries by adding values of common keys and
removing keys with value of 0."""
dict3 = {**dict1, **dict2}
for key, value in dict3.items():
if key in dict1 and key in dict2:
dict3[key] = value + dict1[key]
return {key: val for key, val in dict3.items() if val != 0}

adds = expr.atoms(Add)
DIM_OF = unit_system.get_dimension_system().get_dimensional_dependencies
for a in adds:
deset = set()
for ai in a.args:
if ai.is_number:
deset.add(())
continue
dims = []
skip = False
dimdict = {}
for i in Mul.make_args(ai):
if i.has(Quantity):
i = Dimension(unit_system.get_dimensional_expr(i))
if i.has(Dimension):
dimdict = addDict(dimdict, DIM_OF(i))
elif i.free_symbols:
skip = True
break
dims.extend(dimdict.items())
if not skip:
deset.add(tuple(sorted(dims)))
if len(deset) > 1:
raise ValueError(
"addends have incompatible dimensions: {}".format(deset))

# 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)


@staticmethod
def check_unit(expr):
"""Check if base dimensions of expression are consistent.
Checks for dimension mismatches of the addends, thus preventing
expressions like `meter + second` to be created.
"""

vars1 = {
arg: arg.definition.unit
for arg in preorder_traversal(expr) if
isinstance(arg, BaseVariable)
}
#factor, dim = Variable.collect_factor_and_basedimension(expr)
print(expr.subs(vars1))
Variable.check_dimensions(expr.subs(vars1))
factor, dim = Variable.collect_factor_and_basedimension(expr)
return expr

@staticmethod
Expand Down Expand Up @@ -300,10 +230,14 @@ def collect_factor_and_basedimension(expr):
sum([x[0] for x in expr.args]))
return factor, dim
elif isinstance(expr, Function):
fds = [Variable.collect_factor_and_basedimension(
arg) for arg in expr.args]
return (expr.func(*(f[0] for f in fds)),
expr.func(*(d[1] for d in fds)))
fds = set(Variable.collect_factor_and_basedimension(
arg)[1] for arg in expr.args)
if fds != {Dimension(1)}:
print(fds)
raise ValueError(
'Arguments in function are not dimensionless, '
'but have dimensions of {0}'.format(fds))
return expr, Dimension(1)
elif isinstance(expr, Dimension):
return 1, expr
else:
Expand Down
3 changes: 2 additions & 1 deletion essm/variables/units.py
Expand Up @@ -165,5 +165,6 @@ def derive_base_dimension(dim):

__all__ = (
'derive_baseunit', 'derive_unit', 'markdown',
'joule', 'kelvin', 'kilogram', 'meter', 'mole', 'pascal', 'second', 'watt'
'joule', 'kelvin', 'kilogram', 'meter', 'mole',
'pascal', 'second', 'watt'
)

0 comments on commit bf2a9df

Please sign in to comment.