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