示例#1
0
def test_do_loop_add_after():
    ''' Test that we correctly generate code for a do loop when adding a
    child to it with position *after* '''
    module = ModuleGen(name="testmodule")
    sub = SubroutineGen(module, name="testsub")
    module.add(sub)
    dogen = DoGen(sub, "it", "1", "10", step="2")
    sub.add(dogen)
    assign1 = AssignGen(dogen, lhs="happy", rhs=".TRUE.")
    dogen.add(assign1)
    assign2 = AssignGen(dogen, lhs="sad", rhs=".FALSE.")
    dogen.add(assign2, position=["before", assign1.root])
    a1_line = line_number(sub.root, "happy = ")
    a2_line = line_number(sub.root, "sad = ")
    assert a1_line > a2_line
示例#2
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        setval_c Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # In this case we're assigning a single scalar value to all
        # elements of a field.
        field_name = self.array_ref(self._arguments.args[0].proxy_name)
        scalar_value = self._arguments.args[1]
        parent.add(AssignGen(parent, lhs=field_name, rhs=scalar_value))
示例#3
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        setval_X Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We copy one element of field X (second arg) to the
        # corresponding element of field Y (first arg).
        field_name2 = self.array_ref(self._arguments.args[0].proxy_name)
        field_name1 = self.array_ref(self._arguments.args[1].proxy_name)
        parent.add(AssignGen(parent, lhs=field_name2, rhs=field_name1))
示例#4
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        X_innerproduct_X Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We sum the DoF-wise product of the supplied fields. The variable
        # holding the sum is initialised to zero in the psy layer.
        innprod_name = self._reduction_ref(self._arguments.args[0].name)
        field_name = self.array_ref(self._arguments.args[1].proxy_name)
        rhs_expr = innprod_name + "+" + field_name + "*" + field_name
        parent.add(AssignGen(parent, lhs=innprod_name, rhs=rhs_expr))
示例#5
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        sum_X Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # Sum all the elements of a field. The variable holding the
        # sum is initialised to zero in the psy layer.
        field_name = self.array_ref(self._arguments.args[1].proxy_name)
        sum_name = self._reduction_ref(self._arguments.args[0].name)
        rhs_expr = sum_name + "+" + field_name
        parent.add(AssignGen(parent, lhs=sum_name, rhs=rhs_expr))
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        X_powint_n Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # In this case we're raising each element of a field to a
        # supplied integer scalar value.
        field_name = self.array_ref(self._arguments.args[0].proxy_name)
        integer_power = self._arguments.args[1].name
        parent.add(AssignGen(parent, lhs=field_name,
                             rhs=field_name + "**" + integer_power))
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        inc_X_divideby_Y Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We divide each element of f1 by the corresponding element of
        # f2 and store the result back in f1.
        field_name1 = self.array_ref(self._arguments.args[0].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[1].proxy_name)
        parent.add(AssignGen(parent, lhs=field_name1,
                             rhs=field_name1 + " / " + field_name2))
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        inc_a_times_X Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # In this case we're multiplying each element of a field by the
        # supplied scalar value.
        field_name = self.array_ref(self._arguments.args[1].proxy_name)
        scalar_name = self._arguments.args[0].name
        parent.add(AssignGen(parent, lhs=field_name,
                             rhs=scalar_name + "*" + field_name))
示例#9
0
def test_typeselectiongen():
    ''' Check that SelectionGen works as expected for a type '''
    from psyclone.f2pygen import SelectionGen
    module = ModuleGen(name="testmodule")
    sub = SubroutineGen(module, name="testsubroutine")
    module.add(sub)
    sgen = SelectionGen(sub, expr="my_var=>another_var", typeselect=True)
    sub.add(sgen)
    agen = AssignGen(sgen, lhs="happy", rhs=".TRUE.")
    sgen.addcase("fspace", [agen])
    sgen.adddefault()
    gen = str(sub.root)
    print gen
    assert "SELECT TYPE ( my_var=>another_var )" in gen
    assert "TYPE IS ( fspace )" in gen
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        a_times_X Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We multiply each element of f1 by the scalar argument and
        # store the result in f2.
        field_name2 = self.array_ref(self._arguments.args[0].proxy_name)
        scalar_name = self._arguments.args[1].name
        field_name1 = self.array_ref(self._arguments.args[2].proxy_name)
        parent.add(AssignGen(parent, lhs=field_name2,
                             rhs=scalar_name + " * " + field_name1))
