def test_strang_splitting(plot_solution=False): from leap.rk import LSRK4Method method1 = LSRK4Method("y", rhs_func_name="<func>y1") method2 = LSRK4Method("y", rhs_func_name="<func>y2") code1 = method1.generate() code2 = method2.generate() from leap.transform import strang_splitting code = strang_splitting(code1, code2, "primary") print(code) from utils import python_method_impl_codegen def exact(t): return np.exp(3j * t) from pytools.convergence import EOCRecorder eocrec = EOCRecorder() for dt in 2**-np.array(range(4, 7), dtype=np.float64): # noqa pylint:disable=invalid-unary-operand-type interp = python_method_impl_codegen(code, function_map={ "<func>y1": lambda t, y: 1j * y, "<func>y2": lambda t, y: 2j * y, }) interp.set_up(t_start=0, dt_start=dt, context={"y": 1}) final_t = 4 times = [] values = [] for event in interp.run(t_end=final_t): if isinstance(event, interp.StateComputed): values.append(event.state_component) times.append(event.t) assert abs(times[-1] - final_t) / final_t < 0.1 times = np.array(times) # Check that the timestep is preserved. assert np.allclose(np.diff(times), dt) if plot_solution: import matplotlib.pyplot as pt pt.plot(times, values, label="comp") pt.plot(times, exact(times), label="true") pt.show() error = abs(values[-1] - exact(final_t)) eocrec.add_data_point(dt, error) print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > 2 * 0.9
def check_simple_convergence(method, method_impl, expected_order, problem=DefaultProblem(), dts=_default_dts, show_dag=False, plot_solution=False): component_id = method.component_id code = method.generate() print(code) if show_dag: from dagrt.language import show_dependency_graph show_dependency_graph(code) from pytools.convergence import EOCRecorder eocrec = EOCRecorder() for dt in dts: t = problem.t_start y = problem.initial() final_t = problem.t_end interp = method_impl(code, function_map={ "<func>" + component_id: problem, }) interp.set_up(t_start=t, dt_start=dt, context={component_id: y}) times = [] values = [] for event in interp.run(t_end=final_t): if isinstance(event, interp.StateComputed): assert event.component_id == component_id values.append(event.state_component[0]) times.append(event.t) assert abs(times[-1] - final_t) / final_t < 0.1 times = np.array(times) if plot_solution: import matplotlib.pyplot as pt pt.plot(times, values, label="comp") pt.plot(times, problem.exact(times), label="true") pt.show() error = abs(values[-1] - problem.exact(final_t)) eocrec.add_data_point(dt, error) print("------------------------------------------------------") print("%s: expected order %d" % (method.__class__.__name__, expected_order)) print("------------------------------------------------------") print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > expected_order * 0.9
def test_convergence(python_method_impl, problem, method, expected_order): pytest.importorskip("scipy") code = method.generate() from leap.implicit import replace_AssignImplicit code = replace_AssignImplicit(code, {"solve": solver_hook}) from pytools.convergence import EOCRecorder eocrec = EOCRecorder() for n in range(2, 7): dt = 2**(-n) y_0 = problem.initial() t_start = problem.t_start t_end = problem.t_end from functools import partial interp = python_method_impl(code, function_map={ "<func>expl_y": problem.nonstiff, "<func>impl_y": problem.stiff, "<func>solver": partial(solver, problem.stiff), }) interp.set_up(t_start=t_start, dt_start=dt, context={"y": y_0}) times = [] values = [] for event in interp.run(t_end=t_end): if isinstance(event, interp.StateComputed): values.append(event.state_component) times.append(event.t) times = np.array(times) values = np.array(values) assert abs(times[-1] - t_end) < 1e-10 times = np.array(times) error = np.linalg.norm(values[-1] - problem.exact(t_end)) eocrec.add_data_point(dt, error) print("------------------------------------------------------") print("expected order %d" % expected_order) print("------------------------------------------------------") print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > 0.9 * expected_order
def __call__(self): """Run the test and output the estimated the order of convergence.""" from pytools.convergence import EOCRecorder if self.display_dag: self.show_dag() eocrec = EOCRecorder() for n in range(6, 8): dt = 2**(-n) error = self.get_error(dt, "mrab-%d.dat" % self.order) eocrec.add_data_point(dt, error) print("------------------------------------------------------") print("ORDER %d" % self.order) print("------------------------------------------------------") print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > self.order * 0.70
def test_dependent_state(order=3, step_ratio=3): # Solve # f' = f+s # s' = -f+s def true_f(t): return np.exp(t) * np.sin(t) def true_s(t): return np.exp(t) * np.cos(t) method = MultiRateMultiStepMethodBuilder(order, ( ( "dt", "fast", "=", MRHistory(1, "<func>f", ( "two_fast", "slow", )), ), ("dt", "slow", "=", MRHistory(step_ratio, "<func>s", ("fast", "slow"))), ( "two_fast", "=", MRHistory(step_ratio, "<func>twice", ("fast", )), ), ), static_dt=True) code = method.generate() print(code) from pytools.convergence import EOCRecorder eocrec = EOCRecorder() from dagrt.codegen import PythonCodeGenerator codegen = PythonCodeGenerator(class_name="Method") stepper_cls = codegen.get_class(code) for n in range(4, 7): t = 0 dt = 2**(-n) final_t = 10 stepper = stepper_cls( function_map={ "<func>f": lambda t, two_fast, slow: 0.5 * two_fast + slow, "<func>s": lambda t, fast, slow: -fast + slow, "<func>twice": lambda t, fast: 2 * fast, }) stepper.set_up(t_start=t, dt_start=dt, context={ "fast": true_f(t), "slow": true_s(t), }) f_times = [] f_values = [] s_times = [] s_values = [] for event in stepper.run(t_end=final_t): if isinstance(event, stepper_cls.StateComputed): if event.component_id == "fast": f_times.append(event.t) f_values.append(event.state_component) elif event.component_id == "slow": s_times.append(event.t) s_values.append(event.state_component) else: assert False, event.component_id f_times = np.array(f_times) s_times = np.array(s_times) f_values_true = true_f(f_times) s_values_true = true_s(s_times) f_err = f_values - f_values_true s_err = s_values - s_values_true error = ( la.norm(f_err) / la.norm(f_values_true) + # noqa: W504 la.norm(s_err) / la.norm(s_values_true)) eocrec.add_data_point(dt, error) print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > 3 * 0.95
def test_im_euler_accuracy(python_method_impl, show_dag=False, plot_solution=False): component_id = "y" from implicit_euler import ImplicitEulerMethod method = ImplicitEulerMethod(component_id) code = method.generate(solver_hook) expected_order = 1 if show_dag: from dagrt.language import show_dependency_graph show_dependency_graph(code) h = -0.5 y_0 = 1.0 def rhs(t, y): return h * y def soln(t): return y_0 * np.exp(h * t) from pytools.convergence import EOCRecorder eocrec = EOCRecorder() for n in range(1, 5): dt = 2**(-n) t = 0.0 y = y_0 final_t = 1 from functools import partial interp = python_method_impl(code, function_map={ method.rhs_func.name: rhs, "<func>solver": partial(solver, rhs) }) interp.set_up(t_start=t, dt_start=dt, context={component_id: y}) times = [] values = [] for event in interp.run(t_end=final_t): if isinstance(event, interp.StateComputed): assert event.component_id == component_id values.append(event.state_component) times.append(event.t) assert abs(times[-1] - final_t) < 1e-10 times = np.array(times) if plot_solution: import matplotlib.pyplot as pt pt.plot(times, values, label="comp") pt.plot(times, soln(times), label="true") pt.show() error = abs(values[-1] - soln(final_t)) eocrec.add_data_point(dt, error) print("------------------------------------------------------") print("%s: expected order %d" % (method, expected_order)) print("------------------------------------------------------") print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > expected_order * 0.9
def test_adaptive(python_method_impl, problem, method): pytest.importorskip("scipy") t_start = problem.t_start t_end = problem.t_end dt = 1.0e-1 tols = [10.0**(-j) for j in range(1, 5)] from pytools.convergence import EOCRecorder eocrec = EOCRecorder() # Test that tightening the tolerance will decrease the overall error. for atol in tols: generator = method("y", atol=atol) code = generator.generate() #sgen = ScipySolverGenerator(*generator.implicit_expression()) from leap.implicit import replace_AssignImplicit code = replace_AssignImplicit(code, {"solve": solver_hook}) from functools import partial interp = python_method_impl(code, function_map={ "<func>expl_y": problem.nonstiff, "<func>impl_y": problem.stiff, "<func>solver": partial(solver, problem.stiff) }) interp.set_up(t_start=t_start, dt_start=dt, context={"y": problem.initial()}) times = [] values = [] new_times = [] new_values = [] for event in interp.run(t_end=t_end): clear_flag = False if isinstance(event, interp.StateComputed): assert event.component_id == "y" new_values.append(event.state_component) new_times.append(event.t) elif isinstance(event, interp.StepCompleted): values.extend(new_values) times.extend(new_times) clear_flag = True elif isinstance(event, interp.StepFailed): clear_flag = True if clear_flag: del new_times[:] del new_values[:] times = np.array(times) values = np.array(values) exact = problem.exact(times[-1]) error = np.linalg.norm(values[-1] - exact) eocrec.add_data_point(atol, error) print("Error vs. tolerance") print(eocrec.pretty_print()) order = eocrec.estimate_order_of_convergence()[0, 1] assert order > 0.9
def main(show_dag=False, plot_solution=False): component_id = "y" method = ODE23Method(component_id, use_high_order=True) expected_order = 3 # Use "DEBUG" to trace execution logging.basicConfig(level=logging.INFO) code = method.generate() if show_dag: from dagrt.language import show_dependency_graph show_dependency_graph(code) from dagrt.exec_numpy import NumpyInterpreter def rhs(t, y): u, v = y return np.array([v, -u/t**2], dtype=np.float64) def soln(t): inner = np.sqrt(3)/2*np.log(t) return np.sqrt(t)*( 5*np.sqrt(3)/3*np.sin(inner) + np.cos(inner) ) from pytools.convergence import EOCRecorder eocrec = EOCRecorder() for n in range(4, 7): dt = 2**(-n) t = 1 y = np.array([1, 3], dtype=np.float64) final_t = 10 interp = NumpyInterpreter(code, function_map={"<func>" + component_id: rhs}) interp.set_up(t_start=t, dt_start=dt, context={component_id: y}) times = [] values = [] for event in interp.run(t_end=final_t): if isinstance(event, interp.StateComputed): assert event.component_id == component_id values.append(event.state_component[0]) times.append(event.t) assert abs(times[-1] - final_t) < 1e-10 times = np.array(times) if plot_solution: import matplotlib.pyplot as pt pt.plot(times, values, label="comp") pt.plot(times, soln(times), label="true") pt.show() error = abs(values[-1]-soln(final_t)) eocrec.add_data_point(dt, error) print("------------------------------------------------------") print("%s: expected order %d" % (method, expected_order)) print("------------------------------------------------------") print(eocrec.pretty_print()) orderest = eocrec.estimate_order_of_convergence()[0, 1] assert orderest > expected_order*0.95