Esempio n. 1
0
def test_adaptive_rk_codegen_error():
    """Test whether Fortran code generation for the Runge-Kutta
    timestepper works.
    """

    component_id = 'y'
    rhs_function = '<func>y'

    stepper = ODE45MethodBuilder(component_id, use_high_order=False, atol=1e-6)

    from dagrt.function_registry import (
            base_function_registry, register_ode_rhs)
    freg = register_ode_rhs(base_function_registry, component_id,
                            identifier=rhs_function)
    freg = freg.register_codegen(rhs_function, "fortran",
            f.CallCode("""
                ${result} = -2*${y}
                """))

    code = stepper.generate()

    codegen = f.CodeGenerator(
            "RKMethod",
            user_type_map={
                component_id: f.ArrayType(
                    (2,),
                    f.BuiltinType('real (kind=8)'),
                    )
                },
            function_registry=freg)

    run_fortran([
        ("rkmethod.f90", codegen(code)),
        ("test_rk_adaptive_error.f90", read_file("test_rk_adaptive_error.f90")),
        ])
Esempio n. 2
0
def test_elementwise_abs():
    with CodeBuilder(name="primary") as cb:
        cb("i", "<builtin>array(20)")
        cb("i[j]", "-j", loops=(("j", 0, 20), ))
        # Test new builtin on an array type.
        cb("k", "<builtin>elementwise_abs(i)")
        with cb.if_("k[20] > 19"):
            cb.raise_(AbsFailure)
        with cb.if_("k[20] < 19"):
            cb.raise_(AbsFailure)
        # Test new builtin on a scalar.
        cb("l", "<builtin>elementwise_abs(-20)")
        with cb.if_("l > 20"):
            cb.raise_(AbsFailure)
        with cb.if_("l < 20"):
            cb.raise_(AbsFailure)
        cb("y", "<func>f(0, <state>ytype)")
        cb("<state>ytype", "y")
        # Test new builtin on a usertype.
        cb("<state>ytype", "<builtin>elementwise_abs(<state>ytype)")
        # (We check this in the outer test code)

    code = create_DAGCode_with_steady_phase(cb.statements)

    rhs_function = "<func>f"

    from dagrt.function_registry import (base_function_registry,
                                         register_ode_rhs)
    freg = register_ode_rhs(base_function_registry,
                            "ytype",
                            identifier=rhs_function,
                            input_names=("y", ))
    freg = freg.register_codegen(
        rhs_function, "fortran",
        f.CallCode("""
                ${result} = -2*${y}
                """))

    codegen = f.CodeGenerator(
        "element_abs_test",
        function_registry=freg,
        user_type_map={"ytype": f.ArrayType((100, ), f.BuiltinType("real*8"))},
        timing_function="second")

    code_str = codegen(code)

    run_fortran([
        ("element_abs.f90", code_str),
        ("test_element_abs.f90", read_file("test_element_abs.f90")),
    ],
                fortran_libraries=["lapack", "blas"])