示例#11
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        inc_X_minus_bY Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We multiply one element of field f2 (3rd arg) by a scalar (2nd arg),
        # subtract it fom  the corresponding element of a first field f1
        # (1st arg) and write the value back into the element of field f1.
        scalar_name = self._arguments.args[1].name
        field_name1 = self.array_ref(self._arguments.args[0].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[2].proxy_name)
        rhs_expr = field_name1 + " - " + scalar_name + "*" + field_name2
        parent.add(AssignGen(parent, lhs=field_name1, rhs=rhs_expr))
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        X_times_Y Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We subtract each element of f2 from the corresponding element
        # of f1 and store the result in f3.
        field_name3 = self.array_ref(self._arguments.args[0].proxy_name)
        field_name1 = self.array_ref(self._arguments.args[1].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[2].proxy_name)
        assign = AssignGen(parent, lhs=field_name3,
                           rhs=field_name1 + " * " + field_name2)
        parent.add(assign)
示例#13
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        inc_aX_times_Y Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We multiply a scalar (1st arg) by a DoF-wise product of fields
        # f1 (2nd arg) and f2 (3rd arg) and write the value back into
        # the element of field f1.
        scalar_name = self._arguments.args[0].name
        field_name1 = self.array_ref(self._arguments.args[1].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[2].proxy_name)
        rhs_expr = scalar_name + "*" + field_name1 + " * " + field_name2
        parent.add(AssignGen(parent, lhs=field_name1, rhs=rhs_expr))
示例#14
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        X_plus_Y Built-in.

        :param parent: Node in f2pygen tree to which to add call.
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`

        '''
        # We add each element of f2 to the corresponding element of f1
        # and store the result in f3.
        field_name3 = self.array_ref(self._arguments.args[0].proxy_name)
        field_name1 = self.array_ref(self._arguments.args[1].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[2].proxy_name)
        parent.add(
            AssignGen(parent,
                      lhs=field_name3,
                      rhs=field_name1 + " + " + field_name2))
示例#15
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        inc_aX_plus_Y Built-in.

        :param parent: Node in f2pygen tree to which to add call.
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`

        '''
        # We multiply one element of field f1 (2nd arg) by a scalar
        # (1st arg), add it to the corresponding element of a
        # second field (3rd arg) and write the value back into
        # the element of field f1.
        scalar_name = self._arguments.args[0].name
        field_name1 = self.array_ref(self._arguments.args[1].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[2].proxy_name)
        rhs_expr = scalar_name + "*" + field_name1 + " + " + field_name2
        parent.add(AssignGen(parent, lhs=field_name1, rhs=rhs_expr))
示例#16
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        aX_minus_Y Built-in.

        :param parent: Node in f2pygen tree to which to add call.
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`

        '''
        # We multiply one element of field f1 (3rd arg) by a scalar
        # (2nd arg), subtract it from the corresponding
        # element of a second field (4th arg)  and write the value to the
        # corresponding element of field f3 (1st arg).
        field_name3 = self.array_ref(self._arguments.args[0].proxy_name)
        scalar_name = self._arguments.args[1].name
        field_name1 = self.array_ref(self._arguments.args[2].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[3].proxy_name)
        rhs_expr = scalar_name + "*" + field_name1 + " - " + field_name2
        parent.add(AssignGen(parent, lhs=field_name3, rhs=rhs_expr))
