def __new__(cls, name, dimension, scale_factor=S.One, abbrev=None, **assumptions): if not isinstance(name, Symbol): name = Symbol(name) if not isinstance(dimension, dimensions.Dimension): if dimension == 1: dimension = Dimension(1) else: raise ValueError("expected dimension or 1") scale_factor = sympify(scale_factor) dimex = Quantity.get_dimensional_expr(scale_factor) if dimex != 1: if dimension != Dimension(dimex): raise ValueError("quantity value and dimension mismatch") # replace all prefixes by their ratio to canonical units: scale_factor = scale_factor.replace(lambda x: isinstance(x, Prefix), lambda x: x.scale_factor) # replace all quantities by their ratio to canonical units: scale_factor = scale_factor.replace(lambda x: isinstance(x, Quantity), lambda x: x.scale_factor) if abbrev is None: abbrev = name elif isinstance(abbrev, string_types): abbrev = Symbol(abbrev) obj = AtomicExpr.__new__(cls, name, dimension, scale_factor, abbrev) obj._name = name obj._dimension = dimension obj._scale_factor = scale_factor obj._abbrev = abbrev return obj
def _get_conversion_matrix_for_expr(expr, target_units, unit_system): """depend on sympy 1.5-1.6!!!""" from sympy import Matrix dimension_system = unit_system.get_dimension_system() expr_dim = Dimension(unit_system.get_dimensional_expr(expr)) dim_dependencies = dimension_system.get_dimensional_dependencies(expr_dim, mark_dimensionless=True) target_dims = [Dimension(unit_system.get_dimensional_expr(x)) for x in target_units] canon_dim_units = [i for x in target_dims for i in dimension_system.get_dimensional_dependencies(x, mark_dimensionless=True)] canon_expr_units = {i for i in dim_dependencies} if not canon_expr_units.issubset(set(canon_dim_units)): raise TypeError("There is an invalid character in '%s'" % expr, "the expr must be sympy.physics.unit or number") seen = set([]) canon_dim_units = [i for i in canon_dim_units if not (i in seen or seen.add(i))] camat = Matrix( [[dimension_system.get_dimensional_dependencies(i, 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, canon_dim_units
def _collect_factor_and_dimension(expr): """Return tuple with factor expression and dimension expression.""" if isinstance(expr, Quantity): return expr.scale_factor, expr.dimension elif isinstance(expr, Mul): factor = 1 dimension = Dimension(1) for arg in expr.args: arg_factor, arg_dim = Quantity._collect_factor_and_dimension( arg) factor *= arg_factor dimension *= arg_dim return factor, dimension elif isinstance(expr, Pow): factor, dim = Quantity._collect_factor_and_dimension(expr.base) return factor**expr.exp, dim**expr.exp elif isinstance(expr, Add): factor, dim = Quantity._collect_factor_and_dimension(expr.args[0]) for addend in expr.args[1:]: addend_factor, addend_dim = \ Quantity._collect_factor_and_dimension(addend) assert dim == addend_dim factor += addend_factor return factor, dim elif isinstance(expr, Function): fds = [ Quantity._collect_factor_and_dimension(arg) for arg in expr.args ] return expr.func(*(f[0] for f in fds)), expr.func(*(d[1] for d in fds)) else: return expr, Dimension(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))
def match_dimensionless_units(lhs_units, rhs_units): '''if lhs_units is dimensionless and rhs_units is not dimensionless, assign rhs_units to lhs_units (and vice versa)''' if lhs_units == Dimension(1): # f = ... if rhs_units != lhs_units: # f = rho[kg/m^3] lhs_units = rhs_units # f[kg/m^3] = rho[kg/m^3] elif rhs_units == Dimension(1): # ... = x if rhs_units != lhs_units: # f[kg/m^3] = x rhs_units = lhs_units # f[kg/m^3] = x[kg/m^3] return lhs_units, rhs_units
def __div__(self, other): if isinstance(other, Dim): if self.name == other.name: return Dim(Dimension(1)) else: return Dim(Dimension(self.name / other.name)) elif isinstance(other, (numbers.Real, sympy.Rational, sympy.Float)): return self else: raise TypeError
def __new__(cls, name, dimension, scale_factor=S.One, abbrev=None, dim_sys=dimsys_default, **assumptions): if not isinstance(name, Symbol): name = Symbol(name) if not isinstance(dim_sys, DimensionSystem): raise TypeError("%s is not a DimensionSystem" % dim_sys) if not isinstance(dimension, dimensions.Dimension): if dimension == 1: dimension = Dimension(1) else: raise ValueError("expected dimension or 1") else: for dim_sym in dimension.name.atoms(Dimension): if dim_sym not in [ i.name for i in dim_sys._dimensional_dependencies ]: raise ValueError("Dimension %s is not registered in the " "dimensional dependency tree." % dim_sym) scale_factor = sympify(scale_factor) dimex = Quantity.get_dimensional_expr(scale_factor) if dimex != 1: if not dim_sys.equivalent_dims(dimension, Dimension(dimex)): raise ValueError("quantity value and dimension mismatch") # replace all prefixes by their ratio to canonical units: scale_factor = scale_factor.replace(lambda x: isinstance(x, Prefix), lambda x: x.scale_factor) # replace all quantities by their ratio to canonical units: scale_factor = scale_factor.replace(lambda x: isinstance(x, Quantity), lambda x: x.scale_factor) if abbrev is None: abbrev = name elif isinstance(abbrev, string_types): abbrev = Symbol(abbrev) obj = AtomicExpr.__new__(cls, name, dimension, scale_factor, abbrev) obj._name = name obj._dimension = dimension obj._scale_factor = scale_factor obj._dim_sys = dim_sys obj._abbrev = abbrev return obj
def _collect_factor_and_dimension(expr): """Return tuple with factor expression and dimension expression.""" if isinstance(expr, Quantity): return expr.scale_factor, expr.dimension elif isinstance(expr, Mul): factor = 1 dimension = Dimension(1) for arg in expr.args: arg_factor, arg_dim = Quantity._collect_factor_and_dimension( arg) factor *= arg_factor dimension *= arg_dim return factor, dimension elif isinstance(expr, Pow): factor, dim = Quantity._collect_factor_and_dimension(expr.base) exp_factor, exp_dim = Quantity._collect_factor_and_dimension( expr.exp) if exp_dim.is_dimensionless: exp_dim = 1 return factor**exp_factor, dim**(exp_factor * exp_dim) elif isinstance(expr, Add): factor, dim = Quantity._collect_factor_and_dimension(expr.args[0]) for addend in expr.args[1:]: addend_factor, addend_dim = \ Quantity._collect_factor_and_dimension(addend) if dim != addend_dim: raise TypeError('Dimension of "{0}" is {1}, ' 'but it should be {2}'.format( addend, addend_dim.name, dim.name)) factor += addend_factor return factor, dim elif isinstance(expr, Derivative): factor, dim = Quantity._collect_factor_and_dimension(expr.args[0]) for independent in expr.args[1:]: ifactor, idim = Quantity._collect_factor_and_dimension( independent) factor /= ifactor dim /= idim return factor, dim elif isinstance(expr, Function): fds = [ Quantity._collect_factor_and_dimension(arg) for arg in expr.args ] return (expr.func(*(f[0] for f in fds)), expr.func(*(d[1] for d in fds))) elif isinstance(expr, Dimension): return 1, expr else: return expr, Dimension(1)
def check_unit(expr): """Construct postprocessor for the addition. Checks for dimension mismatches of the addends, thus preventing expressions like `meter + second` to be created. """ deset = { tuple( sorted( dimsys_default.get_dimensional_dependencies( Dimension( Variable.get_dimensional_expr(i) if not i.is_number else 1 ) ).items() ) ) for i in expr.args } # If `deset` has more than one element, then some dimensions do not # match in the sum: if len(deset) > 1: raise ValueError( "summation of quantities of incompatible dimensions" ) return expr
def get_unit(unit_str, unit_subs=unit_subs): """get the unit quantity corresponding to this string unit_subs should contain a dictonary {symbol: quantity} of custom units not available in sympy""" unit_str = clean_unit(unit_str) units = get_unit_quantities() if unit_subs is not None: units.update(unit_subs) if len(unit_str) == 0: return Dimension(1) unit_expr = parse_expr(unit_str.replace('^', '**'), locals=_clash) try: unit = unit_expr.subs(units) except: raise NameError('something wrong with unit str [{}], type {}, {}'.format( unit_str, type(unit_str), unit_expr)) try: assert len(unit.free_symbols) == 0 except: raise NameError("Unsupported unit: {} {} {}".format( unit_str, type(unit_str), unit.free_symbols)) return unit
def __new__(cls, name, parents, dct): """Build and register new variable.""" if '__registry__' not in dct: unit = dct.pop('unit', S.One) if unit == 1: unit = S.One definition = dct.pop('expr', None) dct.setdefault('name', name) dct.setdefault('assumptions', {'real': True}) dct.setdefault('latex_name', dct['name']) dct.setdefault('unit', unit) instance = super(VariableMeta, cls).__new__(cls, name, parents, dct) # Variable with definition expression. if definition is not None: definition = build_instance_expression(instance, definition) derived_unit = derive_unit(definition, name=name) if unit == S.One: unit = derived_unit # only if unit is None instance.expr, instance.unit = definition, unit dim_derived = dimsys_SI.get_dimensional_dependencies( Variable.get_dimensional_expr(derived_unit)) dim_unit = dimsys_SI.get_dimensional_dependencies( Variable.get_dimensional_expr(unit)) if dim_derived != dim_unit: raise ValueError( 'Invalid expression units {0} should be {1}'.format( instance.unit, unit)) expr = BaseVariable(instance, dct['name'], abbrev=dct['latex_name'], dimension=Dimension( SI.get_dimensional_expr(unit)), scale_factor=unit or S.One, **dct['assumptions']) instance[expr] = instance # Store definition as variable expression. if definition is not None: instance.__expressions__[expr] = definition # Store default variable only if it is defined. if 'default' in dct: instance.__defaults__[expr] = dct['default'] # Store unit for each variable: instance.__units__[expr] = unit return expr return super(VariableMeta, cls).__new__(cls, name, parents, dct)
def _eval_power(self, other): other = sympify(other) if isinstance(other, (numbers.Real, sympy.Rational, sympy.Float)): return Dim(Dimension(self.name**other)) elif isinstance(other, Dim): if other.name == 1: return self else: raise TypeError
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 from sympy.physics.units import Dimension from sympy.physics.units.dimensions import dimsys_SI variables = extract_variables(expr) for var1 in variables: q1 = Quantity('q_' + str(var1)) q1.set_dimension( Dimension(Quantity.get_dimensional_expr(var1.definition.unit))) q1.set_scale_factor(var1.definition.unit) expr = expr.xreplace({var1: q1}) dim = Dimension(Quantity.get_dimensional_expr(expr)) return functools.reduce( operator.mul, (SI_DIMENSIONS[d]**p for d, p in dimsys_SI.get_dimensional_dependencies(dim).items()), 1)
def generate(pset0, dim_list): """generate_index core method""" same = False # same = True comp = pset0.terminals_comp prop = pset0.terminals_prop expr = [] if dim_list[3] != Dim(Dimension(1)): prop_count = [pset0.mapping['powre'], pset0.mapping['pow1'], pset0.mapping['pow2'], pset0.mapping['pow3']] else: prop_count = [pset0.mapping['exp'], pset0.mapping['log'], pset0.mapping['sqrt'], pset0.mapping['powre'], pset0.mapping['pow1'], pset0.mapping['pow2'], pset0.mapping['pow3']] comp_count = [pset0.mapping['exp'], pset0.mapping['log'], pset0.mapping['sqrt'], pset0.mapping['powre'], pset0.mapping['pow1'], pset0.mapping['pow2'], pset0.mapping['pow3']] out1_count = [pset0.mapping['pow1'], ] link_count = [pset0.mapping['Add'], pset0.mapping['Div'], ] out2_count = [pset0.mapping['exp'], pset0.mapping['log'], pset0.mapping['sqrt'], pset0.mapping['pow1'], ] for i in prop_count: for j in comp_count: for l in out1_count: expr.append([prop[0], i, comp[0], j, pset0.mapping['Mul'], l]) expr_list0 = [] for k in range(len(comp)): exprco = copy.deepcopy(expr) for expri in exprco: expri[0] = prop[k] expri[2] = comp[k] expr_list0.append(exprco) if same is True: expr_list = list(zip(*expr_list0)) else: expr_list = list(product(*expr_list0)) expr_list2 = [] for m in out2_count: for t in link_count: exprr = [t] * (len(comp) - 1) exprr.append(m) for exp1 in expr_list: ex = list(chain(*exp1)) expp = ex + exprr expp.reverse() expr_list2.append(expp) return expr_list2
def validate_units(expr, units): result = expr.subs(units, simultaneous=True) if len(result.free_symbols) != 0: return Dimension(1) else: for s, unit in list(units.items()): try: result = result.replace(wildcard(s), unit) except: pass return result
def test_prefix_unit(): length = Dimension("length") m = Quantity("meter", length, 1, abbrev="m") pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]} res = [Quantity("millimeter", length, PREFIXES["m"], abbrev="mm"), Quantity("centimeter", length, PREFIXES["c"], abbrev="cm"), Quantity("decimeter", length, PREFIXES["d"], abbrev="dm")] prefs = prefix_unit(m, pref) assert set(prefs) == set(res) assert set(map(lambda x: x.abbrev, prefs)) == set(symbols("mm,cm,dm"))
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 get_kamodo_unit_system(): """Same as SI but supports anglular frequency""" radian = sympy.physics.units.radian degree = sympy.physics.units.degree si_unit_system = UnitSystem.get_unit_system('SI') si_dimension_system = si_unit_system.get_dimension_system() angle = Dimension('angle', 'A') kamodo_dims = si_dimension_system.extend( new_base_dims=(angle, ), new_derived_dims=[Dimension('angular_velocity')], new_dim_deps={ Symbol('angular_velocity'): { Symbol('angle'): 1, Symbol('time'): -1 } }) kamodo_units = si_unit_system.extend((radian, ), (radian, degree), dimension_system=kamodo_dims) return kamodo_units
def _Quantity_constructor_postprocessor_Add(expr): # Construction postprocessor for the addition, # checks for dimension mismatches of the addends, thus preventing # expressions like `meter + second` to be created. deset = { tuple(Dimension(Quantity.get_dimensional_expr(i)).get_dimensional_dependencies().items()) for i in expr.args if i.free_symbols == set() # do not raise if there are symbols # (free symbols could contain the units corrections) and not i.is_number } # If `deset` has more than one element, then some dimensions do not # match in the sum: if len(deset) > 1: raise ValueError("summation of quantities of incompatible dimensions") return expr
def set_dimension(self, dimension, unit_system="SI"): from sympy.physics.units.dimensions import dimsys_default, DimensionSystem if unit_system != "SI": # TODO: add support for more units and dimension systems: raise NotImplementedError("Currently only SI is supported") dim_sys = dimsys_default if not isinstance(dimension, dimensions.Dimension): if dimension == 1: dimension = Dimension(1) else: raise ValueError("expected dimension or 1") else: for dim_sym in dimension.name.atoms(Dimension): if dim_sym not in [i.name for i in dim_sys._dimensional_dependencies]: raise ValueError("Dimension %s is not registered in the " "dimensional dependency tree." % dim_sym) Quantity.SI_quantity_dimension_map[self] = dimension
def get_unit(unit_str, unit_subs=unit_subs): unit_str = clean_unit(unit_str) units = get_unit_quantities() if unit_subs is not None: units.update(unit_subs) if len(unit_str) == 0: return Dimension(1) try: unit = parse_expr(unit_str.replace('^', '**')).subs(units) except: raise NameError('something wrong with unit str [{}], type {}'.format( unit_str, type(unit_str))) try: assert len(unit.free_symbols) == 0 except: raise ValueError("Unsupported unit: {} {}".format( unit_str, type(unit_str))) return unit
def __setitem__(self, sym_name, input_expr): """Assigns a function or expression to a new symbol, performing unit conversion where necessary """ if self.verbose: print('') try: symbol, args, units, lhs_expr = self.parse_key(sym_name) except KeyError as error: if self.verbose: print(error) found_sym_name = str(error).split('found')[0].strip("'").strip(' ') if self.verbose: print('replacing {}'.format(found_sym_name)) self.remove_symbol(found_sym_name) symbol, args, units, lhs_expr = self.parse_key(sym_name) if hasattr(input_expr, '__call__'): self.register_function(input_expr, symbol, lhs_expr, units) else: rhs_expr = self.parse_value(input_expr, self.symbol_registry) units_map = self.get_units_map() lhs_units = get_unit(units) rhs_units = validate_units( rhs_expr, units_map) # check that rhs units are consistent try: lhs_units, rhs_units = match_dimensionless_units( lhs_units, rhs_units) check_unit_compatibility(rhs_units, lhs_units) except: print(type(rhs_units)) print(get_unit(units), validate_units(rhs_expr, units_map)) raise rhs_expr_with_units = get_expr_with_units(rhs_expr, units_map) if self.verbose: print('rhs_expr with units:', rhs_expr_with_units) # convert back to expression without units for lambdify if units != '': try: if self.verbose: print('converting to {}'.format(lhs_units)) for k, v in list(units_map.items()): print('\t', k, v, type(k)) rhs_expr = get_expr_without_units(rhs_expr_with_units, lhs_units, units_map) if self.verbose: print('rhs_expr without units:', rhs_expr) except: print('error with units? [{}]'.format(units)) raise else: if lhs_units != Dimension( 1): # lhs_units were obtained from rhs_units units = str(lhs_units) rhs_args = rhs_expr.free_symbols if self.verbose: print('lhs_expr:', lhs_expr, 'units:', lhs_units) print('rhs_expr:', rhs_expr, 'units:', rhs_units) try: symbol = self.check_or_replace_symbol(symbol, rhs_args, rhs_expr) self.validate_function(symbol, rhs_expr) except: if self.verbose: print('\n Error in __setitem__', input_expr) print(symbol, lhs_expr, rhs_args) print('symbol registry:', self.symbol_registry) print('signatures:', self.signatures) raise composition = self.get_composition(lhs_expr, rhs_expr) func = self.vectorize_function(symbol, rhs_expr, composition) self.register_signature(symbol, units, lhs_expr, rhs_expr) super(Kamodo, self).__setitem__(symbol, func) super(Kamodo, self).__setitem__(type(symbol), self[symbol]) self.register_symbol(symbol) self[symbol].meta = dict(units=units)
from sympy.physics.units import Dimension angle = Dimension(name="angle") # type: Dimension # base dimensions (MKS) length = Dimension(name="length", symbol="L") mass = Dimension(name="mass", symbol="M") time = Dimension(name="time", symbol="T") # base dimensions (MKSA not in MKS) current = Dimension(name='current', symbol='I') # type: Dimension # other base dimensions: temperature = Dimension("temperature", "T") # type: Dimension amount_of_substance = Dimension("amount_of_substance") # type: Dimension luminous_intensity = Dimension("luminous_intensity") # type: Dimension # derived dimensions (MKS) velocity = Dimension(name="velocity") acceleration = Dimension(name="acceleration") momentum = Dimension(name="momentum") force = Dimension(name="force", symbol="F") energy = Dimension(name="energy", symbol="E") power = Dimension(name="power") pressure = Dimension(name="pressure") frequency = Dimension(name="frequency", symbol="f") action = Dimension(name="action", symbol="A") area = Dimension("area") volume = Dimension("volume")
SI.set_quantity_scale_factor(curie, 37000000000*becquerel) SI.set_quantity_dimension(rutherford, 1 / time) SI.set_quantity_scale_factor(rutherford, 1000000*becquerel) # check that scale factors are the right SI dimensions: for _scale_factor, _dimension in zip( SI._quantity_scale_factors.values(), SI._quantity_dimension_map.values() ): dimex = SI.get_dimensional_expr(_scale_factor) if dimex != 1: # XXX: equivalent_dims is an instance method taking two arguments in # addition to self so this can not work: if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): # type: ignore raise ValueError("quantity value and dimension mismatch") del _scale_factor, _dimension __all__ = [ 'mmHg', 'atmosphere', 'inductance', 'newton', 'meter', 'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage', 'angular_mil', 'luminous_intensity', 'all_units', 'julian_year', 'weber', 'exbibyte', 'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant', 'lightyear', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'planck_momentum', 'bar', 'magnetic_density', 'prefix_unit', 'PREFIXES', 'planck_time', 'dimex', 'gram', 'candela', 'force', 'planck_intensity', 'energy', 'becquerel', 'planck_acceleration', 'speed_of_light', 'conductance', 'frequency', 'coulomb_constant', 'degree', 'lux', 'planck', 'current', 'planck_current', 'tebibyte', 'planck_power', 'MKSA', 'power',
def base_dimensions(d): dependencies = dimsys_SI.get_dimensional_dependencies(d) return Mul.fromiter( Pow(Dimension(base), exp_) for base, exp_ in dependencies.items())
SI.set_quantity_dimension(curie, 1 / time) SI.set_quantity_scale_factor(curie, 37000000000 * becquerel) SI.set_quantity_dimension(rutherford, 1 / time) SI.set_quantity_scale_factor(rutherford, 1000000 * becquerel) # check that scale factors are the right SI dimensions: for _scale_factor, _dimension in zip(SI._quantity_scale_factors.values(), SI._quantity_dimension_map.values()): dimex = SI.get_dimensional_expr(_scale_factor) if dimex != 1: # XXX: equivalent_dims is an instance method taking two arguments in # addition to self so this can not work: if not DimensionSystem.equivalent_dims( _dimension, Dimension(dimex)): # type: ignore raise ValueError("quantity value and dimension mismatch") del _scale_factor, _dimension __all__ = [ 'mmHg', 'atmosphere', 'inductance', 'newton', 'meter', 'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage', 'angular_mil', 'luminous_intensity',
SI.set_quantity_scale_factor(planck_current, planck_charge / planck_time) SI.set_quantity_dimension(planck_voltage, voltage) SI.set_quantity_scale_factor(planck_voltage, planck_energy / planck_charge) SI.set_quantity_dimension(planck_impedance, impedance) SI.set_quantity_scale_factor(planck_impedance, planck_voltage / planck_current) SI.set_quantity_dimension(planck_acceleration, acceleration) SI.set_quantity_scale_factor(planck_acceleration, speed_of_light / planck_time) # Older units for radioactivity SI.set_quantity_dimension(curie, 1 / time) SI.set_quantity_scale_factor(curie, 37000000000*becquerel) SI.set_quantity_dimension(rutherford, 1 / time) SI.set_quantity_scale_factor(rutherford, 1000000*becquerel) # check that scale factors are the right SI dimensions: for _scale_factor, _dimension in zip( SI._quantity_scale_factors.values(), SI._quantity_dimension_map.values() ): dimex = SI.get_dimensional_expr(_scale_factor) if dimex != 1: if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): raise ValueError("quantity value and dimension mismatch") del _scale_factor, _dimension
def summarise_results(logdir): dirlist = os.listdir(logdir) try: dirlist.remove('results.csv') except ValueError: pass dim_dict = {'exp': exp, 'log': log} m = Dimension('length') s = Dimension('time') input_dims = {"grad_u_T1": 1 / s, "grad_u_T2": 1 / s, "grad_u_T3": 1 / s, "grad_u_T4": 1 / s, "k": (m ** 2) / (s ** 2), "inv1": m / m, "inv2": m / m, "T1": m / m, "T2": m / m, "T3": m / m, "T4": m / m} df_results = pd.DataFrame() for run in dirlist: if '.csv' in run: continue run_dir = os.path.join(logdir, run) print(f'Working on: {run}') with open(os.path.join(run_dir, 'config.json'), encoding='utf-8') as f: config_run = json.load(f) output = config_run['task']['dataset']['output'][:4] case = ''.join([letter for letter in config_run['task']['dataset']['name'] if not letter.isnumeric()]) sw = config_run['task']['dataset']['skip_wall'] ntok = config_run['prior']['length']['max_'] run_name = f'{output}_{case}_sw{sw}_{ntok}tokens' results = load_iterations(os.path.join(logdir, run)) df_joined = pd.DataFrame() for key in results: df_joined = pd.concat([df_joined, results[key]], axis=0, ignore_index=True) inputs = config_run['task']['dataset']['input'] for ii in range(len(inputs)): dim_dict[f'x{ii+1}'] = input_dims[inputs[ii]] df_joined = df_joined[~df_joined['batch_r_max_expression'].isna()] df_joined['r_sum'] = df_joined.apply(lambda x: x['r_max_PH'] + x['r_max_CD'] + x['r_max_CBFS'], axis=1) if output == 'kDef': df_joined['dimensions'] = df_joined.apply( lambda x: check_expression_dim(x['batch_r_max_expression'], dim_dict), axis=1) target_dim = (0, 2, -3, 0, 0, 0, 0) if output == 'bDel': target_dim = (0, 0, 0, 0, 0, 0, 0) df_joined['dimensions'] = [(0, 0, 0, 0, 0, 0, 0) for _ in df_joined.index] df_joined = df_joined.drop_duplicates(subset=['batch_r_max_expression']) df_joined['converted_expression'] = df_joined.apply(lambda x: convert_expression(x['batch_r_max_expression'], inputs), axis=1) df_joined['name'] = run_name df_joined['output'] = output df_joined['training_case'] = case df_joined['skip_wall'] = sw if 'tokens' in df_joined.columns: df_joined['ntokens'] = df_joined.apply(lambda x: count_tokens(x['tokens'], ntok), axis=1) else: df_joined['ntokens'] = ntok df_right_dim = df_joined[df_joined['dimensions'] == target_dim] df_right_dim = df_right_dim.drop_duplicates(subset=['batch_r_max_expression']) df_right_dim['correct_dim'] = True # add best on all cases df_best = df_right_dim.sort_values('r_sum', ascending=False).head(70) df_best['rank'] = np.arange(len(df_best)) df_best['ranked_by'] = 'r_sum' df_results = pd.concat([df_results, df_best], axis=0, ignore_index=True) # add best on all cases df_best = df_right_dim.sort_values(f'r_max_{case}', ascending=False).head(70) df_best['rank'] = np.arange(len(df_best)) df_best['ranked_by'] = f'r_max_{case}' df_results = pd.concat([df_results, df_best], axis=0, ignore_index=True) save_arr = df_joined['r_max_PH'].values np.savetxt(os.path.join(logdir, f'LR{config_run["controller"]["learning_rate"]}_ent{config_run["controller"]["entropy_weight"]}_rewards.csv'), save_arr, delimiter=',') plt.figure() plt.hist(df_joined['r_max_PH'], bins=20) plt.title(f'{df_joined["r_max_PH"].max()}') plt.savefig(f'../logs_completed/aa_plots/aatmp_len{config_run["prior"]["length"]["max_"]}_LR{config_run["controller"]["learning_rate"]}_ent{config_run["controller"]["entropy_weight"]}.png') # df_wrong_dim = df_joined[df_joined['dimensions'] != target_dim] # df_wrong_dim = df_wrong_dim.drop_duplicates(subset=['batch_r_max_expression']) # df_wrong_dim['correct_dim'] = False # # # add best on all cases # df_best = df_wrong_dim.sort_values('r_sum', ascending=False).head(70) # df_best['rank'] = np.arange(len(df_best)) # df_best['ranked_by'] = 'r_sum' # df_results = pd.concat([df_results, df_best], axis=0, ignore_index=True) # # # add best on all cases # df_best = df_wrong_dim.sort_values(f'r_max_{case}', ascending=False).head(70) # df_best['rank'] = np.arange(len(df_best)) # df_best['ranked_by'] = f'r_max_{case}' # df_results = pd.concat([df_results, df_best], axis=0, ignore_index=True) save_cols = ['name','rank', 'ranked_by', 'r_max_PH', 'r_max_CD', 'r_max_CBFS', 'r_sum', 'batch_r_max_expression', 'dimensions', 'training_case', 'skip_wall', 'ntokens', 'correct_dim', 'converted_expression'] df_save = df_results[save_cols] df_save = df_save.drop_duplicates(subset=['batch_r_max_expression']) df_save.to_csv(os.path.join(logdir, 'results.csv'),index=False)
def plot_ntokens_r_max(logdir): dirlist = os.listdir(logdir) tokens = [] r_max_PH = [] r_max_CD = [] r_max_CBFS = [] dim_dict = {'exp': exp, 'log': log} m = Dimension('length') s = Dimension('time') input_dims = {"grad_u_T1": 1 / s, "grad_u_T2": 1 / s, "grad_u_T3": 1 / s, "grad_u_T4": 1 / s, "k": (m ** 2) / (s ** 2), "inv1": m / m, "inv2": m / m, "T1": m / m, "T2": m / m, "T3": m / m, "T4": m / m} for run in dirlist: if '.csv' in run: continue run_dir = os.path.join(logdir, run) print(f'Working on: {run}') with open(os.path.join(run_dir, 'config.json'), encoding='utf-8') as f: config_run = json.load(f) output = config_run['task']['dataset']['output'][:4] case = ''.join([letter for letter in config_run['task']['dataset']['name'] if not letter.isnumeric()]) sw = config_run['task']['dataset']['skip_wall'] ntok = config_run['prior']['length']['max_'] run_name = f'{output}_{case}_sw{sw}_{ntok}tokens' results = load_iterations(os.path.join(logdir, run)) df_joined = pd.DataFrame() for key in results: df_joined = pd.concat([df_joined, results[key]], axis=0, ignore_index=True) df_joined['r_sum'] = df_joined.apply(lambda x: x['r_max_PH'] + x['r_max_CD'] + x['r_max_CBFS'], axis=1) inputs = config_run['task']['dataset']['input'] for ii in range(len(inputs)): dim_dict[f'x{ii + 1}'] = input_dims[inputs[ii]] df_joined['dimensions'] = df_joined.apply(lambda x: check_expression_dim(x['batch_r_max_expression'], dim_dict), axis=1) if output == 'kDef': target_dim = (0, 2, -3, 0, 0, 0, 0) if output == 'bDel': target_dim = (0, 0, 0, 0, 0, 0, 0) df_joined = df_joined[df_joined['dimensions'] == target_dim] df_joined['name'] = run_name df_joined['output'] = output df_joined['training_case'] = case df_joined['skip_wall'] = sw if 'tokens' in df_joined.columns: df_joined['ntokens'] = df_joined.apply(lambda x: count_tokens(x['tokens'], ntok), axis=1) else: df_joined['ntokens'] = ntok tokens.append(df_joined['ntokens'].values) r_max_PH.append(df_joined['r_max_PH'].values) r_max_CD.append(df_joined['r_max_CD'].values) r_max_CBFS.append(df_joined['r_max_CBFS'].values) tokens = np.concatenate(tokens, axis=0) r_max_PH = np.concatenate(r_max_PH, axis=0) r_max_CD = np.concatenate(r_max_CD, axis=0) r_max_CBFS = np.concatenate(r_max_CBFS, axis=0) sorted_tokens = [] sorted_r_max_PH = [] sorted_r_max_CD = [] sorted_r_max_CBFS = [] for token in np.unique(tokens): sorted_tokens.append(token) best_model_PH = np.argmax(r_max_PH[tokens == token]) sorted_r_max_PH.append(r_max_PH[tokens == token][best_model_PH]) sorted_r_max_CD.append(r_max_CD[tokens == token][best_model_PH]) sorted_r_max_CBFS.append(r_max_CBFS[tokens == token][best_model_PH]) markersize = 25 lw = 2 width = 7 figsize = (width, 3*width/4) cm = 1 / 2.54 # centimeters in inches plt.figure(figsize=tuple([val*cm for val in list(figsize)])) plt.xlabel(r"$n_{tokens}$") plt.ylabel(r"$r_{max}$") plt.xticks(np.arange(0,25,2)) plt.yticks(np.arange(0,1,0.05)) ax = plt.gca() ax.set_axisbelow(True) plt.grid('both', linestyle=':') plt.plot(sorted_tokens, sorted_r_max_CD, label='$CD_{12600}$', c='C1', linestyle='--', linewidth=lw, marker='^') plt.plot(sorted_tokens, sorted_r_max_CBFS, label='$CBFS_{13700}$', c='C2', linestyle=':', linewidth=lw, marker='v') plt.plot(sorted_tokens, sorted_r_max_PH, label='$PH_{10595}$', c='C0', linestyle=(0, (3, 1, 1, 1)), linewidth=lw, marker='d') order = [2, 0, 1] handles, labels = ax.get_legend_handles_labels() plt.legend(handles=[handles[idx] for idx in order], labels=[labels[idx] for idx in order], ncol=3, loc='center', bbox_to_anchor=(0.5, 1.15), prop={'size': 8}) # ,ncol=4, loc='center', bbox_to_anchor=(0.5, 1.1), prop={'size': 9} plt.savefig(f'../logs_completed/aa_plots/ntokens_r_max{logdir.split("/")[-1]}.eps', format='eps', bbox_inches='tight')
def collect_factor_and_basedimension(expr): """Return tuple with factor expression and dimension expression.""" if isinstance(expr, BaseVariable): expr = expr.definition.unit if isinstance(expr, Quantity): return expr.scale_factor, derive_base_dimension(expr.dimension) elif isinstance(expr, Mul): factor = 1 dimension = Dimension(1) for arg in expr.args: arg_factor, arg_dim = \ Variable.collect_factor_and_basedimension(arg) factor *= arg_factor dimension *= arg_dim return factor, dimension elif isinstance(expr, Pow): factor, dim = Variable.collect_factor_and_basedimension(expr.base) exp_factor, exp_dim = \ Variable.collect_factor_and_basedimension(expr.exp) if exp_dim.is_dimensionless: exp_dim = 1 return factor**exp_factor, derive_base_dimension( dim**(exp_factor * exp_dim)).simplify() elif isinstance(expr, log): return expr, Dimension(1) elif isinstance(expr, Add): factor, dim = \ Variable.collect_factor_and_basedimension(expr.args[0]) for addend in expr.args[1:]: addend_factor, addend_dim = \ Variable.collect_factor_and_basedimension(addend) if dim != addend_dim: raise ValueError( 'Dimension of "{0}" is {1}, ' 'but it should be the same as {2}, i.e. {3}'.format( addend, addend_dim, expr.args[0], dim)) factor += addend_factor return factor, dim elif isinstance(expr, Derivative): factor, dim = \ Variable.collect_factor_and_basedimension(expr.args[0]) for independent, count in expr.variable_count: ifactor, idim = \ Variable.collect_factor_and_basedimension(independent) factor /= ifactor**count dim /= idim**count return factor, dim elif isinstance(expr, Integral): try: Variable.collect_factor_and_basedimension(sum(expr.args[1])) except ValueError: raise ValueError( "Wrong dimensions of integration limits ({expr}).".format( expr=expr)) factor, dim = \ Variable.collect_factor_and_basedimension(expr.args[0] * expr.args[1][0]) return factor, dim elif isinstance(expr, Piecewise): factor, dim = Variable.collect_factor_and_basedimension( sum([x[0] for x in expr.args])) return factor, dim elif isinstance(expr, Function): fds = { Variable.collect_factor_and_basedimension(arg)[1] for arg in expr.args } if fds != {Dimension(1)}: 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: return expr, Dimension(1)