예제 #1
0
    def update_dynamics(self):
        eqs = dict(self.rhs())
        keys = set(eqs.keys())
        symvars = [getattr(self, v) for v in self.vars]
        if keys <= set(self.nodes):
            # by node
            dep = flatten(zip(*symvars))
            expr = flatten(sym.Matrix([eqs[node] for node in self]))
        elif keys <= set(self.vars):
            # by variable
            dep = it.chain.from_iterable(symvars)
            expr = flatten(sym.Matrix([eqs[v] for v in self.vars]))
        else:
            raise ValueError(
                "rhs must map either nodes to rhs or variables to rhs")

        dep_expr = [(d, e + Zero()) for d, e in zip(dep, expr)]
        if any(expr == sym.nan for _, expr in dep_expr):
            raise ValueError(
                "At least one rhs expression is NaN. Missing parameters?")

        self._sys = SymbolicSys(dep_expr, self.t)
        if self.use_native:
            self._native_sys = native_sys[self.integrator].from_other(
                self._sys)

        self._stale_dynamics = False
예제 #2
0
def main(y0='1,0',
         mu=1.0,
         tend=10.,
         nt=50,
         savefig='None',
         plot=False,
         savetxt='None',
         integrator='scipy',
         dpi=100,
         kwargs='',
         verbose=False):
    assert nt > 1
    y = sp.symarray('y', 2)
    p = sp.Symbol('p', real=True)
    f = [y[1], -y[0] + p * y[1] * (1 - y[0]**2)]
    odesys = SymbolicSys(zip(y, f), params=[p], names=True)
    tout = np.linspace(0, tend, nt)
    y0 = list(map(float, y0.split(',')))
    kwargs = dict(eval(kwargs) if kwargs else {})
    xout, yout, info = odesys.integrate(tout,
                                        y0, [mu],
                                        integrator=integrator,
                                        **kwargs)
    if verbose:
        print(info)
    if savetxt != 'None':
        np.savetxt(stack_1d_on_left(xout, yout), savetxt)
    if plot:
        import matplotlib.pyplot as plt
        odesys.plot_result()
        plt.legend()
        if savefig != 'None':
            plt.savefig(savefig, dpi=dpi)
        else:
            plt.show()
예제 #3
0
def numerical_solver(left,
                     right,
                     y0,
                     params=[],
                     params_value=[],
                     tstart=0.,
                     tend=10.,
                     nt=100,
                     plot=False,
                     savetxt='None',
                     savefig='None',
                     integrator='scipy',
                     dpi=100,
                     kwargs='',
                     verbose=False):
    ''' 
    Пояснение:
    y0 - начальные значения для переменных в виде строки 'X0,X1, ..., Xn' 
    tstart,  tend, nt - начало, конец и количество шагов по времени соответственно
    '''
    ''' 
    Zip группирует в соответствии левую и правую часть системы
    x, y = 'x', 'y'
    f = ['x**2 - y', 'y-y**3+x']
    list(zip([x,y], f))   ->   [('x', 'x**2 - y'), ('y', 'y-y**3+x')]
    '''
    odesys = SymbolicSys(zip(left, right), params=params, names=True)
    ''' Создаем точки по t'''
    tout = np.linspace(tstart, tend, nt)
    ''' Преобразуем начальные условия '''
    y0 = list(map(float, y0.split(',')))
    '''kwargs пока не нужен'''
    kwargs = dict(eval(kwargs) if kwargs else {})
    ''' Интегрируем '''
    xout, yout, info = odesys.integrate(tout,
                                        y0,
                                        params_value,
                                        integrator=integrator,
                                        **kwargs)

    return xout, yout, info

    if verbose:
        print(info)
    if savetxt != 'None':
        # stack_1d_on_left(xout, yout) -> [[t_0, x1_0, x2_0, x3_0], ... , [t_n, x1_n, x2_n, x3_n]]
        np.savetxt(savetxt, stack_1d_on_left(xout, yout))
    if plot:
        odesys.plot_result()
        plt.legend()
        plt.figure(figsize=(20, 10))
        if savefig != 'None':
            plt.savefig(savefig, dpi=dpi)
        else:
            plt.show()