示例#17
0
    def gen_code(self, parent):
        '''
        Generates Dynamo0.3 API specific PSy code for a call to the
        inc_aX_plus_bY Built-in.

        :param parent: Node in f2pygen tree to which to add call
        :type parent: :py:class:`psyclone.f2pygen.BaseGen`
        '''
        from psyclone.f2pygen import AssignGen
        # We multiply one element of field f1 (2nd arg) by the first scalar
        # (1st arg), add it to the product of the corresponding element of
        # a second field (4th arg) with the second scalar (4rd arg) and
        # write the value back into the element of field f1.
        scalar_name1 = self._arguments.args[0].name
        scalar_name2 = self._arguments.args[2].name
        field_name1 = self.array_ref(self._arguments.args[1].proxy_name)
        field_name2 = self.array_ref(self._arguments.args[3].proxy_name)
        rhs_expr = (scalar_name1 + "*" + field_name1 + " + " + scalar_name2 +
                    "*" + field_name2)
        parent.add(AssignGen(parent, lhs=field_name1, rhs=rhs_expr))
示例#18
0
def test_selectiongen():
    ''' Check that SelectionGen works as expected '''
    from psyclone.f2pygen import SelectionGen
    module = ModuleGen(name="testmodule")
    sub = SubroutineGen(module, name="testsubroutine")
    module.add(sub)
    sgen = SelectionGen(sub, expr="my_var")
    sub.add(sgen)
    agen = AssignGen(sgen, lhs="happy", rhs=".TRUE.")
    sgen.addcase("1", [agen])
    # TODO how do we specify what happens in the default case?
    sgen.adddefault()
    gen = str(sub.root)
    print gen
    expected = ("SELECT CASE ( my_var )\n"
                "CASE ( 1 )\n"
                "        happy = .TRUE.\n"
                "CASE DEFAULT\n"
                "      END SELECT")
    assert expected in gen
    assert False
