예제 #1
0
 def setup_model(self):
     """perform all necessary steps to setup the model and make it ready to reproduce the experimental data"""
     self.starting_concentration = self.update_starting_concentration()
     self.model = self.create_reaction_system()
     # create system of ordinary differential equations
     self.odesys, extra = get_odesys(self.model, include_params=False)
     self.time = self.exp_data.index
     self.integration_times, self.org_time_index = self.expand_integration_times(
         self.time)
예제 #2
0
def integration_with_sliders(
    rsys,
    tend,
    c0,
    parameters,
    fig_kwargs=None,
    slider_kwargs=None,
    conc_bounds=None,
    x_axis_type="linear",
    y_axis_type="linear",
    integrate_kwargs=None,
    odesys_extra=None,
    get_odesys_kw=None,
    integrate=None,
):
    """
    Parameters
    ----------
    rsys : ReactionSystem
    tend : float like
    c0 : dict
        Initial concentrations.
    parameters : dict
        Parameter values.
    fig_kwargs : dict
        Keyword-arguments passed to bokeh's ``Figure``.
    slider_kwargs : dict
        Keyword-arguments passed to bokeh's ``Slider``.
    conc_bounds : dict of dicts
        Mapping substance key to dict of bounds ('start', 'end', 'step').
    x_axis_type : str
    y_axis_type : str
    integrate_kwargs : dict
        Keyword-arguments passed to integrate.
    odesys_extra : tuple
        If odesys & extra have already been generated (avoids call to ``get_odesys``).
    get_odesys_kw : dict
        Keyword-arguments passed to ``get_odesys``.
    integrate : callback
        Defaults to ``odesys.integrate``.

    """

    import numpy as np
    from bokeh.plotting import Figure
    from bokeh.models import ColumnDataSource, Column, Row
    from bokeh.models.widgets import Slider

    if slider_kwargs is None:
        slider_kwargs = {}
    if get_odesys_kw is None:
        get_odesys_kw = {}
    if odesys_extra is None:
        odesys, extra = get_odesys(rsys, **get_odesys_kw)
    else:
        odesys, extra = odesys_extra
    if integrate is None:
        integrate = odesys.integrate

    state_keys, rarg_keys, p_units = [
        extra[k] for k in ("param_keys", "unique", "p_units")
    ]
    output_conc_unit = get_odesys_kw.get("output_conc_unit", None)
    output_time_unit = get_odesys_kw.get("output_time_unit", None)
    unit_registry = get_odesys_kw.get("unit_registry", None)
    if output_conc_unit is None:
        if unit_registry is not None:
            raise ValueError(
                "if unit_registry is given, output_conc_unit must also be given"
            )
        output_conc_unit = 1
    if output_time_unit is None:
        if unit_registry is not None:
            raise ValueError(
                "if unit_registry is given, output_time_unit must also be given"
            )
        output_conc_unit = 1

    param_keys = list(chain(state_keys, rarg_keys))
    if x_axis_type == "linear":
        tout = linspace(tend * 0, tend)
    elif x_axis_type == "log":
        tout = logspace_from_lin(tend * 1e-9, tend)
    else:
        raise NotImplementedError("Unknown x_axis_type: %s" % x_axis_type)

    result = integrate(tout, c0, parameters, **(integrate_kwargs or {}))
    sources = [
        ColumnDataSource(
            data={
                "tout": to_unitless(result.xout, output_time_unit),
                k: to_unitless(result.yout[:, idx], output_conc_unit),
            }) for idx, k in enumerate(rsys.substances)
    ]
    if fig_kwargs is None:
        Cmax = np.max(result.yout)
        x_range = list(
            to_unitless([result.xout[0], result.xout[-1]], output_time_unit))
        y_range = list(to_unitless([Cmax * 0, Cmax * 1.1], output_conc_unit))
        fig_kwargs = dict(
            plot_height=400,
            plot_width=400,
            title="C vs t",
            tools="crosshair,pan,reset,save,wheel_zoom",
            x_range=x_range,
            y_range=y_range,
            x_axis_type=x_axis_type,
            y_axis_type=y_axis_type,
        )
    plot = Figure(**fig_kwargs)

    colors = "red green blue black cyan magenta".split()
    for idx, k in enumerate(rsys.substances):
        plot.line(
            "tout",
            k,
            source=sources[idx],
            line_width=3,
            line_alpha=0.6,
            color=colors[idx % len(colors)],
        )

    def _C(k):
        return to_unitless(c0[k], output_conc_unit)

    if p_units is None:
        p_units = [None] * len(param_keys)
    p_ul = [
        to_unitless(parameters[k], _u) for k, _u in zip(param_keys, p_units)
    ]

    def _dict_to_unitless(d, u):
        return {k: to_unitless(v, u) for k, v in d.items()}

    c0_widgets = OrderedDict()
    for k in rsys.substances:
        if conc_bounds is not None and k in conc_bounds:
            if k in slider_kwargs:
                raise ValueError(
                    "Key '%s' both in slider_kwargs and conc_bounds" % k)
            slider_defaults = _dict_to_unitless(conc_bounds[k],
                                                output_conc_unit)
        else:
            ck = _C(k)
            if ck == 0:
                max_ = max(*[_C(k) for k in rsys.substances])
                slider_defaults = dict(start=0, end=max_, step=max_ / 100)
            else:
                slider_defaults = dict(start=_C(k) / 2,
                                       end=_C(k) * 2,
                                       step=_C(k) / 10)
        c0_widgets[k] = Slider(
            title=(k + " / " + output_conc_unit.dimensionality.unicode)
            if hasattr(output_conc_unit, "dimensionality") else k,
            value=_C(k),
            **slider_kwargs.get(k, slider_defaults))

    param_widgets = OrderedDict([(
        k,
        Slider(title=k if u is None else k + " / " + u.dimensionality.unicode,
               value=v,
               **_dict_to_unitless(
                   slider_kwargs.get(
                       k, dict(start=v / 10, end=v * 10, step=v / 10)),
                   u,
               )),
    ) for k, v, u in zip(param_keys, p_ul, p_units)])
    all_widgets = list(chain(param_widgets.values(), c0_widgets.values()))

    def update_data(attrname, old, new):
        _c0 = defaultdict(lambda: 0 * output_conc_unit)
        for k, w in c0_widgets.items():
            _c0[k] = w.value * output_conc_unit
        _params = {}
        for (k, w), u in zip(param_widgets.items(), p_units):
            _params[k] = w.value if u is None else w.value * u
        _result = integrate(tout, _c0, _params)
        for idx, k in enumerate(rsys.substances):
            sources[idx].data = {
                "tout": to_unitless(_result.xout, output_time_unit),
                k: to_unitless(_result.yout[:, idx], output_conc_unit),
            }

    for w in all_widgets:
        w.on_change("value", update_data)

    inputs = Column(children=all_widgets)
    return Row(children=[inputs, plot], width=800)