예제 #4
0
    def solve(self, initial_conditions, parameters):
        """

        :param initial_conditions:
        :param parameters:
        :return:
        """
        if not isinstance(initial_conditions, dict):
            raise TypeError('Input must be dict. Got "{}"'.format(
                type(initial_conditions)))

        if not isinstance(parameters, dict):
            raise TypeError('Input must be dict. Got "{}"'.format(
                type(parameters)))

        node_names = [i for i in self.ode.keys()]
        ode_list = [i for i in self.ode.values()]
        print(ode_list)
        NotImplementedError('Now make our new ODEs compatible with jitcode')
        SymbolicSys(ode_list)
예제 #5
0
def main(m=1,
         g=9.81,
         l=1,
         q1=.1,
         q2=.2,
         u1=0,
         u2=0,
         tend=10.,
         nt=200,
         savefig='None',
         plot=False,
         savetxt='None',
         integrator='scipy',
         dpi=100,
         kwargs="",
         verbose=False):
    assert nt > 1
    kwargs = dict(eval(kwargs) if kwargs else {})
    odesys = SymbolicSys(get_equations(m, g, l))
    tout = np.linspace(0, tend, nt)
    y0 = [q1, q2, u1, u2]
    xout, yout, info = odesys.integrate(tout,
                                        y0,
                                        integrator=integrator,
                                        **kwargs)
    if verbose:
        print(info)
    if savetxt != 'None':
        np.savetxt(stack_1d_on_left(xout, yout), savetxt)
    if plot:
        import matplotlib.pyplot as plt
        odesys.plot_result(xout, yout)
        if savefig != 'None':
            plt.savefig(savefig, dpi=dpi)
        else:
            plt.show()
예제 #6
0
def _create_odesys(rsys, substance_symbols=None, parameter_symbols=None, pretty_replace=lambda x: x,
                   backend=None, SymbolicSys=None, time_symbol=None, unit_registry=None):
    """ This will be a simpler version of get_odesys without the unit handling code.
    The motivation is to reduce complexity (the code of get_odesys is long with multiple closures).

    This will also rely on SymPy explicitly and the user will be expected to deal with SymPy
    expressions.

    Only when this function has the same capabilities as get_odesys will it become and public API
    (along with a deprecation of get_odesys).

    Parameters
    ----------
    rsys : ReactionSystem instance
    substance_symbols : OrderedDict
       If ``None``: ``rsys.substances`` will be used.
    parameter_symbols : OrderedDict
    backend : str or module
        Symbolic backend (e.g. sympy). The package ``sym`` is used as a wrapper.


    Returns
    -------
    SymbolicSys (subclass of ``pyodesys.ODESys``)
    dict :
        - ``'symbols'``: dict mapping str to symbol.
        - ``'validate'``: callable acppeting a dictionary mapping str to quantities
    """
    if backend is None:
        from sym import Backend
        backend = Backend(backend)
    if SymbolicSys is None:
        from pyodesys.symbolic import SymbolicSys

    if substance_symbols is None:
        substance_symbols = OrderedDict([(key, backend.Symbol(key)) for key in rsys.substances])
    if isinstance(substance_symbols, OrderedDict):
        if list(substance_symbols) != list(rsys.substances):
            raise ValueError("substance_symbols needs to have same (oredered) keys as rsys.substances")

    if parameter_symbols is None:
        keys = []
        for rxn in rsys.rxns:
            uk, = rxn.param.unique_keys
            keys.append(uk)
            for pk in rxn.param.parameter_keys:
                if pk not in keys:
                    keys.append(pk)
        parameter_symbols = OrderedDict([(key, backend.Symbol(key)) for key in keys])

    if not isinstance(parameter_symbols, OrderedDict):
        raise ValueError("parameter_symbols needs to be an OrderedDict")

    symbols = OrderedDict(chain(substance_symbols.items(), parameter_symbols.items()))
    symbols['time'] = time_symbol or backend.Symbol('t')
    if any(symbols['time'] == v for k, v in symbols.items() if k != 'time'):
        raise ValueError("time_symbol already in use (name clash?)")
    rates = rsys.rates(symbols)
    compo_vecs, compo_names = rsys.composition_balance_vectors()

    odesys = SymbolicSys(
        zip([substance_symbols[key] for key in rsys.substances], [rates[key] for key in rsys.substances]),
        symbols['time'],
        parameter_symbols.values(),
        names=list(rsys.substances.keys()),
        latex_names=[s.latex_name for s in rsys.substances.values()],
        param_names=parameter_symbols.keys(),
        latex_param_names=[pretty_replace(n) for n in parameter_symbols.keys()],
        linear_invariants=compo_vecs,
        linear_invariant_names=list(map(str, compo_names)),
        backend=backend,
        dep_by_name=True,
        par_by_name=True
    )

    validate = partial(_validate, rsys=rsys, symbols=symbols, odesys=odesys, backend=backend)
    return odesys, {
        'symbols': symbols,
        'validate': validate,
        'unit_aware_solve': _mk_unit_aware_solve(odesys, unit_registry, validate=validate) if unit_registry else None
    }