示例#19
0
    def create_driver(self, input_list, output_list):
        # pylint: disable=too-many-locals, too-many-statements
        '''This function creates a driver that can read the
        output created by the extraction code. This is a stand-alone
        program that will read the input data, calls the kernels/
        instrumented region, and then compares the results with the
        stored results in the file.

        TODO: #644: we need type information here.

        :param input_list: list of variables that are input parameters.
        :type input_list: list of str
        :param output_list: list of variables that are output parameters.
        :type output_list: list or str
        '''

        from psyclone.f2pygen import AllocateGen, AssignGen, CallGen,\
            CommentGen, DeclGen, ModuleGen, SubroutineGen, UseGen, \
            TypeDeclGen
        from psyclone.gocean1p0 import GOSymbolTable
        from psyclone.psyir.symbols import Symbol

        all_vars = list(set(input_list).union(set(output_list)))
        all_vars.sort()

        module_name, region_name = self.region_identifier
        module = ModuleGen(name=module_name)
        prog = SubroutineGen(parent=module, name=module_name+"_code",
                             implicitnone=True)
        module.add(prog)
        use = UseGen(prog, self.add_psydata_class_prefix("psy_data_mod"),
                     only=True,
                     funcnames=[self.add_psydata_class_prefix("PSyDataType")])
        prog.add(use)

        # Use a symbol table to make sure all variable names are unique
        sym_table = GOSymbolTable()
        sym = Symbol("PSyDataType")
        sym_table.add(sym)

        psy_data = sym_table.new_symbol_name(self.add_psydata_class_prefix
                                             ("psy_data"))
        sym_table.add(Symbol(psy_data))
        var_decl = TypeDeclGen(prog, datatype=self.add_psydata_class_prefix
                               ("PSyDataType"),
                               entity_decls=[psy_data])
        prog.add(var_decl)

        call = CallGen(prog,
                       "{0}%OpenRead(\"{1}\", \"{2}\")"
                       .format(psy_data, module_name, region_name))
        prog.add(call)

        post_suffix = self._post_name

        # Variables might need to be renamed in order to guarantee unique
        # variable names in the driver: An example of this would be if the
        # user code contains a variable 'dx', and the kernel takes a
        # property 'dx' as well. In the original code that is no problem,
        # since the property is used via field%grid%dx. But the stand-alone
        # driver renames field%grid%dx to dx, which can cause a name clash.
        # Similar problems can exist with any user defined type, since all
        # user defined types are rewritten to just use the field name.
        # We use a mapping to support renaming of variables: it takes as
        # key the variable as used in the original program (e.g. 'dx' from
        # an expression like field%grid%dx), and maps it to a unique local
        # name (e.g. dx_0).

        rename_variable = {}
        for var_name in all_vars:
            # TODO #644: we need to identify arrays!!
            # Support GOcean properties, which are accessed via a
            # derived type (e.g. 'fld%grid%dx'). In this stand-alone
            # driver we don't have the derived type, instead we create
            # variable based on the field in the derived type ('dx'
            # in the example above), and pass this variable to the
            # instrumented code.
            last_percent = var_name.rfind("%")
            if last_percent > -1:
                # Strip off the derived type, and only leave the last
                # field, which is used as the local variable name.
                local_name = var_name[last_percent+1:]
            else:
                # No derived type, so we can just use the
                # variable name directly in the driver
                local_name = var_name
            unique_local_name = sym_table.new_symbol_name(local_name)
            rename_variable[local_name] = unique_local_name
            sym_table.add(Symbol(unique_local_name))
            local_name = unique_local_name

            # TODO: #644 - we need to identify arrays!!
            # Any variable used needs to be defined. We also need
            # to handle the kind property better and not rely on
            # a hard-coded value.
            decl = DeclGen(prog, "real", [local_name], kind="8",
                           dimension=":,:", allocatable=True)
            prog.add(decl)
            is_input = var_name in input_list
            is_output = var_name in output_list

            if is_input and not is_output:
                # We only need the pre-variable, and we can read
                # it from the file (this call also allocates space for it).
                call = CallGen(prog,
                               "{0}%ReadVariable(\"{1}\", {2})"
                               .format(psy_data, var_name, local_name))
                prog.add(call)
            elif is_input:
                # Now must be input and output:
                # First read the pre-variable (which also allocates it):
                call = CallGen(prog,
                               "{0}%ReadVariable(\"{1}\", {2})"
                               .format(psy_data, var_name, local_name))
                prog.add(call)
                # Then declare the post variable, and and read its values
                # (ReadVariable will also allocate it)
                sym = Symbol(local_name+post_suffix)
                sym_table.add(sym)
                decl = DeclGen(prog, "real", [local_name+post_suffix],
                               dimension=":,:", kind="8", allocatable=True)
                prog.add(decl)
                call = CallGen(prog,
                               "{0}%ReadVariable(\"{1}{3}\", {2}{3})"
                               .format(psy_data, var_name, local_name,
                                       post_suffix))
                prog.add(call)
            else:
                # Now the variable is output only. We need to read the
                # post variable in, and create and allocate a pre variable
                # with the same size as the post
                sym = Symbol(local_name+post_suffix)
                sym_table.add(sym)
                decl = DeclGen(prog, "real", [local_name+post_suffix],
                               dimension=":,:", kind="8", allocatable=True)
                prog.add(decl)
                call = CallGen(prog,
                               "{0}%ReadVariable(\"{1}{3}\", {2}{3})"
                               .format(psy_data, var_name, local_name,
                                       post_suffix))
                prog.add(call)
                decl = DeclGen(prog, "real", [local_name], kind="8",
                               dimension=":,:", allocatable=True)
                prog.add(decl)
                alloc = AllocateGen(prog, [var_name],
                                    mold="{0}".format(local_name +
                                                      post_suffix))
                prog.add(alloc)
                # Initialise the variable with 0, since it might contain
                # values that are not set at all (halo regions, or a
                # kernel might not set all values). This way the array
                # comparison with the post value works as expected
                # TODO #644 - create the right "0.0" type here (e.g.
                # 0.0d0, ...)
                assign = AssignGen(prog, local_name, "0.0d0")
                prog.add(assign)

        # Now add the region that was extracted here:
        prog.add(CommentGen(prog, ""))
        prog.add(CommentGen(prog, " RegionStart"))

        # For the driver we have to re-create the code of the
        # instrumented region, but in this stand-alone driver the
        # arguments are not dl_esm_inf fields anymore, but simple arrays.
        # Similarly, for properties we cannot use e.g. 'fld%grid%dx'
        # anymore, we have to use e.g. a local variable 'dx' that has
        # been created. Since we are using the existing way of creating
        # the code for the instrumented region, we need to modify how
        # these variables are created. We do this by temporarily
        # modifying the properties in the config file.
        api_config = Config.get().api_conf("gocean1.0")
        all_props = api_config.grid_properties
        # Keep a copy of the original values, so we can restore
        # them later
        orig_props = dict(all_props)

        # 1) A grid property is defined like "{0}%grid%dx". This is
        #    changed to be just 'dx', i.e. the final component of
        #    the current value (but we also take renaming into account,
        #    so 'dx' might become 'dx_0').
        #    If a property is not used, it doesn't matter if we modify
        #    its definition, so we just change all properties.
        for name, prop in all_props.items():
            last_percent = prop.fortran.rfind("%")
            if last_percent > -1:
                # Get the last field name, which will be the
                # local variable name
                local_name = prop.fortran[last_percent+1:]
                unique_name = rename_variable.get(local_name, local_name)
                all_props[name] = GOceanConfig.make_property(
                    unique_name, prop.type, prop.intrinsic_type)

        # 2) The property 'grid_data' is a reference to the data on the
        #    grid (i.e. the actual field) , and it is defined as "{0}%data".
        #    This just becomes {0} ('a_fld%data' in the original program
        #    becomes just 'a_fld', and 'a_fld' is declared to be a plain
        #    Fortran 2d-array)
        all_props["go_grid_data"] = GOceanConfig.make_property(
            "{0}", "array", "real")

        # Each kernel caches the argument code, so we also
        # need to clear this cached data to make sure the new
        # value for "go_grid_data" is actually used.
        from psyclone.psyGen import CodedKern
        for kernel in self.psy_data_body.walk(CodedKern):
            kernel.clear_cached_data()

        # Recreate the instrumented region. Due to the changes in the
        # config files, fields and properties will now become local
        # plain arrays and variables:
        for child in self.psy_data_body:
            child.gen_code(prog)

        # Now reset all properties back to the original values:
        for name in all_props.keys():
            all_props[name] = orig_props[name]

        prog.add(CommentGen(prog, " RegionEnd"))
        prog.add(CommentGen(prog, ""))

        for var_name in output_list:
            prog.add(CommentGen(prog, " Check {0}".format(var_name)))

        code = str(module.root)

        with open("driver-{0}-{1}.f90".
                  format(module_name, region_name), "w") as out:
            out.write(code)