예제 #3
0
def integration_with_sliders(rsys,
                             tend,
                             c0,
                             parameters,
                             fig_kwargs=None,
                             unit_registry=None,
                             output_conc_unit=None,
                             output_time_unit=None,
                             slider_kwargs=None,
                             x_axis_type="linear",
                             y_axis_type="linear",
                             integrate_kwargs=None,
                             odesys_extra=None,
                             get_odesys_kw=None):
    """
    Parameters
    ----------
    odesys_extra : tuple of :class:`pyodesys.ODESys` & dict
        From :func:`chempy.kinetics.ode.get_odesys`.
    get_odesys_kw : dict
        If odesys_extra is ``None`` the user may pass this for :func:`chempy.kinetics.ode.get_odesys`.
    """

    import numpy as np
    from bokeh.plotting import Figure
    from bokeh.models import ColumnDataSource, HBox, VBoxForm
    from bokeh.models.widgets import Slider

    if slider_kwargs is None:
        slider_kwargs = {}
    if get_odesys_kw is None:
        get_odesys_kw = {}
    if odesys_extra is None:
        odesys, extra = get_odesys(rsys, **get_odesys_kw)
    else:
        odesys, extra = odesys_extra

    state_keys, rarg_keys, p_units = [
        extra[k] for k in ('param_keys', 'unique', 'p_units')
    ]
    if output_conc_unit is None:
        output_conc_unit = 1
    if output_time_unit is None:
        output_conc_unit = 1

    param_keys = list(chain(state_keys, rarg_keys))
    if x_axis_type == 'linear':
        tout = linspace(tend * 0, tend)
    elif x_axis_type == 'log':
        tout = logspace_from_lin(tend * 1e-9, tend)
    else:
        raise NotImplementedError("Unknown x_axis_type: %s" % x_axis_type)

    tout, Cout, info = odesys.integrate(tout, c0, parameters,
                                        **(integrate_kwargs or {}))
    sources = [
        ColumnDataSource(
            data={
                'tout': to_unitless(tout, output_time_unit),
                k: to_unitless(Cout[:, idx], output_conc_unit)
            }) for idx, k in enumerate(rsys.substances)
    ]

    if fig_kwargs is None:
        Cmax = np.max(Cout)
        x_range = list(to_unitless([tend * 0, tend], output_time_unit))
        y_range = list(to_unitless([Cmax * 0, Cmax * 1.1], output_conc_unit))
        fig_kwargs = dict(plot_height=400,
                          plot_width=400,
                          title="C vs t",
                          tools="crosshair,pan,reset,resize,save,wheel_zoom",
                          x_range=x_range,
                          y_range=y_range,
                          x_axis_type=x_axis_type,
                          y_axis_type=y_axis_type)
    plot = Figure(**fig_kwargs)

    colors = 'red green blue black cyan magenta'.split()
    for idx, k in enumerate(rsys.substances):
        plot.line('tout',
                  k,
                  source=sources[idx],
                  line_width=3,
                  line_alpha=0.6,
                  color=colors[idx % len(colors)])

    def _C(k):
        return to_unitless(c0[k], output_conc_unit)

    if p_units is None:
        p_units = [None] * len(param_keys)
    p_ul = [
        to_unitless(parameters[k], _u) for k, _u in zip(param_keys, p_units)
    ]
    c0_widgets = OrderedDict([
        (k,
         Slider(title=k if output_conc_unit is 1 else k + ' / ' +
                output_conc_unit.dimensionality.unicode,
                value=_C(k),
                **slider_kwargs.get(
                    k, dict(start=_C(k) / 2, end=_C(k) * 2, step=_C(k) / 10))))
        for k in rsys.substances
    ])

    def _dict_to_unitless(d, u):
        return {k: to_unitless(v, u) for k, v in d.items()}

    param_widgets = OrderedDict([
        (k,
         Slider(title=k if u is None else k + ' / ' + u.dimensionality.unicode,
                value=v,
                **_dict_to_unitless(
                    slider_kwargs.get(
                        k, dict(start=v / 10, end=v * 10, step=v / 10)), u)))
        for k, v, u in zip(param_keys, p_ul, p_units)
    ])
    all_widgets = list(chain(param_widgets.values(), c0_widgets.values()))

    def update_data(attrname, old, new):
        _c0 = defaultdict(lambda: 0 * output_conc_unit)
        for k, w in c0_widgets.items():
            _c0[k] = w.value * output_conc_unit
        _params = {}
        for (k, w), u in zip(param_widgets.items(), p_units):
            _params[k] = w.value if u is None else w.value * u
        _tout, _Cout, _info = odesys.integrate(tout, _c0, _params)
        for idx, k in enumerate(rsys.substances):
            sources[idx].data = {
                'tout': to_unitless(_tout, output_time_unit),
                k: to_unitless(_Cout[:, idx], output_conc_unit)
            }

    for w in all_widgets:
        w.on_change('value', update_data)

    inputs = VBoxForm(children=all_widgets)
    return HBox(children=[inputs, plot], width=800)
