def test_bad_timestep_handling(): """ Check that rejecting timesteps works. """ tmax = 0.4 tol = 1e-4 def list_cummulative_sums(values, start): temp = [start] for v in values: temp.append(temp[-1] + v) return temp dts = [1e-6, 1e-6, 1e-6, (1. - 0.01)*tmax] initial_ts = list_cummulative_sums(dts[:-1], 0.) initial_ys = [sp.array(exp3_exact(t), ndmin=1) for t in initial_ts] adaptor = par(general_time_adaptor, lte_calculator=bdf2_mp_lte_estimate, method_order=2) ts, ys = _odeint(exp3_residual, initial_ts, initial_ys, dts[-1], tmax, bdf2_residual, tol, adaptor) # plt.plot(ts,ys) # plt.plot(ts[1:], utils.ts2dts(ts)) # plt.plot(ts, map(exp3_exact, ts)) # plt.show() overall_tol = len(ys) * tol * 2 # 2 is a fudge factor... utils.assert_list_almost_equal(ys, map(exp3_exact, ts), overall_tol)
def test_bad_timestep_handling(): """ Check that rejecting timesteps works. """ tmax = 0.4 tol = 1e-4 def list_cummulative_sums(values, start): temp = [start] for v in values: temp.append(temp[-1] + v) return temp dts = [1e-6, 1e-6, 1e-6, (1. - 0.01) * tmax] initial_ts = list_cummulative_sums(dts[:-1], 0.) initial_ys = [sp.array(exp3_exact(t), ndmin=1) for t in initial_ts] adaptor = par(general_time_adaptor, lte_calculator=bdf2_mp_lte_estimate, method_order=2) ts, ys = _odeint(exp3_residual, initial_ts, initial_ys, dts[-1], tmax, bdf2_residual, tol, adaptor) # plt.plot(ts,ys) # plt.plot(ts[1:], utils.ts2dts(ts)) # plt.plot(ts, map(exp3_exact, ts)) # plt.show() overall_tol = len(ys) * tol * 2 # 2 is a fudge factor... utils.assert_list_almost_equal(ys, map(exp3_exact, ts), overall_tol)
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_problem(method, residual, exact, tol=1e-4, tmax=2.0): """Helper function to run odeint with a specified method for a problem and check that the solution matches. """ ts, ys = odeint(residual, [exact(0.0)], tmax, dt=1e-6, method=method, target_error=tol) # Total error should be bounded by roughly n_steps * LTE overall_tol = len(ys) * tol * 10 utils.assert_list_almost_equal(ys, map(exact, ts), overall_tol) return ts, ys
def check_dydt_calcs(dydt_calculator, order, dt, dydt_exact, y_exact): """Check that derivative approximations are roughly as accurate as expected for a few functions. """ ts = sp.arange(0, 0.5, dt) exact_ys = map(y_exact, ts) exact_dys = map(dydt_exact, ts, exact_ys) est_dys = map(dydt_calculator, utils.partial_lists(ts, 5), utils.partial_lists(exact_ys, 5)) utils.assert_list_almost_equal(est_dys, exact_dys[4:], 10*(dt**order))
def check_dydt_calcs(dydt_calculator, order, dt, dydt_exact, y_exact): """Check that derivative approximations are roughly as accurate as expected for a few functions. """ ts = sp.arange(0, 0.5, dt) exact_ys = map(y_exact, ts) exact_dys = map(dydt_exact, ts, exact_ys) est_dys = map(dydt_calculator, utils.partial_lists(ts, 5), utils.partial_lists(exact_ys, 5)) utils.assert_list_almost_equal(est_dys, exact_dys[4:], 10 * (dt**order))
def low_accuracy_recompute_alpha_varying_fields( sph_start, sph_end, t_start, t_end, mag_params): """ Compute effective damping from change in magnetisation and change in applied field. From Nonlinear magnetization dynamics in nanosystems eqn (2.15). See notes 30/7/13. Derivatives are estimated using BDF1 finite differences. """ # Only for normalised problems! assert(mag_params.Ms == 1) # Get some values dt = t_end - t_start m_cart_end = utils.sph2cart(sph_end) h_eff_end = heff(mag_params, t_end, m_cart_end) mxh = sp.cross(m_cart_end, h_eff_end) # Finite difference derivatives dhadt = (mag_params.Hvec(t_start) - mag_params.Hvec(t_end))/dt assert(all(dhadt == 0)) # no field for now dedt = (llg_state_energy(sph_end, mag_params, t_end) - llg_state_energy(sph_start, mag_params, t_start) )/dt sigma = sp.dot(mxh, mxh) / (dedt + sp.dot(m_cart_end, dhadt)) possible_alphas = sp.roots([1, sigma, 1]) a = (-sigma + sqrt(sigma**2 - 4))/2 b = (-sigma - sqrt(sigma**2 - 4))/2 possible_alphas2 = [a, b] utils.assert_list_almost_equal(possible_alphas, possible_alphas2) print(sigma, possible_alphas) def real_and_positive(x): return sp.isreal(x) and x > 0 alphas = filter(real_and_positive, possible_alphas) assert(len(alphas) == 1) return sp.real(alphas[0])
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 test_damping_self_consistency(self): a2s = energy.recompute_alpha_list(self.sphs, self.times, self.mag_params) # Check that we get the same values with the varying fields version a3s = energy.recompute_alpha_list(self.sphs, self.times, self.mag_params, energy.recompute_alpha_varying_fields) utils.assert_list_almost_equal(a2s, a3s, (1.1/len(self.times))) # one of the examples doesn't quite pass with tol=1.0/len, so use # 1.1 # Use 1/length as error estimate because it's proportional to dt # and so proportional to the expected error def check_alpha_ok(a2): return abs(a2 - self.mag_params.alpha) < (1.0/len(self.times)) assert(all(map(check_alpha_ok, a2s)))
def check_residual(residual, initial_m): mag_params = utils.MagParameters() tmax = 3.0 f_residual = ft.partial(residual, mag_params) # Timestep to a solution + convert to spherical result_times, m_list = ode.odeint(f_residual, sp.array(initial_m), tmax, dt=0.01) m_sph = [utils.array2sph(m) for m in m_list] result_pols = [m.pol for m in m_sph] result_azis = [m.azi for m in m_sph] # Calculate exact solutions exact_times, exact_azis = \ mlsn.calculate_equivalent_dynamics(mag_params, result_pols) # Check utils.assert_list_almost_equal(exact_azis, result_azis, 1e-3) utils.assert_list_almost_equal(exact_times, result_times, 1e-3)
def test_damping_self_consistency(self): a2s = energy.recompute_alpha_list(self.sphs, self.times, self.mag_params) # Check that we get the same values with the varying fields version a3s = energy.recompute_alpha_list( self.sphs, self.times, self.mag_params, energy.recompute_alpha_varying_fields) utils.assert_list_almost_equal(a2s, a3s, (1.1 / len(self.times))) # one of the examples doesn't quite pass with tol=1.0/len, so use # 1.1 # Use 1/length as error estimate because it's proportional to dt # and so proportional to the expected error def check_alpha_ok(a2): return abs(a2 - self.mag_params.alpha) < (1.0 / len(self.times)) assert (all(map(check_alpha_ok, a2s)))
def check_newton(residual, exact): solution = newton(residual, sp.array([1.0] * len(exact))) utils.assert_list_almost_equal(solution, exact)
def check_newton(residual, exact): solution = newton(residual, sp.array([1.0]*len(exact))) utils.assert_list_almost_equal(solution, exact)
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)