예제 #7
0
def _test_render_native_code_cse(NativeSys):
    # regression test taken from chempy
    from pyodesys.symbolic import SymbolicSys
    from sympy import symbols, log, exp
    import numpy as np

    symbs = symbols(
        'N U A L NL t T He_dis Se_dis Cp_dis Tref_dis '
        'He_u Se_u Cp_u Tref_u Ha_agg Sa_agg Ha_as Sa_as Ha_f Sa_f '
        'R h k_B')
    di = {s.name: s for s in symbs}

    class NS:
        pass

    ns = NS()
    ns.__dict__.update(di)

    def _gibbs(H, S, Cp, Tref):
        H2 = H + Cp * (ns.T - Tref)
        S2 = S + Cp * log(ns.T / Tref)
        return exp(-(H2 - ns.T * S2) / (ns.R * ns.T))

    def _eyring(H, S):
        return ns.k_B / ns.h * ns.T * exp(-(H - ns.T * S) / (ns.R * ns.T))

    k_agg = _eyring(di['Ha_agg'], di['Sa_agg'])
    k_as = _eyring(di['Ha_as'], di['Sa_as'])
    k_f = _eyring(di['Ha_f'], di['Sa_f'])
    k_dis = k_as * _gibbs(
        *[di[k] for k in ('He_dis', 'Se_dis', 'Cp_dis', 'Tref_dis')])
    k_u = k_f * _gibbs(*[di[k] for k in ('He_u', 'Se_u', 'Cp_u', 'Tref_u')])
    r_agg = k_agg * ns.U
    r_as = k_as * ns.N * ns.L
    r_f = k_f * ns.U
    r_dis = k_dis * ns.NL
    r_u = k_u * ns.N
    exprs = [
        -r_as + r_f + r_dis - r_u, -r_agg - r_f + r_u, r_agg, r_dis - r_as,
        r_as - r_dis
    ]

    def _solve(odesys, **kwargs):
        default_c0 = defaultdict(float, {'N': 1e-9, 'L': 1e-8})
        params = dict(
            R=8.314472,  # or N_A & k_B
            k_B=1.3806504e-23,
            h=6.62606896e-34,  # k_B/h == 2.083664399411865e10 K**-1 * s**-1
            He_dis=-45e3,
            Se_dis=-400,
            Cp_dis=1.78e3,
            Tref_dis=298.15,
            He_u=60e3,
            Se_u=130.5683,
            Cp_u=20.5e3,
            Tref_u=298.15,
            Ha_agg=106e3,
            Sa_agg=70,
            Ha_as=4e3,
            Sa_as=-10,
            Ha_f=90e3,
            Sa_f=50,
            T=50 + 273.15)
        return odesys.integrate(3600 * 24,
                                [default_c0[s.name] for s in symbs[:5]],
                                [params[s.name] for s in symbs[6:]], **kwargs)

    symbolic = SymbolicSys(zip(symbs[:5], exprs), symbs[5], params=symbs[6:])
    kw = dict(integrator='cvode', nsteps=35000, atol=1e-11, rtol=1e-11)
    ref = _solve(symbolic, **kw)
    assert ref.info['success']

    native = NativeSys.from_other(
        symbolic)  # <-- regression test, optional: save_temp=True
    sol = _solve(native, **kw)
    assert sol.info['success']

    assert np.allclose(sol.yout[-1, :], ref.yout[-1, :])
