def _validate(conditions, rsys, symbols, odesys, backend=None, transform=None, ignore=('time',)): """ For use with create_odesys Parameters ---------- conditions : OrderedDict Parameters, values with units from ``chempy.units``. rsys : ReactionSystem symbols : dict Mapping variable name to symbols. backend : module Module for symbolic mathematics. (defaults to SymPy) transform : callable for rewriting expressions Raises ------ ``KeyError`` if a key in conditions is not in odesys.names or odesys.param_names """ if backend is None: from sym import Backend backend = Backend(backend) if transform is None: if backend.__name__ != 'sympy': warnings.warn("Backend != SymPy, provide your own transform function.") def transform(arg): expr = backend.logcombine(arg, force=True) v, w = map(backend.Wild, 'v w'.split()) expr = expr.replace(backend.log(w**v), v*backend.log(w)) return expr args = [symbols[key] for key in conditions] seen = [False]*len(args) rates = {} for k, v in rsys.rates(symbols).items(): expr = transform(v) if expr == 0: rate = 0 * u.molar/u.second else: rate = backend.lambdify(args, expr)(*conditions.values()) to_unitless(rate, u.molar/u.second) rates[k] = rate seen = [b or a in expr.free_symbols for b, a in zip(seen, args)] not_seen = [a for s, a in zip(seen, args) if not s] for k in conditions: if k not in odesys.param_names and k not in odesys.names and k not in ignore: raise KeyError("Unknown param: %s" % k) return {'not_seen': not_seen, 'rates': rates}
def _validate( conditions, rsys, symbols, odesys, backend=None, transform=None, ignore=("time", ), check_conditions_no_extra=False, ): """For use with create_odesys Parameters ---------- conditions : OrderedDict Parameters, values with units from ``chempy.units``. rsys : ReactionSystem symbols : dict Mapping variable name to symbols. backend : module Module for symbolic mathematics. (defaults to SymPy) transform : callable for rewriting expressions check_conditions_no_extra : bool When True, conditions may not contain keys not referenced in any expression. Raises ------ ``KeyError`` if a key in conditions is not in odesys.names or odesys.param_names """ if backend is None: from sym import Backend backend = Backend(backend) if transform is None: if backend.__name__ != "sympy": warnings.warn( "Backend != SymPy, provide your own transform function.") def transform(arg): expr = backend.logcombine(arg, force=True) v, w = map(backend.Wild, "v w".split()) return expr.replace(backend.log(w**v), v * backend.log(w)) rates = {} seen = set() for k, v in rsys.rates(symbols).items(): expr = transform(v) if expr == 0: rate = 0 * u.molar / u.second else: rate = None for term in (expr.args if hasattr(expr, "is_Add") and expr.is_Add else (expr, )): args = sorted(expr.free_symbols, key=lambda e: e.name) values = [conditions[s.name] for s in args] result = backend.lambdify(args, term)(*map(_exact, values)) to_unitless(result, u.molar / u.second) # raises an exception upon unit error if rate is None: rate = result else: rate += result rates[k] = rate seen |= set([s.name for s in expr.free_symbols]) if check_conditions_no_extra: for k in conditions: if (k not in odesys.param_names and k not in odesys.names and k not in ignore): raise KeyError("Unknown param: %s" % k) return { "not_seen": (set(rsys.substances) | set(conditions)) - seen, "rates": rates }