예제 #4
0
H2O = H+ + OH-; 10**-14/55.4
""")
arr, info, sane = eqsys.root(defaultdict(float, {'H2O': 55.4, 'HCO3-': 1e-2}))
conc = dict(zip(eqsys.substances, arr))
from math import log10
print("pH: %.2f" % -log10(conc['H+']))

# 测量离子浓度

from chempy import ReactionSystem  # The rate constants below are arbitrary
rsys = ReactionSystem.from_string("""2 Fe+2 + H2O2 -> 2 Fe+3 + 2 OH-; 42
	   2 Fe+3 + H2O2 -> 2 Fe+2 + O2 + 2 H+; 17
       H+ + OH- -> H2O; 1e10
       H2O -> H+ + OH-; 1e-4""")  # "[H2O]" = 1.0 (actually 55.4 at RT)
from chempy.kinetics.ode import get_odesys
odesys, extra = get_odesys(rsys)
from collections import defaultdict
import numpy as np
tout = sorted(np.concatenate((np.linspace(0, 23), np.logspace(-8, 1))))
c0 = defaultdict(float, {
    'Fe+2': 0.05,
    'H2O2': 0.1,
    'H2O': 1.0,
    'H+': 1e-2,
    'OH-': 1e-12
})
result = odesys.integrate(tout, c0, atol=1e-12, rtol=1e-14)
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
for ax in axes:
    _ = result.plot(names=[k for k in rsys.substances if k != 'H2O'], ax=ax)
예제 #5
0
def integrate_rd(tend=1e2, A0=1.0, B0=0.0, C0=0.0, k1=0.04, k2=1e4, k3=3e7,
                 t0=1e2, nt=100, N=1, nstencil=3, logt=False, logy=False,
                 plot=False, savefig='None', verbose=False, dump_expr='False',
                 use_chempy=False, D=2e-3):
    if N == 1:
        init_conc = (A0, B0, C0)
    else:
        init_conc = np.tile((A0, B0, C0), (N, 1))
        init_conc /= np.linspace(1, 2, N).reshape((N, 1))**.5

    rsys = ReactionSystem(get_reactions((k1, k2, k3)), 'ABC')
    if verbose:
        print([str(_) for _ in rsys.rxns])
    if use_chempy:
        from chempy.kinetics.ode import get_odesys
        odesys = get_odesys(rsys, include_params=True)
        if N != 1:
            raise ValueError("ChemPy does not support diffusion")
        odesys.integrate(np.logspace(log10(t0), log10(tend)), init_conc)
        if plot:
            odesys.plot_result(xscale='log', yscale='log')
        result = None
    else:
        rd = ReactionDiffusion.from_ReactionSystem(
            rsys, N=N, nstencil=1 if N == 1 else nstencil, logt=logt,
            logy=logy, D=[D/2, D/3, D/5])

        if dump_expr.lower() not in ('false', '0'):
            from chemreac.symbolic import SymRD
            import sympy as sp
            cb = {'latex': sp.latex,
                  'ccode': sp.ccode}.get(dump_expr.lower(), str)
            srd = SymRD.from_rd(rd, k=sp.symbols('k:3'))
            print('dydx:')
            print('\n'.join(map(cb, srd._f)))
            print('jac:')
            for ri, row in enumerate(srd.jacobian.tolist()):
                for ci, expr in enumerate(row):
                    if expr == 0:
                        continue
                    print(ri, ci, cb(expr))
            return None

        if t0 == 0 and logt:
            t0 = 1e-3*suggest_t0(rd, init_conc)
            if verbose:
                print("Using t0 = %12.5g" % t0)

        t = np.logspace(np.log10(t0), np.log10(tend), nt)
        print(t[0], t[-1])
        integr = run(rd, init_conc, t)

        if verbose:
            import pprint
            pprint.pprint(integr.info)

        if plot:
            if N == 1:
                plot_C_vs_t(integr, xscale='log', yscale='log')
            else:
                import matplotlib.pyplot as plt
                for idx, name in enumerate('ABC', 1):
                    plt.subplot(1, 3, idx)
                    rgb = [.5, .5, .5]
                    rgb[idx-1] = 1
                    plot_faded_time(integr, name, rgb=rgb, log_color=True)
        result = integr

    if plot:
        save_and_or_show_plot(savefig=savefig)

    return result
예제 #6
0
파일: bkh.py 프로젝트: bjodah/chempy
def integration_with_sliders(
        rsys, tend, c0, parameters, fig_kwargs=None, slider_kwargs=None, conc_bounds=None,
        x_axis_type="linear", y_axis_type="linear", integrate_kwargs=None, odesys_extra=None,
        get_odesys_kw=None, integrate=None):
    """
    Parameters
    ----------
    rsys : ReactionSystem
    tend : float like
    c0 : dict
        Initial concentrations.
    parameters : dict
        Parameter values.
    fig_kwargs : dict
        Keyword-arguments passed to bokeh's ``Figure``.
    slider_kwargs : dict
        Keyword-arguments passed to bokeh's ``Slider``.
    conc_bounds : dict of dicts
        Mapping substance key to dict of bounds ('start', 'end', 'step').
    x_axis_type : str
    y_axis_type : str
    integrate_kwargs : dict
        Keyword-arguments passed to integrate.
    odesys_extra : tuple
        If odesys & extra have already been generated (avoids call to ``get_odesys``).
    get_odesys_kw : dict
        Keyword-arguments passed to ``get_odesys``.
    integrate : callback
        Defaults to ``odesys.integrate``.

    """

    import numpy as np
    from bokeh.plotting import Figure
    from bokeh.models import ColumnDataSource, Column, Row
    from bokeh.models.widgets import Slider

    if slider_kwargs is None:
        slider_kwargs = {}
    if get_odesys_kw is None:
        get_odesys_kw = {}
    if odesys_extra is None:
        odesys, extra = get_odesys(rsys, **get_odesys_kw)
    else:
        odesys, extra = odesys_extra
    if integrate is None:
        integrate = odesys.integrate

    state_keys, rarg_keys, p_units = [extra[k] for k in ('param_keys', 'unique', 'p_units')]
    output_conc_unit = get_odesys_kw.get('output_conc_unit', None)
    output_time_unit = get_odesys_kw.get('output_time_unit', None)
    unit_registry = get_odesys_kw.get('unit_registry', None)
    if output_conc_unit is None:
        if unit_registry is not None:
            raise ValueError("if unit_registry is given, output_conc_unit must also be given")
        output_conc_unit = 1
    if output_time_unit is None:
        if unit_registry is not None:
            raise ValueError("if unit_registry is given, output_time_unit must also be given")
        output_conc_unit = 1

    param_keys = list(chain(state_keys, rarg_keys))
    if x_axis_type == 'linear':
        tout = linspace(tend*0, tend)
    elif x_axis_type == 'log':
        tout = logspace_from_lin(tend*1e-9, tend)
    else:
        raise NotImplementedError("Unknown x_axis_type: %s" % x_axis_type)

    result = integrate(tout, c0, parameters, **(integrate_kwargs or {}))
    sources = [ColumnDataSource(data={
        'tout': to_unitless(result.xout, output_time_unit),
        k: to_unitless(result.yout[:, idx], output_conc_unit)
    }) for idx, k in enumerate(rsys.substances)]
    if fig_kwargs is None:
        Cmax = np.max(result.yout)
        x_range = list(to_unitless([result.xout[0], result.xout[-1]], output_time_unit))
        y_range = list(to_unitless([Cmax*0, Cmax*1.1], output_conc_unit))
        fig_kwargs = dict(plot_height=400, plot_width=400, title="C vs t",
                          tools="crosshair,pan,reset,save,wheel_zoom",
                          x_range=x_range, y_range=y_range, x_axis_type=x_axis_type,
                          y_axis_type=y_axis_type)
    plot = Figure(**fig_kwargs)

    colors = 'red green blue black cyan magenta'.split()
    for idx, k in enumerate(rsys.substances):
        plot.line('tout', k, source=sources[idx], line_width=3, line_alpha=0.6,
                  color=colors[idx % len(colors)])

    def _C(k):
        return to_unitless(c0[k], output_conc_unit)
    if p_units is None:
        p_units = [None]*len(param_keys)
    p_ul = [to_unitless(parameters[k], _u) for k, _u in zip(param_keys, p_units)]

    def _dict_to_unitless(d, u):
        return {k: to_unitless(v, u) for k, v in d.items()}

    c0_widgets = OrderedDict()
    for k in rsys.substances:
        if conc_bounds is not None and k in conc_bounds:
            if k in slider_kwargs:
                raise ValueError("Key '%s' both in slider_kwargs and conc_bounds" % k)
            slider_defaults = _dict_to_unitless(conc_bounds[k], output_conc_unit)
        else:
            ck = _C(k)
            if ck == 0:
                max_ = max(*[_C(k) for k in rsys.substances])
                slider_defaults = dict(start=0, end=max_, step=max_/100)
            else:
                slider_defaults = dict(start=_C(k)/2, end=_C(k)*2, step=_C(k)/10)
        c0_widgets[k] = Slider(
            title=k if output_conc_unit is 1 else k + ' / ' + output_conc_unit.dimensionality.unicode,
            value=_C(k), **slider_kwargs.get(k, slider_defaults)
        )

    param_widgets = OrderedDict([
        (k, Slider(title=k if u is None else k + ' / ' + u.dimensionality.unicode,
                   value=v, **_dict_to_unitless(
                       slider_kwargs.get(k, dict(start=v/10, end=v*10, step=v/10)),
                       u)))
        for k, v, u in zip(param_keys, p_ul, p_units)])
    all_widgets = list(chain(param_widgets.values(), c0_widgets.values()))

    def update_data(attrname, old, new):
        _c0 = defaultdict(lambda: 0*output_conc_unit)
        for k, w in c0_widgets.items():
            _c0[k] = w.value * output_conc_unit
        _params = {}
        for (k, w), u in zip(param_widgets.items(), p_units):
            _params[k] = w.value if u is None else w.value * u
        _result = integrate(tout, _c0, _params)
        for idx, k in enumerate(rsys.substances):
            sources[idx].data = {
                'tout': to_unitless(_result.xout, output_time_unit),
                k: to_unitless(_result.yout[:, idx], output_conc_unit)
            }

    for w in all_widgets:
        w.on_change('value', update_data)

    inputs = Column(children=all_widgets)
    return Row(children=[inputs, plot], width=800)
예제 #7
0
파일: bkh.py 프로젝트: adelq/chempy
def integration_with_sliders(
        rsys, tend, c0, parameters, fig_kwargs=None, unit_registry=None, output_conc_unit=None,
        output_time_unit=None, slider_kwargs=None, x_axis_type="linear", y_axis_type="linear",
        integrate_kwargs=None, substitutions=None):

    import numpy as np
    from bokeh.plotting import Figure
    from bokeh.models import ColumnDataSource, HBox, VBoxForm
    from bokeh.models.widgets import Slider

    if slider_kwargs is None:
        slider_kwargs = {}
    odesys, state_keys, rarg_keys, p_units = get_odesys(
        rsys, unit_registry=unit_registry, substitutions=substitutions,
        output_conc_unit=output_conc_unit,
        output_time_unit=output_time_unit)[:4]
    if output_conc_unit is None:
        output_conc_unit = 1
    if output_time_unit is None:
        output_conc_unit = 1

    param_keys = list(chain(state_keys, rarg_keys))
    if x_axis_type == 'linear':
        tout = linspace(tend*0, tend)
    elif x_axis_type == 'log':
        tout = logspace_from_lin(tend*1e-9, tend)
    else:
        raise NotImplementedError("Unknown x_axis_type: %s" % x_axis_type)

    tout, Cout, info = odesys.integrate(tout, c0, parameters, **(integrate_kwargs or {}))
    sources = [ColumnDataSource(data={
        'tout': to_unitless(tout, output_time_unit),
        k: to_unitless(Cout[:, idx], output_conc_unit)
    }) for idx, k in enumerate(rsys.substances)]

    if fig_kwargs is None:
        Cmax = np.max(Cout)
        x_range = list(to_unitless([tend*0, tend], output_time_unit))
        y_range = list(to_unitless([Cmax*0, Cmax*1.1], output_conc_unit))
        fig_kwargs = dict(plot_height=400, plot_width=400, title="C vs t",
                          tools="crosshair,pan,reset,resize,save,wheel_zoom",
                          x_range=x_range, y_range=y_range, x_axis_type=x_axis_type,
                          y_axis_type=y_axis_type)
    plot = Figure(**fig_kwargs)

    colors = 'red green blue black cyan magenta'.split()
    for idx, k in enumerate(rsys.substances):
        plot.line('tout', k, source=sources[idx], line_width=3, line_alpha=0.6,
                  color=colors[idx % len(colors)])

    def _C(k):
        return to_unitless(c0[k], output_conc_unit)
    p_ul = [to_unitless(parameters[k], _u) for k, _u in zip(param_keys, p_units)]
    c0_widgets = OrderedDict([
        (k, Slider(
            title=k if output_conc_unit is 1 else k + ' / ' + output_conc_unit.dimensionality.unicode,
            value=_C(k), **slider_kwargs.get(k, dict(start=_C(k)/2, end=_C(k)*2, step=_C(k)/10))))
        for k in rsys.substances])

    def _dict_to_unitless(d, u):
        return {k: to_unitless(v, u) for k, v in d.items()}

    param_widgets = OrderedDict([
        (k, Slider(title=k if u is None else k + ' / ' + u.dimensionality.unicode,
                   value=v, **_dict_to_unitless(
                       slider_kwargs.get(k, dict(start=v/10, end=v*10, step=v/10)),
                       u)))
        for k, v, u in zip(param_keys, p_ul, p_units)])
    all_widgets = list(chain(param_widgets.values(), c0_widgets.values()))

    def update_data(attrname, old, new):
        _c0 = defaultdict(lambda: 0*output_conc_unit)
        for k, w in c0_widgets.items():
            _c0[k] = w.value * output_conc_unit
        _params = {}
        for (k, w), u in zip(param_widgets.items(), p_units):
            _params[k] = w.value if u is None else w.value * u
        _tout, _Cout, _info = odesys.integrate(tout, _c0, _params)
        for idx, k in enumerate(rsys.substances):
            sources[idx].data = {
                'tout': to_unitless(_tout, output_time_unit),
                k: to_unitless(_Cout[:, idx], output_conc_unit)
            }

    for w in all_widgets:
        w.on_change('value', update_data)

    inputs = VBoxForm(children=all_widgets)
    return HBox(children=[inputs, plot], width=800)