예제 #8
0
                 Derivative(alpha, t): eq['dot(alpha)'],
                 alpha: eq['alpha']}).\
            doit()
        eq['dot(theta)'][i] = eq['dot(theta)'][i].\
            subs({nu[1]: eq['nu1'],
                  nu[2]: eq['nu2'],
                  Derivative(alpha, t): eq['dot(alpha)'],
                  alpha: eq['alpha']}).\
            doit()  

    psi0, psi1, psi2, theta0, theta1, theta2, x, y, alpha = symbols('psi_0, psi_1, psi_2, theta_0, theta_1, theta_2, x, y, alpha')

    for i in range(3):
        eq['dot(psi)'][i] = subs_symbols(eq['dot(psi)'][i])
        eq['dot(theta)'][i] = subs_symbols(eq['dot(theta)'][i])

    left = [psi0, psi1, psi2, theta0, theta1, theta2]
    right = [eq['dot(psi)'][0], eq['dot(psi)'][1], eq['dot(psi)'][2], eq['dot(theta)'][0], eq['dot(theta)'][1], eq['dot(theta)'][2]]
    print(right)
    print('Количество совпадает:', len(left) == len(right))

    odesys = SymbolicSys(list(zip(left, right)), t, [p, r, d])
    xout, yout, info = odesys.integrate(t_end,
                                        initial_conditions,
                                        params,
                                        integrator='gsl',
                                        method='rk8pd',
                                        atol=1e-11,
                                        rtol=1e-12)

    return xout, yout, info, left, right
예제 #9
0
 def setup(self):
     self.odesys = SymbolicSys(_get_equations(1, 9.81, 1))
     self.tout = np.linspace(0, 10., 200)
     self.y0 = [.1, .2, 0, 0]
