Ejemplo n.º 1
0
def test_stub_cross2d_stencil():
    '''
    Check that the correct stub code is generated when using a CROSS2D
    stencil
    '''
    ast = fpapi.parse(os.path.join(BASE_PATH,
                                   "testkern_stencil_cross2d_mod.f90"),
                      ignore_comments=False)

    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = str(kernel.gen_stub)
    print(generated_code)
    result1 = (
        "    SUBROUTINE testkern_stencil_cross2d_code(nlayers, field_1_w1, "
        "field_2_w2, field_2_stencil_size, field_2_max_branch_length, "
        "field_2_stencil_dofmap, field_3_w2, field_4_w3, ndf_w1, undf_w1, "
        "map_w1, ndf_w2, undf_w2, map_w2, ndf_w3, undf_w3, map_w3)"
    )
    assert result1 in generated_code
    result2 = (
        "      INTEGER(KIND=i_def), intent(in), dimension(4) :: "
        "field_2_stencil_size\n"
        "      INTEGER(KIND=i_def), intent(in) :: field_2_max_branch_length\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w2,"
        "field_2_max_branch_length,4) :: field_2_stencil_dofmap")
    assert result2 in generated_code
Ejemplo n.º 2
0
def generate(filename, api=""):
    '''
    Generates an empty kernel subroutine with the required arguments
    and datatypes (which we call a stub) when presented with Kernel
    Metadata. This is useful for Kernel developers to make sure
    they are using the correct arguments in the correct order.  The
    Kernel Metadata must be presented in the standard Kernel
    format.

    :param str filename: the name of the file for which to create a \
                         kernel stub for.
    :param str api: the name of the API for which to create a kernel \
                    stub. Must be one of the supported stub APIs.

    :returns: root of fparser1 parse tree for the stub routine.
    :rtype: :py:class:`fparser.one.block_statements.Module`

    :raises GenerationError: if an invalid stub API is specified.
    :raises IOError: if filename does not specify a file.
    :raises ParseError: if the given file could not be parsed.
    :raises GenerationError: if a kernel stub does not have a supported \
                             iteration space (currently only "cells").

    '''
    if api == "":
        api = Config.get().default_stub_api
    if api not in Config.get().supported_stub_apis:
        raise GenerationError(
            "Kernel stub generator: Unsupported API '{0}' specified. "
            "Supported APIs are {1}.".format(api,
                                             Config.get().supported_stub_apis))

    if not os.path.isfile(filename):
        raise IOError(
            "Kernel stub generator: File '{0}' not found.".format(filename))

    # Drop cache
    fparser.one.parsefortran.FortranParser.cache.clear()
    fparser.logging.disable(fparser.logging.CRITICAL)
    try:
        ast = fparser.api.parse(filename, ignore_comments=False)

    except (fparser.common.utils.AnalyzeError, AttributeError) as error:
        raise ParseError("Kernel stub generator: Code appears to be invalid "
                         "Fortran: {0}.".format(str(error)))

    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)

    # Check kernel iteration space before generating code
    if (api == "dynamo0.3"
            and kernel.iterates_over not in USER_KERNEL_ITERATION_SPACES):
        raise GenerationError(
            "The LFRic API kernel stub generator supports kernels that operate"
            " on one of {0}, but found '{1}' in kernel '{2}'.".format(
                USER_KERNEL_ITERATION_SPACES, kernel.iterates_over,
                kernel.name))

    return kernel.gen_stub
