def check_exact_predictors(exact, predictor): p1_func, y_np1_p1_expr = \ generate_predictor_scheme(*predictor, symbolic=exact) # LTE for IMR: just natural lte: y_np1_imr_expr = y_np1_exact - imr_lte(Sdts[0], Sdddynph, SFddynph) # Generate another predictor p2_func, y_np1_p2_expr = \ generate_predictor_scheme([PTInfo(sRat(1, 2), None, "imr"), PTInfo(2, "corr_val", None), PTInfo(3, "corr_val", None)], "ibdf2") A = system2matrix([y_np1_p1_expr, y_np1_p2_expr, y_np1_imr_expr], [Sdddynph, SFddynph, y_np1_exact]) # Solve for dddy and Fddy: x = A.inv() dddy_symb = sum([y_est * xi.factor() for xi, y_est in zip(x.row(0), [y_np1_p1, y_np1_p2, y_np1_imr])]) Fddy_symb = sum([y_est * xi.factor() for xi, y_est in zip(x.row(1), [y_np1_p1, y_np1_p2, y_np1_imr])]) # Check we got the right matrix and the right formulae if predictor[1] == "use exact dddy": assert A.row(0) == sympy.Matrix([[1, 0, 0]]).row(0) utils.assert_sym_eq(dddy_symb.simplify(), y_np1_p1) elif predictor[1] == "use exact Fddy": assert A.row(0) == sympy.Matrix([[0, 1, 0]]).row(0) utils.assert_sym_eq(Fddy_symb.simplify(), y_np1_p1) else: assert False
def test_sum_dts(): # Check a simple fractional case utils.assert_sym_eq(sum_dts(sRat(1, 2), 1), Sdts[0]/2) # Check two numbers the same gives zero always utils.assert_sym_eq(sum_dts(1, 1), 0) utils.assert_sym_eq(sum_dts(0, 0), 0) utils.assert_sym_eq(sum_dts(sRat(1, 2), sRat(1, 2)), 0) def check_sum_dts(a, b): # Check we can swap the sign utils.assert_sym_eq(sum_dts(a, b), -sum_dts(b, a)) # Starting half a step earlier utils.assert_sym_eq(sum_dts(a, b + sRat(1, 2)), sRat(1, 2)*Sdts[int(b)] + sum_dts(a, b)) # Check that we can split it up utils.assert_sym_eq(sum_dts(a, b), sum_dts(a, b-1) + sum_dts(b-1, b)) # Make sure b>=1 or the last check will fail due to negative b. cases = [(0, 1), (5, 8), (sRat(1, 2), 3), (sRat(2, 2), 3), (sRat(3, 2), 3), (0, sRat(9, 7)), (sRat(3/4), sRat(9, 7)), ] for a, b in cases: yield check_sum_dts, a, b
def test_imr_predictor_equivalence(): # Check the we generate imr's lte if we plug in the right times and # approximations to ebdf2 (~explicit midpoint rule). ynp1_imr = y_np1_exact - imr_lte(Sdts[0], Sdddynph, SFddynph) _, ynp1_p1 = generate_predictor_scheme([PTInfo(0, None, None), PTInfo( sRat(1, 2), "bdf2 imr", "imr"), PTInfo(1, "corr_val", None)], "ebdf2") utils.assert_sym_eq(ynp1_imr, ynp1_p1) # Should be exactly the same with ebdf to calculate the y-est at the # midpoint (because the midpoint value is ignored). _, ynp1_p2 = generate_predictor_scheme([PTInfo(0, None, None), PTInfo( sRat(1, 2), "bdf3 imr", "imr"), PTInfo(1, "corr_val", None)], "ebdf2") utils.assert_sym_eq(ynp1_imr, ynp1_p2)
def test_imr_predictor_equivalence(): # Check the we generate imr's lte if we plug in the right times and # approximations to ebdf2 (~explicit midpoint rule). ynp1_imr = y_np1_exact - imr_lte(Sdts[0], Sdddynph, SFddynph) _, ynp1_p1 = generate_predictor_scheme([ PTInfo(0, None, None), PTInfo(sRat(1, 2), "bdf2 imr", "imr"), PTInfo(1, "corr_val", None) ], "ebdf2") utils.assert_sym_eq(ynp1_imr, ynp1_p1) # Should be exactly the same with ebdf to calculate the y-est at the # midpoint (because the midpoint value is ignored). _, ynp1_p2 = generate_predictor_scheme([ PTInfo(0, None, None), PTInfo(sRat(1, 2), "bdf3 imr", "imr"), PTInfo(1, "corr_val", None) ], "ebdf2") utils.assert_sym_eq(ynp1_imr, ynp1_p2)
def test_symbolic_compare_step_time_residual(): # Define the symbols we need St = sympy.symbols('t') Sdts = sympy.symbols('Delta0:9') Sys = sympy.symbols('y0:9') Sdys = sympy.symbols('dy0:9') # Generate the stuff needed to run the residual def fake_eqn_residual(ts, ys, dy): return Sdys[0] - dy fake_ts = utils.dts2ts(St, Sdts[::-1]) fake_ys = Sys[::-1] # Check bdf2 step_result_bdf2 = ibdf2_step(Sdts[0], Sys[1], Sdys[0], Sdts[1], Sys[2]) res_result_bdf2 = bdf2_residual(fake_eqn_residual, fake_ts, fake_ys) res_bdf2_step = sympy.solve(res_result_bdf2, Sys[0]) assert len(res_bdf2_step) == 1 utils.assert_sym_eq(res_bdf2_step[0], step_result_bdf2)
def test_bdf2_ebdf2_scheme_generation(): """Make sure adaptive bdf2 can be derived using same methodology as I'm using (also checks lte expressions). """ dddy = sympy.symbols("y'''") y_np1_bdf2 = sympy.symbols("y_{n+1}_bdf2") y_np1_ebdf2_expr = y_np1_exact - ebdf2_lte(Sdts[0], Sdts[1], dddy) y_np1_bdf2_expr = y_np1_exact - bdf2_lte(Sdts[0], Sdts[1], dddy) A = system2matrix([y_np1_ebdf2_expr, y_np1_bdf2_expr], [dddy, y_np1_exact]) x = A.inv() exact_ynp1_symb = sum([y_est * xi.factor() for xi, y_est in zip(x.row(1), [y_np1_p1, y_np1_bdf2])]) answer = -(Sdts[1] + Sdts[0])*( y_np1_bdf2 - y_np1_p1)/(3*Sdts[0] + 2*Sdts[1]) utils.assert_sym_eq(exact_ynp1_symb - y_np1_bdf2, answer)
def test_bdf2_ebdf2_scheme_generation(): """Make sure adaptive bdf2 can be derived using same methodology as I'm using (also checks lte expressions). """ dddy = sympy.symbols("y'''") y_np1_bdf2 = sympy.symbols("y_{n+1}_bdf2") y_np1_ebdf2_expr = y_np1_exact - ebdf2_lte(Sdts[0], Sdts[1], dddy) y_np1_bdf2_expr = y_np1_exact - bdf2_lte(Sdts[0], Sdts[1], dddy) A = system2matrix([y_np1_ebdf2_expr, y_np1_bdf2_expr], [dddy, y_np1_exact]) x = A.inv() exact_ynp1_symb = sum([ y_est * xi.factor() for xi, y_est in zip(x.row(1), [y_np1_p1, y_np1_bdf2]) ]) answer = -(Sdts[1] + Sdts[0]) * (y_np1_bdf2 - y_np1_p1) / (3 * Sdts[0] + 2 * Sdts[1]) utils.assert_sym_eq(exact_ynp1_symb - y_np1_bdf2, answer)
def check_exact_predictors(exact, predictor): p1_func, y_np1_p1_expr = \ generate_predictor_scheme(*predictor, symbolic=exact) # LTE for IMR: just natural lte: y_np1_imr_expr = y_np1_exact - imr_lte(Sdts[0], Sdddynph, SFddynph) # Generate another predictor p2_func, y_np1_p2_expr = \ generate_predictor_scheme([PTInfo(sRat(1, 2), None, "imr"), PTInfo(2, "corr_val", None), PTInfo(3, "corr_val", None)], "ibdf2") A = system2matrix([y_np1_p1_expr, y_np1_p2_expr, y_np1_imr_expr], [Sdddynph, SFddynph, y_np1_exact]) # Solve for dddy and Fddy: x = A.inv() dddy_symb = sum([ y_est * xi.factor() for xi, y_est in zip(x.row(0), [y_np1_p1, y_np1_p2, y_np1_imr]) ]) Fddy_symb = sum([ y_est * xi.factor() for xi, y_est in zip(x.row(1), [y_np1_p1, y_np1_p2, y_np1_imr]) ]) # Check we got the right matrix and the right formulae if predictor[1] == "use exact dddy": assert A.row(0) == sympy.Matrix([[1, 0, 0]]).row(0) utils.assert_sym_eq(dddy_symb.simplify(), y_np1_p1) elif predictor[1] == "use exact Fddy": assert A.row(0) == sympy.Matrix([[0, 1, 0]]).row(0) utils.assert_sym_eq(Fddy_symb.simplify(), y_np1_p1) else: assert False
def check_sum_dts(a, b): # Check we can swap the sign utils.assert_sym_eq(sum_dts(a, b), -sum_dts(b, a)) # Starting half a step earlier utils.assert_sym_eq(sum_dts(a, b + sRat(1, 2)), sRat(1, 2)*Sdts[int(b)] + sum_dts(a, b)) # Check that we can split it up utils.assert_sym_eq(sum_dts(a, b), sum_dts(a, b-1) + sum_dts(b-1, b))
def check_sum_dts(a, b): # Check we can swap the sign utils.assert_sym_eq(sum_dts(a, b), -sum_dts(b, a)) # Starting half a step earlier utils.assert_sym_eq(sum_dts(a, b + sRat(1, 2)), sRat(1, 2) * Sdts[int(b)] + sum_dts(a, b)) # Check that we can split it up utils.assert_sym_eq(sum_dts(a, b), sum_dts(a, b - 1) + sum_dts(b - 1, b))
def test_sum_dts(): # Check a simple fractional case utils.assert_sym_eq(sum_dts(sRat(1, 2), 1), Sdts[0] / 2) # Check two numbers the same gives zero always utils.assert_sym_eq(sum_dts(1, 1), 0) utils.assert_sym_eq(sum_dts(0, 0), 0) utils.assert_sym_eq(sum_dts(sRat(1, 2), sRat(1, 2)), 0) def check_sum_dts(a, b): # Check we can swap the sign utils.assert_sym_eq(sum_dts(a, b), -sum_dts(b, a)) # Starting half a step earlier utils.assert_sym_eq(sum_dts(a, b + sRat(1, 2)), sRat(1, 2) * Sdts[int(b)] + sum_dts(a, b)) # Check that we can split it up utils.assert_sym_eq(sum_dts(a, b), sum_dts(a, b - 1) + sum_dts(b - 1, b)) # Make sure b>=1 or the last check will fail due to negative b. cases = [ (0, 1), (5, 8), (sRat(1, 2), 3), (sRat(2, 2), 3), (sRat(3, 2), 3), (0, sRat(9, 7)), (sRat(3 / 4), sRat(9, 7)), ] for a, b in cases: yield check_sum_dts, a, b
def test_tr_ab2_scheme_generation(): """Make sure tr-ab can be derived using same methodology as I'm using (also checks lte expressions). """ dddy = sympy.symbols("y'''") y_np1_tr = sympy.symbols("y_{n+1}_tr") ab_pred, ynp1_ab2_expr = generate_predictor_scheme([PTInfo(0, None, None), PTInfo( 1, "corr_val", "exp test"), PTInfo( 2, "corr_val", "exp test")], "ab2", symbolic=sympy.exp(St)) # ??ds hacky, have to change the symbol to represent where y''' is being # evaluated by hand! ynp1_ab2_expr = ynp1_ab2_expr.subs(Sdddynph, dddy) # Check that it gives the same result as we know from the lte utils.assert_sym_eq(y_np1_exact - ab2_lte(Sdts[0], Sdts[1], dddy), ynp1_ab2_expr) # Now do the solve etc. y_np1_tr_expr = y_np1_exact - tr_lte(Sdts[0], dddy) A = system2matrix([ynp1_ab2_expr, y_np1_tr_expr], [dddy, y_np1_exact]) x = A.inv() exact_ynp1_symb = sum([y_est * xi.factor() for xi, y_est in zip(x.row(1), [y_np1_p1, y_np1_tr])]) exact_ynp1_f = sympy.lambdify( (y_np1_p1, y_np1_tr, Sdts[0], Sdts[1]), exact_ynp1_symb) utils.assert_sym_eq(exact_ynp1_symb - y_np1_tr, (y_np1_p1 - y_np1_tr)/(3*(1 + Sdts[1]/Sdts[0]))) # Construct an lte estimator from this estimate def lte_est(ts, ys): ynp1_p = ab_pred(ts, ys) dtn = ts[-1] - ts[-2] dtnm1 = ts[-2] - ts[-3] ynp1_exact = exact_ynp1_f(ynp1_p, ys[-1], dtn, dtnm1) return ynp1_exact - ys[-1] # Solve exp using tr t0 = 0.0 dt = 1e-2 ts, ys = ode.odeint(er.exp_residual, er.exp_exact(t0), tmax=2.0, dt=dt, method='tr') # Get error estimates using standard tr ab and the one we just # constructed here, then compare. this_ltes = ode.get_ltes_from_data(ts, ys, lte_est) tr_ab_lte = par(ode.tr_ab_lte_estimate, dydt_func=lambda t, y: y) standard_ltes = ode.get_ltes_from_data(ts, ys, tr_ab_lte) # Should be the same (actually the sign is different, but this doesn't # matter in lte). utils.assert_list_almost_equal( this_ltes, map(lambda a: a*-1, standard_ltes), 1e-8)
def test_tr_ab2_scheme_generation(): """Make sure tr-ab can be derived using same methodology as I'm using (also checks lte expressions). """ dddy = sympy.symbols("y'''") y_np1_tr = sympy.symbols("y_{n+1}_tr") ab_pred, ynp1_ab2_expr = generate_predictor_scheme([ PTInfo(0, None, None), PTInfo(1, "corr_val", "exp test"), PTInfo(2, "corr_val", "exp test") ], "ab2", symbolic=sympy.exp(St)) # ??ds hacky, have to change the symbol to represent where y''' is being # evaluated by hand! ynp1_ab2_expr = ynp1_ab2_expr.subs(Sdddynph, dddy) # Check that it gives the same result as we know from the lte utils.assert_sym_eq(y_np1_exact - ab2_lte(Sdts[0], Sdts[1], dddy), ynp1_ab2_expr) # Now do the solve etc. y_np1_tr_expr = y_np1_exact - tr_lte(Sdts[0], dddy) A = system2matrix([ynp1_ab2_expr, y_np1_tr_expr], [dddy, y_np1_exact]) x = A.inv() exact_ynp1_symb = sum([ y_est * xi.factor() for xi, y_est in zip(x.row(1), [y_np1_p1, y_np1_tr]) ]) exact_ynp1_f = sympy.lambdify((y_np1_p1, y_np1_tr, Sdts[0], Sdts[1]), exact_ynp1_symb) utils.assert_sym_eq(exact_ynp1_symb - y_np1_tr, (y_np1_p1 - y_np1_tr) / (3 * (1 + Sdts[1] / Sdts[0]))) # Construct an lte estimator from this estimate def lte_est(ts, ys): ynp1_p = ab_pred(ts, ys) dtn = ts[-1] - ts[-2] dtnm1 = ts[-2] - ts[-3] ynp1_exact = exact_ynp1_f(ynp1_p, ys[-1], dtn, dtnm1) return ynp1_exact - ys[-1] # Solve exp using tr t0 = 0.0 dt = 1e-2 ts, ys = ode.odeint(er.exp_residual, er.exp_exact(t0), tmax=2.0, dt=dt, method='tr') # Get error estimates using standard tr ab and the one we just # constructed here, then compare. this_ltes = ode.get_ltes_from_data(ts, ys, lte_est) tr_ab_lte = par(ode.tr_ab_lte_estimate, dydt_func=lambda t, y: y) standard_ltes = ode.get_ltes_from_data(ts, ys, tr_ab_lte) # Should be the same (actually the sign is different, but this doesn't # matter in lte). utils.assert_list_almost_equal(this_ltes, map(lambda a: a * -1, standard_ltes), 1e-8)