Esempio n. 3
0
def test_singlerate_squarewave(min_order, hist_length):
    from leap.multistep import AdamsBashforthMethodBuilder

    component_id = "y"
    rhs_function = "<func>y"

    stepper = AdamsBashforthMethodBuilder("y",
                                          min_order,
                                          hist_length=hist_length)

    from dagrt.function_registry import (base_function_registry,
                                         register_ode_rhs)
    freg = register_ode_rhs(base_function_registry,
                            component_id,
                            identifier=rhs_function)
    freg = freg.register_codegen(
        rhs_function, "fortran",
        f.CallCode("""
                ${result} = -2*${y}
                """))

    code = stepper.generate()

    codegen = f.CodeGenerator("ABMethod",
                              user_type_map={
                                  component_id:
                                  f.ArrayType(
                                      (2, ),
                                      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)
    with open("abmethod_test.f90", "wt") as outf:
        outf.write(code_str)

    run_fortran(
        [
            ("abmethod.f90", code_str),
            ("test_ab_squarewave.f90",
             read_file("test_ab_squarewave.f90").replace(
                 "MIN_ORDER",
                 str(min_order - 0.3) + "d0")),
        ],
        fortran_libraries=["lapack", "blas"],
    )
Esempio n. 4
0
def test_rk_codegen(min_order, stepper, print_code=False):
    """Test whether Fortran code generation for the Runge-Kutta
    timestepper works.
    """

    component_id = 'y'
    rhs_function = '<func>y'

    from dagrt.function_registry import (base_function_registry,
                                         register_ode_rhs)
    freg = register_ode_rhs(base_function_registry,
                            component_id,
                            identifier=rhs_function)
    freg = freg.register_codegen(
        rhs_function, "fortran",
        f.CallCode("""
                ${result} = -2*${y}
                """))

    code = stepper.generate()

    codegen = f.CodeGenerator('RKMethod',
                              user_type_map={
                                  component_id:
                                  f.ArrayType(
                                      (2, ),
                                      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 print_code:
        print(code_str)

    run_fortran([
        ("rkmethod.f90", code_str),
        ("test_rk.f90",
         read_file("test_rk.f90").replace("MIN_ORDER",
                                          str(min_order - 0.3) + "d0")),
    ])
Esempio n. 5
0
def test_basic_codegen():
    """Test whether the code generator returns a working method. The
    generated method always returns 0."""
    cbuild = RawCodeBuilder()
    cbuild.add_and_get_ids(
        YieldState(id="return",
                   time=0,
                   time_id="final",
                   expression=0,
                   component_id="state",
                   depends_on=[]))
    cbuild.commit()
    code = create_DAGCode_with_steady_phase(cbuild.statements)
    codegen = f.CodeGenerator("simple",
                              user_type_map={
                                  "state":
                                  f.ArrayType(
                                      (200, ),
                                      f.BuiltinType("real (kind=8)"),
                                  )
                              })
    print(codegen(code))
Esempio n. 6
0
def test_adaptive_rk_codegen():
    """Test whether Fortran code generation for the Runge-Kutta
    timestepper works.
    """

    component_id = "y"
    rhs_function = "<func>y"

    stepper = ODE45MethodBuilder(component_id, use_high_order=False, rtol=1e-6)

    from dagrt.function_registry import (base_function_registry,
                                         register_ode_rhs)
    freg = register_ode_rhs(base_function_registry,
                            component_id,
                            identifier=rhs_function)
    freg = freg.register_codegen(
        rhs_function, "fortran",
        f.CallCode("""
                ${result}(1) = ${y}(2)
                ${result}(2) = -30*((${y}(1))**2 - 1)*${y}(2) - ${y}(1)
                """))

    code = stepper.generate()

    codegen = f.CodeGenerator("RKMethod",
                              user_type_map={
                                  "y":
                                  f.ArrayType(
                                      (2, ),
                                      f.BuiltinType("real (kind=8)"),
                                  ),
                              },
                              function_registry=freg)

    run_fortran([
        ("rkmethod.f90", codegen(code)),
        ("test_rk_adaptive.f90", read_file("test_rk_adaptive.f90")),
    ])
Esempio n. 7
0
def test_self_dep_in_loop():
    with CodeBuilder(name="primary") as cb:
        cb("y", "<state>y")
        cb("y",
           "<func>f(0, 2*i*<func>f(0, y if i > 2 else 2*y))",
           loops=(("i", 0, 5), ))
        cb("<state>y", "y")

    code = create_DAGCode_with_steady_phase(cb.statements)

    rhs_function = "<func>f"

    from dagrt.function_registry import (base_function_registry,
                                         register_ode_rhs)
    freg = register_ode_rhs(base_function_registry,
                            "ytype",
                            identifier=rhs_function,
                            input_names=("y", ))
    freg = freg.register_codegen(
        rhs_function, "fortran",
        f.CallCode("""
                ${result} = -2*${y}
                """))

    codegen = f.CodeGenerator(
        "selfdep",
        function_registry=freg,
        user_type_map={"ytype": f.ArrayType((100, ), f.BuiltinType("real*8"))},
        timing_function="second")

    code_str = codegen(code)
    run_fortran([
        ("selfdep.f90", code_str),
        ("test_selfdep.f90", read_file("test_selfdep.f90")),
    ],
                fortran_libraries=["lapack", "blas"])
Esempio n. 8
0
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"])
Esempio n. 9
0
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"])
Esempio n. 10
0
def test_rk_codegen_fancy():
    """Test whether Fortran code generation with lots of fancy features for the
    Runge-Kutta timestepper works.
    """

    component_id = 'y'
    rhs_function = '<func>y'
    state_filter_name = 'state_filter_y'

    stepper = ODE23MethodBuilder(component_id, use_high_order=True,
            state_filter_name=state_filter_name)

    from dagrt.function_registry import (
            base_function_registry, register_ode_rhs,
            register_function, UserType)
    freg = register_ode_rhs(base_function_registry, component_id,
                            identifier=rhs_function)
    freg = freg.register_codegen(rhs_function, "fortran",
            f.CallCode("""
                <%

                igrid = declare_new("integer", "igrid")
                i = declare_new("integer", "i")

                %>

                do ${igrid} = 1, region%n_grids
                  do ${i} = 1, region%n_grid_dofs(${igrid})
                    ${result}(${igrid})%conserved_var(${i}) = &
                     -2*${y}(${igrid})%conserved_var(${i})
                  end do
                end do

                """))
    freg = register_function(freg, "notify_pre_state_update", ("updated_component",))
    freg = freg.register_codegen("notify_pre_state_update", "fortran",
            f.CallCode("""
                write(*,*) 'before state update'
                """))
    freg = register_function(
            freg, "notify_post_state_update", ("updated_component",))
    freg = freg.register_codegen("notify_post_state_update", "fortran",
            f.CallCode("""
                write(*,*) 'after state update'
                """))

    freg = register_function(freg, "<func>"+state_filter_name, ("y",),
            result_names=("result",), result_kinds=(UserType("y"),))
    freg = freg.register_codegen("<func>"+state_filter_name, "fortran",
            f.CallCode("""
                ! mess with state
                <%

                igrid = declare_new("integer", "igrid")
                i = declare_new("integer", "i")

                %>

                do ${igrid} = 1, region%n_grids
                  do ${i} = 1, region%n_grid_dofs(${igrid})
                    ${result}(${igrid})%conserved_var(${i}) = &
                     0.95*${y}(${igrid})%conserved_var(${i})
                  end do
                end do

                """))

    code = stepper.generate()

    codegen = f.CodeGenerator(
            "RKMethod",
            user_type_map={
                component_id: f.ArrayType(
                    "region%n_grids",
                    index_vars="igrid",
                    element_type=f.StructureType(
                        "sim_grid_state_type",
                        (
                            ("conserved_var", f.PointerType(
                                f.ArrayType(
                                    ("region%n_grid_dofs(igrid)",),
                                    f.BuiltinType('real (kind=8)')))),
                        )))
                },
            function_registry=freg,
            module_preamble="""
                use sim_types
                use timing

                """,
            call_before_state_update="notify_pre_state_update",
            call_after_state_update="notify_post_state_update",
            extra_arguments="region",
            extra_argument_decl="""
                type(region_type), pointer :: region
                """,
            parallel_do_preamble="!dir$ simd",
            emit_instrumentation=True,
            timing_function="get_time")

    code_str = codegen(code)
    print(code_str)

    run_fortran([
        ("sim_types.f90", read_file("sim_types.f90")),
        ("timing.f90", read_file("timing.f90")),
        ("rkmethod.f90", code_str),
        ("test_fancy_rk.f90", read_file("test_fancy_rk.f90")),
        ])