示例#20
0
    def gen_code(self, parent):
        ''' Generates GOcean specific invocation code (the subroutine called
            by the associated invoke call in the algorithm layer). This
            consists of the PSy invocation subroutine and the declaration of
            its arguments.'''
        from psyclone.f2pygen import SubroutineGen, DeclGen, TypeDeclGen, \
            CommentGen, AssignGen
        # create the subroutine
        invoke_sub = SubroutineGen(parent,
                                   name=self.name,
                                   args=self.psy_unique_var_names)
        parent.add(invoke_sub)

        # add declarations for the variables holding the upper bounds
        # of loops in i and j
        if self.schedule.const_loop_bounds:
            invoke_sub.add(
                DeclGen(invoke_sub,
                        datatype="INTEGER",
                        entity_decls=[
                            self.schedule.iloop_stop, self.schedule.jloop_stop
                        ]))

        # Generate the code body of this subroutine
        self.schedule.gen_code(invoke_sub)

        # add the subroutine argument declarations for fields
        if len(self.unique_args_arrays) > 0:
            my_decl_arrays = TypeDeclGen(invoke_sub,
                                         datatype="r2d_field",
                                         intent="inout",
                                         entity_decls=self.unique_args_arrays)
            invoke_sub.add(my_decl_arrays)

        # add the subroutine argument declarations for real scalars
        if len(self.unique_args_rscalars) > 0:
            my_decl_rscalars = DeclGen(invoke_sub,
                                       datatype="REAL",
                                       intent="inout",
                                       kind="wp",
                                       entity_decls=self.unique_args_rscalars)
            invoke_sub.add(my_decl_rscalars)
        # add the subroutine argument declarations for integer scalars
        if len(self.unique_args_iscalars) > 0:
            my_decl_iscalars = DeclGen(invoke_sub,
                                       datatype="INTEGER",
                                       intent="inout",
                                       entity_decls=self.unique_args_iscalars)
            invoke_sub.add(my_decl_iscalars)

        if self._schedule.const_loop_bounds and \
           len(self.unique_args_arrays) > 0:

            # Look-up the loop bounds using the first field object in the
            # list
            sim_domain = self.unique_args_arrays[0] +\
                "%grid%simulation_domain%"
            position = invoke_sub.last_declaration()

            invoke_sub.add(CommentGen(invoke_sub, ""),
                           position=["after", position])
            invoke_sub.add(AssignGen(invoke_sub,
                                     lhs=self.schedule.jloop_stop,
                                     rhs=sim_domain + "ystop"),
                           position=["after", position])
            invoke_sub.add(AssignGen(invoke_sub,
                                     lhs=self.schedule.iloop_stop,
                                     rhs=sim_domain + "xstop"),
                           position=["after", position])
            invoke_sub.add(CommentGen(invoke_sub, " Look-up loop bounds"),
                           position=["after", position])
            invoke_sub.add(CommentGen(invoke_sub, ""),
                           position=["after", position])