예제 #10
0
def _create_odesys(
    rsys,
    substance_symbols=None,
    parameter_symbols=None,
    pretty_replace=lambda x: x,
    backend=None,
    SymbolicSys=None,
    time_symbol=None,
    unit_registry=None,
    rates_kw=None,
    parameter_expressions=None,
    symbolic_kw=None,
):
    """This will be a simpler version of get_odesys without the unit handling code.
    The motivation is to reduce complexity (the code of get_odesys is long with multiple closures).

    This will also rely on SymPy explicitly and the user will be expected to deal with SymPy
    expressions.

    Only when this function has the same capabilities as get_odesys will it become and public API
    (along with a deprecation of get_odesys).

    Parameters
    ----------
    rsys : ReactionSystem instance
    substance_symbols : OrderedDict
       If ``None``: ``rsys.substances`` will be used.
    parameter_symbols : OrderedDict
    backend : str or module
        Symbolic backend (e.g. sympy). The package ``sym`` is used as a wrapper.
    SymbolicSys: class
        See ``pyodesys`` for API.
    time_symbol : Symbol
    unit_registry : object
        e.g. ``chempy.units.SI_base_registry``
    rates_kw : dict
        Keyword arguments passed to the ``rates`` method of rsys.
    parameter_expressions : dict
        Optional overrides.
    symbolic_kw : dict
        Keyword arguments passed on to SymbolicSys.

    Returns
    -------
    SymbolicSys (subclass of ``pyodesys.ODESys``)
    dict :
        - ``'symbols'``: dict mapping str to symbol.
        - ``'validate'``: callable acppeting a dictionary mapping str to quantities
    """
    if backend is None:
        from sym import Backend

        backend = Backend(backend)
    if SymbolicSys is None:
        from pyodesys.symbolic import SymbolicSys

    if substance_symbols is None:
        substance_symbols = OrderedDict([(key, backend.Symbol(key))
                                         for key in rsys.substances])
    if isinstance(substance_symbols, OrderedDict):
        if list(substance_symbols) != list(rsys.substances):
            raise ValueError(
                "substance_symbols needs to have same (oredered) keys as rsys.substances"
            )

    if parameter_symbols is None:
        keys = []
        for rxnpar in map(attrgetter("param"), rsys.rxns):
            if isinstance(rxnpar, str):
                if rxnpar in (parameter_expressions or {}):
                    for pk in parameter_expressions[rxnpar].all_parameter_keys(
                    ):
                        keys.append(pk)
                else:
                    keys.append(rxnpar)
            elif isinstance(rxnpar, Expr):
                keys.extend(rxnpar.all_unique_keys())
                for pk in rxnpar.all_parameter_keys():
                    if pk not in keys:
                        keys.append(pk)
            else:
                raise NotImplementedError("Unknown")
        if rates_kw and "cstr_fr_fc" in rates_kw:
            flowrate_volume, feed_conc = rates_kw["cstr_fr_fc"]
            keys.append(flowrate_volume)
            keys.extend(feed_conc.values())
            assert all(sk in rsys.substances for sk in feed_conc)
        if len(keys) != len(set(keys)):
            raise ValueError("Duplicates in keys")
        parameter_symbols = OrderedDict([(key, backend.Symbol(key))
                                         for key in keys])

    if not isinstance(parameter_symbols, OrderedDict):
        raise ValueError("parameter_symbols needs to be an OrderedDict")

    symbols = OrderedDict(
        chain(substance_symbols.items(), parameter_symbols.items()))
    symbols["time"] = time_symbol or backend.Symbol("t")
    if any(symbols["time"] == v for k, v in symbols.items() if k != "time"):
        raise ValueError("time_symbol already in use (name clash?)")
    varbls = dict(symbols, **parameter_symbols)
    varbls.update(parameter_expressions or {})
    rates = rsys.rates(varbls, **(rates_kw or {}))
    compo_vecs, compo_names = rsys.composition_balance_vectors()

    odesys = SymbolicSys(
        zip(
            [substance_symbols[key] for key in rsys.substances],
            [rates[key] for key in rsys.substances],
        ),
        symbols["time"],
        parameter_symbols.values(),
        names=list(rsys.substances.keys()),
        latex_names=[s.latex_name for s in rsys.substances.values()],
        param_names=parameter_symbols.keys(),
        latex_param_names=[
            pretty_replace(n) for n in parameter_symbols.keys()
        ],
        linear_invariants=compo_vecs,
        linear_invariant_names=list(map(str, compo_names)),
        backend=backend,
        dep_by_name=True,
        par_by_name=True,
        **(symbolic_kw or {}))

    validate = partial(_validate,
                       rsys=rsys,
                       symbols=symbols,
                       odesys=odesys,
                       backend=backend)
    return odesys, {
        "symbols":
        symbols,
        "validate":
        validate,
        "unit_aware_solve":
        _mk_unit_aware_solve(odesys, unit_registry, validate=validate)
        if unit_registry else None,
    }