def test_get_odesys_3(): M = u.molar s = u.second mol = u.mol m = u.metre substances = list(map(Substance, 'H2O H+ OH-'.split())) dissociation = Reaction({'H2O': 1}, {'H+': 1, 'OH-': 1}, 2.47e-5/s) recombination = Reaction({'H+': 1, 'OH-': 1}, {'H2O': 1}, 1.37e11/M/s) rsys = ReactionSystem([dissociation, recombination], substances) odesys = get_odesys( rsys, include_params=True, unit_registry=SI_base_registry, output_conc_unit=M)[0] c0 = {'H2O': 55.4*M, 'H+': 1e-7*M, 'OH-': 1e-4*mol/m**3} x, y, p = odesys.to_arrays(-42*u.second, rsys.as_per_substance_array(c0, unit=M), ()) fout = odesys.f_cb(x, y, p) time_unit = get_derived_unit(SI_base_registry, 'time') conc_unit = get_derived_unit(SI_base_registry, 'concentration') r1 = to_unitless(55.4*2.47e-5*M/s, conc_unit/time_unit) r2 = to_unitless(1e-14*1.37e11*M/s, conc_unit/time_unit) assert np.all(abs(fout[:, 0] - r2 + r1)) < 1e-10 assert np.all(abs(fout[:, 1] - r1 + r2)) < 1e-10 assert np.all(abs(fout[:, 2] - r1 + r2)) < 1e-10
def render_setup(self, *, ics, atol, tex=True, tspan=None): export = "" export += "p = %s\n" % jl_dict(self.pars) export += "ics = %s\n" % jl_dict( OrderedDict({ self.substance_key_map[k]: v for k, v in to_unitless(ics, u.molar).items() })) if atol: export += "abstol_d = %s\n" % jl_dict({ self.substance_key_map[k]: v for k, v in to_unitless(atol, u.molar).items() }) export += "abstol = Array([get(abstol_d, k, 1e-10) for k=keys(speciesmap(rn))])" if tex: export += "subst_tex = Dict([%s])\n" % ", ".join( '(:%s, ("%s", "%s"))' % (v, k, self.latex_names[k]) for k, v in self.substance_key_map.items()) if tspan: export += """\ tspan = (0., %12.5g) u0 = Array([get(ics, k, 1e-28) for k=keys(speciesmap(rn))]) parr = Array([p[k] for k=keys(paramsmap(rn))]) oprob = ODEProblem(rn, u0, tspan, parr) """ return export
def check(rsys): odesys, extra = get_odesys(rsys, unit_registry=SI_base_registry, constants=const) res = odesys.integrate(t, init_cond, params, integrator='cvode') NOBr_ref = NOBr0_M*np.exp(-kref*to_unitless(res.xout, u.second)) ref = np.array([NOBr_ref] + [NOBr0_M - NOBr_ref]*2).T cmp = to_unitless(res.yout, u.M) assert np.allclose(cmp, ref)
def check(rsys): odesys, extra = get_odesys(rsys, unit_registry=SI_base_registry, constants=const) res = odesys.integrate(t, init_cond, params, integrator='cvode') NOBr_ref = NOBr0_M*np.exp(-kref*to_unitless(res.xout, u.second)) ref = np.array([NOBr_ref] + [NOBr0_M - NOBr_ref]*2).T cmp = to_unitless(res.yout, u.M) assert np.allclose(cmp, ref)
def test_get_odesys_3(): M = u.molar s = u.second mol = u.mol m = u.metre substances = list(map(Substance, 'H2O H+ OH-'.split())) dissociation = Reaction({'H2O': 1}, {'H+': 1, 'OH-': 1}, 2.47e-5/s) recombination = Reaction({'H+': 1, 'OH-': 1}, {'H2O': 1}, 1.37e11/M/s) rsys = ReactionSystem([dissociation, recombination], substances) odesys = get_odesys( rsys, include_params=True, unit_registry=SI_base_registry, output_conc_unit=M)[0] c0 = {'H2O': 55.4*M, 'H+': 1e-7*M, 'OH-': 1e-4*mol/m**3} x, y, p = odesys.pre_process(-42*u.second, rsys.as_per_substance_array(c0, unit=M)) fout = odesys.f_cb(x, y, p) time_unit = get_derived_unit(SI_base_registry, 'time') conc_unit = get_derived_unit(SI_base_registry, 'concentration') r1 = to_unitless(55.4*2.47e-5*M/s, conc_unit/time_unit) r2 = to_unitless(1e-14*1.37e11*M/s, conc_unit/time_unit) assert abs(fout[0] - r2 + r1) < 1e-10 assert abs(fout[1] - r1 + r2) < 1e-10 assert abs(fout[2] - r1 + r2) < 1e-10
def check(rsys): odesys, extra = get_odesys(rsys, unit_registry=SI_base_registry, constants=const) res = odesys.integrate(t, init_cond, params, integrator='cvode') t_sec = to_unitless(res.xout, u.second) NOBr_ref = analytic_b(t_sec) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index('NOBr')] = NOBr_ref ref[:, odesys.names.index('Br')] = Br0_M - NOBr_ref ref[:, odesys.names.index('NO')] = NO0_M - NOBr_ref assert np.allclose(cmp, ref)
def check(rsys): odesys, extra = get_odesys(rsys, unit_registry=SI_base_registry, constants=const) res = odesys.integrate(t, init_cond, params, integrator='cvode') t_sec = to_unitless(res.xout, u.second) NOBr_ref = analytic_b(t_sec) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index('NOBr')] = NOBr_ref ref[:, odesys.names.index('Br')] = Br0_M - NOBr_ref ref[:, odesys.names.index('NO')] = NO0_M - NOBr_ref assert np.allclose(cmp, ref)
def check(rsys): odes, extra = get_odesys(rsys, unit_registry=SI_base_registry, constants=const, substitutions={ 'temperature': RampedTemp([T_K*u.K, dTdt_Ks*u.K/u.s])}) for odesys in [odes, odes.as_autonomous()]: res = odesys.integrate(t, init_cond, integrator='cvode') t_sec = to_unitless(res.xout, u.second) NO2_ref = analytic_unit0(t_sec, dTdt_Ks, T_K, dH, dS) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index('NO2')] = NO2_ref ref[:, odesys.names.index('N2O4')] = (NO2_M - NO2_ref)/2 assert np.allclose(cmp, ref)
def check(rsys): odes, extra = get_odesys(rsys, unit_registry=SI_base_registry, constants=const, substitutions={ 'temperature': RampedTemp([T_K*u.K, dTdt_Ks*u.K/u.s])}) for odesys in [odes, odes.as_autonomous()]: res = odesys.integrate(t, init_cond, integrator='cvode') t_sec = to_unitless(res.xout, u.second) NO2_ref = analytic_unit0(t_sec, dTdt_Ks, T_K, dH, dS) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index('NO2')] = NO2_ref ref[:, odesys.names.index('N2O4')] = (NO2_M - NO2_ref)/2 assert np.allclose(cmp, ref)
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) }
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), }
def check(rsys, params): odes, extra = get_odesys(rsys, include_params=False, unit_registry=SI_base_registry, constants=const) for odesys in [odes, odes.as_autonomous()]: res = odesys.integrate(t, init_cond, params, integrator='cvode') t_sec = to_unitless(res.xout, u.second) FeSCN_ref = binary_rev(t_sec, kf_ref, kb_ref, 0, Fe0, SCN0) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index('FeSCN+2')] = FeSCN_ref ref[:, odesys.names.index('Fe+3')] = Fe0 - FeSCN_ref ref[:, odesys.names.index('SCN-')] = SCN0 - FeSCN_ref assert np.allclose(cmp, ref)
def check(rsys, params): odes, extra = get_odesys(rsys, include_params=False, unit_registry=SI_base_registry, constants=const) for odesys in [odes, odes.as_autonomous()]: res = odesys.integrate(t, init_cond, params, integrator='cvode') t_sec = to_unitless(res.xout, u.second) FeSCN_ref = binary_rev(t_sec, kf_ref, kb_ref, 0, Fe0, SCN0) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index('FeSCN+2')] = FeSCN_ref ref[:, odesys.names.index('Fe+3')] = Fe0 - FeSCN_ref ref[:, odesys.names.index('SCN-')] = SCN0 - FeSCN_ref assert np.allclose(cmp, ref)
def test_get_native__Radiolytic__named_parameter__units(dep_scaling): rsys = ReactionSystem.from_string(""" -> H; Radiolytic(2*per100eV) H + H -> H2; 'k2' """, checks=('substance_keys', 'duplicate', 'duplicate_names')) gval = 2 * u.per100eV from pyodesys.symbolic import ScaledSys kwargs = {} if dep_scaling == 1 else dict(SymbolicSys=ScaledSys, dep_scaling=dep_scaling) odesys, extra = get_odesys(rsys, include_params=False, unit_registry=SI_base_registry, **kwargs) c0 = {'H': 42e-6 * u.molar, 'H2': 17e3 * u.nanomolar} native = get_native(rsys, odesys, 'cvode') tend = 7 * 60 * u.minute params = { 'doserate': 314 * u.Gy / u.hour, 'k2': 53 / u.molar / u.minute, 'density': 998 * u.g / u.dm3 } result = native.integrate(tend, c0, params, atol=1e-15, rtol=1e-15, integrator='cvode', nsteps=8000) assert result.info['success'] def analytic_H(t, p, k, H0): # dH/dt = p - k2*H**2 x0 = np.sqrt(2) * np.sqrt(p) x1 = x0 x2 = np.sqrt(k) x3 = t * x1 * x2 x4 = H0 * x2 x5 = np.sqrt(x0 + 2 * x4) x6 = np.sqrt(-1 / (2 * H0 * x2 - x0)) x7 = x5 * x6 * np.exp(x3) x8 = np.exp(-x3) / (x5 * x6) return x1 * (x7 - x8) / (2 * x2 * (x7 + x8)) t_ul = to_unitless(result.xout, u.s) p_ul = to_unitless(params['doserate'] * params['density'] * gval, u.micromolar / u.s) ref_H_uM = analytic_H(t_ul, p_ul, to_unitless(params['k2'], 1 / u.micromolar / u.s), to_unitless(c0['H'], u.micromolar)) ref_H2_uM = to_unitless(c0['H2'], u.micromolar) + to_unitless( c0['H'], u.micromolar) / 2 + t_ul * p_ul / 2 - ref_H_uM / 2 assert np.allclose(to_unitless(result.named_dep('H'), u.micromolar), ref_H_uM) assert np.allclose(to_unitless(result.named_dep('H2'), u.micromolar), ref_H2_uM)
def test_get_native__named_parameter__units(dep_scaling): rsys = ReactionSystem.from_string( """ -> H; 'p' H + H -> H2; 'k2' """, checks=("substance_keys", "duplicate", "duplicate_names"), ) from pyodesys.symbolic import ScaledSys kwargs = ({} if dep_scaling == 1 else dict(SymbolicSys=ScaledSys, dep_scaling=dep_scaling)) odesys, extra = get_odesys(rsys, include_params=False, unit_registry=SI_base_registry, **kwargs) c0 = {"H": 42e-6 * u.molar, "H2": 17 * u.micromolar} native = get_native(rsys, odesys, "cvode") tend = 7 * 60 * u.minute g_rho_Ddot = g, rho, Ddot = 2 * u.per100eV, 998 * u.g / u.dm3, 314 * u.Gy / u.hour params = {"p": reduce(mul, g_rho_Ddot), "k2": 53 / u.molar / u.minute} result = native.integrate(tend, c0, params, atol=1e-15, rtol=1e-15, integrator="cvode", nsteps=16000) assert result.info["success"] def analytic_H(t, p, k, H0): # dH/dt = p - k2*H**2 x0 = np.sqrt(2) * np.sqrt(p) x1 = x0 x2 = np.sqrt(k) x3 = t * x1 * x2 x4 = H0 * x2 x5 = np.sqrt(x0 + 2 * x4) x6 = np.sqrt(-1 / (2 * H0 * x2 - x0)) x7 = x5 * x6 * np.exp(x3) x8 = np.exp(-x3) / (x5 * x6) return x1 * (x7 - x8) / (2 * x2 * (x7 + x8)) t_ul = to_unitless(result.xout, u.s) p_ul = to_unitless(params["p"], u.micromolar / u.s) ref_H_uM = analytic_H( t_ul, p_ul, to_unitless(params["k2"], 1 / u.micromolar / u.s), to_unitless(c0["H"], u.micromolar), ) ref_H2_uM = (to_unitless(c0["H2"], u.micromolar) + to_unitless(c0["H"], u.micromolar) / 2 + t_ul * p_ul / 2 - ref_H_uM / 2) assert np.allclose(to_unitless(result.named_dep("H"), u.micromolar), ref_H_uM) assert np.allclose(to_unitless(result.named_dep("H2"), u.micromolar), ref_H2_uM)
def test_get_odesys__with_units(): a = Substance('A') b = Substance('B') molar = u.molar second = u.second r = Reaction({'A': 2}, {'B': 1}, param=1e-3/molar/second) rsys = ReactionSystem([r], [a, b]) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = { 'A': 13*u.mol / u.metre**3, 'B': .2 * u.molar } conc_unit = get_derived_unit(SI_base_registry, 'concentration') t = np.linspace(0, 10)*u.hour xout, yout, info = odesys.integrate( t, rsys.as_per_substance_array(c0, unit=conc_unit), atol=1e-10, rtol=1e-12) t_unitless = to_unitless(xout, u.second) Aref = dimerization_irrev(t_unitless, 1e-6, 13.0) # Aref = 1/(1/13 + 2*1e-6*t_unitless) yref = np.zeros((xout.size, 2)) yref[:, 0] = Aref yref[:, 1] = 200 + (13-Aref)/2 print((yout - yref*conc_unit)/yout) assert allclose(yout, yref*conc_unit)
def test_ArrheniusMassAction__units(R_from_constants): import numpy as np Ea = 40e3 * u.J / u.mol R = (default_constants.molar_gas_constant if R_from_constants else (8.3145 * u.J / u.mol / u.K)) A, Ea_over_R = 1.2e11 / u.molar**2 / u.second, Ea / R ref1 = A * np.exp(-to_unitless(Ea_over_R / (290 * u.K))) arrh = Arrhenius([A, Ea_over_R]) assert allclose(arrh({"temperature": 290 * u.K}), ref1) ama = MassAction(arrh) r = Reaction({"A": 2, "B": 1}, {"C": 1}, ama, {"B": 1}) T_ = "temperature" def ref(v): return (1.2e11 / u.molar**2 / u.second * math.exp(-Ea_over_R.simplified / v[T_]) * v["B"] * v["A"]**2) ma = r.rate_expr() for params in [ (11.0 * u.molar, 13.0 * u.molar, 17.0 * u.molar, 311.2 * u.kelvin), (12 * u.molar, 8 * u.molar, 5 * u.molar, 270 * u.kelvin), ]: var = dict(zip(["A", "B", "C", T_], params)) ref_val = ref(var) assert abs((ma(var, reaction=r) - ref_val) / ref_val) < 1e-14
def test_create_odesys(): rsys = ReactionSystem.from_string(""" A -> B; 'k1' B + C -> P; 'k2' """, substance_factory=Substance) odesys, odesys_extra = create_odesys(rsys, unit_registry=SI_base_registry) tend = 10 c0 = {'A': 1e-6, 'B': 0, 'C': 1, 'P': 0} p = dict(k1=3, k2=4) tend_units = tend*u.s p_units = {'k1': p['k1']/u.s, 'k2': p['k2']/u.M/u.s} c0_units = {k: v*u.molar for k, v in c0.items()} validation = odesys_extra['validate'](dict(c0_units, **p_units)) P, = validation['not_seen'] assert P.name == 'P' ref_rates = {'A': -p_units['k1']*c0_units['A'], 'P': p_units['k2']*c0_units['B']*c0_units['C']} ref_rates['B'] = -ref_rates['A'] - ref_rates['P'] ref_rates['C'] = -ref_rates['P'] assert validation['rates'] == ref_rates result1, result1_extra = odesys_extra['unit_aware_solve']( tend_units, c0_units, p_units, integrator='cvode') assert result1.info['success'] result2 = odesys.integrate(tend, c0, p, integrator='cvode') assert np.allclose(result2.yout[-1, :], to_unitless(result1.yout[-1, :], u.molar))
def _check(r): res = r({ "doserate": 0.15 * u.gray / u.second, "density": 0.998 * u.kg / u.decimetre**3, }) ref = 0.15 * 0.998 * 2.1e-7 * u.molar / u.second assert abs(to_unitless((res - ref) / ref)) < 1e-15
def test_get_odesys__with_units(): a = Substance('A') b = Substance('B') molar = u.molar second = u.second r = Reaction({'A': 2}, {'B': 1}, param=1e-3/molar/second) rsys = ReactionSystem([r], [a, b]) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = { 'A': 13*u.mol / u.metre**3, 'B': .2 * u.molar } conc_unit = get_derived_unit(SI_base_registry, 'concentration') t = np.linspace(0, 10)*u.hour xout, yout, info = odesys.integrate( t, rsys.as_per_substance_array(c0, unit=conc_unit), atol=1e-10, rtol=1e-12) t_unitless = to_unitless(xout, u.second) Aref = dimerization_irrev(t_unitless, 1e-6, 13.0) # Aref = 1/(1/13 + 2*1e-6*t_unitless) yref = np.zeros((xout.size, 2)) yref[:, 0] = Aref yref[:, 1] = 200 + (13-Aref)/2 assert allclose(yout, yref*conc_unit)
def test_create_odesys(): rsys = ReactionSystem.from_string(""" A -> B; 'k1' B + C -> P; 'k2' """, substance_factory=Substance) odesys, odesys_extra = create_odesys(rsys, unit_registry=SI_base_registry) tend = 10 c0 = {'A': 1e-6, 'B': 0, 'C': 1, 'P': 0} p = dict(k1=3, k2=4) tend_units = tend*u.s p_units = {'k1': p['k1']/u.s, 'k2': p['k2']/u.M/u.s} c0_units = {k: v*u.molar for k, v in c0.items()} validation = odesys_extra['validate'](dict(c0_units, **p_units)) P, = validation['not_seen'] assert P.name == 'P' ref_rates = {'A': -p_units['k1']*c0_units['A'], 'P': p_units['k2']*c0_units['B']*c0_units['C']} ref_rates['B'] = -ref_rates['A'] - ref_rates['P'] ref_rates['C'] = -ref_rates['P'] assert validation['rates'] == ref_rates result1, result1_extra = odesys_extra['unit_aware_solve']( tend_units, c0_units, p_units, integrator='cvode') assert result1.info['success'] result2 = odesys.integrate(tend, c0, p, integrator='cvode') assert np.allclose(result2.yout[-1, :], to_unitless(result1.yout[-1, :], u.molar))
def decompose_yields(yields, rxns, atol=1e-10): """ Decomposes yields into mass-action reactions This function offers a way to express a reaction with non-integer stoichiometric coefficients as a linear combination of production reactions with integer coefficients. Ak = y A is (n_species x n_reactions) matrix, k is "rate coefficient", y is yields Parameters ---------- yields : OrderedDict Specie names as keys and yields as values. rxns : iterable :class:`Reaction` instances Dict keys must match those of ``yields`` each pair of dictionaries gives stoichiometry (1st is reactant, 2nd is products). atol : float Absolute tolerance for residuals. Examples -------- >>> from chempy import Reaction >>> h2a = Reaction({'H2O': 1}, {'H2': 1, 'O': 1}) >>> h2b = Reaction({'H2O': 1}, {'H2': 1, 'H2O2': 1}, inact_reac={'H2O': 1}) >>> decompose_yields({'H2': 3, 'O': 2, 'H2O2': 1}, [h2a, h2b]) array([2., 1.]) Raises ------ ValueError When atol is exceeded numpy.LinAlgError When numpy.linalg.lstsq fails to converge Returns ------- 1-dimensional array of effective rate coefficients. """ from chempy import ReactionSystem # Sanity check: rxn_keys = set.union(*(rxn.keys() for rxn in rxns)) for key in yields.keys(): if key not in rxn_keys: raise ValueError("Substance key: %s not in reactions" % key) rsys = ReactionSystem(rxns, rxn_keys) A = rsys.net_stoichs(yields.keys()) b = list(yields.values()) unit = unit_of(b[0]) x, residuals, rank, s = np.linalg.lstsq( np.asarray(A.T, dtype=np.float64), to_unitless(b, unit), rcond=2e-16*max(A.shape)) if len(residuals) > 0: if np.any(residuals > atol): raise ValueError("atol not satisfied") return x*unit
def decompose_yields(yields, rxns, atol=1e-10): """ Decomposes yields into mass-action reactions This function offers a way to express a reaction with non-integer stoichiometric coefficients as a linear combination of production reactions with integer coefficients. Ak = y A is (n_species x n_reactions) matrix, k is "rate coefficient", y is yields Parameters ---------- yields: OrderedDict specie names as keys and yields as values rxns: iterable :class:`Reaction` instances dict keys must match those of ``yields`` each pair of dictionaries gives stoichiometry (1st is reactant, 2nd is products) atol: float absolute tolerance for residuals Examples -------- >>> from chempy import Reaction >>> h2a = Reaction({'H2O': 1}, {'H2': 1, 'O': 1}) >>> h2b = Reaction({'H2O': 1}, {'H2': 1, 'H2O2': 1}, inact_reac={'H2O': 1}) >>> decompose_yields({'H2': 3, 'O': 2, 'H2O2': 1}, [h2a, h2b]) array([ 2., 1.]) Raises ------ ValueError When atol is exceeded numpy.LinAlgError When numpy.linalg.lstsq fails to converge Returns ------- 1-dimensional array of effective rate coefficients. """ from chempy import ReactionSystem # Sanity check: rxn_keys = set.union(*(rxn.keys() for rxn in rxns)) for key in yields.keys(): if key not in rxn_keys: raise ValueError("Substance key: %s not in reactions" % key) rsys = ReactionSystem(rxns, rxn_keys) A = rsys.net_stoichs(yields.keys()) b = list(yields.values()) unit = unit_of(b[0]) x, residuals, rank, s = np.linalg.lstsq(A.T, to_unitless(b, unit)) if len(residuals) > 0: if np.any(residuals > atol): raise ValueError("atol not satisfied") return x*unit
def _check(r): res = r({ 'doserate': 0.15 * u.gray / u.second, 'density': 0.998 * u.kg / u.decimetre**3, 'temperature': 298.15 * u.K }) ref = 0.15 * 0.998 * 2.1e-7 * u.molar / u.second assert abs(to_unitless((res - ref) / ref)) < 1e-15
def _r(r, p, doserate, substmap, parmap, density=998 * u.kg / u.m3, unit_conc=u.molar, unit_time=u.second): pk, = r.param.unique_keys if isinstance(r.param, MassAction): ratcoeff = to_unitless(p[pk], unit_conc**(1 - r.order()) / unit_time) if not r.inact_reac: r_str = '{}, {}'.format( parmap[pk], r.string(substances=substmap, with_param=False, Reaction_arrow='-->', Reaction_coeff_space='')) else: all_keys = r.keys() reac_stoichs = r.all_reac_stoich(all_keys) act_stoichs = r.active_reac_stoich(all_keys) rate = '*'.join([parmap[pk]] + [('%s^%d' % (substmap[k], v)) if v > 1 else substmap[k] for k, v in zip(all_keys, act_stoichs) if v > 0]) r2 = Reaction( dict([(k, v) for k, v in zip(all_keys, reac_stoichs) if v]), r.prod) r_str = '{}, {}'.format( rate, r2.string(substances=substmap, with_param=False, Reaction_arrow='\u21D2', Reaction_coeff_space='')) elif isinstance(r.param, RadiolyticBase): ratcoeff = to_unitless(p[pk] * doserate * density, unit_conc / unit_time) assert not r.reac and not r.inact_reac and not r.inact_prod (prod, n), = r.prod.items() assert n == 1 r_str = ('{}, 0 \u21D2 {}' if ratcoeff > 0 else '{}, {} \u21D2 0').format(parmap[pk], substmap[prod]) else: raise NotImplementedError("Whats that?") return r_str, pk, abs(ratcoeff)
def check(rsys): odes, extra = get_odesys( rsys, unit_registry=SI_base_registry, constants=const, substitutions={"temperature": RampedTemp([T_K * u.K, 1 * u.K / u.s])}, ) for odesys in [odes, odes.as_autonomous()]: res = odesys.integrate(t, init_cond, integrator="cvode") t_sec = to_unitless(res.xout, u.second) NOBr_ref = NOBr0_M * analytic_unit0(t_sec, T_K, dH, dS) cmp = to_unitless(res.yout, u.M) ref = np.empty_like(cmp) ref[:, odesys.names.index("NOBr")] = NOBr_ref ref[:, odesys.names.index("Br")] = NOBr0_M - NOBr_ref ref[:, odesys.names.index("NO")] = NOBr0_M - NOBr_ref assert np.allclose(cmp, ref)
def _check(T=273.15 * u.kelvin): result = cv['Be']({ 'temperature': T, 'molar_gas_constant': R }, backend=Backend()) ref = 0.7342617587256584 * u.joule / u.gram / u.kelvin assert abs(to_unitless((result - ref) / ref)) < 1e-10
def test_SpecialFraction_with_units(): k, kprime = 3.142 * u.s**-1 * u.molar**-0.5, 2.718 rsys = _get_SpecialFraction_rsys(k, kprime) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = {'H2': 13*u.molar, 'Br2': 16*u.molar, 'HBr': 19*u.molar} r = k*c0['H2']*c0['Br2']**(3/2)/(c0['Br2'] + kprime*c0['HBr']) conc_unit = u.mol/u.metre**3 rate_unit = conc_unit/u.second ref = rsys.as_per_substance_array({'H2': -r, 'Br2': -r, 'HBr': 2*r}, unit=rate_unit) res = odesys.f_cb(0, rsys.as_per_substance_array(c0, unit=conc_unit)) assert allclose(to_unitless(ref, rate_unit), res)
def test_SpecialFraction_with_units(): k, kprime = 3.142 * u.s**-1 * u.molar**-0.5, 2.718 rsys = _get_SpecialFraction_rsys(k, kprime) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = {'H2': 13*u.molar, 'Br2': 16*u.molar, 'HBr': 19*u.molar} r = k*c0['H2']*c0['Br2']**(3/2)/(c0['Br2'] + kprime*c0['HBr']) conc_unit = u.mol/u.metre**3 rate_unit = conc_unit/u.second ref = rsys.as_per_substance_array({'H2': -r, 'Br2': -r, 'HBr': 2*r}, unit=rate_unit) res = odesys.f_cb(0, rsys.as_per_substance_array(c0, unit=conc_unit)) assert allclose(to_unitless(ref, rate_unit), res)
def radyields2pdf_table(rd, output_dir=None, save=True, unit_registry=None, siunitx=False, fmtstr='{0:.3f}', **kwargs): """ Generate a table with radiolytic yields Calls chempy.util.table.render_tex_to_pdf Parameters ---------- rd: ReactionDiffusion output_dir: str save: bool unit_registry: dict siunitx: bool fmtstr: str \*\*kwargs: extends the table template dictionary """ line_term = r' \\' col_delim = ' & ' header = (col_delim.join(rd.substance_latex_names or rd.substance_names) + line_term) lines = [] for cur_gs in rd.g_values: if unit_registry is not None: gunit = get_derived_unit(unit_registry, 'radiolytic_yield') cur_gs = to_unitless(cur_gs, gunit) lines.append(col_delim.join(map( lambda v: fmtstr.format(v), cur_gs)) + line_term) table_template_dict = { 'table_env': 'table', 'alignment': ('@{}S' if siunitx else '@{}l')*rd.n, 'header': header, 'short_cap': 'G-values', 'long_cap': 'G-values', 'label': 'none', 'body': '\n'.join(lines) } table_template_dict.update(kwargs) table = tex_templates['table']['default'] % table_template_dict _envs = ['landscape', 'tiny'] _pkgs = (['siunitx'] if siunitx else []) + [ 'booktabs', 'lscape', 'amsmath', 'hyperref'] contents = tex_templates['document']['default'] % { 'usepkg': '\n'.join([r'\usepackage{%s}' % pkg for pkg in _pkgs]), 'begins': '\n'.join([r'\begin{%s}' % env for env in _envs]), 'ends': '\n'.join([r'\end{%s}' % env for env in _envs[::-1]]), 'table': table } return render_tex_to_pdf(contents, 'gvalues.tex', 'gvalues.pdf', output_dir, save)
def test_get_native__Radiolytic__named_parameter__units(scaling_density): scaling, density = scaling_density rsys = ReactionSystem.from_string(""" -> H; Radiolytic(2*per100eV) H + H -> H2; 'k2' """, checks=('substance_keys', 'duplicate', 'duplicate_names')) gval = 2*u.per100eV from pyodesys.symbolic import ScaledSys kwargs = {} if scaling == 1 else dict(SymbolicSys=ScaledSys, dep_scaling=scaling) dens = {'density': 998*u.g/u.dm3} odesys, extra = get_odesys(rsys, include_params=False, substitutions=dens if density else {}, unit_registry=SI_base_registry, **kwargs) c0 = {'H': 42e-6*u.molar, 'H2': 17e3*u.nanomolar} native = get_native(rsys, odesys, 'cvode') tend = 7*60*u.minute params = {'doserate': 314*u.Gy/u.hour, 'k2': 53/u.molar/u.minute} if not density: params.update(dens) result = native.integrate(tend, c0, params, atol=1e-15, rtol=1e-15, integrator='cvode', nsteps=8000) assert result.info['success'] def analytic_H(t, p, k, H0): # dH/dt = p - k2*H**2 x0 = np.sqrt(2)*np.sqrt(p) x1 = x0 x2 = np.sqrt(k) x3 = t*x1*x2 x4 = H0*x2 x5 = np.sqrt(x0 + 2*x4) x6 = np.sqrt(-1/(2*H0*x2 - x0)) x7 = x5*x6*np.exp(x3) x8 = np.exp(-x3)/(x5*x6) return x1*(x7 - x8)/(2*x2*(x7 + x8)) t_ul = to_unitless(result.xout, u.s) p_ul = to_unitless(params['doserate']*dens['density']*gval, u.micromolar/u.s) ref_H_uM = analytic_H( t_ul, p_ul, to_unitless(params['k2'], 1/u.micromolar/u.s), to_unitless(c0['H'], u.micromolar) ) ref_H2_uM = to_unitless(c0['H2'], u.micromolar) + to_unitless(c0['H'], u.micromolar)/2 + t_ul*p_ul/2 - ref_H_uM/2 assert np.allclose(to_unitless(result.named_dep('H'), u.micromolar), ref_H_uM) assert np.allclose(to_unitless(result.named_dep('H2'), u.micromolar), ref_H2_uM)
def test_get_native__named_parameter__units(dep_scaling): rsys = ReactionSystem.from_string(""" -> H; 'p' H + H -> H2; 'k2' """, checks=('substance_keys', 'duplicate', 'duplicate_names')) from pyodesys.symbolic import ScaledSys kwargs = {} if dep_scaling == 1 else dict(SymbolicSys=ScaledSys, dep_scaling=dep_scaling) odesys, extra = get_odesys(rsys, include_params=False, unit_registry=SI_base_registry, **kwargs) c0 = {'H': 42e-6*u.molar, 'H2': 17*u.micromolar} native = get_native(rsys, odesys, 'cvode') tend = 7*60*u.minute g_rho_Ddot = g, rho, Ddot = 2*u.per100eV, 998*u.g/u.dm3, 314*u.Gy/u.hour params = { 'p': reduce(mul, g_rho_Ddot), 'k2': 53/u.molar/u.minute } result = native.integrate(tend, c0, params, atol=1e-15, rtol=1e-15, integrator='cvode', nsteps=16000) assert result.info['success'] def analytic_H(t, p, k, H0): # dH/dt = p - k2*H**2 x0 = np.sqrt(2)*np.sqrt(p) x1 = x0 x2 = np.sqrt(k) x3 = t*x1*x2 x4 = H0*x2 x5 = np.sqrt(x0 + 2*x4) x6 = np.sqrt(-1/(2*H0*x2 - x0)) x7 = x5*x6*np.exp(x3) x8 = np.exp(-x3)/(x5*x6) return x1*(x7 - x8)/(2*x2*(x7 + x8)) t_ul = to_unitless(result.xout, u.s) p_ul = to_unitless(params['p'], u.micromolar/u.s) ref_H_uM = analytic_H( t_ul, p_ul, to_unitless(params['k2'], 1/u.micromolar/u.s), to_unitless(c0['H'], u.micromolar) ) ref_H2_uM = to_unitless(c0['H2'], u.micromolar) + to_unitless(c0['H'], u.micromolar)/2 + t_ul*p_ul/2 - ref_H_uM/2 assert np.allclose(to_unitless(result.named_dep('H'), u.micromolar), ref_H_uM) assert np.allclose(to_unitless(result.named_dep('H2'), u.micromolar), ref_H2_uM)
def export2julia(armor_rsys, armor_extra, *, ics, kw2=None): debj = to_diffeqbiojl(armor_rsys, armor_extra, **(kw2 or {})) export = debj['rn'] def p_odj(od): return "Dict([%s])" % ", ".join( ['(:%s, %.4g)' % (k, v) for k, v in od.items()]) # str(od).replace('Ordered', '').replace("',", ',').replace("'", ":") export += "p = %s\n" % p_odj(debj['pars']) export += "ics = %s\n" % p_odj( OrderedDict({ debj['sbstmap'][k]: v for k, v in to_unitless(ics, u.molar).items() })) export += "subst_tex = Dict([%s])\n" % ", ".join( '(:%s, ("%s", "%s"))' % (v, k, armor_rsys.substances[k].latex_name) for k, v in debj['sbstmap'].items()) return export
def test_create_odesys(): rsys = ReactionSystem.from_string( """ A -> B; 'k1' B + C -> P; 'k2' """, substance_factory=Substance, ) odesys, odesys_extra = create_odesys(rsys, unit_registry=SI_base_registry) tend_ul = 10 init_conc_ul = {"A": 1e-6, "B": 0, "C": 1} params_ul = dict(k1=3, k2=4) tend = tend_ul * u.s params = {"k1": params_ul["k1"] / u.s, "k2": params_ul["k2"] / u.M / u.s} init_conc = {k: v * u.molar for k, v in init_conc_ul.items()} validation = odesys_extra["validate"](dict(init_conc, **params)) (P,) = validation["not_seen"] assert P == "P" ref_rates = { "A": -params["k1"] * init_conc["A"], "P": params["k2"] * init_conc["B"] * init_conc["C"], } ref_rates["B"] = -ref_rates["A"] - ref_rates["P"] ref_rates["C"] = -ref_rates["P"] assert validation["rates"] == ref_rates result1, result1_extra = odesys_extra["unit_aware_solve"]( tend, defaultdict(lambda: 0 * u.molar, init_conc), params, integrator="cvode" ) assert result1.info["success"] result2 = odesys.integrate( tend_ul, defaultdict(lambda: 0, init_conc_ul), params_ul, integrator="cvode" ) assert np.allclose(result2.yout[-1, :], to_unitless(result1.yout[-1, :], u.molar))
def test_ArrheniusMassAction__units(R_from_constants): import numpy as np Ea = 40e3*u.J/u.mol R = default_constants.molar_gas_constant if R_from_constants else (8.3145*u.J/u.mol/u.K) A, Ea_over_R = 1.2e11/u.molar**2/u.second, Ea/R ref1 = A*np.exp(-to_unitless(Ea_over_R/(290*u.K))) arrh = Arrhenius([A, Ea_over_R]) assert allclose(arrh({'temperature': 290*u.K}), ref1) ama = MassAction(arrh) r = Reaction({'A': 2, 'B': 1}, {'C': 1}, ama, {'B': 1}) T_ = 'temperature' def ref(v): return 1.2e11/u.molar**2/u.second*math.exp( -Ea_over_R.simplified/v[T_])*v['B']*v['A']**2 ma = r.rate_expr() for params in [(11.*u.molar, 13.*u.molar, 17.*u.molar, 311.2*u.kelvin), (12*u.molar, 8*u.molar, 5*u.molar, 270*u.kelvin)]: var = dict(zip(['A', 'B', 'C', T_], params)) ref_val = ref(var) assert abs((ma(var, reaction=r) - ref_val)/ref_val) < 1e-14
def test_chained_parameter_variation_from_ReactionSystem(): g_E_mol_J = 2.1e-7 rsys = ReactionSystem.from_string( """ (H2O) -> e-(aq) + H+ + OH; Radiolytic(%.2e*mol/J) 2 OH -> H2O2; 3.6e9/M/s H+ + OH- -> H2O; 1.4e11/M/s H2O -> H+ + OH-; 1.4e-3/s N2O + e-(aq) -> N2 + O-; 9.6e9/M/s O- + H+ -> OH; 1e11/M/s """ % g_E_mol_J # neglecting a large body of reactions (just a test-case after all) ) ureg = SI_base_registry field_u = get_derived_unit(ureg, 'doserate') * get_derived_unit(ureg, 'density') rd = ReactionDiffusion.from_ReactionSystem(rsys, fields=[[0*field_u]], unit_registry=ureg, param_names=['doserate']) dens_kg_dm3 = 0.998 odesys = rd._as_odesys( variables_from_params=dict( density=lambda self, params: dens_kg_dm3*1e3*u.kg/u.m**3 ) ) npoints = 5 durations = [59*u.second, 42*u.minute, 2*u.hour] doserates = [135*u.Gy/u.s, 11*u.Gy/u.s, 180*u.Gy/u.minute] M = u.molar ic = defaultdict(lambda: 0*M, {'H2O': 55.4*M, 'H+': 1e-7*M, 'OH-': 1e-7*M, 'N2O': 20e-3*M}) result = odesys.chained_parameter_variation(durations, ic, {'doserate': doserates}, npoints=npoints) ref_xout_s = [0] for dur in map(lambda dur: to_unitless(dur, u.s), durations): ref_xout_s += list(np.linspace(ref_xout_s[-1], ref_xout_s[-1] + dur, npoints+1)[1:]) assert allclose(result.xout, ref_xout_s*u.s) N2_M = to_unitless(result.named_dep('N2'), u.M) H2O2_M = to_unitless(result.named_dep('H2O2'), u.M) e_accum_molar = 0 for i, (dur, dr) in enumerate(zip(durations, doserates)): dur_s = to_unitless(dur, u.s) dr_Gy_s = to_unitless(dr, u.Gy/u.s) local_ts = np.linspace(0, dur_s, npoints+1) # local_ic = {k: result.named_dep(k)[i*npoints] for k in odesys.names} for j, (lt, ld) in enumerate(zip(local_ts[1:], np.diff(local_ts))): e_accum_molar += ld*g_E_mol_J*dr_Gy_s*dens_kg_dm3 assert abs(N2_M[i*npoints + j + 1] - e_accum_molar)/e_accum_molar < 1e-3 assert abs(H2O2_M[i*npoints + j + 1] - e_accum_molar)/e_accum_molar < 1e-3 res2 = odesys.integrate(durations[0], ic, {'doserate': doserates[0]}, integrator='cvode') dr2 = res2.params[res2.odesys.param_names.index('doserate')] assert np.asarray(res2.params).shape[-1] == len(odesys.param_names) assert allclose(dr2, doserates[0]) assert allclose(res2.xout[-1], durations[0]) assert allclose(res2.named_dep('N2')[-1], durations[0]*doserates[0]*g_E_mol_J*u.mol/u.J*dens_kg_dm3*u.kg/u.dm3) to_unitless(res2.xout, u.s) to_unitless(res2.yout, u.molar) to_unitless(dr2, u.Gy/u.s)
def test_get_native__Radiolytic__named_parameter__units(scaling_density): scaling, density = scaling_density rsys = ReactionSystem.from_string( """ -> H; Radiolytic(2*per100eV) H + H -> H2; 'k2' """, checks=("substance_keys", "duplicate", "duplicate_names"), ) gval = 2 * u.per100eV from pyodesys.symbolic import ScaledSys kwargs = {} if scaling == 1 else dict(SymbolicSys=ScaledSys, dep_scaling=scaling) dens = {"density": 998 * u.g / u.dm3} odesys, extra = get_odesys(rsys, include_params=False, substitutions=dens if density else {}, unit_registry=SI_base_registry, **kwargs) c0 = {"H": 42e-6 * u.molar, "H2": 17e3 * u.nanomolar} native = get_native(rsys, odesys, "cvode") tend = 7 * 60 * u.minute params = {"doserate": 314 * u.Gy / u.hour, "k2": 53 / u.molar / u.minute} if not density: params.update(dens) result = native.integrate(tend, c0, params, atol=1e-15, rtol=1e-15, integrator="cvode", nsteps=8000) assert result.info["success"] def analytic_H(t, p, k, H0): # dH/dt = p - k2*H**2 x0 = np.sqrt(2) * np.sqrt(p) x1 = x0 x2 = np.sqrt(k) x3 = t * x1 * x2 x4 = H0 * x2 x5 = np.sqrt(x0 + 2 * x4) x6 = np.sqrt(-1 / (2 * H0 * x2 - x0)) x7 = x5 * x6 * np.exp(x3) x8 = np.exp(-x3) / (x5 * x6) return x1 * (x7 - x8) / (2 * x2 * (x7 + x8)) t_ul = to_unitless(result.xout, u.s) p_ul = to_unitless(params["doserate"] * dens["density"] * gval, u.micromolar / u.s) ref_H_uM = analytic_H( t_ul, p_ul, to_unitless(params["k2"], 1 / u.micromolar / u.s), to_unitless(c0["H"], u.micromolar), ) ref_H2_uM = (to_unitless(c0["H2"], u.micromolar) + to_unitless(c0["H"], u.micromolar) / 2 + t_ul * p_ul / 2 - ref_H_uM / 2) assert np.allclose(to_unitless(result.named_dep("H"), u.micromolar), ref_H_uM) assert np.allclose(to_unitless(result.named_dep("H2"), u.micromolar), ref_H2_uM)
def _check(T=273.15*u.kelvin): result = cv['Be']({'temperature': T, 'molar_gas_constant': R}, backend=Backend()) ref = 0.7342617587256584*u.joule/u.gram/u.kelvin assert abs(to_unitless((result - ref)/ref)) < 1e-10
def _C(k): return to_unitless(c0[k], output_conc_unit)
# FutureLab # Primer taller de Python # Propiedades físicas de compuestos para su uso en química analítica from chempy import Substance from chempy.properties.water_density_tanaka_2001 import water_density as rho from chempy.units import to_unitless, default_units as u water = Substance.from_formula('H2O') for T_C in (10, 15, 17): concentration_H2O = rho(T=(273.15 + T_C) * u.kelvin, units=u) / water.molar_mass(units=u) print('[H2O] = %.2f M (at %d °C)' % (to_unitless(concentration_H2O, u.molar), T_C))
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)
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 _dict_to_unitless(d, u): return {k: to_unitless(v, u) for k, v in d.items()}
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 _C(k): return to_unitless(c0[k], output_conc_unit)
def _dict_to_unitless(d, u): return {k: to_unitless(v, u) for k, v in d.items()}
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)
def _check(r): res = r({'doserate': 0.15*u.gray/u.second, 'density': 0.998*u.kg/u.decimetre**3, 'temperature': 298.15*u.K}) ref = 0.15*0.998*2.1e-7*u.molar/u.second assert abs(to_unitless((res - ref)/ref)) < 1e-15