Ejemplo n.º 3
0
def test_sub_name():
    ''' test for expected behaviour when the kernel subroutine does
    not conform to the convention of having "_code" at the end of its
    name. In this case we append "_code to the name and _mod to the
    kernel name.'''
    ast = fpapi.parse(SUB_NAME, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = kernel.gen_stub
    output = (
        "  MODULE dummy_mod\n"
        "    IMPLICIT NONE\n"
        "    CONTAINS\n"
        "    SUBROUTINE dummy_code(nlayers, field_1_w1, "
        "ndf_w1, undf_w1, map_w1)\n"
        "      USE constants_mod, ONLY: r_def, i_def\n"
        "      IMPLICIT NONE\n"
        "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w1\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w1) :: map_w1\n"
        "      INTEGER(KIND=i_def), intent(in) :: undf_w1\n"
        "      REAL(KIND=r_def), intent(inout), dimension(undf_w1) :: "
        "field_1_w1\n"
        "    END SUBROUTINE dummy_code\n"
        "  END MODULE dummy_mod")
    assert output in str(generated_code)
Ejemplo n.º 4
0
def test_null_loop():
    ''' Check that we can create a 'null'-type loop and that the validation
    check in the load() method behaves as expected.
    '''
    loop = DynLoop(loop_type="null")
    assert loop.loop_type == "null"
    assert loop.node_str(colour=False) == "Loop[type='null']"

    # Create a kernel by parsing some metadata
    ast = fpapi.parse('''
module testkern_mod
  type, extends(kernel_type) :: testkern_type
     type(arg_type), meta_args(2) =                         &
          (/ arg_type(gh_scalar, gh_real, gh_read),         &
             arg_type(gh_field,  gh_real, gh_readwrite, w3) &
           /)
     integer :: operates_on = cell_column
   contains
     procedure, nopass :: code => testkern_code
  end type testkern_type
contains
  subroutine testkern_code(a, b, c, d)
  end subroutine testkern_code
end module testkern_mod
''',
                      ignore_comments=False)
    dkm = DynKernMetadata(ast, name="testkern_type")
    kern = DynKern()
    kern.load_meta(dkm)
    with pytest.raises(GenerationError) as err:
        loop.load(kern)
    assert ("A DynLoop of type 'null' can only contain a kernel that "
            "operates on the 'domain' but kernel 'testkern_code' operates "
            "on 'cell_column'" in str(err.value))
Ejemplo n.º 5
0
def generate(filename, api=""):
    '''Generates an empty kernel subroutine with the required arguments
       and datatypes (which we call a stub) when presented with Kernel
       Metadata. This is useful for Kernel developers to make sure
       they are using the correct arguments in the correct order.  The
       Kernel Metadata must be presented in the standard Kernel
       format.
    '''
    if api == "":
        api = DEFAULTSTUBAPI
    if api not in SUPPORTEDSTUBAPIS:
        print "Unsupported API '{0}' specified. Supported API's are {1}.".\
              format(api, SUPPORTEDSTUBAPIS)
        raise GenerationError(
            "generate: Unsupported API '{0}' specified. Supported types are "
            "{1}.".format(api, SUPPORTEDSTUBAPIS))

    if not os.path.isfile(filename):
        raise IOError("file '{0}' not found".format(filename))

    # drop cache
    fparser.one.parsefortran.FortranParser.cache.clear()
    fparser.logging.disable('CRITICAL')
    try:
        ast = fparser.api.parse(filename, ignore_comments=False)

    except (fparser.common.utils.AnalyzeError, AttributeError) as error:
        raise ParseError("Code appears to be invalid Fortran: " + str(error))

    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    return kernel.gen_stub
Ejemplo n.º 6
0
def test_intent():
    ''' test that field intent is generated correctly for kernel stubs '''
    ast = fpapi.parse(INTENT, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = kernel.gen_stub
    output = (
        "  MODULE dummy_mod\n"
        "    IMPLICIT NONE\n"
        "    CONTAINS\n"
        "    SUBROUTINE dummy_code(nlayers, field_1_w3, field_2_w1, "
        "field_3_w1, ndf_w3, undf_w3, map_w3, ndf_w1, undf_w1, map_w1)\n"
        "      USE constants_mod, ONLY: r_def, i_def\n"
        "      IMPLICIT NONE\n"
        "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w1\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w1) :: map_w1\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w3\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w3) :: map_w3\n"
        "      INTEGER(KIND=i_def), intent(in) :: undf_w3, undf_w1\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w3) :: "
        "field_1_w3\n"
        "      REAL(KIND=r_def), intent(inout), dimension(undf_w1) :: "
        "field_2_w1\n"
        "      REAL(KIND=r_def), intent(in), dimension(undf_w1) :: "
        "field_3_w1\n"
        "    END SUBROUTINE dummy_code\n"
        "  END MODULE dummy_mod")
    assert output in str(generated_code)
Ejemplo n.º 7
0
def test_lfric_stub_cma_operators():
    '''Check variable usage detection cma operators.
    mesh_ncell2d, cma_operator

    '''
    from psyclone.dynamo0p3 import DynKernMetadata, DynKern
    from psyclone.domain.lfric import KernStubArgList
    ast = get_ast("dynamo0.3", "columnwise_op_mul_2scalars_kernel_mod.F90")
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    var_accesses = VariablesAccessInfo()
    create_arg_list = KernStubArgList(kernel)
    create_arg_list.generate(var_accesses=var_accesses)
    var_info = str(var_accesses)
    for num in ["1", "3", "5"]:
        assert "ncell_2d: READ" in var_info
        assert "cma_op_"+num+": READ" in var_info
        assert "cma_op_"+num+"_nrow: READ" in var_info
        assert "cma_op_"+num+"_ncol: READ" in var_info
        assert "cma_op_"+num+"_bandwidth: READ" in var_info
        assert "cma_op_"+num+"_alpha: READ" in var_info
        assert "cma_op_"+num+"_beta: READ" in var_info
        assert "cma_op_"+num+"_gamma_m: READ" in var_info
        assert "cma_op_"+num+"_gamma_p: READ" in var_info
Ejemplo n.º 8
0
def test_enforce_bc_kernel_stub_gen():
    ''' Test that the enforce_bc_kernel boundary layer argument modification
    is handled correctly for kernel stubs.

    '''
    ast = fpapi.parse(os.path.join(BASE_PATH, "enforce_bc_kernel_mod.f90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = kernel.gen_stub
    output = ("  MODULE enforce_bc_mod\n"
              "    IMPLICIT NONE\n"
              "    CONTAINS\n"
              "    SUBROUTINE enforce_bc_code(nlayers, field_1_aspc1_field_1, "
              "ndf_aspc1_field_1, undf_aspc1_field_1, map_aspc1_field_1, "
              "boundary_dofs_field_1)\n"
              "      USE constants_mod, ONLY: r_def, i_def\n"
              "      IMPLICIT NONE\n"
              "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
              "      INTEGER(KIND=i_def), intent(in) :: ndf_aspc1_field_1\n"
              "      INTEGER(KIND=i_def), intent(in), "
              "dimension(ndf_aspc1_field_1) :: map_aspc1_field_1\n"
              "      INTEGER(KIND=i_def), intent(in) :: undf_aspc1_field_1\n"
              "      REAL(KIND=r_def), intent(inout), "
              "dimension(undf_aspc1_field_1) :: field_1_aspc1_field_1\n"
              "      INTEGER(KIND=i_def), intent(in), "
              "dimension(ndf_aspc1_field_1,2) :: boundary_dofs_field_1\n"
              "    END SUBROUTINE enforce_bc_code\n"
              "  END MODULE enforce_bc_mod")
    assert output in str(generated_code)
def test_stub_dbasis_wrong_shape(monkeypatch):
    ''' Check that stub generation for a kernel requiring differential basis
    functions for quadrature raises the correct errors if the kernel meta-data
    is broken '''
    from psyclone import dynamo0p3
    # Change meta-data to specify differential basis functions
    diff_basis = BASIS.replace("gh_basis", "gh_diff_basis")
    print diff_basis
    ast = fpapi.parse(diff_basis, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    monkeypatch.setattr(kernel, "_eval_shape", value="gh_quadrature_wrong")
    with pytest.raises(GenerationError) as excinfo:
        _ = kernel.gen_stub
    assert (
        "Internal error: unrecognised evaluator shape (gh_quadrature_wrong)"
        in str(excinfo))
    monkeypatch.setattr(dynamo0p3,
                        "VALID_QUADRATURE_SHAPES",
                        value=[
                            "gh_quadrature_xyz", "gh_quadrature_xyoz",
                            "gh_quadrature_xoyoz", "gh_quadrature_wrong"
                        ])
    with pytest.raises(NotImplementedError) as excinfo:
        _ = kernel.gen_stub
    assert ("diff-basis for quadrature shape 'gh_quadrature_wrong' not yet "
            "implemented" in str(excinfo))
Ejemplo n.º 10
0
def test_lfric_stub_args():
    '''Check that correct stub code is produced when there are multiple
    stencils.

    '''
    ast = get_ast("dynamo0.3", "testkern_stencil_multi_mod.f90")
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    var_accesses = VariablesAccessInfo()
    create_arg_list = KernStubArgList(kernel)
    create_arg_list.generate(var_accesses=var_accesses)
    var_info = str(var_accesses)
    assert "field_1_w1: READ+WRITE" in var_info
    assert "field_2_stencil_dofmap: READ" in var_info
    assert "field_2_stencil_size: READ" in var_info
    assert "field_2_w2: READ" in var_info
    assert "field_3_direction: READ" in var_info
    assert "field_3_stencil_dofmap: READ" in var_info
    assert "field_3_stencil_size: READ" in var_info
    assert "field_3_w2: READ" in var_info
    assert "field_4_stencil_dofmap: READ" in var_info
    assert "field_4_stencil_size: READ" in var_info
    assert "field_4_w3: READ" in var_info
    assert "map_w1: READ" in var_info
    assert "map_w2: READ" in var_info
    assert "map_w3: READ" in var_info
    assert "ndf_w1: READ" in var_info
    assert "ndf_w2: READ" in var_info
    assert "ndf_w3: READ" in var_info
    assert "nlayers: READ" in var_info
    assert "undf_w1: READ" in var_info
    assert "undf_w2: READ" in var_info
    assert "undf_w3: READ" in var_info
Ejemplo n.º 11
0
def test_enforce_op_bc_kernel_stub_gen():
    ''' Test that the enforce_operator_bc_kernel boundary dofs argument
    modification is handled correctly for kernel stubs.

    '''
    ast = fpapi.parse(os.path.join(BASE_PATH,
                                   "enforce_operator_bc_kernel_mod.F90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = str(kernel.gen_stub)
    output = ("  MODULE enforce_operator_bc_mod\n"
              "    IMPLICIT NONE\n"
              "    CONTAINS\n"
              "    SUBROUTINE enforce_operator_bc_code(cell, nlayers, "
              "op_1_ncell_3d, op_1, ndf_aspc1_op_1, ndf_aspc2_op_1, "
              "boundary_dofs_op_1)\n"
              "      USE constants_mod, ONLY: r_def, i_def\n"
              "      IMPLICIT NONE\n"
              "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
              "      INTEGER(KIND=i_def), intent(in) :: ndf_aspc1_op_1, "
              "ndf_aspc2_op_1\n"
              "      INTEGER(KIND=i_def), intent(in) :: cell\n"
              "      INTEGER(KIND=i_def), intent(in) :: op_1_ncell_3d\n"
              "      REAL(KIND=r_def), intent(inout), dimension("
              "ndf_aspc1_op_1,ndf_aspc2_op_1,op_1_ncell_3d) :: op_1\n"
              "      INTEGER(KIND=i_def), intent(in), "
              "dimension(ndf_aspc1_op_1,2) :: boundary_dofs_op_1\n"
              "    END SUBROUTINE enforce_operator_bc_code\n"
              "  END MODULE enforce_operator_bc_mod")
    assert output in generated_code
def test_stub_basis_wrong_shape(monkeypatch):
    ''' Check that stub generation for a kernel requiring basis functions
    for quadrature raises the correct errors if the kernel meta-data is
    broken '''
    from psyclone import dynamo0p3
    ast = fpapi.parse(BASIS, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    monkeypatch.setattr(kernel, "_eval_shape", value="gh_quadrature_wrong")
    with pytest.raises(GenerationError) as excinfo:
        _ = kernel.gen_stub
    assert (
        "Internal error: unrecognised evaluator shape (gh_quadrature_wrong)"
        in str(excinfo))
    monkeypatch.setattr(dynamo0p3,
                        "VALID_QUADRATURE_SHAPES",
                        value=[
                            "gh_quadrature_xyz", "gh_quadrature_xyoz",
                            "gh_quadrature_xoyoz", "gh_quadrature_wrong"
                        ])
    with pytest.raises(GenerationError) as excinfo:
        _ = kernel.gen_stub
    assert ("shapes other than GH_QUADRATURE_XYoZ are not yet supported"
            in str(excinfo))
Ejemplo n.º 13
0
def test_refelem_quad_stub_gen():
    ''' Check that correct stub code is produced when the kernel metadata
    contain reference element and quadrature properties (quadrature
    properties should be placed at the end of subroutine argument list). '''
    ast = fpapi.parse(REF_ELEM_QUAD_MDATA, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    gen = str(kernel.gen_stub)

    output1 = (
        "  SUBROUTINE testkern_refelem_quad_code(nlayers, field_1_w1, "
        "field_2_wtheta, ndf_w1, undf_w1, map_w1, basis_w1_qr_xyoz, "
        "ndf_wtheta, undf_wtheta, map_wtheta, basis_wtheta_qr_xyoz, "
        "nfaces_re, normals_to_faces, out_normals_to_faces, np_xy_qr_xyoz, "
        "np_z_qr_xyoz, weights_xy_qr_xyoz, weights_z_qr_xyoz)")
    assert output1 in gen
    output2 = (
        "      INTEGER(KIND=i_def), intent(in) :: np_xy_qr_xyoz, "
        "np_z_qr_xyoz\n"
        "      REAL(KIND=r_def), intent(in), "
        "dimension(3,ndf_w1,np_xy_qr_xyoz,np_z_qr_xyoz) :: basis_w1_qr_xyoz\n"
        "      REAL(KIND=r_def), intent(in), "
        "dimension(1,ndf_wtheta,np_xy_qr_xyoz,np_z_qr_xyoz) :: "
        "basis_wtheta_qr_xyoz\n"
        "      REAL(KIND=r_def), intent(in), dimension(np_xy_qr_xyoz) :: "
        "weights_xy_qr_xyoz\n"
        "      REAL(KIND=r_def), intent(in), dimension(np_z_qr_xyoz) :: "
        "weights_z_qr_xyoz\n"
        "      INTEGER(KIND=i_def), intent(in) :: nfaces_re\n"
        "      REAL(KIND=r_def), intent(in), dimension(3,nfaces_re) :: "
        "normals_to_faces\n"
        "      REAL(KIND=r_def), intent(in), dimension(3,nfaces_re) :: "
        "out_normals_to_faces")
    assert output2 in gen
Ejemplo n.º 14
0
def test_stub_stencil_multi():
    '''Check that correct stub code is produced when there are multiple
    stencils'''
    ast = fpapi.parse(os.path.join(BASE_PATH,
                                   "testkern_stencil_multi_mod.f90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = str(kernel.gen_stub)
    result1 = (
        "    SUBROUTINE testkern_stencil_multi_code(nlayers, field_1_w1, "
        "field_2_w2, field_2_stencil_size, field_2_stencil_dofmap, field_3_w2,"
        " field_3_stencil_size, field_3_direction, field_3_stencil_dofmap, "
        "field_4_w3, field_4_stencil_size, field_4_stencil_dofmap, ndf_w1, "
        "undf_w1, map_w1, ndf_w2, undf_w2, map_w2, ndf_w3, undf_w3, map_w3)")
    assert result1 in generated_code
    result2 = (
        "      REAL(KIND=r_def), intent(in), dimension(undf_w2) :: "
        "field_3_w2\n"
        "      REAL(KIND=r_def), intent(in), dimension(undf_w3) :: "
        "field_4_w3\n"
        "      INTEGER(KIND=i_def), intent(in) :: field_2_stencil_size, "
        "field_3_stencil_size, field_4_stencil_size\n"
        "      INTEGER(KIND=i_def), intent(in) :: field_3_direction\n"
        "      INTEGER(KIND=i_def), intent(in), "
        "dimension(ndf_w2,field_2_stencil_size) :: field_2_stencil_dofmap\n"
        "      INTEGER(KIND=i_def), intent(in), "
        "dimension(ndf_w2,field_3_stencil_size) :: field_3_stencil_dofmap\n"
        "      INTEGER(KIND=i_def), intent(in), "
        "dimension(ndf_w3,field_4_stencil_size) :: field_4_stencil_dofmap")

    assert result2 in generated_code
Ejemplo n.º 15
0
def test_vectors():
    ''' test that field vectors are handled correctly for kernel stubs '''
    ast = fpapi.parse(VECTORS, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = kernel.gen_stub
    output = (
        "  MODULE dummy_mod\n"
        "    IMPLICIT NONE\n"
        "    CONTAINS\n"
        "    SUBROUTINE dummy_code(nlayers, field_1_w0_v1, "
        "field_1_w0_v2, field_1_w0_v3, ndf_w0, undf_w0, map_w0)\n"
        "      USE constants_mod, ONLY: r_def, i_def\n"
        "      IMPLICIT NONE\n"
        "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w0\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w0) :: map_w0\n"
        "      INTEGER(KIND=i_def), intent(in) :: undf_w0\n"
        "      REAL(KIND=r_def), intent(inout), dimension(undf_w0) :: "
        "field_1_w0_v1\n"
        "      REAL(KIND=r_def), intent(inout), dimension(undf_w0) :: "
        "field_1_w0_v2\n"
        "      REAL(KIND=r_def), intent(inout), dimension(undf_w0) :: "
        "field_1_w0_v3\n"
        "    END SUBROUTINE dummy_code\n"
        "  END MODULE dummy_mod")
    assert output in str(generated_code)
Ejemplo n.º 16
0
def test_lfricfields_stub_err():
    ''' Check that the LFRicFields constructor raises the expected internal
    error if it encounters an unrecognised intrinsic type of a field
    argument when generating a kernel stub.

    '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    ast = fpapi.parse(FIELD_CODE, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    # Create an empty Kernel stub module and subroutine objects
    psy_module = ModuleGen("testkern_2qr_int_field_mod")
    sub_stub = SubroutineGen(psy_module,
                             name="testkern_2qr_int_field_code",
                             implicitnone=True)
    # Sabotage the field argument to make it have an invalid intrinsic type
    fld_arg = kernel.arguments.args[1]
    fld_arg.descriptor._data_type = "gh_invalid_type"
    print(fld_arg.descriptor._data_type)
    with pytest.raises(InternalError) as err:
        LFRicFields(kernel)._stub_declarations(sub_stub)
    assert ("Found an unsupported data type 'gh_invalid_type' in "
            "kernel stub declarations for the field argument 'field_2'. "
            "Supported types are {0}.".format(
                LFRicArgDescriptor.VALID_FIELD_DATA_TYPES) in str(err.value))
Ejemplo n.º 17
0
def test_mesh_prop_stub_gen():
    ''' Check that correct kernel stub code is produced when the kernel
    metadata contains a mesh property. '''
    ast = fpapi.parse(os.path.join(BASE_PATH,
                                   "testkern_mesh_prop_mod.F90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    gen = str(kernel.gen_stub).lower()

    output = (
        "  module testkern_mesh_prop_mod\n"
        "    implicit none\n"
        "    contains\n"
        "    subroutine testkern_mesh_prop_code(nlayers, rscalar_1, "
        "field_2_w1, ndf_w1, undf_w1, map_w1, nfaces_re_h, adjacent_face)\n"
        "      use constants_mod, only: r_def, i_def\n"
        "      implicit none\n"
        "      integer(kind=i_def), intent(in) :: nlayers\n"
        "      integer(kind=i_def), intent(in) :: ndf_w1\n"
        "      integer(kind=i_def), intent(in), dimension(ndf_w1) :: map_w1\n"
        "      integer(kind=i_def), intent(in) :: undf_w1\n"
        "      real(kind=r_def), intent(in) :: rscalar_1\n"
        "      real(kind=r_def), intent(inout), dimension(undf_w1) :: "
        "field_2_w1\n"
        "      integer(kind=i_def), intent(in) :: nfaces_re_h\n"
        "      integer(kind=i_def), intent(in), dimension(nfaces_re_h) :: "
        "adjacent_face\n"
        "    end subroutine testkern_mesh_prop_code\n"
        "  end module testkern_mesh_prop_mod")
    assert output in gen
Ejemplo n.º 18
0
def test_int_field_all_stencils_gen_stub():
    ''' Test that we generate correct code for kernel stubs that
    contain integer-valued fields with all supported stencil accesses. '''
    ast = fpapi.parse(os.path.join(BASE_PATH,
                                   "testkern_stencil_multi_int_field_mod.f90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = str(kernel.gen_stub)
    output = (
        "  MODULE testkern_stencil_multi_int_field_mod\n"
        "    IMPLICIT NONE\n"
        "    CONTAINS\n"
        "    SUBROUTINE testkern_stencil_multi_int_field_code(nlayers, "
        "field_1_w2broken, field_2_w1, field_2_stencil_size, "
        "field_2_stencil_dofmap, field_3_w0, field_3_stencil_size, "
        "field_3_direction, field_3_stencil_dofmap, field_4_w2v, "
        "field_4_stencil_size, field_4_stencil_dofmap, ndf_w2broken, "
        "undf_w2broken, map_w2broken, ndf_w1, undf_w1, map_w1, "
        "ndf_w0, undf_w0, map_w0, ndf_w2v, undf_w2v, map_w2v)\n"
        "      USE constants_mod, ONLY: r_def, i_def\n"
        "      IMPLICIT NONE\n"
        "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w0\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w0) :: map_w0\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w1\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w1) :: map_w1\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w2broken\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w2broken) :: "
        "map_w2broken\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w2v\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w2v) :: "
        "map_w2v\n"
        "      INTEGER(KIND=i_def), intent(in) :: undf_w2broken, undf_w1, "
        "undf_w0, undf_w2v\n"
        "      INTEGER(KIND=i_def), intent(inout), "
        "dimension(undf_w2broken) :: field_1_w2broken\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(undf_w1) :: "
        "field_2_w1\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(undf_w0) :: "
        "field_3_w0\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(undf_w2v) :: "
        "field_4_w2v\n"
        "      INTEGER(KIND=i_def), intent(in) :: field_2_stencil_size, "
        "field_3_stencil_size, field_4_stencil_size\n"
        "      INTEGER(KIND=i_def), intent(in) :: field_3_direction\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w1,"
        "field_2_stencil_size) :: field_2_stencil_dofmap\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w0,"
        "field_3_stencil_size) :: field_3_stencil_dofmap\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w2v,"
        "field_4_stencil_size) :: field_4_stencil_dofmap\n"
        "    END SUBROUTINE testkern_stencil_multi_int_field_code\n"
        "  END MODULE testkern_stencil_multi_int_field_mod")
    assert output in generated_code
Ejemplo n.º 19
0
def test_lfric_stub_boundary_dofs():
    '''Check variable usage detection for boundary dofs.

    '''
    ast = get_ast("dynamo0.3", "enforce_bc_kernel_mod.f90")
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    var_accesses = VariablesAccessInfo()
    create_arg_list = KernStubArgList(kernel)
    create_arg_list.generate(var_accesses=var_accesses)
    assert "boundary_dofs_field_1: READ" in str(var_accesses)
Ejemplo n.º 20
0
def test_spaces():
    ''' test that field spaces are handled correctly for kernel stubs '''
    ast = fpapi.parse(SPACES, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = str(kernel.gen_stub)
    output = (
        "  MODULE dummy_mod\n"
        "    IMPLICIT NONE\n"
        "    CONTAINS\n"
        "    SUBROUTINE dummy_code(nlayers, field_1_w0, field_2_w1, "
        "field_3_w2, field_4_w3, field_5_wtheta, field_6_w2h, field_7_w2v, "
        "ndf_w0, undf_w0, map_w0, ndf_w1, undf_w1, map_w1, ndf_w2, undf_w2, "
        "map_w2, ndf_w3, undf_w3, map_w3, ndf_wtheta, undf_wtheta, "
        "map_wtheta, ndf_w2h, undf_w2h, map_w2h, ndf_w2v, undf_w2v, "
        "map_w2v)\n"
        "      USE constants_mod, ONLY: r_def\n"
        "      IMPLICIT NONE\n"
        "      INTEGER, intent(in) :: nlayers\n"
        "      INTEGER, intent(in) :: ndf_w0\n"
        "      INTEGER, intent(in), dimension(ndf_w0) :: map_w0\n"
        "      INTEGER, intent(in) :: ndf_w1\n"
        "      INTEGER, intent(in), dimension(ndf_w1) :: map_w1\n"
        "      INTEGER, intent(in) :: ndf_w2\n"
        "      INTEGER, intent(in), dimension(ndf_w2) :: map_w2\n"
        "      INTEGER, intent(in) :: ndf_w2h\n"
        "      INTEGER, intent(in), dimension(ndf_w2h) :: map_w2h\n"
        "      INTEGER, intent(in) :: ndf_w2v\n"
        "      INTEGER, intent(in), dimension(ndf_w2v) :: map_w2v\n"
        "      INTEGER, intent(in) :: ndf_w3\n"
        "      INTEGER, intent(in), dimension(ndf_w3) :: map_w3\n"
        "      INTEGER, intent(in) :: ndf_wtheta\n"
        "      INTEGER, intent(in), dimension(ndf_wtheta) :: map_wtheta\n"
        "      INTEGER, intent(in) :: undf_w0, undf_w1, undf_w2, undf_w3, "
        "undf_wtheta, undf_w2h, undf_w2v\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w0) :: "
        "field_1_w0\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w1) :: "
        "field_2_w1\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w2) :: "
        "field_3_w2\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w3) :: "
        "field_4_w3\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_wtheta) :: "
        "field_5_wtheta\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w2h) :: "
        "field_6_w2h\n"
        "      REAL(KIND=r_def), intent(out), dimension(undf_w2v) :: "
        "field_7_w2v\n"
        "    END SUBROUTINE dummy_code\n"
        "  END MODULE dummy_mod")
    assert output in generated_code
Ejemplo n.º 21
0
def test_load_meta_wrong_type():
    ''' Test that the load_meta function raises an appropriate error
    if the meta-data contains an un-recognised type '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    ast = fpapi.parse(INTENT, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    # Break the meta-data
    metadata.arg_descriptors[0]._type = "gh_hedge"
    with pytest.raises(GenerationError) as excinfo:
        kernel.load_meta(metadata)
    assert "load_meta expected one of '['gh_field'," in str(excinfo.value)
Ejemplo n.º 22
0
def test_kernel_stub_invalid_iteration_space():
    ''' Check that we raise an exception if we attempt to generate kernel
    stub for a kernel with an unsupported iteration space. '''
    ast = fpapi.parse(os.path.join(BASE_PATH, "testkern_dofs_mod.f90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    with pytest.raises(InternalError) as excinfo:
        _ = kernel.gen_stub
    assert ("Expected the kernel to operate on one of "
            "['cells', 'cell_column'] but found 'dof' in kernel "
            "'testkern_dofs_code'." in str(excinfo.value))
Ejemplo n.º 23
0
def test_lfric_stub_indirection_dofmap():
    '''Check variable usage detection in indirection dofmap.
    '''
    ast = get_ast("dynamo0.3", "columnwise_op_app_kernel_mod.F90")
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    var_accesses = VariablesAccessInfo()
    create_arg_list = KernStubArgList(kernel)
    create_arg_list.generate(var_accesses=var_accesses)
    var_info = str(var_accesses)
    assert "cma_indirection_map_aspc1_field_1: READ" in var_info
    assert "cma_indirection_map_aspc2_field_2: READ" in var_info
Ejemplo n.º 24
0
def test_lfric_stub_banded_dofmap():
    '''Check variable usage detection for banded dofmaps.

    '''
    ast = get_ast("dynamo0.3", "columnwise_op_asm_kernel_mod.F90")
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    var_accesses = VariablesAccessInfo()
    create_arg_list = KernStubArgList(kernel)
    create_arg_list.generate(var_accesses=var_accesses)
    var_info = str(var_accesses)
    assert "cbanded_map_adspc1_op_1: READ" in var_info
    assert "cbanded_map_adspc2_op_1: READ" in var_info
Ejemplo n.º 25
0
def test_stub_operator_different_spaces():
    ''' Test that the correct function spaces are provided in the
    correct order when generating a kernel stub with an operator on
    different spaces.

    '''
    # Check the original code (to- and from- spaces both continuous)
    ast = fpapi.parse(OPERATOR_DIFFERENT_SPACES, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    result = str(kernel.gen_stub)
    assert "(cell, nlayers, op_1_ncell_3d, op_1, ndf_w0, ndf_w1)" in result
    assert "dimension(ndf_w0,ndf_w1,op_1_ncell_3d)" in result
    # Check for discontinuous to- and from- spaces
    code = OPERATOR_DIFFERENT_SPACES.replace(
        "(gh_operator, gh_real, gh_write, w0, w1)",
        "(gh_operator, gh_real, gh_write, w3, any_discontinuous_space_2)", 1)
    ast = fpapi.parse(code, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    result = str(kernel.gen_stub)
    assert ("(cell, nlayers, op_1_ncell_3d, op_1, ndf_w3, ndf_adspc2_op_1)"
            in result)
    assert "dimension(ndf_w3,ndf_adspc2_op_1,op_1_ncell_3d)" in result
    field_descriptor = metadata.arg_descriptors[0]
    result = str(field_descriptor)
    assert "function_space_to[3]='w3'" in result
    assert "function_space_from[4]='any_discontinuous_space_2'" in result
Ejemplo n.º 26
0
def test_load_meta_wrong_type():
    ''' Test that the load_meta function raises an appropriate error
    if the meta-data contains an un-recognised type. '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    ast = fpapi.parse(INTENT, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    # Break the meta-data
    metadata.arg_descriptors[0]._argument_type = "gh_hedge"
    with pytest.raises(GenerationError) as excinfo:
        kernel.load_meta(metadata)
    assert ("DynKern.load_meta() expected one of {0} but found "
            "'gh_hedge'".format(LFRicArgDescriptor.VALID_ARG_TYPE_NAMES)
            in str(excinfo.value))
Ejemplo n.º 27
0
def test_kernstubarglist_arglist_error():
    '''Check that we raise an exception if we call the arglist method in
    kernstubarglist without first calling the generate method'''
    ast = get_ast(TEST_API, "testkern_one_int_scalar_mod.f90")

    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    # Now call KernStubArgList to raise an exception
    create_arg_list = KernStubArgList(kernel)
    with pytest.raises(InternalError) as excinfo:
        _ = create_arg_list.arglist
    assert ("The argument list in KernStubArgList is "
            "empty. Has the generate() method been "
            "called?") in str(excinfo.value)
Ejemplo n.º 28
0
def test_lfric_stub_boundary_dofmap():
    '''Check variable usage detection in boundary_dofs array fix
    for operators.

    '''
    from psyclone.dynamo0p3 import DynKernMetadata, DynKern
    from psyclone.domain.lfric import KernStubArgList
    ast = get_ast("dynamo0.3", "enforce_operator_bc_kernel_mod.F90")
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    var_accesses = VariablesAccessInfo()
    create_arg_list = KernStubArgList(kernel)
    create_arg_list.generate(var_accesses=var_accesses)
    assert "boundary_dofs_op_1: READ" in str(var_accesses)
Ejemplo n.º 29
0
def test_orientation_stubs():
    ''' Test that orientation is handled correctly for kernel
    stubs '''
    # Read-in the meta-data from file (it's in a file because it's also
    # used when testing the genkernelstub script from the command
    # line).
    with open(os.path.join(BASE_PATH, "dummy_orientation_mod.f90"),
              "r") as myfile:
        orientation = myfile.read()

    ast = fpapi.parse(orientation, ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    generated_code = kernel.gen_stub
    assert ORIENTATION_OUTPUT in str(generated_code)
Ejemplo n.º 30
0
def test_refelem_stub_gen():
    ''' Check that correct kernel stub code is produced when the kernel
    metadata contain reference element properties. '''
    ast = fpapi.parse(os.path.join(BASE_PATH, "testkern_ref_elem_mod.F90"),
                      ignore_comments=False)
    metadata = DynKernMetadata(ast)
    kernel = DynKern()
    kernel.load_meta(metadata)
    gen = str(kernel.gen_stub)

    output = (
        "  MODULE testkern_ref_elem_mod\n"
        "    IMPLICIT NONE\n"
        "    CONTAINS\n"
        "    SUBROUTINE testkern_ref_elem_code(nlayers, rscalar_1, "
        "field_2_w1, field_3_w2, field_4_w2, field_5_w3, ndf_w1, undf_w1, "
        "map_w1, ndf_w2, undf_w2, map_w2, ndf_w3, undf_w3, map_w3, "
        "nfaces_re_h, nfaces_re_v, normals_to_horiz_faces, "
        "normals_to_vert_faces)\n"
        "      USE constants_mod, ONLY: r_def, i_def\n"
        "      IMPLICIT NONE\n"
        "      INTEGER(KIND=i_def), intent(in) :: nlayers\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w1\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w1) :: map_w1\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w2\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w2) :: map_w2\n"
        "      INTEGER(KIND=i_def), intent(in) :: ndf_w3\n"
        "      INTEGER(KIND=i_def), intent(in), dimension(ndf_w3) :: map_w3\n"
        "      INTEGER(KIND=i_def), intent(in) :: undf_w1, undf_w2, undf_w3\n"
        "      REAL(KIND=r_def), intent(in) :: rscalar_1\n"
        "      REAL(KIND=r_def), intent(inout), dimension(undf_w1) :: "
        "field_2_w1\n"
        "      REAL(KIND=r_def), intent(in), dimension(undf_w2) :: "
        "field_3_w2\n"
        "      REAL(KIND=r_def), intent(in), dimension(undf_w2) :: "
        "field_4_w2\n"
        "      REAL(KIND=r_def), intent(in), dimension(undf_w3) :: "
        "field_5_w3\n"
        "      INTEGER(KIND=i_def), intent(in) :: nfaces_re_h\n"
        "      INTEGER(KIND=i_def), intent(in) :: nfaces_re_v\n"
        "      REAL(KIND=r_def), intent(in), dimension(3,nfaces_re_h) :: "
        "normals_to_horiz_faces\n"
        "      REAL(KIND=r_def), intent(in), dimension(3,nfaces_re_v) :: "
        "normals_to_vert_faces\n"
        "    END SUBROUTINE testkern_ref_elem_code\n"
        "  END MODULE testkern_ref_elem_mod")
    assert output in gen