def check_lte(method_residual, lte, exact_symb, base_dt, implicit): exact, residual, dys, J = utils.symb2functions(exact_symb) dddy = dys[3] Fddy = lambda t, y: J(t, y) * dys[2](t, y) newton_tol = 1e-10 # tmax varies with dt so that we can vary dt over orders of # magnitude. tmax = 50*dt # Run ode solver if implicit: ts, ys = ode._odeint( residual, [0.0], [sp.array([exact(0.0)], ndmin=1)], dt, tmax, method_residual, target_error=None, time_adaptor=ode.create_random_time_adaptor(base_dt), initialisation_actions=par(ode.higher_order_start, 3), newton_tol=newton_tol) else: ts, ys = ode.odeint_explicit( dys[1], exact(0.0), base_dt, tmax, method_residual, time_adaptor=ode.create_random_time_adaptor(base_dt)) dts = utils.ts2dts(ts) # Check it's accurate-ish exact_ys = map(exact, ts) errors = map(op.sub, exact_ys, ys) utils.assert_list_almost_zero(errors, 1e-3) # Calculate ltes by two methods. Note that we need to drop a few # values because exact calculation (may) need a few dts. Could be # dodgy: exact dddys might not correspond to dddy in experiment if # done over long time and we've wandered away from the solution. exact_dddys = map(dddy, ts, ys) exact_Fddys = map(Fddy, ts, ys) exact_ltes = map(lte, dts[2:], dts[1:-1], dts[:-2], exact_dddys[3:], exact_Fddys[3:]) error_diff_ltes = map(op.sub, errors[1:], errors[:-1])[2:] # Print for debugging when something goes wrong print exact_ltes print error_diff_ltes # Probably the best test is that they give the same order of # magnitude and the same sign... Can't test much more than that # because we have no idea what the constant in front of the dt**4 # term is. Effective zero (noise level) is either dt**4 or newton # tol, whichever is larger. z = 50 * max(dt**4, newton_tol) map(par(utils.assert_same_sign, fp_zero=z), exact_ltes, error_diff_ltes) map(par(utils.assert_same_order_of_magnitude, fp_zero=z), exact_ltes, error_diff_ltes)
def check_explicit_stepper(stepper, exact_symb): exact, residual, dys, J = utils.symb2functions(exact_symb) base_dt = 1e-3 ts, ys = odeint_explicit(dys[1], exact(0.0), base_dt, 1.0, stepper, time_adaptor=create_random_time_adaptor(base_dt)) exact_ys = map(exact, ts) utils.assert_list_almost_equal(ys, exact_ys, 1e-4)
def check_explicit_stepper(stepper, exact_symb): exact, residual, dys, J = utils.symb2functions(exact_symb) base_dt = 1e-3 ts, ys = odeint_explicit( dys[1], exact(0.0), base_dt, 1.0, stepper, time_adaptor=create_random_time_adaptor(base_dt)) exact_ys = map(exact, ts) utils.assert_list_almost_equal(ys, exact_ys, 1e-4)
def check_lte(method_residual, lte, exact_symb, base_dt, implicit): exact, residual, dys, J = utils.symb2functions(exact_symb) dddy = dys[3] Fddy = lambda t, y: J(t, y) * dys[2](t, y) newton_tol = 1e-10 # tmax varies with dt so that we can vary dt over orders of # magnitude. tmax = 50 * dt # Run ode solver if implicit: ts, ys = ode._odeint( residual, [0.0], [sp.array([exact(0.0)], ndmin=1)], dt, tmax, method_residual, target_error=None, time_adaptor=ode.create_random_time_adaptor(base_dt), initialisation_actions=par(ode.higher_order_start, 3), newton_tol=newton_tol) else: ts, ys = ode.odeint_explicit( dys[1], exact(0.0), base_dt, tmax, method_residual, time_adaptor=ode.create_random_time_adaptor(base_dt)) dts = utils.ts2dts(ts) # Check it's accurate-ish exact_ys = map(exact, ts) errors = map(op.sub, exact_ys, ys) utils.assert_list_almost_zero(errors, 1e-3) # Calculate ltes by two methods. Note that we need to drop a few # values because exact calculation (may) need a few dts. Could be # dodgy: exact dddys might not correspond to dddy in experiment if # done over long time and we've wandered away from the solution. exact_dddys = map(dddy, ts, ys) exact_Fddys = map(Fddy, ts, ys) exact_ltes = map(lte, dts[2:], dts[1:-1], dts[:-2], exact_dddys[3:], exact_Fddys[3:]) error_diff_ltes = map(op.sub, errors[1:], errors[:-1])[2:] # Print for debugging when something goes wrong print exact_ltes print error_diff_ltes # Probably the best test is that they give the same order of # magnitude and the same sign... Can't test much more than that # because we have no idea what the constant in front of the dt**4 # term is. Effective zero (noise level) is either dt**4 or newton # tol, whichever is larger. z = 50 * max(dt**4, newton_tol) map(par(utils.assert_same_sign, fp_zero=z), exact_ltes, error_diff_ltes) map(par(utils.assert_same_order_of_magnitude, fp_zero=z), exact_ltes, error_diff_ltes)