示例#21
0
    def gen_code(self, parent):
        ''' Generates dynamo version 0.1 specific psy code for a call to
            the dynamo kernel instance. '''
        from psyclone.f2pygen import CallGen, DeclGen, AssignGen, UseGen

        # TODO: we simply choose the first field as the lookup for the moment
        field_name = self.arguments.args[0].name

        # add a dofmap lookup using first field.
        # TODO: This needs to be generalised to work for multiple dofmaps
        parent.add(
            CallGen(parent, field_name + "%vspace%get_cell_dofmap",
                    ["cell", "map"]))
        parent.add(DeclGen(parent, datatype="integer", entity_decls=["cell"]))
        parent.add(
            DeclGen(parent,
                    datatype="integer",
                    pointer=True,
                    entity_decls=["map(:)"]))

        # create the argument list on the fly so we can also create
        # appropriate variables and lookups
        arglist = []
        arglist.append("nlayers")
        arglist.append("ndf")
        arglist.append("map")

        found_gauss_quad = False
        gauss_quad_arg = None
        for arg in self._arguments.args:
            if arg.requires_basis:
                basis_name = arg.function_space + "_basis_" + arg.name
                arglist.append(basis_name)
                new_parent, position = parent.start_parent_loop()
                new_parent.add(CallGen(new_parent,
                                       field_name + "%vspace%get_basis",
                                       [basis_name]),
                               position=["before", position])
                parent.add(
                    DeclGen(parent,
                            datatype="real",
                            kind="dp",
                            pointer=True,
                            entity_decls=[basis_name + "(:,:,:,:,:)"]))
            if arg.requires_diff_basis:
                raise GenerationError("differential basis has not yet "
                                      "been coded")
            if arg.requires_gauss_quad:
                if found_gauss_quad:
                    raise GenerationError("found more than one gaussian "
                                          "quadrature in this kernel")
                found_gauss_quad = True
                gauss_quad_arg = arg
            dataref = "%data"
            arglist.append(arg.name + dataref)

        if found_gauss_quad:
            gq_name = "gaussian_quadrature"
            arglist.append(gauss_quad_arg.name + "%" + gq_name)

        # generate the kernel call and associated use statement
        parent.add(CallGen(parent, self._name, arglist))
        if not self.module_inline:
            parent.add(
                UseGen(parent,
                       name=self._module_name,
                       only=True,
                       funcnames=[self._name]))

        # declare and initialise the number of layers and the number
        # of degrees of freedom. Needs to be generalised.
        parent.add(
            DeclGen(parent,
                    datatype="integer",
                    entity_decls=["nlayers", "ndf"]))
        new_parent, position = parent.start_parent_loop()
        new_parent.add(AssignGen(new_parent,
                                 lhs="nlayers",
                                 rhs=field_name + "%get_nlayers()"),
                       position=["before", position])
        new_parent.add(AssignGen(new_parent,
                                 lhs="ndf",
                                 rhs=field_name + "%vspace%get_ndf()"),
                       position=["before", position])