def test_2rab_scheme_explainers(method_name, order=3, step_ratio=3, explainer=TextualSchemeExplainer()): method = TwoRateAdamsBashforthMethodBuilder(method_name, order=order, step_ratio=step_ratio) method.generate(explainer=explainer) print(explainer)
def test_dot(order=3, step_ratio=3, method_name="F", show=False): method = TwoRateAdamsBashforthMethodBuilder( method_name, order=order, step_ratio=step_ratio, hist_consistency_threshold=1e-8) code = method.generate() from dagrt.language import get_dot_dependency_graph print(get_dot_dependency_graph(code)) if show: from dagrt.language import show_dependency_graph show_dependency_graph(code)
def get_code(self, dt): method = TwoRateAdamsBashforthMethodBuilder( self.method, self.order, self.step_ratio, static_dt=self.static_dt, hist_consistency_threshold=1e-8, early_hist_consistency_threshold=dt**self.order, hist_length_slow=self.hist_length, hist_length_fast=self.hist_length) # Early consistency threshold checked for convergence # with timestep change - C. Mikida, 2/6/18 (commit hash 2e6ca077) # With method 4-Ss (limiting case), the following maximum relative # errors were observed: # for dt = 0.015625: 3.11E-09 # for dt = 0.0078125: 1.04e-10 # Corresponding EOC: 4.90 # Reported relative errors show that no constant factor is needed on # early consistency threshold return method.generate()
def make_multirate_method(f2f, s2f, f2s, s2s, ratio=2, order=3): """Return the object that drives the multirate method for the given parameters.""" FastestFirst = "Fq" code = TwoRateAdamsBashforthMethodBuilder(FastestFirst, order, ratio).generate() MRABMethod = PythonCodeGenerator(class_name='MRABMethod').get_class(code) rhs_map = { '<func>f2f': f2f, '<func>s2f': s2f, '<func>f2s': f2s, '<func>s2s': s2s } return MRABMethod(rhs_map)
def test_multirate_squarewave(min_order, hist_length, method_name): stepper = TwoRateAdamsBashforthMethodBuilder(method_name, min_order, 4, hist_consistency_threshold=1e-8, early_hist_consistency_threshold="3.5e3 * <dt>**%d" % min_order, hist_length_slow=hist_length, hist_length_fast=hist_length) # Early consistency threshold checked for convergence # with timestep change - C. Mikida, 2/6/18 (commit hash 0fb6148) # With method 3-4-Ss (limiting case), the following maximum relative # errors were observed: # for dt = 0.0011: 6.96E-08 # for dt = 0.00073: 5.90E-09 # Reported relative errors motivate constant factor of 3.5e3 for early # consistency threshold code = stepper.generate() from dagrt.function_registry import ( base_function_registry, register_ode_rhs) freg = base_function_registry for func_name in [ "<func>s2s", "<func>f2s", "<func>s2f", "<func>f2f", ]: component_id = { "s": "slow", "f": "fast", }[func_name[-1]] freg = register_ode_rhs(freg, identifier=func_name, output_type_id=component_id, input_type_ids=("slow", "fast"), input_names=("s", "f")) freg = freg.register_codegen("<func>s2f", "fortran", f.CallCode(""" ${result} = (sin(2*${t}) - 1)*${s} """)) freg = freg.register_codegen("<func>f2s", "fortran", f.CallCode(""" ${result} = (sin(2*${t}) + 1)*${f} """)) freg = freg.register_codegen("<func>f2f", "fortran", f.CallCode(""" ${result} = cos(2*${t})*${f} """)) freg = freg.register_codegen("<func>s2s", "fortran", f.CallCode(""" ${result} = -cos(2*${t})*${s} """)) codegen = f.CodeGenerator( "MRAB", user_type_map={ "slow": f.ArrayType( (1,), f.BuiltinType('real (kind=8)'), ), "fast": f.ArrayType( (1,), f.BuiltinType('real (kind=8)'), ) }, function_registry=freg, module_preamble=""" ! lines copied to the start of the module, e.g. to say: ! use ModStuff """) code_str = codegen(code) # Build in conditionals to alter the timestep based on order such that all # tests pass if min_order == 2: fac = 200 elif min_order == 3: fac = 100 else: fac = 12 num_trips_one = 100*fac num_trips_two = 150*fac run_fortran([ ("abmethod.f90", code_str), ("test_mrab_squarewave.f90", ( read_file("test_mrab_squarewave.f90") .replace("MIN_ORDER", str(min_order - 0.3)+"d0") .replace("NUM_TRIPS_ONE", str(num_trips_one)) .replace("NUM_TRIPS_TWO", str(num_trips_two)))), ], fortran_libraries=["lapack", "blas"])
def test_multirate_codegen(min_order, method_name): from leap.multistep.multirate import TwoRateAdamsBashforthMethodBuilder stepper = TwoRateAdamsBashforthMethodBuilder( method_name, min_order, 4, slow_state_filter_name="slow_filt", fast_state_filter_name="fast_filt", # should pass with either, let's alternate by order # static_dt=True is 'more finnicky', so use that at min_order=5. static_dt=True if min_order % 2 == 1 else False, hist_consistency_threshold=1e-8, early_hist_consistency_threshold="1.25e3 * <dt>**%d" % min_order) # Early consistency threshold checked for convergence # with timestep change - C. Mikida, 2/6/18 (commit hash 2e6ca077) # With method 5-Fqs (limiting case), the following maximum relative # errors were observed: # for dt = 0.0384: 1.03E-04 # for dt = 0.0128: 5.43E-08 # Reported relative errors motivate constant factor of 1.25e3 for early # consistency threshold code = stepper.generate() from dagrt.function_registry import ( base_function_registry, register_ode_rhs, UserType, register_function) freg = base_function_registry for func_name in [ "<func>s2s", "<func>f2s", "<func>s2f", "<func>f2f", ]: component_id = { "s": "slow", "f": "fast", }[func_name[-1]] freg = register_ode_rhs(freg, identifier=func_name, output_type_id=component_id, input_type_ids=("slow", "fast"), input_names=("s", "f")) freg = freg.register_codegen("<func>s2f", "fortran", f.CallCode(""" ${result} = (sin(2d0*${t}) - 1d0)*${s} """)) freg = freg.register_codegen("<func>f2s", "fortran", f.CallCode(""" ${result} = (sin(2d0*${t}) + 1d0)*${f} """)) freg = freg.register_codegen("<func>f2f", "fortran", f.CallCode(""" ${result} = cos(2d0*${t})*${f} """)) freg = freg.register_codegen("<func>s2s", "fortran", f.CallCode(""" ${result} = -cos(2d0*${t})*${s} """)) freg = register_function(freg, "<func>slow_filt", ("arg",), result_names=("result",), result_kinds=(UserType("slow"),)) freg = freg.register_codegen("<func>slow_filt", "fortran", f.CallCode(""" ! mess with state ${result} = ${arg} """)) freg = register_function(freg, "<func>fast_filt", ("arg",), result_names=("result",), result_kinds=(UserType("fast"),)) freg = freg.register_codegen("<func>fast_filt", "fortran", f.CallCode(""" ! mess with state ${result} = ${arg} """)) codegen = f.CodeGenerator( "MRAB", user_type_map={ "slow": f.ArrayType( (1,), f.BuiltinType('real (kind=8)'), ), "fast": f.ArrayType( (1,), f.BuiltinType('real (kind=8)'), ) }, function_registry=freg, module_preamble=""" ! lines copied to the start of the module, e.g. to say: ! use ModStuff """) code_str = codegen(code) if 0: with open("abmethod.f90", "wt") as outf: outf.write(code_str) fac = 130 if min_order == 5 and method_name in ["Srs", "Ss"]: pytest.xfail("Srs,Ss do not achieve fifth order convergence") num_trips_one = 10*fac num_trips_two = 30*fac run_fortran([ ("abmethod.f90", code_str), ("test_mrab.f90", ( read_file("test_mrab.f90") .replace("MIN_ORDER", str(min_order - 0.3)+"d0") .replace("NUM_TRIPS_ONE", str(num_trips_one)) .replace("NUM_TRIPS_TWO", str(num_trips_two)))), ], fortran_libraries=["lapack", "blas"])
def main(): from leap.step_matrix import StepMatrixFinder from pymbolic import var speed_factor = 10 step_ratio = 7 method_name = "Fq" order = 3 print("speed factor: %g - step ratio: %g - method: %s " "- order: %d" % (speed_factor, step_ratio, method_name, order)) method = TwoRateAdamsBashforthMethodBuilder(method=method_name, order=order, step_ratio=step_ratio, static_dt=True) code = method.generate() finder = StepMatrixFinder(code, function_map={ "<func>f2f": lambda t, f, s: var("f2f") * f, "<func>s2f": lambda t, f, s: var("s2f") * s, "<func>f2s": lambda t, f, s: var("f2s") * f, "<func>s2s": lambda t, f, s: var("s2s") * s, }, exclude_variables=["<p>bootstrap_step"]) mat = finder.get_phase_step_matrix("primary") if 0: print("Variables: %s" % finder.variables) np.set_printoptions(formatter={"all": str}) print(mat) tol = 1e-8 from leap.step_matrix import fast_evaluator evaluate_mat = fast_evaluator(mat) def is_stable(direction, dt): smat = evaluate_mat({ "<dt>": dt, "f2f": direction, "s2f": 1 / speed_factor, "f2s": 1 / speed_factor, "s2s": direction * 1 / speed_factor, }) eigvals = la.eigvals(smat) return (np.abs(eigvals) <= 1 + tol).all() from leap.stability import find_truth_bdry from functools import partial prec = 1e-5 print("stable imaginary timestep:", find_truth_bdry(partial(is_stable, 1j), prec=prec)) print("stable neg real timestep:", find_truth_bdry(partial(is_stable, -1), prec=prec))
def main(): from leap.step_matrix import StepMatrixFinder from pymbolic import var speed_factor = 10 method_name = "Fq" order = 3 tol = 1e-8 prec = 1e-5 angles = np.linspace(0, 2*np.pi, 100, endpoint=False) for step_ratio in [1, 2, 3, 4, 5, 6]: print("speed factor: %g - step ratio: %g - method: %s " "- order: %d" % (speed_factor, step_ratio, method_name, order)) method = TwoRateAdamsBashforthMethodBuilder( method=method_name, order=order, step_ratio=step_ratio, static_dt=True) code = method.generate() finder = StepMatrixFinder(code, function_map={ "<func>f2f": lambda t, f, s: var("f2f") * f, "<func>s2f": lambda t, f, s: var("s2f") * s, "<func>f2s": lambda t, f, s: var("f2s") * f, "<func>s2s": lambda t, f, s: var("s2s") * s, }, exclude_variables=["<p>bootstrap_step"]) mat = finder.get_phase_step_matrix("primary") if 0: print('Variables: %s' % finder.variables) np.set_printoptions(formatter={"all": str}) print(mat) from leap.step_matrix import fast_evaluator evaluate = fast_evaluator(mat) def is_stable(major_eigval, dt): smat = evaluate({ "<dt>": dt, "f2f": major_eigval, "s2f": 1/speed_factor, "f2s": 1/speed_factor, "s2s": major_eigval*1/speed_factor, }) eigvals = la.eigvals(smat) return (np.abs(eigvals) <= 1 + tol).all() from leap.stability import find_truth_bdry from functools import partial points = [] for angle in angles: eigval = np.exp(1j*angle) max_dt = find_truth_bdry(partial(is_stable, eigval), prec=prec) stable_fake_eigval = eigval*max_dt points.append([stable_fake_eigval.real, stable_fake_eigval.imag]) points = np.array(points).T pt.plot(points[0], points[1], "x", label="steprat: %d" % step_ratio) pt.legend(loc="best") pt.grid() outfile = "mr-stability-diagram.pdf" pt.savefig(outfile) print("Output written to %s" % outfile)
def main(): from leap.step_matrix import StepMatrixFinder from pymbolic import var speed_factor = 10 method_name = "Fq" order = 3 step_ratio = 3 prec = 1e-5 method = TwoRateAdamsBashforthMethodBuilder( method=method_name, order=order, step_ratio=step_ratio, static_dt=True) code = method.generate() finder = StepMatrixFinder(code, function_map={ "<func>f2f": lambda t, f, s: var("f2f") * f, "<func>s2f": lambda t, f, s: var("s2f") * s, "<func>f2s": lambda t, f, s: var("f2s") * f, "<func>s2s": lambda t, f, s: var("s2s") * s, }, exclude_variables=["<p>bootstrap_step"]) mat = finder.get_phase_step_matrix("primary") left = -3 right = 1 bottom = -4 top = 4 res = 200 points = np.mgrid[left:right:res*1j, bottom:top:res*1j] eigvals = points[0] + 1j*points[1] eigvals_flat = eigvals.reshape(-1) from multiprocessing import Pool pool = Pool() from leap.step_matrix import fast_evaluator evaluate_mat = fast_evaluator(mat) stable_dts_list = pool.map( partial(process_eigval, evaluate_mat, speed_factor, prec), eigvals_flat) max_eigvals = np.zeros(eigvals.shape) max_eigvals.reshape(-1)[:] = stable_dts_list pt.title("speed factor: %g - step ratio: %g - method: %s " "- order: %d" % (speed_factor, step_ratio, method_name, order)) log_max_eigvals = np.log10(1e-15+max_eigvals.T) pt.imshow(log_max_eigvals, extent=(left, right, bottom, top), cmap="viridis") pt.colorbar() pt.contour(eigvals.real, eigvals.imag, log_max_eigvals.T, [0], zorder=10) pt.gca().set_aspect("equal") pt.grid() outfile = "mr-max-eigvals.pdf" pt.savefig(outfile) print("Output written to %s" % outfile)