Exemple #1
0
def test_driver_generation_flag(tmpdir, create_driver):
    '''Test that driver generation can be enabled and disabled, and
    that it is disabled by default. If create_driver is None, the
    default behaviour (don't create driver) is tested.

    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    psy, invoke = get_invoke("driver_test.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule

    if create_driver is None:
        etrans.apply(schedule.children[0:2])
    else:
        etrans.apply(schedule.children[0:2], {'create_driver': create_driver})
    # We are only interested in the potentially triggered driver-creation.
    str(psy.gen)

    driver = tmpdir.join("driver-psy_extract_example_with_various_variable_"
                         "access_patterns-invoke_0_compute_kernel:compute_"
                         "kernel_code:r0.f90")
    # When create_driver is None, as a default no driver should be created.
    # Since "None or False" is "False", this simple test can be used in all
    # three cases.
    assert driver.isfile() == (create_driver or False)
Exemple #2
0
def test_change_prefix(tmpdir, monkeypatch):
    '''
    This tests that the prefix of a gocean extract transformation
    can be changed, and that the new prefix is also used in the
    created driver.
    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    psy, invoke = get_invoke("single_invoke_scalar_float_arg.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)

    # In order to use a different prefix, this prefix needs to be valid.
    # So monkeypatch the valid prefix names in the config object:
    config = Config.get()
    monkeypatch.setattr(config, "_valid_psy_data_prefixes", ["NEW"])

    etrans = GOceanExtractTrans()
    etrans.apply(invoke.schedule.children[0], {
        'create_driver': True,
        'region_name': ("main", "update"),
        'prefix': "NEW"
    })

    # Test that the extraction code contains the new prefix:
    assert 'CALL NEW_psy_data%PreStart("main", "update", 4, 3)' \
        in str(psy.gen)

    # Now test if the created driver has the right prefix:
    driver_name = tmpdir.join("driver-main-update.f90")
    with open(str(driver_name), "r") as driver_file:
        driver_code = driver_file.read()
    assert 'CALL NEW_psy_data%OpenRead("main", "update")' in driver_code
Exemple #3
0
def test_rename_region(tmpdir):
    '''
    This tests that an extract region can be renamed, and that the created
    driver will use the new names.
    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    psy, invoke = get_invoke("single_invoke_scalar_float_arg.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)

    etrans.apply(invoke.schedule.children[0], {
        'create_driver': True,
        'region_name': ("main", "update")
    })

    # Test that the extraction code contains the right names
    assert 'CALL extract_psy_data%PreStart("main", "update", 4, 3)' \
        in str(psy.gen)

    # Now test if the created driver has the right name, and will open the
    # right file:
    driver_name = tmpdir.join("driver-main-update.f90")
    with open(str(driver_name), "r") as driver_file:
        driver_code = driver_file.read()
    assert 'CALL extract_psy_data%OpenRead("main", "update")' in driver_code
Exemple #4
0
def trans(psy):
    '''
    Take the supplied psy object, and add kernel extraction code.

    :param psy: the PSy layer to transform.
    :type psy: :py:class:`psyclone.gocean1p0.GOPSy`

    :returns: the transformed PSy object.
    :rtype: :py:class:`psyclone.gocean1p0.GOPSy`

    '''
    from psyclone.domain.gocean.transformations import GOceanExtractTrans
    extract = GOceanExtractTrans()

    invoke = psy.invokes.get("invoke_0")
    schedule = invoke.schedule
    _, _ = extract.apply(schedule.children,
                         {"create_driver": True,
                          "region_name": ("main", "init")})

    invoke = psy.invokes.get("invoke_1_update_field")
    schedule = invoke.schedule

    # Enclose everything in a extract region
    newschedule, _ = extract.apply(schedule.children,
                                   {"create_driver": True,
                                    "region_name": ("main", "update")})

    invoke.schedule = newschedule
    newschedule.view()
    return psy
Exemple #5
0
def test_extract_node_position():
    ''' Test that Extract Transformation inserts the ExtractNode
    at the position of the first node in the Node list
    marked for extraction. '''

    # Test GOcean1.0 API for extraction of a single Node
    gocetrans = GOceanExtractTrans()
    _, invoke = get_invoke("single_invoke_three_kernels.f90",
                           GOCEAN_API,
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule
    # Apply Extract transformation to the second Node and assert that
    # position and the absolute position of the ExtractNode are the same as
    # respective positions of the second Node before the transformation.
    pos = 1
    child = schedule.children[pos]
    abspos = child.abs_position
    dpth = child.depth
    gocetrans.apply(child)
    extract_node = schedule.walk(ExtractNode)
    # The result is only one ExtractNode in the list with position 1
    assert extract_node[0].position == pos
    assert extract_node[0].abs_position == abspos
    assert extract_node[0].depth == dpth
    assert extract_node[0].dag_name == "gocean_extract_1"
Exemple #6
0
def test_driver_grid_properties(tmpdir):
    '''
    This tests the extraction and driver generated for grid properties.
    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    psy, invoke = get_invoke("single_invoke_scalar_float_arg.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)

    etrans.apply(invoke.schedule.children[0], {'create_driver': True})

    # First test extraction code
    # --------------------------
    extract_code = str(psy.gen)

    # Test the handling of scalar and array grid properties
    expected_lines = [
        'CALL extract_psy_data%PreDeclareVariable("ssh_fld%grid%'
        'subdomain%internal%xstop", ssh_fld%grid%subdomain%'
        'internal%xstop)', 'CALL extract_psy_data%PreDeclareVariable('
        '"ssh_fld%grid%tmask", ssh_fld%grid%tmask)',
        'CALL extract_psy_data%ProvideVariable('
        '"ssh_fld%grid%subdomain%internal%xstop", '
        'ssh_fld%grid%subdomain%internal%xstop)',
        'CALL extract_psy_data%ProvideVariable('
        '"ssh_fld%grid%tmask", ssh_fld%grid%tmask)'
    ]

    # Check that the above lines occur in the same order. There might be
    # other lines between the expected lines, which will be ignored in
    # 'ordered_linex_in_text'.
    ordered_lines_in_text(expected_lines, extract_code)

    # Now test the created driver:
    # ----------------------------
    driver_name = tmpdir.join("driver-psy_single_invoke_scalar_float_test-"
                              "invoke_0_bc_ssh:bc_ssh_code:r0.f90")
    with open(str(driver_name), "r") as driver_file:
        driver_code = driver_file.read()

    expected_lines = [
        'REAL(KIND=8), allocatable, dimension(:,:) :: tmask',
        'INTEGER :: xstop', 'CALL extract_psy_data%OpenRead(',
        '"psy_single_invoke_scalar_float_test", '
        '"invoke_0_bc_ssh:bc_ssh_code:r0")',
        'CALL extract_psy_data%ReadVariable('
        '"ssh_fld%grid%subdomain%internal%xstop", xstop)',
        'CALL extract_psy_data%ReadVariable('
        '"ssh_fld%grid%tmask", tmask)'
    ]

    # Check that the above lines occur in the same order. There might be
    # other lines between the expected lines, which will be ignored in
    # 'ordered_linex_in_text'.
    ordered_lines_in_text(expected_lines, driver_code)
Exemple #7
0
def test_single_node_ompparalleldo_gocean1p0():
    ''' Test that applying Extract Transformation on a Node enclosed
    within an OMP Parallel DO Directive produces the correct result
    in GOcean1.0 API. Note that this test only pases due to TODO #969:
    the loop boundaries are actually missing. Once #969 is fixed, this
    test should be removed, since it is covered by the test further down!
    But for now this test is left in place since it tests the omp
    functionality with a passing test.
    '''

    etrans = GOceanExtractTrans()
    otrans = GOceanOMPParallelLoopTrans()

    # Test a Loop nested within the OMP Parallel DO Directive
    psy, invoke = get_invoke("single_invoke_three_kernels.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule
    # This test expects constant loop bounds
    schedule._const_loop_bounds = True

    # Apply GOceanOMPParallelLoopTrans to the second Loop
    otrans.apply(schedule.children[1])
    # Now enclose the parallel region within an ExtractNode (inserted
    # at the previous location of the OMPParallelDoDirective
    etrans.apply(schedule.children[1])

    code = str(psy.gen)
    output = """      ! ExtractStart
      !
      CALL extract_psy_data%PreStart("psy_single_invoke_three_kernels", """ \
      """"invoke_0:compute_cv_code:r0", 2, 3)
      CALL extract_psy_data%PreDeclareVariable("p_fld", p_fld)
      CALL extract_psy_data%PreDeclareVariable("v_fld", v_fld)
      CALL extract_psy_data%PreDeclareVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%PreDeclareVariable("i_post", i)
      CALL extract_psy_data%PreDeclareVariable("j_post", j)
      CALL extract_psy_data%PreEndDeclaration
      CALL extract_psy_data%ProvideVariable("p_fld", p_fld)
      CALL extract_psy_data%ProvideVariable("v_fld", v_fld)
      CALL extract_psy_data%PreEnd
      !$omp parallel do default(shared), private(i,j), schedule(static)
      DO j=2,jstop+1
        DO i=2,istop
          CALL compute_cv_code(i, j, cv_fld%data, p_fld%data, v_fld%data)
        END DO
      END DO
      !$omp end parallel do
      CALL extract_psy_data%PostStart
      CALL extract_psy_data%ProvideVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%ProvideVariable("i_post", i)
      CALL extract_psy_data%ProvideVariable("j_post", j)
      CALL extract_psy_data%PostEnd
      !
      ! ExtractEnd"""

    assert output in code
Exemple #8
0
def test_driver_scalars(tmpdir):
    '''
    This tests the extraction and driver generated for scalars.
    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    psy, invoke = get_invoke("single_invoke_scalar_float_arg.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)

    etrans.apply(invoke.schedule.children[0], {'create_driver': True})

    # First test extraction code
    # --------------------------
    extract_code = str(psy.gen)

    # Test the handling of scalar parameter in extraction code:
    expected_lines = [
        'USE extract_psy_data_mod, ONLY: extract_PSyDataType',
        'CALL extract_psy_data%PreDeclareVariable("a_scalar", '
        'a_scalar)', 'CALL extract_psy_data%ProvideVariable("a_scalar", '
        'a_scalar)'
    ]

    # Check that the above lines occur in the same order. There might be
    # other lines between the expected lines, which will be ignored in
    # 'ordered_linex_in_text'.
    ordered_lines_in_text(expected_lines, extract_code)

    # Now test the created driver:
    # ----------------------------
    driver_name = tmpdir.join("driver-psy_single_invoke_scalar_float_test-"
                              "invoke_0_bc_ssh:bc_ssh_code:r0.f90")
    with open(str(driver_name), "r") as driver_file:
        driver_code = driver_file.read()

    expected_lines = [
        'USE extract_psy_data_mod, ONLY: extract_PSyDataType',
        'TYPE(extract_PSyDataType) extract_psy_data', 'INTEGER :: xstop',
        'REAL(KIND=8) :: a_scalar',
        'CALL extract_psy_data%OpenRead("kernel_scalar_float", '
        '"bc_ssh_code")', 'CALL extract_psy_data%ReadVariable("a_scalar", '
        'a_scalar)'
    ]

    # Check that the above lines occur in the same order. There might be
    # other lines between the expected lines, which will be ignored in
    # 'ordered_linex_in_text'.
    with pytest.raises(ValueError):
        ordered_lines_in_text(expected_lines, driver_code)
    pytest.xfail("#644 Scalars not supported yet.")
Exemple #9
0
def test_no_parent_accdirective():
    ''' Test that applying Extract Transformation on an orphaned
    ACCLoopDirective without its ancestor ACCParallelDirective
    when optimisations are applied raises a TransformationError. '''

    etrans = GOceanExtractTrans()
    acclpt = ACCLoopTrans()
    accpara = ACCParallelTrans()
    accdata = ACCEnterDataTrans()

    _, invoke = get_invoke("single_invoke_three_kernels.f90",
                           GOCEAN_API,
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule

    # Apply the OpenACC Loop transformation to every loop in the Schedule
    for child in schedule.children:
        if isinstance(child, Loop):
            acclpt.apply(child)
    # Enclose all of these loops within a single ACC Parallel region
    accpara.apply(schedule.children)
    # Add a mandatory ACC enter-data directive
    accdata.apply(schedule)

    orphaned_directive = schedule.children[1].children[0]
    with pytest.raises(TransformationError) as excinfo:
        _, _ = etrans.apply(orphaned_directive)
    assert "Error in GOceanExtractTrans: Application to Nodes enclosed " \
           "within a thread-parallel region is not allowed." \
           in str(excinfo.value)
Exemple #10
0
def test_single_node_ompparalleldo_gocean1p0():
    ''' Test that applying Extract Transformation on a Node enclosed
    within an OMP Parallel DO Directive produces the correct result
    in GOcean1.0 API. '''

    etrans = GOceanExtractTrans()
    otrans = GOceanOMPParallelLoopTrans()

    # Test a Loop nested within the OMP Parallel DO Directive
    psy, invoke = get_invoke("single_invoke_three_kernels.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule
    # This test expects constant loop bounds
    schedule._const_loop_bounds = True

    # Apply GOceanOMPParallelLoopTrans to the second Loop
    schedule, _ = otrans.apply(schedule.children[1])
    # Now enclose the parallel region within an ExtractNode (inserted
    # at the previous location of the OMPParallelDoDirective
    schedule, _ = etrans.apply(schedule.children[1])

    code = str(psy.gen)
    output = """      ! ExtractStart
      !
      CALL extract_psy_data%PreStart("psy_single_invoke_three_kernels", """ \
      """"invoke_0:compute_cv_code:r0", 2, 3)
      CALL extract_psy_data%PreDeclareVariable("p_fld", p_fld)
      CALL extract_psy_data%PreDeclareVariable("v_fld", v_fld)
      CALL extract_psy_data%PreDeclareVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%PreDeclareVariable("i_post", i)
      CALL extract_psy_data%PreDeclareVariable("j_post", j)
      CALL extract_psy_data%PreEndDeclaration
      CALL extract_psy_data%ProvideVariable("p_fld", p_fld)
      CALL extract_psy_data%ProvideVariable("v_fld", v_fld)
      CALL extract_psy_data%PreEnd
      !$omp parallel do default(shared), private(i,j), schedule(static)
      DO j=2,jstop+1
        DO i=2,istop
          CALL compute_cv_code(i, j, cv_fld%data, p_fld%data, v_fld%data)
        END DO
      END DO
      !$omp end parallel do
      CALL extract_psy_data%PostStart
      CALL extract_psy_data%ProvideVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%ProvideVariable("i_post", i)
      CALL extract_psy_data%ProvideVariable("j_post", j)
      CALL extract_psy_data%PostEnd
      !
      ! ExtractEnd"""

    assert output in code
Exemple #11
0
def test_driver_loop_variables(tmpdir):
    '''Test that loop variables are not stored. ATM this test
    fails because of #641 but also because of #644 (scalars are considered
    to be arrays)

    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    psy, invoke = get_invoke("driver_test.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule

    etrans.apply(schedule.children[0], {'create_driver': True})
    # We are only interested in the driver, so ignore results.
    str(psy.gen)

    driver = tmpdir.join("driver-psy_extract_example_with_various_variable_"
                         "access_patterns-invoke_0_compute_kernel:compute_"
                         "kernel_code:r0.f90")

    assert driver.isfile()

    with open(str(driver), "r") as driver_file:
        driver_code = driver_file.read()

    # Since atm types are not handled, scalars are actually considered
    # to be arrays. Once this is fixed, none of those lines should be
    # in the code anymore (j_post should be declared as scalar):
    unexpected = '''      REAL(KIND=8), allocatable, dimension(:,:) :: j_post
      ALLOCATE (j, mold=j_post)'''
    unexpected_lines = unexpected.split("\n")

    for line in unexpected_lines:
        if line in driver_code:
            pytest.xfail("#641 Loop variables are stored.")
    assert False, "X-failing test working: #641 Loop variables."
Exemple #12
0
def test_kern_builtin_no_loop():
    ''' Test that applying Extract Transformation on a Kernel or Built-in
    call without its parent Loop raises a TransformationError. '''

    gocetrans = GOceanExtractTrans()
    _, invoke = get_invoke("single_invoke_three_kernels.f90",
                           GOCEAN_API,
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule
    # Test Kernel call
    kernel_call = schedule.children[0].loop_body[0].loop_body[0]
    with pytest.raises(TransformationError) as excinfo:
        _, _ = gocetrans.apply(kernel_call)
    assert "Error in GOceanExtractTrans: Application to a Kernel or a " \
           "Built-in call without its parent Loop is not allowed." \
           in str(excinfo.value)
Exemple #13
0
def test_no_outer_loop_gocean1p0():
    ''' Test that applying GOceanExtractTrans on an inner Loop without
    its parent outer Loop in GOcean1.0 API raises a TransformationError. '''
    etrans = GOceanExtractTrans()
    _, invoke = get_invoke("single_invoke_three_kernels.f90",
                           GOCEAN_API,
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule

    # Try to extract the region between the outer and the inner Loop
    inner_loop = schedule[0].loop_body
    with pytest.raises(TransformationError) as excinfo:
        _, _ = etrans.apply(inner_loop)
    assert "Error in GOceanExtractTrans: Application to an inner Loop " \
           "without its ancestor outer Loop is not allowed." \
           in str(excinfo.value)
Exemple #14
0
def test_rename_suffix_if_name_clash(tmpdir):
    '''Test that driver is created correctly if there is a clash
    with the variable names, e.g. an output variable 'a', and
    an input variable 'a_post' - writing the output variable 'a'
    would use 'a_post' as name, so the suffix must be changed.

    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    psy, invoke = get_invoke("driver_test.f90",
                             GOCEAN_API,
                             idx=1,
                             dist_mem=False)
    schedule = invoke.schedule

    etrans.apply(schedule.children[0], {'create_driver': True})
    extract_code = str(psy.gen)

    # Due to the name clash of "out_fld"+"_post" and "out_fld_post"
    # the _post suffix is changed to _post0. So the file will
    # contain out_fld_post for the input variable out_fld_post,
    # and "out_fld_post0" for the output value of out_fld.
    expected = """
      CALL extract_psy_data%PreDeclareVariable("out_fld_post", out_fld_post)
      CALL extract_psy_data%PreDeclareVariable("in_out_fld_post0", in_out_fld)
      CALL extract_psy_data%PreDeclareVariable("out_fld_post0", out_fld)
      CALL extract_psy_data%ProvideVariable("in_out_fld", in_out_fld)
      CALL extract_psy_data%ProvideVariable("out_fld_post", out_fld_post)
      CALL extract_psy_data%ProvideVariable("in_out_fld_post0", in_out_fld)
      CALL extract_psy_data%ProvideVariable("out_fld_post0", out_fld)"""
    expected_lines = expected.split("\n")
    ordered_lines_in_text(expected_lines, extract_code)

    # Now we also need to check that the driver uses the new suffix,
    # i.e. both as key for ReadVariable, as well as for the variable
    # names.
    driver = tmpdir.join("driver-psy_extract_example_with_various_variable_"
                         "access_patterns-invoke_1_compute_kernel:compute_"
                         "kernel_code:r0.f90")
    assert driver.isfile()

    with driver.open("r") as driver_file:
        driver_code = driver_file.read()

    expected = """
      REAL(KIND=8), allocatable, dimension(:,:) :: out_fld_post
      REAL(KIND=8), allocatable, dimension(:,:) :: out_fld_post0
      REAL(KIND=8), allocatable, dimension(:,:) :: out_fld
      REAL(KIND=8), allocatable, dimension(:,:) :: in_out_fld_post0
      REAL(KIND=8), allocatable, dimension(:,:) :: in_out_fld
      CALL extract_psy_data%ReadVariable("in_out_fld", in_out_fld)
      CALL extract_psy_data%ReadVariable("in_out_fld_post0", in_out_fld_post0)
      CALL extract_psy_data%ReadVariable("out_fld_post0", out_fld_post0)
      ALLOCATE (out_fld, mold=out_fld_post0)
      CALL extract_psy_data%ReadVariable("out_fld_post", out_fld_post)"""

    ordered_lines_in_text(expected.split("\n"), driver_code)

    # Now test that more than one variable clash is handled. The third
    # invoke uses:
    # "out_fld" as output field
    # "out_fld_post" as input field (first clash --> suffix becomes "_post0")
    # "out_fld_post0" as input+output field (next clash --> suffix = "_post1")
    psy, invoke = get_invoke("driver_test.f90",
                             GOCEAN_API,
                             idx=2,
                             dist_mem=False)
    schedule = invoke.schedule
    # We don't check the driver, we already tested that the
    # driver picks up the adjusted suffix above
    etrans.apply(schedule.children[0])
    extract_code = str(psy.gen)

    # Check that *out_fld* is declared correctly: it is only declared as
    # output value, so must use key out_fld_post1 once, and not be declared
    # as input value:
    assert 'PreDeclareVariable("out_fld_post1", out_fld)' in extract_code
    assert 'PreDeclareVariable("out_fld", out_fld)' not in extract_code

    # Check that *out_fld_post* (input/output) is declared correctly. It must
    # be declared twice: once for the input value using the original variable
    # name, and once as output using the "_post1" suffix"
    assert 'PreDeclareVariable("out_fld_post", out_fld_post)' in extract_code
    assert 'PreDeclareVariable("out_fld_post_post1", out_fld_post)' \
        in extract_code

    # Check that *out_fld_post0* is declared correctly: as input-only
    # variable it must be declared once for using the original variable name.
    assert 'PreDeclareVariable("out_fld_post0", out_fld_post0)' in extract_code
    assert 'PreDeclareVariable("out_fld_post0_post1", out_fld_post0)' \
        not in extract_code
Exemple #15
0
def test_driver_creation(tmpdir):
    '''Test that driver is created correctly for all variable access \
    modes (input, input-output, output).

    '''
    # Use tmpdir so that the driver is created in tmp
    tmpdir.chdir()

    etrans = GOceanExtractTrans()
    ctrans = GOConstLoopBoundsTrans()
    psy, invoke = get_invoke("driver_test.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule
    # This test expects constant loop bounds
    ctrans.apply(schedule)

    etrans.apply(schedule.children[0], {'create_driver': True})
    # We are only interested in the driver, so ignore results.
    str(psy.gen)

    driver = tmpdir.join("driver-psy_extract_example_with_various_variable_"
                         "access_patterns-invoke_0_compute_kernel:compute_"
                         "kernel_code:r0.f90")
    assert driver.isfile()

    with driver.open("r") as driver_file:
        driver_code = driver_file.read()

    # This is an excerpt of the code that should get created.
    # It is tested line by line since there is other code in between
    # which is not important, and the order might also change. It also
    # tests if unique variable names are created in the driver: the user
    # program contains a local variable 'dx', which clashes with the grid
    # property dx. The grid property will be renamed to 'dx_1':
    expected = '''USE extract_psy_data_mod, ONLY: extract_PSyDataType
      IMPLICIT NONE
      REAL(KIND=8), allocatable, dimension(:,:) :: gphiu
      REAL(KIND=8), allocatable, dimension(:,:) :: out_fld
      REAL(KIND=8), allocatable, dimension(:,:) :: out_fld_post
      REAL(KIND=8), allocatable, dimension(:,:) :: in_fld
      REAL(KIND=8), allocatable, dimension(:,:) :: dx
      REAL(KIND=8), allocatable, dimension(:,:) :: dx_1
      REAL(KIND=8), allocatable, dimension(:,:) :: in_out_fld
      REAL(KIND=8), allocatable, dimension(:,:) :: in_out_fld_post

      TYPE(extract_PSyDataType) extract_psy_data
      CALL extract_psy_data%OpenRead("psy_extract_example_with_various_variable''' \
      '''_access_patterns", "invoke_0_compute_kernel:compute_kernel_code:r0")
      CALL extract_psy_data%ReadVariable("out_fld_post", out_fld_post)
      ALLOCATE (out_fld, mold=out_fld_post)
      out_fld = 0.0
      CALL extract_psy_data%ReadVariable("in_fld", in_fld)
      CALL extract_psy_data%ReadVariable("in_out_fld_post", in_out_fld_post)
      CALL extract_psy_data%ReadVariable("dx", dx)
      CALL extract_psy_data%ReadVariable("in_fld%grid%dx", dx_1)
      CALL extract_psy_data%ReadVariable("in_fld%grid%gphiu", gphiu)
      ! RegionStart
      DO j=2,jstop
        DO i=2,istop+1
          CALL compute_kernel_code(i, j, out_fld, in_out_fld, in_fld, ''' \
      '''dx, dx_1, gphiu)
        END DO
      END DO
      ! RegionEnd
      !
      ! Check out_fld
      ! Check i
      ! Check j
      ! Check in_out_fld'''
    expected_lines = expected.split("\n")
    for line in expected_lines:
        assert line in driver_code
Exemple #16
0
def test_node_list_ompparallel_gocean1p0():
    ''' Test that applying Extract Transformation on a list of Nodes
    enclosed within an OMP Parallel Region produces the correct result
    in GOcean1.0 API. '''

    etrans = GOceanExtractTrans()
    ltrans = GOceanOMPLoopTrans()
    otrans = OMPParallelTrans()
    ctrans = GOConstLoopBoundsTrans()

    # Test a Loop nested within the OMP Parallel DO Directive
    psy, invoke = get_invoke("single_invoke_three_kernels.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule

    # Apply GOConstLoopBoundsTrans
    ctrans.apply(schedule)
    # Apply GOceanOMPParallelLoopTrans to the first two Loops
    ltrans.apply(schedule.children[0])
    ltrans.apply(schedule.children[1])
    # and enclose them within a parallel region
    otrans.apply(schedule.children[0:2])
    # Now enclose the parallel region within an ExtractNode (inserted
    # at the previous location of the OMPParallelDirective
    etrans.apply(schedule.children[0])

    code = str(psy.gen)
    output = """
      ! ExtractStart
      !
      CALL extract_psy_data%PreStart("psy_single_invoke_three_kernels", """ \
      """"invoke_0:r0", 3, 4)
      CALL extract_psy_data%PreDeclareVariable("p_fld", p_fld)
      CALL extract_psy_data%PreDeclareVariable("u_fld", u_fld)
      CALL extract_psy_data%PreDeclareVariable("v_fld", v_fld)
      CALL extract_psy_data%PreDeclareVariable("cu_fld_post", cu_fld)
      CALL extract_psy_data%PreDeclareVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%PreDeclareVariable("i_post", i)
      CALL extract_psy_data%PreDeclareVariable("j_post", j)
      CALL extract_psy_data%PreEndDeclaration
      CALL extract_psy_data%ProvideVariable("p_fld", p_fld)
      CALL extract_psy_data%ProvideVariable("u_fld", u_fld)
      CALL extract_psy_data%ProvideVariable("v_fld", v_fld)
      CALL extract_psy_data%PreEnd
      !$omp parallel default(shared), private(i,j)
      !$omp do schedule(static)
      DO j=2,jstop
        DO i=2,istop+1
          CALL compute_cu_code(i, j, cu_fld%data, p_fld%data, u_fld%data)
        END DO
      END DO
      !$omp end do
      !$omp do schedule(static)
      DO j=2,jstop+1
        DO i=2,istop
          CALL compute_cv_code(i, j, cv_fld%data, p_fld%data, v_fld%data)
        END DO
      END DO
      !$omp end do
      !$omp end parallel
      CALL extract_psy_data%PostStart
      CALL extract_psy_data%ProvideVariable("cu_fld_post", cu_fld)
      CALL extract_psy_data%ProvideVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%ProvideVariable("i_post", i)
      CALL extract_psy_data%ProvideVariable("j_post", j)
      CALL extract_psy_data%PostEnd
      !
      ! ExtractEnd"""
    assert output in code
Exemple #17
0
def test_single_node_ompparalleldo_gocean1p0_failing_const_loop():
    ''' Test that applying Extract Transformation on a Node enclosed
    within an OMP Parallel DO Directive produces the correct result
    in GOcean1.0 API. This test is mostly identical to the previous one,
    but uses const loop bounds. At this stage, the dependency analysis
    still reports `cv_fld%internal%xstart` etc as loop boundaries, but
    the code created will be using istop and jstop.

    '''
    etrans = GOceanExtractTrans()
    otrans = GOceanOMPParallelLoopTrans()
    ctrans = GOConstLoopBoundsTrans()

    # Test a Loop nested within the OMP Parallel DO Directive
    psy, invoke = get_invoke("single_invoke_three_kernels.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule
    ctrans.apply(schedule)
    # Required for #969
    schedule.view()

    # Apply GOceanOMPParallelLoopTrans to the second Loop
    otrans.apply(schedule.children[1])

    # Now enclose the parallel region within an ExtractNode (inserted
    # at the previous location of the OMPParallelDoDirective
    etrans.apply(schedule.children[1])

    code = str(psy.gen)
    output = """      ! ExtractStart
      !
      CALL extract_psy_data%PreStart("psy_single_invoke_three_kernels", """ \
      """"invoke_0:compute_cv_code:r0", 6, 3)
      CALL extract_psy_data%PreDeclareVariable("istop", istop)
      CALL extract_psy_data%PreDeclareVariable("jstop", jstop)
      CALL extract_psy_data%PreDeclareVariable("p_fld", p_fld)
      CALL extract_psy_data%PreDeclareVariable("v_fld", v_fld)
      CALL extract_psy_data%PreDeclareVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%PreDeclareVariable("i_post", i)
      CALL extract_psy_data%PreDeclareVariable("j_post", j)
      CALL extract_psy_data%PreEndDeclaration
      CALL extract_psy_data%ProvideVariable("istop", istop)
      CALL extract_psy_data%ProvideVariable("jstop", jstop)
      CALL extract_psy_data%ProvideVariable("p_fld", p_fld)
      CALL extract_psy_data%ProvideVariable("v_fld", v_fld)
      CALL extract_psy_data%PreEnd
      !$omp parallel do default(shared), private(i,j), schedule(static)
      DO j=2,jstop+1
        DO i=2,istop
          CALL compute_cv_code(i, j, cv_fld%data, p_fld%data, v_fld%data)
        END DO
      END DO
      !$omp end parallel do
      CALL extract_psy_data%PostStart
      CALL extract_psy_data%ProvideVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%ProvideVariable("i_post", i)
      CALL extract_psy_data%ProvideVariable("j_post", j)
      CALL extract_psy_data%PostEnd
      !
      ! ExtractEnd"""
    assert output in code
Exemple #18
0
def test_single_node_ompparalleldo_gocean1p0_failing():
    ''' Test that applying Extract Transformation on a Node enclosed
    within an OMP Parallel DO Directive produces the correct result
    in GOcean1.0 API. This test is mostly identical to the previous one,
    but due to TODO #969 the loop boundaries are not defined and are
    therefore missing. Once #969 is fixed, the previous test can be
    removed.

    '''
    etrans = GOceanExtractTrans()
    otrans = GOceanOMPParallelLoopTrans()

    # Test a Loop nested within the OMP Parallel DO Directive
    psy, invoke = get_invoke("single_invoke_three_kernels.f90",
                             GOCEAN_API,
                             idx=0,
                             dist_mem=False)
    schedule = invoke.schedule

    # Apply GOceanOMPParallelLoopTrans to the second Loop
    otrans.apply(schedule.children[1])

    # Now enclose the parallel region within an ExtractNode (inserted
    # at the previous location of the OMPParallelDoDirective
    etrans.apply(schedule.children[1])

    code = str(psy.gen)
    output = """      ! ExtractStart
      !
      CALL extract_psy_data%PreStart("psy_single_invoke_three_kernels", """ \
      """"invoke_0:compute_cv_code:r0", 6, 3)
      CALL extract_psy_data%PreDeclareVariable("cv_fld%internal%xstart", """ \
                                               """cv_fld%internal%xstart)
      CALL extract_psy_data%PreDeclareVariable("cv_fld%internal%xstop", """ \
                                               """cv_fld%internal%xstop)
      CALL extract_psy_data%PreDeclareVariable("cv_fld%internal%ystart", """ \
                                               """cv_fld%internal%ystart)
      CALL extract_psy_data%PreDeclareVariable("cv_fld%internal%ystop", """ \
                                               """cv_fld%internal%ystop)
      CALL extract_psy_data%PreDeclareVariable("p_fld", p_fld)
      CALL extract_psy_data%PreDeclareVariable("v_fld", v_fld)
      CALL extract_psy_data%PreDeclareVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%PreDeclareVariable("i_post", i)
      CALL extract_psy_data%PreDeclareVariable("j_post", j)
      CALL extract_psy_data%PreEndDeclaration
      CALL extract_psy_data%ProvideVariable("cv_fld%internal%xstart", """ \
                                            """cv_fld%internal%xstart)
      CALL extract_psy_data%ProvideVariable("cv_fld%internal%xstop", """ \
                                            """cv_fld%internal%xstop)
      CALL extract_psy_data%ProvideVariable("cv_fld%internal%ystart", """ \
                                            """cv_fld%internal%ystart)
      CALL extract_psy_data%ProvideVariable("cv_fld%internal%ystop", """ \
                                            """cv_fld%internal%ystop)
      CALL extract_psy_data%ProvideVariable("p_fld", p_fld)
      CALL extract_psy_data%ProvideVariable("v_fld", v_fld)
      CALL extract_psy_data%PreEnd
      !$omp parallel do default(shared), private(i,j), schedule(static)
      DO j=cv_fld%internal%ystart,cv_fld%internal%ystop
        DO i=cv_fld%internal%xstart,cv_fld%internal%xstop
          CALL compute_cv_code(i, j, cv_fld%data, p_fld%data, v_fld%data)
        END DO
      END DO
      !$omp end parallel do
      CALL extract_psy_data%PostStart
      CALL extract_psy_data%ProvideVariable("cv_fld_post", cv_fld)
      CALL extract_psy_data%ProvideVariable("i_post", i)
      CALL extract_psy_data%ProvideVariable("j_post", j)
      CALL extract_psy_data%PostEnd
      !
      ! ExtractEnd"""
    assert output in code