def test_get_native__first_step(solve): integrator = 'cvode' forgive = 20 def k(num): return "MassAction(unique_keys=('k%d',))" % num lines = [ # fictitious isomerization "CNO -> ONC; %s" % k(1), "ONC -> NCO; %s" % k(2), "NCO -> CON; %s" % k(3) ] rsys = ReactionSystem.from_string('\n'.join(lines), 'CNO ONC NCO CON') odesys, extra = get_odesys(rsys, include_params=False) if len(solve) > 0: from pyodesys.symbolic import PartiallySolvedSystem odesys = PartiallySolvedSystem(odesys, extra['linear_dependencies'](solve)) c0 = defaultdict(float, {'CNO': .7}) rate_coeffs = (1e78, 2, 3.) args = (5, c0, dict(zip('k1 k2 k3'.split(), rate_coeffs))) kwargs = dict(integrator=integrator, atol=1e-9, rtol=1e-9, nsteps=1000) native = get_native(rsys, odesys, integrator) h0 = extra['max_euler_step_cb'](0, *args[1:]) xout1, yout1, info1 = odesys.integrate(*args, first_step=h0, **kwargs) xout2, yout2, info2 = native.integrate(*args, **kwargs) ref1 = decay_get_Cref(rate_coeffs, [c0[key] for key in native.names], xout1) ref2 = decay_get_Cref(rate_coeffs, [c0[key] for key in native.names], xout2) allclose_kw = dict(atol=kwargs['atol']*forgive, rtol=kwargs['rtol']*forgive) assert np.allclose(yout1[:, :3], ref1, **allclose_kw) assert info2['success'] assert info2['nfev'] > 10 and info2['nfev'] > 1 and info2['time_cpu'] < 10 and info2['time_wall'] < 10 assert np.allclose(yout2[:, :3], ref2, **allclose_kw)
def test_get_odesys__linear_dependencies__PartiallySolvedSystem(preferred): import sympy from pyodesys.symbolic import PartiallySolvedSystem rsys = ReactionSystem.from_string('\n'.join( ['H2O -> H+ + OH-; 1e-4', 'OH- + H+ -> H2O; 1e10'])) odesys, extra = get_odesys(rsys) c0 = {'H2O': 0, 'H+': 2e-7, 'OH-': 3e-7} h0max = extra['max_euler_step_cb'](0, c0) analytic_factory = extra['linear_dependencies']() y0 = {k: sympy.Symbol(k + '0') for k in rsys.substances} analytic_factory(None, {odesys[k]: v for k, v in y0.items()}, None, sympy) psys = PartiallySolvedSystem(odesys, analytic_factory) xout, yout, info = psys.integrate(1, c0, atol=1e-12, rtol=1e-10, first_step=h0max * 1e-12, integrator='cvode') c_reac = c0['H+'], c0['OH-'] H2O_ref = binary_rev(xout, 1e10, 1e-4, c0['H2O'], max(c_reac), min(c_reac)) assert np.allclose(yout[:, psys.names.index('H2O')], H2O_ref) assert np.allclose(yout[:, psys.names.index('H+')], c0['H+'] + c0['H2O'] - H2O_ref) assert np.allclose(yout[:, psys.names.index('OH-')], c0['OH-'] + c0['H2O'] - H2O_ref)
def test_get_native__a_substance_no_composition(solve): rsys = ReactionSystem.from_string('\n'.join(['H2O -> H2O+ + e-(aq); 1e-8', 'e-(aq) + H2O+ -> H2O; 1e10'])) odesys, extra = get_odesys(rsys) c0 = {'H2O': 0, 'H2O+': 2e-9, 'e-(aq)': 3e-9} if len(solve) > 0: from pyodesys.symbolic import PartiallySolvedSystem odesys = PartiallySolvedSystem(odesys, extra['linear_dependencies'](solve)) odesys = get_native(rsys, odesys, 'gsl') xout, yout, info = odesys.integrate(1, c0, atol=1e-15, rtol=1e-15, integrator='gsl') c_reac = c0['H2O+'], c0['e-(aq)'] H2O_ref = binary_rev(xout, 1e10, 1e-4, c0['H2O'], max(c_reac), min(c_reac)) assert np.allclose(yout[:, odesys.names.index('H2O')], H2O_ref) assert np.allclose(yout[:, odesys.names.index('H2O+')], c0['H2O+'] + c0['H2O'] - H2O_ref) assert np.allclose(yout[:, odesys.names.index('e-(aq)')], c0['e-(aq)'] + c0['H2O'] - H2O_ref)
def test_NativeSys__PartiallySolvedSystem__roots(idx): def f(x, y, p): return [-p[0] * y[0], p[0] * y[0] - p[1] * y[1], p[1] * y[1]] def roots(x, y): return ([y[0] - y[1]], [y[0] - y[2]], [y[1] - y[2]])[idx] odesys = SymbolicSys.from_callback(f, 3, 2, roots_cb=roots) _p, _q, tend = 7, 3, 0.7 dep0 = (1, 0, 0) ref = [0.11299628093544488, 0.20674119231833346, 0.3541828705348678] def check(odesys): res = odesys.integrate(tend, dep0, (_p, _q), integrator='cvode', return_on_root=True) assert abs(res.xout[-1] - ref[idx]) < 1e-7 check(odesys) native = NativeSys.from_other(odesys) check(native) psys = PartiallySolvedSystem( odesys, lambda t0, xyz, par0, be: {odesys.dep[0]: xyz[0] * be.exp(-par0[0] * (odesys.indep - t0))}) check(psys) pnative = NativeSys.from_other(psys) check(pnative)
def test_get_odesys__linear_dependencies__PartiallySolvedSystem(preferred): import sympy from pyodesys.symbolic import PartiallySolvedSystem rsys = ReactionSystem.from_string('\n'.join(['H2O -> H+ + OH-; 1e-4', 'OH- + H+ -> H2O; 1e10'])) odesys, extra = get_odesys(rsys) c0 = {'H2O': 0, 'H+': 2e-7, 'OH-': 3e-7} h0max = extra['max_euler_step_cb'](0, c0) analytic_factory = extra['linear_dependencies']() y0 = {k: sympy.Symbol(k+'0') for k in rsys.substances} analytic_factory(None, {odesys[k]: v for k, v in y0.items()}, None, sympy) psys = PartiallySolvedSystem(odesys, analytic_factory) xout, yout, info = psys.integrate(1, c0, atol=1e-12, rtol=1e-10, first_step=h0max*1e-12, integrator='cvode') c_reac = c0['H+'], c0['OH-'] H2O_ref = binary_rev(xout, 1e10, 1e-4, c0['H2O'], max(c_reac), min(c_reac)) assert np.allclose(yout[:, psys.names.index('H2O')], H2O_ref) assert np.allclose(yout[:, psys.names.index('H+')], c0['H+'] + c0['H2O'] - H2O_ref) assert np.allclose(yout[:, psys.names.index('OH-')], c0['OH-'] + c0['H2O'] - H2O_ref)
def test_get_native__a_substance_no_composition(solve): rsys = ReactionSystem.from_string("\n".join( ["H2O -> H2O+ + e-(aq); 1e-8", "e-(aq) + H2O+ -> H2O; 1e10"])) odesys, extra = get_odesys(rsys) c0 = {"H2O": 0, "H2O+": 2e-9, "e-(aq)": 3e-9} if len(solve) > 0: from pyodesys.symbolic import PartiallySolvedSystem odesys = PartiallySolvedSystem(odesys, extra["linear_dependencies"](solve)) odesys = get_native(rsys, odesys, "gsl") xout, yout, info = odesys.integrate(1, c0, atol=1e-15, rtol=1e-15, integrator="gsl") c_reac = c0["H2O+"], c0["e-(aq)"] H2O_ref = binary_rev(xout, 1e10, 1e-4, c0["H2O"], max(c_reac), min(c_reac)) assert np.allclose(yout[:, odesys.names.index("H2O")], H2O_ref) assert np.allclose(yout[:, odesys.names.index("H2O+")], c0["H2O+"] + c0["H2O"] - H2O_ref) assert np.allclose(yout[:, odesys.names.index("e-(aq)")], c0["e-(aq)"] + c0["H2O"] - H2O_ref)
def test_get_odesys__linear_dependencies__PartiallySolvedSystem(preferred): import sympy from pyodesys.symbolic import PartiallySolvedSystem rsys = ReactionSystem.from_string( "\n".join(["H2O -> H+ + OH-; 1e-4", "OH- + H+ -> H2O; 1e10"]) ) odesys, extra = get_odesys(rsys) c0 = {"H2O": 0, "H+": 2e-7, "OH-": 3e-7} h0max = extra["max_euler_step_cb"](0, c0) analytic_factory = extra["linear_dependencies"]() y0 = {k: sympy.Symbol(k + "0") for k in rsys.substances} analytic_factory(None, {odesys[k]: v for k, v in y0.items()}, None, sympy) psys = PartiallySolvedSystem(odesys, analytic_factory) xout, yout, info = psys.integrate( 1, c0, atol=1e-12, rtol=1e-10, first_step=h0max * 1e-12, integrator="cvode" ) c_reac = c0["H+"], c0["OH-"] H2O_ref = binary_rev(xout, 1e10, 1e-4, c0["H2O"], max(c_reac), min(c_reac)) assert np.allclose(yout[:, psys.names.index("H2O")], H2O_ref) assert np.allclose(yout[:, psys.names.index("H+")], c0["H+"] + c0["H2O"] - H2O_ref) assert np.allclose( yout[:, psys.names.index("OH-")], c0["OH-"] + c0["H2O"] - H2O_ref )
def _test_PartiallySolvedSystem_Native(NativeSys, integrator): class TransformedNativeSys(TransformedSys, NativeSys): pass logexp = get_logexp(1, 1e-24) NativeLogLogSys = symmetricsys(logexp, logexp, SuperClass=TransformedNativeSys) odesys = _get_decay3(lower_bounds=[0, 0, 0], linear_invariants=[[1, 1, 1]]) n_sys = NativeSys.from_other(odesys) assert odesys.linear_invariants == n_sys.linear_invariants scaledsys = ScaledSys.from_other(odesys, dep_scaling=42) ns_sys = NativeSys.from_other(scaledsys) partsys = PartiallySolvedSystem.from_linear_invariants(scaledsys) np_sys = NativeSys.from_other(partsys) LogLogSys = symmetricsys(logexp, logexp) ll_scaledsys = LogLogSys.from_other(scaledsys) ll_partsys = LogLogSys.from_other(partsys) nll_scaledsys = NativeLogLogSys.from_other(scaledsys) nll_partsys = NativeLogLogSys.from_other(partsys) assert len(ll_scaledsys.nonlinear_invariants) > 0 assert ll_scaledsys.nonlinear_invariants == nll_scaledsys.nonlinear_invariants y0 = [3.3, 2.4, 1.5] k = [3.5, 2.5, 0] systems = [ odesys, n_sys, scaledsys, ns_sys, partsys, np_sys, ll_scaledsys, ll_partsys, nll_scaledsys, nll_partsys ] for idx, system in enumerate(systems): result = system.integrate([0, .3, .5, .7, .9, 1.3], y0, k, integrator=integrator, atol=1e-9, rtol=1e-9) ref = np.array( bateman_full(y0, k, result.xout - result.xout[0], exp=np.exp)).T assert result.info['success'] assert np.allclose(result.yout, ref)
def _get_transformed_partially_solved_system(NativeSys, multiple=False): odesys = _get_decay3() if multiple: def substitutions(x0, y0, p0, be): analytic0 = y0[0] * be.exp(-p0[0] * (odesys.indep - x0)) analytic2 = y0[0] + y0[1] + y0[2] - analytic0 - odesys.dep[1] return {odesys.dep[0]: analytic0, odesys.dep[2]: analytic2} else: def substitutions(x0, y0, p0, be): return { odesys.dep[0]: y0[0] * sp.exp(-p0[0] * (odesys.indep - x0)) } partsys = PartiallySolvedSystem(odesys, substitutions) class TransformedNativeSys(TransformedSys, NativeSys): pass LogLogSys = symmetricsys(get_logexp(), get_logexp(), SuperClass=TransformedNativeSys) return LogLogSys.from_other(partsys)