From bf523ba26b8b8f48404c355cc7042076a75de97c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 24 Jul 2025 09:25:09 +0100 Subject: [PATCH 001/122] #1312: create initial ScalarArray example --- examples/lfric/eg21/scalar_array_alg_mod.x90 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/lfric/eg21/scalar_array_alg_mod.x90 diff --git a/examples/lfric/eg21/scalar_array_alg_mod.x90 b/examples/lfric/eg21/scalar_array_alg_mod.x90 new file mode 100644 index 0000000000..e69de29bb2 From dc1ec4ad6e353fa6019f84d5c661b6e75df62168 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:27:16 +0100 Subject: [PATCH 002/122] #1312: start adding code generation for ScalarArrays --- src/psyclone/domain/lfric/arg_ordering.py | 26 +++++++++++++ .../domain/lfric/kern_call_acc_arg_list.py | 14 +++++++ .../domain/lfric/kern_call_arg_list.py | 27 +++++++++++++ .../domain/lfric/kern_call_invoke_arg_list.py | 38 +++++++++++++++++++ src/psyclone/lfric.py | 10 +++++ 5 files changed, 115 insertions(+) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index eaf0547f78..d2068d77f7 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -788,6 +788,32 @@ def scalar(self, scalar_arg, var_accesses=None): self.append(scalar_arg.name, var_accesses, mode=scalar_arg.access, metadata_posn=scalar_arg.metadata_index) + def scalar_array(self, scalar_arr_arg, var_accesses=None): + '''Add the name associated with the ScalarArray argument to the + argument list and optionally add this ScalarArray to the variable + access information. + + :param scalar_arr_arg: the kernel argument. + :type scalar_arr_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` + :param var_accesses: optional VariablesAccessMap instance that \ + stores information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` + + :raises InternalError: if the argument is not a recognised ScalarArray \ + type. + + ''' + const = LFRicConstants() + if not scalar_arr_arg.is_scalar_array: + raise InternalError( + f"Expected argument type to be one of " + f"{const.VALID_ARRAY_NAMES} but got " + f"'{scalar_arr_arg.argument_type}'") + + self.append(scalar_arr_arg.name, var_accesses, mode=scalar_arr_arg.access, + metadata_posn=scalar_arr_arg.metadata_index) + def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and fields. If supplied it also stores this access in var_accesses. diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index f9d28f26b1..f2b8695f82 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -272,6 +272,20 @@ def scalar(self, scalar_arg, var_accesses=None): ''' + def scalar_array(self, scalar_arr_arg, var_accesses=None): + ''' + Override the default implementation as there's no need to specify + ScalarArrays for an OpenACC data region. + + :param scalar_arr_arg: the kernel argument. + :type scalar_arr_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` + :param var_accesses: optional VariablesAccessMap instance that + stores information about variable accesses. + :type var_accesses: Optional[ + :py:class:`psyclone.core.VariablesAccessMap`] + + ''' + # ============================================================================ # For automatic documentation creation: diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 205a6e865c..8c1d854d8a 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -261,6 +261,33 @@ def scalar(self, scalar_arg, var_accesses=None): sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) + def scalar_array(self, scalar_array_arg, var_accesses=None): + '''Add the ScalarArray associated with the with the argument 'arg' + to the argument list. If suppiled it also stores this access in + var_accesses. + + :param scalar_array_arg: the kernel argument with which the stencil is associated. + :type scalar_array_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` + :param var_accesses: optional VariablesAccessMap instance to store \ + the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` + + ''' + const = LFRicConstants() + if not scalar_array_arg.is_scalar_array: + raise.InternalError( + f"Expected argument type to be of type " + f"{const.VALID_ARRAY_NAMES} but got " + f"{scalar_array_arg.argument_type}" + ) + if not scalar_array_arg: + self.psyir_append(scalar_array_arg.psyir_expression()) + else: + sym = self._symtab.lookup(scalar_array_arg.name) + self.psyir_append(Reference(sym)) + + # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): diff --git a/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py b/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py index 2a7b6cd6e0..7d408a9576 100644 --- a/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py @@ -169,6 +169,44 @@ def scalar(self, scalar_arg, var_accesses=None): datatype=datatype) self._scalars.append(sym) + def scalar_array(self, scalar_arr_arg, var_accesses=None): + ''' + Add the necessary argument for a ScalarArray quantity as well as + an appropriate Symbol to the SymbolTable. + + :param scalar_arr_arg: the ScalarArray kernel argument. + :type scalar_arr_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` + :param var_accesses: optional VariablesAccessMap instance that \ + stores information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` + + :raises NotImplementedError: if a ScalarArray of type other than \ + real or integer is found. + + ''' + super().scalar_array(scalar_arr_arg, var_accesses) + + # Create a DataSymbol for this kernel argument. + if scalar_arr_arg.intrinsic_type == "real": + datatype = LFRicTypes("LFRicRealScalarDataType")() + elif scalar_arr_arg.intrinsic_type == "integer": + datatype = LFRicTypes("LFRicIntegerScalarDataType")() + elif scalar_arr_arg.intrinsic_type == "logical": + datatype = LFRicTypes("LFRicLogicalScalarDataType")() + else: + raise NotImplementedError( + f"ScalarArray of type '{scalar_arr_arg.intrinsic_type}' not supported.") + + consts = LFRicConstants() + precision_name = consts.SCALAR_PRECISION_MAP[scalar_arr_arg.intrinsic_type] + self._symtab.add_lfric_precision_symbol(precision_name) + + sym = self._symtab.new_symbol(scalar_arr_arg.name, + symbol_type=DataSymbol, + datatype=datatype) + self._scalars.append(sym) + def fs_common(self, function_space, var_accesses=None): ''' Does nothing as there are no arguments associated with function spaces at the algorithm level. diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 39a1c652c5..d5374a95b1 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -6100,6 +6100,16 @@ def is_scalar(self): const = LFRicConstants() return self._argument_type in const.VALID_SCALAR_NAMES + @property + def is_scalar_array(self): + ''' + :returns: True if this kernel argument represents a \ + ScalarArray, False otherwise. + :rtype: bool + ''' + const = LFRicConstants() + return self._argument_type in const.VALID_ARRAY_NAMES + @property def is_field(self): ''' From 1a07148a0a044ba31c80801c9dc64545fa682e03 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 13:54:15 +0100 Subject: [PATCH 003/122] #1312: lint fix --- src/psyclone/domain/lfric/arg_ordering.py | 7 ++++--- src/psyclone/domain/lfric/kern_call_arg_list.py | 6 +++--- src/psyclone/domain/lfric/kern_call_invoke_arg_list.py | 6 ++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index d2068d77f7..0535a66f2e 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -800,8 +800,8 @@ def scalar_array(self, scalar_arr_arg, var_accesses=None): :type var_accesses: \ :py:class:`psyclone.core.VariablesAccessMap` - :raises InternalError: if the argument is not a recognised ScalarArray \ - type. + :raises InternalError: if the argument is not a recognised \ + ScalarArray type. ''' const = LFRicConstants() @@ -811,7 +811,8 @@ def scalar_array(self, scalar_arr_arg, var_accesses=None): f"{const.VALID_ARRAY_NAMES} but got " f"'{scalar_arr_arg.argument_type}'") - self.append(scalar_arr_arg.name, var_accesses, mode=scalar_arr_arg.access, + self.append(scalar_arr_arg.name, var_accesses, + mode=scalar_arr_arg.access, metadata_posn=scalar_arr_arg.metadata_index) def fs_common(self, function_space, var_accesses=None): diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 2644ffb9ac..c6b1afa1e6 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -260,7 +260,8 @@ def scalar_array(self, scalar_array_arg, var_accesses=None): to the argument list. If suppiled it also stores this access in var_accesses. - :param scalar_array_arg: the kernel argument with which the stencil is associated. + :param scalar_array_arg: the kernel argument with which the stencil \ + is associated. :type scalar_array_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. @@ -270,7 +271,7 @@ def scalar_array(self, scalar_array_arg, var_accesses=None): ''' const = LFRicConstants() if not scalar_array_arg.is_scalar_array: - raise.InternalError( + raise InternalError( f"Expected argument type to be of type " f"{const.VALID_ARRAY_NAMES} but got " f"{scalar_array_arg.argument_type}" @@ -281,7 +282,6 @@ def scalar_array(self, scalar_array_arg, var_accesses=None): sym = self._symtab.lookup(scalar_array_arg.name) self.psyir_append(Reference(sym)) - # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): diff --git a/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py b/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py index 7d408a9576..44a493e3a9 100644 --- a/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py @@ -196,10 +196,12 @@ def scalar_array(self, scalar_arr_arg, var_accesses=None): datatype = LFRicTypes("LFRicLogicalScalarDataType")() else: raise NotImplementedError( - f"ScalarArray of type '{scalar_arr_arg.intrinsic_type}' not supported.") + f"ScalarArray of type '{scalar_arr_arg.intrinsic_type}' not '" + f"supported.") consts = LFRicConstants() - precision_name = consts.SCALAR_PRECISION_MAP[scalar_arr_arg.intrinsic_type] + precision_name = consts.SCALAR_PRECISION_MAP[ + scalar_arr_arg.intrinsic_type] self._symtab.add_lfric_precision_symbol(precision_name) sym = self._symtab.new_symbol(scalar_arr_arg.name, From decf6c1be1945478d974cfae6084360053b1c0e3 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:55:03 +0100 Subject: [PATCH 004/122] #1312: condense the scalar_array functionality into the scalar function --- src/psyclone/domain/lfric/arg_ordering.py | 38 +++--------------- .../domain/lfric/kern_call_acc_arg_list.py | 15 ------- .../domain/lfric/kern_call_arg_list.py | 27 ------------- .../domain/lfric/kern_call_invoke_arg_list.py | 40 ------------------- 4 files changed, 6 insertions(+), 114 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 0535a66f2e..741243e2e6 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -770,11 +770,12 @@ def scalar(self, scalar_arg, var_accesses=None): ''' const = LFRicConstants() - if not scalar_arg.is_scalar: - raise InternalError( - f"Expected argument type to be one of " - f"{const.VALID_SCALAR_NAMES} but got " - f"'{scalar_arg.argument_type}'") + if not scalar_arg.is_scalar or not scalar_arg.is_scalar_array: + raise InternalError( + f"Expected argument type to be one of " + f"{const.VALID_SCALAR_NAMES} or " + f"{const.VALID_ARRAY_NAMES} but got " + f"'{scalar_arg.argument_type}'") if scalar_arg.is_literal: # If we have a literal, do not add it to the variable access @@ -788,33 +789,6 @@ def scalar(self, scalar_arg, var_accesses=None): self.append(scalar_arg.name, var_accesses, mode=scalar_arg.access, metadata_posn=scalar_arg.metadata_index) - def scalar_array(self, scalar_arr_arg, var_accesses=None): - '''Add the name associated with the ScalarArray argument to the - argument list and optionally add this ScalarArray to the variable - access information. - - :param scalar_arr_arg: the kernel argument. - :type scalar_arr_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance that \ - stores information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` - - :raises InternalError: if the argument is not a recognised \ - ScalarArray type. - - ''' - const = LFRicConstants() - if not scalar_arr_arg.is_scalar_array: - raise InternalError( - f"Expected argument type to be one of " - f"{const.VALID_ARRAY_NAMES} but got " - f"'{scalar_arr_arg.argument_type}'") - - self.append(scalar_arr_arg.name, var_accesses, - mode=scalar_arr_arg.access, - metadata_posn=scalar_arr_arg.metadata_index) - def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and fields. If supplied it also stores this access in var_accesses. diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index f2b8695f82..7b9fb78927 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -272,21 +272,6 @@ def scalar(self, scalar_arg, var_accesses=None): ''' - def scalar_array(self, scalar_arr_arg, var_accesses=None): - ''' - Override the default implementation as there's no need to specify - ScalarArrays for an OpenACC data region. - - :param scalar_arr_arg: the kernel argument. - :type scalar_arr_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance that - stores information about variable accesses. - :type var_accesses: Optional[ - :py:class:`psyclone.core.VariablesAccessMap`] - - ''' - - # ============================================================================ # For automatic documentation creation: __all__ = ["KernCallAccArgList"] diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index c6b1afa1e6..81ea67acd0 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -255,33 +255,6 @@ def scalar(self, scalar_arg, sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) - def scalar_array(self, scalar_array_arg, var_accesses=None): - '''Add the ScalarArray associated with the with the argument 'arg' - to the argument list. If suppiled it also stores this access in - var_accesses. - - :param scalar_array_arg: the kernel argument with which the stencil \ - is associated. - :type scalar_array_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ - the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` - - ''' - const = LFRicConstants() - if not scalar_array_arg.is_scalar_array: - raise InternalError( - f"Expected argument type to be of type " - f"{const.VALID_ARRAY_NAMES} but got " - f"{scalar_array_arg.argument_type}" - ) - if not scalar_array_arg: - self.psyir_append(scalar_array_arg.psyir_expression()) - else: - sym = self._symtab.lookup(scalar_array_arg.name) - self.psyir_append(Reference(sym)) - # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): diff --git a/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py b/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py index 44a493e3a9..2a7b6cd6e0 100644 --- a/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_invoke_arg_list.py @@ -169,46 +169,6 @@ def scalar(self, scalar_arg, var_accesses=None): datatype=datatype) self._scalars.append(sym) - def scalar_array(self, scalar_arr_arg, var_accesses=None): - ''' - Add the necessary argument for a ScalarArray quantity as well as - an appropriate Symbol to the SymbolTable. - - :param scalar_arr_arg: the ScalarArray kernel argument. - :type scalar_arr_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance that \ - stores information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` - - :raises NotImplementedError: if a ScalarArray of type other than \ - real or integer is found. - - ''' - super().scalar_array(scalar_arr_arg, var_accesses) - - # Create a DataSymbol for this kernel argument. - if scalar_arr_arg.intrinsic_type == "real": - datatype = LFRicTypes("LFRicRealScalarDataType")() - elif scalar_arr_arg.intrinsic_type == "integer": - datatype = LFRicTypes("LFRicIntegerScalarDataType")() - elif scalar_arr_arg.intrinsic_type == "logical": - datatype = LFRicTypes("LFRicLogicalScalarDataType")() - else: - raise NotImplementedError( - f"ScalarArray of type '{scalar_arr_arg.intrinsic_type}' not '" - f"supported.") - - consts = LFRicConstants() - precision_name = consts.SCALAR_PRECISION_MAP[ - scalar_arr_arg.intrinsic_type] - self._symtab.add_lfric_precision_symbol(precision_name) - - sym = self._symtab.new_symbol(scalar_arr_arg.name, - symbol_type=DataSymbol, - datatype=datatype) - self._scalars.append(sym) - def fs_common(self, function_space, var_accesses=None): ''' Does nothing as there are no arguments associated with function spaces at the algorithm level. From 6d74811cceeea62fc3775e703d38c83499218a8a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:57:43 +0100 Subject: [PATCH 005/122] #1312L lint fix --- src/psyclone/domain/lfric/arg_ordering.py | 10 +++++----- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 741243e2e6..68ed2246a8 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -771,11 +771,11 @@ def scalar(self, scalar_arg, var_accesses=None): ''' const = LFRicConstants() if not scalar_arg.is_scalar or not scalar_arg.is_scalar_array: - raise InternalError( - f"Expected argument type to be one of " - f"{const.VALID_SCALAR_NAMES} or " - f"{const.VALID_ARRAY_NAMES} but got " - f"'{scalar_arg.argument_type}'") + raise InternalError( + f"Expected argument type to be one of " + f"{const.VALID_SCALAR_NAMES} or " + f"{const.VALID_ARRAY_NAMES} but got " + f"'{scalar_arg.argument_type}'") if scalar_arg.is_literal: # If we have a literal, do not add it to the variable access diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 7b9fb78927..f9d28f26b1 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -272,6 +272,7 @@ def scalar(self, scalar_arg, var_accesses=None): ''' + # ============================================================================ # For automatic documentation creation: __all__ = ["KernCallAccArgList"] From 71c7d0c4445afcfa54682ce0a2678ea1c0d19262 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:07:21 +0100 Subject: [PATCH 006/122] #1312: fix the scalar type check logic --- src/psyclone/domain/lfric/arg_ordering.py | 2 +- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 68ed2246a8..157b22f8cc 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -770,7 +770,7 @@ def scalar(self, scalar_arg, var_accesses=None): ''' const = LFRicConstants() - if not scalar_arg.is_scalar or not scalar_arg.is_scalar_array: + if not (scalar_arg.is_scalar or scalar_arg.is_scalar_array): raise InternalError( f"Expected argument type to be one of " f"{const.VALID_SCALAR_NAMES} or " diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index f9d28f26b1..9bd881324c 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -261,7 +261,8 @@ def fs_intergrid(self, function_space, var_accesses=None): def scalar(self, scalar_arg, var_accesses=None): ''' Override the default implementation as there's no need to specify - scalars for an OpenACC data region. + scalar values for an OpenACC data region. But there is a need for + ScalarArrays. :param scalar_arg: the kernel argument. :type scalar_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` From fa6a7e61eb233c5a1cc460610505c4ac8b24294a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:17:07 +0100 Subject: [PATCH 007/122] #1312: remove the empty test file for now --- examples/lfric/eg21/scalar_array_alg_mod.x90 | 0 src/psyclone/domain/lfric/arg_ordering.py | 5 ++--- 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 examples/lfric/eg21/scalar_array_alg_mod.x90 diff --git a/examples/lfric/eg21/scalar_array_alg_mod.x90 b/examples/lfric/eg21/scalar_array_alg_mod.x90 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 157b22f8cc..50427539c2 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -773,9 +773,8 @@ def scalar(self, scalar_arg, var_accesses=None): if not (scalar_arg.is_scalar or scalar_arg.is_scalar_array): raise InternalError( f"Expected argument type to be one of " - f"{const.VALID_SCALAR_NAMES} or " - f"{const.VALID_ARRAY_NAMES} but got " - f"'{scalar_arg.argument_type}'") + f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES}" + f"but got '{scalar_arg.argument_type}'") if scalar_arg.is_literal: # If we have a literal, do not add it to the variable access From ae9ba03ee79d67d88228e05c07ecf5c4054b8d15 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:41:58 +0100 Subject: [PATCH 008/122] #1312: fix the failing test --- src/psyclone/tests/domain/lfric/arg_ordering_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/arg_ordering_test.py b/src/psyclone/tests/domain/lfric/arg_ordering_test.py index acf1e4b24e..e2d6de7936 100644 --- a/src/psyclone/tests/domain/lfric/arg_ordering_test.py +++ b/src/psyclone/tests/domain/lfric/arg_ordering_test.py @@ -214,7 +214,8 @@ def test_kernel_stub_invalid_scalar_argument(): with pytest.raises(InternalError) as excinfo: create_arg_list.scalar(arg) const = LFRicConstants() - assert (f"Expected argument type to be one of {const.VALID_SCALAR_NAMES} " + assert (f"Expected argument type to be one of " + f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES} " f"but got 'invalid'" in str(excinfo.value)) From 49610462b711847dd6e4420126f903e07986d176 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:52:38 +0100 Subject: [PATCH 009/122] #1312: actually fix the failing test --- src/psyclone/domain/lfric/arg_ordering.py | 2 +- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 50427539c2..46af228438 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -773,7 +773,7 @@ def scalar(self, scalar_arg, var_accesses=None): if not (scalar_arg.is_scalar or scalar_arg.is_scalar_array): raise InternalError( f"Expected argument type to be one of " - f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES}" + f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES} " f"but got '{scalar_arg.argument_type}'") if scalar_arg.is_literal: diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 9bd881324c..6029d169b7 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -272,6 +272,7 @@ def scalar(self, scalar_arg, var_accesses=None): :py:class:`psyclone.core.VariablesAccessMap`] ''' + #TODO: Add implementation of OpenACC data region for ScalarArrays # ============================================================================ From bc8260fafe04822500afbf07af2be877e74c19cd Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:56:46 +0100 Subject: [PATCH 010/122] #1312: lint fix --- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 6029d169b7..554068c1c2 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -272,7 +272,7 @@ def scalar(self, scalar_arg, var_accesses=None): :py:class:`psyclone.core.VariablesAccessMap`] ''' - #TODO: Add implementation of OpenACC data region for ScalarArrays + # TODO: Add implementation of OpenACC data region for ScalarArrays # ============================================================================ From 8e2b3de447f10da0678b492ec72af153b6649abd Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 21 Aug 2025 14:00:25 +0100 Subject: [PATCH 011/122] #1312: Add initial test implementation of ScalarArrays --- src/psyclone/lfric.py | 3 + .../lfric/28.scalar_array_invoke.f90 | 53 ++++++++++++++ .../lfric/testkern_scalar_array_mod.f90 | 70 +++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 create mode 100644 src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index c00ce04ad0..eb49040414 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -6273,6 +6273,9 @@ def psyir_expression(self): f"PSyIR contains one or more References.") return lit + # TODO: this possibly needs altering to consider ScalarArrays + # Currently .is_scalar doesn't include ScalarArrays so this won't + # pass. Need to work out if it needs to start for a ScalarArray if self.is_scalar: try: scalar_sym = symbol_table.lookup(self.name) diff --git a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 new file mode 100644 index 0000000000..d47c2a1d48 --- /dev/null +++ b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 @@ -0,0 +1,53 @@ +! ----------------------------------------------------------------------------- +! BSD 3-Clause License +! +! Copyright (c) 2025, Science and Technology Facilities Council +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! * Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! * Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! * Neither the name of the copyright holder nor the names of its +! contributors may be used to endorse or promote products derived from +! this software without specific prior written permission. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +! POSSIBILITY OF SUCH DAMAGE. +!------------------------------------------------------------------------------- +! Author A. Pirrie, Met Office + +program scalar_array_invoke + + ! Description: single function specified in an invoke call + use constants_mod, only: i_def, r_def, l_def + use field_mod, only: field_type + use testkern_scalar_array_mod, only: testkern_scalar_array_type + + implicit none + + real(r_def), dimension(50, 100) :: real_array + logical(l_def), dimension(10) :: logical_array + integer(i_def), dimension(2, 5, 10, 8) :: integer_array + + call invoke( & + testkern_scalar_array_type(real_array,logical_array,integer_array) & + ) + +end program scalar_array_invoke diff --git a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 new file mode 100644 index 0000000000..b0c6558d8a --- /dev/null +++ b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 @@ -0,0 +1,70 @@ +! ----------------------------------------------------------------------------- +! BSD 3-Clause License +! +! Copyright (c) 2025, Science and Technology Facilities Council. +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! * Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! * Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! * Neither the name of the copyright holder nor the names of its +! contributors may be used to endorse or promote products derived from +! this software without specific prior written permission. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +! ----------------------------------------------------------------------------- +! A. Pirrie, Met Office + +module testkern_scalar_array_mod + + use constants_mod + use argument_mod + use fs_continuity_mod + use kernel_mod + + implicit none + + type, extends(kernel_type) :: testkern_scalar_array_type + type(arg_type), dimension(3) :: meta_args = & + (/ arg_type(gh_scalar_array, gh_real, gh_read, 2), & + arg_type(gh_scalar_array, gh_logical, gh_read, 1), & + arg_type(gh_scalar_array, gh_integer, gh_read, 4) & + /) + integer :: operates_on = cell_column + contains + procedure, nopass :: code => testkern_scalar_array_code + end type testkern_scalar_array_type + +contains + + subroutine testkern_scalar_array_code(dims_rarray, real_array, & + dims_larray, logical_array, & + dims_iarray, integer_array) + implicit none + + integer(i_def), intent(in), dimension(2) :: dims_rarray + integer(i_def), intent(in), dimension(1) :: dims_larray + integer(i_def), intent(in), dimension(4) :: dims_iarray + real(r_def), intent(in), dimension(dims_rarray(1),dims_iarray(2)) :: real_array + logical(l_def), intent(in), dimension(dims_larray(1)) :: logical_array + integer(i_def), intent(in), dimension(dims_iarray(1),dims_iarray(2),dims_iarray(3),dims_iarray(4)) :: integer_array + + end subroutine testkern_scalar_array_code + +end module testkern_scalar_array_mod From 5b8c42d1a161fa8e087e8ad7ece6cb2777996d05 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:05:51 +0100 Subject: [PATCH 012/122] #1312: fix tests to check that gh_scalar_array is being assigned properly --- src/psyclone/lfric.py | 3 +- src/psyclone/tests/lfric_test.py | 15 ++++++++++ .../lfric/28.scalar_array_invoke.f90 | 3 +- .../lfric/testkern_scalar_array_mod.f90 | 29 +++++++++++-------- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index eb49040414..be75329b8b 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -5895,6 +5895,7 @@ def _init_data_type_properties(self, arg_info, check=True): # The collection datatype is not recognised or supported. alg_datatype = None + # TODO: Check this is correct after is_scalar is fixed if self.is_scalar: self._init_scalar_properties(alg_datatype, alg_precision, check) @@ -6153,7 +6154,7 @@ def is_scalar(self): :rtype: bool ''' const = LFRicConstants() - return self._argument_type in const.VALID_SCALAR_NAMES + return self._argument_type in (const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) @property def is_scalar_array(self): diff --git a/src/psyclone/tests/lfric_test.py b/src/psyclone/tests/lfric_test.py index 38bf7b239e..c00cbec730 100644 --- a/src/psyclone/tests/lfric_test.py +++ b/src/psyclone/tests/lfric_test.py @@ -1700,6 +1700,21 @@ class for a scalar. "not." in str(info.value)) +def test_lfrickernelargument_idtp_scalar_array(): + '''Test the _init_data_type_properties method in the LFRicKernelArgument + class for a ScalarArray. + + ''' + # Use one of the examples to create an instance of + # LFRicKernelArgument that describes a ScalarArray. + _, invoke_info = parse(os.path.join(BASE_PATH, "28.scalar_array_invoke.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) + scalar_argument = psy.invokes.invoke_list[0].schedule.args[0] + assert scalar_argument.is_scalar + assert scalar_argument.is_scalar_array + + def test_lfrickernelargument_idtp_reduction(): '''Test the _init_data_type_properties method in the LFRicKernelArgument class for a scalar reduction. diff --git a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 index d47c2a1d48..e9bd6a3855 100644 --- a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 +++ b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 @@ -45,9 +45,10 @@ program scalar_array_invoke real(r_def), dimension(50, 100) :: real_array logical(l_def), dimension(10) :: logical_array integer(i_def), dimension(2, 5, 10, 8) :: integer_array + type(field_type) :: afield call invoke( & - testkern_scalar_array_type(real_array,logical_array,integer_array) & + testkern_scalar_array_type(real_array,logical_array,integer_array,afield) & ) end program scalar_array_invoke diff --git a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 index b0c6558d8a..924304a14d 100644 --- a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 +++ b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 @@ -41,10 +41,11 @@ module testkern_scalar_array_mod implicit none type, extends(kernel_type) :: testkern_scalar_array_type - type(arg_type), dimension(3) :: meta_args = & - (/ arg_type(gh_scalar_array, gh_real, gh_read, 2), & - arg_type(gh_scalar_array, gh_logical, gh_read, 1), & - arg_type(gh_scalar_array, gh_integer, gh_read, 4) & + type(arg_type), dimension(4) :: meta_args = & + (/ arg_type(gh_scalar_array, gh_real, gh_read, 2 ), & + arg_type(gh_scalar_array, gh_logical, gh_read, 1 ), & + arg_type(gh_scalar_array, gh_integer, gh_read, 4 ), & + arg_type(gh_field, gh_real, gh_inc, w1) & /) integer :: operates_on = cell_column contains @@ -53,17 +54,21 @@ module testkern_scalar_array_mod contains - subroutine testkern_scalar_array_code(dims_rarray, real_array, & + subroutine testkern_scalar_array_code(nlayers, & + dims_rarray, real_array, & dims_larray, logical_array, & - dims_iarray, integer_array) + dims_iarray, integer_array, & + afield) implicit none - integer(i_def), intent(in), dimension(2) :: dims_rarray - integer(i_def), intent(in), dimension(1) :: dims_larray - integer(i_def), intent(in), dimension(4) :: dims_iarray - real(r_def), intent(in), dimension(dims_rarray(1),dims_iarray(2)) :: real_array - logical(l_def), intent(in), dimension(dims_larray(1)) :: logical_array - integer(i_def), intent(in), dimension(dims_iarray(1),dims_iarray(2),dims_iarray(3),dims_iarray(4)) :: integer_array + integer(kind=i_def), intent(in) :: nlayers + integer(kind=i_def), intent(in), dimension(2) :: dims_rarray + integer(kind=i_def), intent(in), dimension(1) :: dims_larray + integer(kind=i_def), intent(in), dimension(4) :: dims_iarray + real(kind=r_def), intent(in), dimension(dims_rarray(1),dims_iarray(2)) :: real_array + logical(kind=l_def), intent(in), dimension(dims_larray(1)) :: logical_array + integer(kind=i_def), intent(in), dimension(dims_iarray(1),dims_iarray(2),dims_iarray(3),dims_iarray(4)) :: integer_array + real(kind=r_def), intent(inout) :: afield end subroutine testkern_scalar_array_code From ea0e8f7a0a7b07c8f2823ae06f1c05cfc6e2d356 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:18:25 +0100 Subject: [PATCH 013/122] 1312: add TODO to check whether is_scalar references need updating --- src/psyclone/lfric.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index be75329b8b..8c64c7dae9 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -5937,6 +5937,7 @@ def _init_scalar_properties( not declared with default precision. ''' + #TODO: Check whether this needs scalars and ScalarArray separated const = LFRicConstants() # Check the type of scalar defined in the metadata is supported. if self.intrinsic_type not in const.VALID_INTRINSIC_TYPES: From 33caeacfdcbf96896f77e224f0272457c2757978 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:35:55 +0100 Subject: [PATCH 014/122] #1312: lint fix --- src/psyclone/lfric.py | 5 +++-- src/psyclone/tests/lfric_test.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 8c64c7dae9..ab980ae116 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -5937,7 +5937,7 @@ def _init_scalar_properties( not declared with default precision. ''' - #TODO: Check whether this needs scalars and ScalarArray separated + # TODO: Check whether this needs scalars and ScalarArray separated const = LFRicConstants() # Check the type of scalar defined in the metadata is supported. if self.intrinsic_type not in const.VALID_INTRINSIC_TYPES: @@ -6155,7 +6155,8 @@ def is_scalar(self): :rtype: bool ''' const = LFRicConstants() - return self._argument_type in (const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) + return self._argument_type in (const.VALID_SCALAR_NAMES + + const.VALID_ARRAY_NAMES) @property def is_scalar_array(self): diff --git a/src/psyclone/tests/lfric_test.py b/src/psyclone/tests/lfric_test.py index c00cbec730..366bdb7fb3 100644 --- a/src/psyclone/tests/lfric_test.py +++ b/src/psyclone/tests/lfric_test.py @@ -1707,7 +1707,8 @@ class for a ScalarArray. ''' # Use one of the examples to create an instance of # LFRicKernelArgument that describes a ScalarArray. - _, invoke_info = parse(os.path.join(BASE_PATH, "28.scalar_array_invoke.f90"), + _, invoke_info = parse(os.path.join(BASE_PATH, + "28.scalar_array_invoke.f90"), api=TEST_API) psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) scalar_argument = psy.invokes.invoke_list[0].schedule.args[0] From 605d9ab59a528ef4092198b5ec3b5c66a40b9b38 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 21 Aug 2025 16:22:37 +0100 Subject: [PATCH 015/122] #1312: create a loose structure for acc access --- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 554068c1c2..c761f40fc8 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -273,6 +273,11 @@ def scalar(self, scalar_arg, var_accesses=None): ''' # TODO: Add implementation of OpenACC data region for ScalarArrays + if scalar_arg.is_scalar_array: + # Need to add the relevant OpenACC information + pass + # Else the argument is a simple scalar value and doesn't need values + # added to OpenACC region # ============================================================================ From c9a5598a948aa953e76f2c324e4295666b85ef84 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:27:35 +0100 Subject: [PATCH 016/122] #1312: Code gen and stub gen for ScalarArrays --- src/psyclone/domain/lfric/arg_ordering.py | 42 +++++-- .../domain/lfric/kern_stub_arg_list.py | 18 +++ src/psyclone/domain/lfric/kernel_interface.py | 1 + src/psyclone/domain/lfric/lfric_kern.py | 6 +- .../domain/lfric/lfric_scalar_args.py | 107 +++++++++++++++--- src/psyclone/lfric.py | 9 +- .../domain/lfric/lfric_scalar_codegen_test.py | 18 +++ .../domain/lfric/lfric_scalar_stubgen_test.py | 37 ++++++ .../lfric/28.scalar_array_invoke.f90 | 16 ++- .../lfric/testkern_scalar_array_mod.f90 | 15 +-- 10 files changed, 227 insertions(+), 42 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 46af228438..6fa663c97c 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -459,7 +459,7 @@ def generate(self, var_accesses=None): self.operator(arg, var_accesses=var_accesses) elif arg.argument_type == "gh_columnwise_operator": self.cma_operator(arg, var_accesses=var_accesses) - elif arg.is_scalar: + elif arg.is_scalar or arg.is_scalar_array: self.scalar(arg, var_accesses=var_accesses) else: raise GenerationError( @@ -776,17 +776,37 @@ def scalar(self, scalar_arg, var_accesses=None): f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES} " f"but got '{scalar_arg.argument_type}'") - if scalar_arg.is_literal: - # If we have a literal, do not add it to the variable access - # information. We do this by providing None as var access. - self.append(scalar_arg.name, None, mode=scalar_arg.access, - metadata_posn=scalar_arg.metadata_index) - if scalar_arg.precision and var_accesses is not None: - var_accesses.add_access(Signature(scalar_arg.precision), - AccessType.TYPE_INFO, self._kern) + if scalar_arg.is_scalar_array: + # If it's a ScalarArray append the dimensions array + from psyclone.domain.lfric import LFRicTypes + const = LFRicConstants() + text = ('dims_' + scalar_arg.name) + + dims_sym = self._symtab.find_or_create( + text, tag=text, symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [scalar_arg._array_ndims])) + print(dims_sym) + print(dims_sym.name) + self.append_array_reference(array_name=dims_sym.name, + indices=[":"], + intrinsic_type=LFRicTypes("LFRicIntegerScalarDataType")(), + tag=dims_sym.name, symbol=dims_sym) + self.append(dims_sym, var_accesses, mode=AccessType.READ) else: - self.append(scalar_arg.name, var_accesses, mode=scalar_arg.access, - metadata_posn=scalar_arg.metadata_index) + if scalar_arg.is_literal: + # If we have a literal, do not add it to the variable access + # information. We do this by providing None as var access. + self.append(scalar_arg.name, None, mode=scalar_arg.access, + metadata_posn=scalar_arg.metadata_index) + if scalar_arg.precision and var_accesses is not None: + var_accesses.add_access(Signature(scalar_arg.precision), + AccessType.TYPE_INFO, self._kern) + else: + self.append(scalar_arg.name, var_accesses, + mode=scalar_arg.access, + metadata_posn=scalar_arg.metadata_index) def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 3158a90b21..19d40ba7be 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -45,6 +45,7 @@ from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError +from psyclone.psyir.symbols import ArrayType, DataSymbol class KernStubArgList(ArgOrdering): @@ -133,6 +134,23 @@ def cma_operator(self, arg, var_accesses=None): _local_args += [bandwidth, alpha, beta, gamma_m, gamma_p] self.extend(_local_args, var_accesses) + def scalar(self, scalar_arg, var_accesses=None): + '''Add the name associated with the scalar argument to the argument + list and optionally add this scalar to the variable access + information. + + :param scalar_arg: the kernel argument. + :type scalar_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` + :param var_accesses: optional VariablesAccessMap instance that \ + stores information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` + + :raises InternalError: if the argument is not a recognised scalar type. + + ''' + super().scalar(scalar_arg, var_accesses) + def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the argument list. If supplied it also stores these accesses to the diff --git a/src/psyclone/domain/lfric/kernel_interface.py b/src/psyclone/domain/lfric/kernel_interface.py index d98eec3a42..08296ebcdd 100644 --- a/src/psyclone/domain/lfric/kernel_interface.py +++ b/src/psyclone/domain/lfric/kernel_interface.py @@ -423,6 +423,7 @@ def scalar(self, scalar_arg, var_accesses=None): "real": LFRicTypes("LFRicRealScalarDataSymbol"), "logical": LFRicTypes("LFRicLogicalScalarDataSymbol")} try: + # TODO: add the ScalarArray alternative symbol = self._symtab.find_or_create_tag( scalar_arg.name, symbol_type=mapping[scalar_arg.intrinsic_type], diff --git a/src/psyclone/domain/lfric/lfric_kern.py b/src/psyclone/domain/lfric/lfric_kern.py index 3399292fa6..d8d6a8aaef 100644 --- a/src/psyclone/domain/lfric/lfric_kern.py +++ b/src/psyclone/domain/lfric/lfric_kern.py @@ -196,7 +196,8 @@ def load_meta(self, ktype): elif descriptor.argument_type.lower() == "gh_field": pre = "field_" elif (descriptor.argument_type.lower() in - const.VALID_SCALAR_NAMES): + (const.VALID_SCALAR_NAMES + + const.VALID_ARRAY_NAMES)): if descriptor.data_type.lower() == "gh_real": pre = "rscalar_" elif descriptor.data_type.lower() == "gh_integer": @@ -208,6 +209,9 @@ def load_meta(self, ktype): f"Expected one of {const.VALID_SCALAR_DATA_TYPES} " f"data types for a scalar argument but found " f"'{descriptor.data_type}'.") + if (descriptor.argument_type.lower() in + const.VALID_ARRAY_NAMES): + pre += "array_" else: raise GenerationError( f"LFRicKern.load_meta() expected one of " diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index df500f9282..eb840f9747 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -49,7 +49,7 @@ from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES -from psyclone.psyir.symbols import DataSymbol, ArgumentInterface +from psyclone.psyir.symbols import DataSymbol, ArgumentInterface, ArrayType # pylint: disable=too-many-lines # pylint: disable=too-many-locals @@ -76,11 +76,17 @@ def __init__(self, node): self._real_scalars = {} self._integer_scalars = {} self._logical_scalars = {} + self._real_scalar_arrays = {} + self._integer_scalar_arrays = {} + self._logical_scalar_arrays = {} for intent in FORTRAN_INTENT_NAMES: self._scalar_args[intent] = [] self._real_scalars[intent] = [] self._integer_scalars[intent] = [] self._logical_scalars[intent] = [] + self._real_scalar_arrays[intent] = [] + self._integer_scalar_arrays[intent] = [] + self._logical_scalar_arrays[intent] = [] def invoke_declarations(self): ''' @@ -98,7 +104,7 @@ def invoke_declarations(self): # Create dictionary of all scalar arguments for checks const = LFRicConstants() self._scalar_args = self._invoke.unique_declns_by_intent( - const.VALID_SCALAR_NAMES) + const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) # Filter scalar arguments by intent and intrinsic type self._real_scalars = self._invoke.unique_declns_by_intent( const.VALID_SCALAR_NAMES, @@ -109,6 +115,15 @@ def invoke_declarations(self): self._logical_scalars = self._invoke.unique_declns_by_intent( const.VALID_SCALAR_NAMES, intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) + self._real_scalar_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) + self._integer_scalar_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_integer"]) + self._logical_scalar_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: scal = [arg.declaration_name for arg in self._scalar_args[intent]] @@ -118,8 +133,14 @@ def invoke_declarations(self): arg in self._integer_scalars[intent]] lscal = [arg.declaration_name for arg in self._logical_scalars[intent]] + rscalarr = [arg.declaration_name for + arg in self._real_scalar_arrays[intent]] + iscalarr = [arg.declaration_name for + arg in self._integer_scalar_arrays[intent]] + lscalarr = [arg.declaration_name for + arg in self._logical_scalar_arrays[intent]] # Add "real", "integer" and "logical" scalar lists for checks - decl_scal = rscal + iscal + lscal + decl_scal = rscal + iscal + lscal + rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types scal_inv = sorted(set(scal) - set(decl_scal)) if scal_inv: @@ -154,25 +175,40 @@ def stub_declarations(self): super().stub_declarations() # Extract all scalar arguments for arg in self.kernel_calls[0].arguments.args: - if arg.is_scalar: + if arg.is_scalar or arg.is_scalar_array: self._scalar_args[arg.intent].append(arg) const = LFRicConstants() # Filter scalar arguments by intent and data type for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_args[intent]: - if arg.descriptor.data_type == "gh_real": - self._real_scalars[intent].append(arg) - elif arg.descriptor.data_type == "gh_integer": - self._integer_scalars[intent].append(arg) - elif arg.descriptor.data_type == "gh_logical": - self._logical_scalars[intent].append(arg) + # Distinguish whether they are ScalarArrays + if arg.is_scalar_array: + if arg.descriptor.data_type == "gh_real": + self._real_scalar_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_integer": + self._integer_scalar_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_logical": + self._logical_scalar_arrays[intent].append(arg) + else: + raise InternalError( + f"Found an unsupported data type " + f"'{arg.descriptor.data_type}' for the ScalarArray " + f"argument '{arg.declaration_name}'. Supported types " + f"are {const.VALID_SCALAR_DATA_TYPES}.") else: - raise InternalError( - f"Found an unsupported data type " - f"'{arg.descriptor.data_type}' for the scalar " - f"argument '{arg.declaration_name}'. Supported types " - f"are {const.VALID_SCALAR_DATA_TYPES}.") + if arg.descriptor.data_type == "gh_real": + self._real_scalars[intent].append(arg) + elif arg.descriptor.data_type == "gh_integer": + self._integer_scalars[intent].append(arg) + elif arg.descriptor.data_type == "gh_logical": + self._logical_scalars[intent].append(arg) + else: + raise InternalError( + f"Found an unsupported data type " + f"'{arg.descriptor.data_type}' for the scalar " + f"argument '{arg.declaration_name}'. Supported types " + f"are {const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() @@ -207,6 +243,20 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) + # Real ScalarArray arguments + for intent in FORTRAN_INTENT_NAMES: + if self._real_scalar_arrays[intent]: + for arg in self._real_scalar_arrays[intent]: + symbol = self.symtab.find_or_create( + arg.declaration_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + [arg._array_ndims])) + symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(symbol) + # Integer scalar arguments for intent in FORTRAN_INTENT_NAMES: if self._integer_scalars[intent]: @@ -219,6 +269,20 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) + # Integer ScalarArray arguments + for intent in FORTRAN_INTENT_NAMES: + if self._integer_scalar_arrays[intent]: + for arg in self._integer_scalar_arrays[intent]: + symbol = self.symtab.find_or_create( + arg.declaration_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(symbol) + # Logical scalar arguments for intent in FORTRAN_INTENT_NAMES: if self._logical_scalars[intent]: @@ -231,6 +295,19 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) + # Logical ScalarArray arguments + for intent in FORTRAN_INTENT_NAMES: + if self._logical_scalar_arrays[intent]: + for arg in self._logical_scalar_arrays[intent]: + symbol = self.symtab.find_or_create( + arg.declaration_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicLogicalScalarDataType")(), + [arg._array_ndims])) + symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(symbol) # ---------- Documentation utils -------------------------------------------- # # The list of module members that we wish AutoAPI to generate diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index ab980ae116..344da781e6 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -5682,6 +5682,7 @@ def __init__(self, kernel_args, arg_meta_data, arg_info, call, check=True): # any-space function spaces. self._kernel_args = kernel_args self._vector_size = arg_meta_data.vector_size + self._array_ndims = arg_meta_data.array_ndims self._argument_type = arg_meta_data.argument_type self._stencil = None if arg_meta_data.mesh: @@ -6276,10 +6277,10 @@ def psyir_expression(self): f"PSyIR contains one or more References.") return lit - # TODO: this possibly needs altering to consider ScalarArrays - # Currently .is_scalar doesn't include ScalarArrays so this won't - # pass. Need to work out if it needs to start for a ScalarArray - if self.is_scalar: + # TODO: this needs altering to consider ScalarArrays + # Currently, this is adding a ScalarArray as a normal + # scalar variable + if self.is_scalar or self.is_scalar_array: try: scalar_sym = symbol_table.lookup(self.name) except KeyError: diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 33a353af6c..a6f5e51a63 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -603,3 +603,21 @@ def test_three_scalars(tmpdir): " map_w3(:,cell))\n") assert expected in generated_code assert LFRicBuild(tmpdir).code_compiles(psy) + +def test_scalar_array(tmpdir): + ''' Tests that we generate correct code when a kernel has all three + types of valid scalar array argument: 'real', 'integer' and 'logical'. + + ''' + _, invoke_info = parse(os.path.join(BASE_PATH, + "28.scalar_array_invoke.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) + + generated_code = str(psy.gen) + expected = ("test to fail\n") + + print("Generated code - ") + print(generated_code) + assert expected in generated_code + assert LFRicBuild(tmpdir).code_compiles(psy) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 95bcd0a593..ec9a6fa163 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -136,3 +136,40 @@ def test_stub_generate_with_scalar_sums_err(): "A user-supplied LFRic kernel must not write/update a scalar " "argument but kernel 'simple_with_reduction_type' has a scalar " "argument with 'gh_sum' access." in str(err.value)) + +def test_stub_generate_with_scalar_array(): + ''' Check that the stub generate produces the expected output when + the kernel has ScalarArray arguments. ''' + result = generate( + os.path.join(BASE_PATH, "testkern_scalar_array_mod.f90"), + api=TEST_API) + +# I don't think this is actually correct. It doesn't seem to be adding +# the array dimensions (or arrays to hold that information). In fact +# this looks suspiciously like a plain scalar entry + print(result) + expected = """\ +module testkern_scalar_array_mod + implicit none + public + + contains + subroutine testkern_scalar_array_code(nlayers, field_1_w1, \ +rscalar_array_2, lscalar_array_3, iscalar_array_4, ndf_w1, \ +undf_w1, map_w1) + use constants_mod + integer(kind=i_def), intent(in) :: nlayers + integer(kind=i_def), intent(in) :: ndf_w1 + integer(kind=i_def), dimension(ndf_w1), intent(in) :: map_w1 + integer(kind=i_def), intent(in) :: undf_w1 + real(kind=r_def), intent(in) :: rscalar_array_2 + integer(kind=i_def), intent(in) :: iscalar_array_4 + logical(kind=l_def), intent(in) :: lscalar_array_3 + real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 + + + end subroutine testkern_scalar_array_code + +end module testkern_scalar_array_mod +""" + assert expected == result diff --git a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 index e9bd6a3855..33cbcbd1c6 100644 --- a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 +++ b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 @@ -36,8 +36,8 @@ program scalar_array_invoke ! Description: single function specified in an invoke call - use constants_mod, only: i_def, r_def, l_def - use field_mod, only: field_type + use constants_mod, only: i_def, r_def, l_def + use field_mod, only: field_type use testkern_scalar_array_mod, only: testkern_scalar_array_type implicit none @@ -47,8 +47,16 @@ program scalar_array_invoke integer(i_def), dimension(2, 5, 10, 8) :: integer_array type(field_type) :: afield - call invoke( & - testkern_scalar_array_type(real_array,logical_array,integer_array,afield) & + real_array = 666.0_r_def + logical_array = .false. + integer_array = -1 + + write(*,*) "Driver: shape(real_array) = ", shape(real_array) + write(*,*) "Driver: shape(logical_array) = ", shape(logical_array) + write(*,*) "Driver: shape(integer_array) = ", shape(integer_array) + + call invoke( & + testkern_scalar_array_type(afield,real_array,logical_array,integer_array) & ) end program scalar_array_invoke diff --git a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 index 924304a14d..86033962ee 100644 --- a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 +++ b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 @@ -29,7 +29,7 @@ ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ----------------------------------------------------------------------------- -! A. Pirrie, Met Office +! Author A. Pirrie, Met Office module testkern_scalar_array_mod @@ -42,10 +42,10 @@ module testkern_scalar_array_mod type, extends(kernel_type) :: testkern_scalar_array_type type(arg_type), dimension(4) :: meta_args = & - (/ arg_type(gh_scalar_array, gh_real, gh_read, 2 ), & + (/ arg_type(gh_field, gh_real, gh_inc, w1), & + arg_type(gh_scalar_array, gh_real, gh_read, 2 ), & arg_type(gh_scalar_array, gh_logical, gh_read, 1 ), & - arg_type(gh_scalar_array, gh_integer, gh_read, 4 ), & - arg_type(gh_field, gh_real, gh_inc, w1) & + arg_type(gh_scalar_array, gh_integer, gh_read, 4 ) & /) integer :: operates_on = cell_column contains @@ -55,20 +55,21 @@ module testkern_scalar_array_mod contains subroutine testkern_scalar_array_code(nlayers, & + afield, & dims_rarray, real_array, & dims_larray, logical_array, & dims_iarray, integer_array, & - afield) + ) implicit none integer(kind=i_def), intent(in) :: nlayers + real(kind=r_def), intent(inout) :: afield integer(kind=i_def), intent(in), dimension(2) :: dims_rarray integer(kind=i_def), intent(in), dimension(1) :: dims_larray integer(kind=i_def), intent(in), dimension(4) :: dims_iarray - real(kind=r_def), intent(in), dimension(dims_rarray(1),dims_iarray(2)) :: real_array + real(kind=r_def), intent(in), dimension(dims_rarray(1),dims_rarray(2)) :: real_array logical(kind=l_def), intent(in), dimension(dims_larray(1)) :: logical_array integer(kind=i_def), intent(in), dimension(dims_iarray(1),dims_iarray(2),dims_iarray(3),dims_iarray(4)) :: integer_array - real(kind=r_def), intent(inout) :: afield end subroutine testkern_scalar_array_code From bbb37b74c354842c8c124df6d1af958c39d75cfe Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:37:16 +0100 Subject: [PATCH 017/122] #1312: lint fix --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 1 - src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 19d40ba7be..91bc4c347e 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -149,7 +149,6 @@ def scalar(self, scalar_arg, var_accesses=None): :raises InternalError: if the argument is not a recognised scalar type. ''' - super().scalar(scalar_arg, var_accesses) def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index a6f5e51a63..28263f3306 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -615,7 +615,7 @@ def test_scalar_array(tmpdir): psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) generated_code = str(psy.gen) - expected = ("test to fail\n") + expected = "test to fail\n" print("Generated code - ") print(generated_code) From 8e311c222edaaabcbab3d8b1af534d19d3f3c888 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:42:48 +0100 Subject: [PATCH 018/122] #1312: lint fix --- src/psyclone/domain/lfric/lfric_scalar_args.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index eb840f9747..c7437b1b67 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -193,9 +193,10 @@ def stub_declarations(self): else: raise InternalError( f"Found an unsupported data type " - f"'{arg.descriptor.data_type}' for the ScalarArray " - f"argument '{arg.declaration_name}'. Supported types " - f"are {const.VALID_SCALAR_DATA_TYPES}.") + f"'{arg.descriptor.data_type}' for the " + f"ScalarArray argument '{arg.declaration_name}'" + f". Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}.") else: if arg.descriptor.data_type == "gh_real": self._real_scalars[intent].append(arg) @@ -207,8 +208,9 @@ def stub_declarations(self): raise InternalError( f"Found an unsupported data type " f"'{arg.descriptor.data_type}' for the scalar " - f"argument '{arg.declaration_name}'. Supported types " - f"are {const.VALID_SCALAR_DATA_TYPES}.") + f"argument '{arg.declaration_name}'. " + f"Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() From ea6ae8d03174c0ec09519bbfdb4a1359708be6aa Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:33:24 +0100 Subject: [PATCH 019/122] #1312: lint fixes --- src/psyclone/domain/lfric/arg_ordering.py | 8 +++++--- src/psyclone/domain/lfric/kern_stub_arg_list.py | 1 - src/psyclone/domain/lfric/lfric_kern.py | 2 +- src/psyclone/domain/lfric/lfric_scalar_args.py | 7 ++++--- .../tests/domain/lfric/lfric_scalar_codegen_test.py | 1 + .../tests/domain/lfric/lfric_scalar_stubgen_test.py | 1 + 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 6fa663c97c..becc9eb761 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -789,10 +789,12 @@ def scalar(self, scalar_arg, var_accesses=None): [scalar_arg._array_ndims])) print(dims_sym) print(dims_sym.name) + arr_type = LFRicTypes("LFRicIntegerScalarDataType")() self.append_array_reference(array_name=dims_sym.name, - indices=[":"], - intrinsic_type=LFRicTypes("LFRicIntegerScalarDataType")(), - tag=dims_sym.name, symbol=dims_sym) + indices=[":"], + intrinsic_type=arr_type, + tag=dims_sym.name, + symbol=dims_sym) self.append(dims_sym, var_accesses, mode=AccessType.READ) else: if scalar_arg.is_literal: diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 91bc4c347e..f2c2a43a61 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -45,7 +45,6 @@ from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError -from psyclone.psyir.symbols import ArrayType, DataSymbol class KernStubArgList(ArgOrdering): diff --git a/src/psyclone/domain/lfric/lfric_kern.py b/src/psyclone/domain/lfric/lfric_kern.py index 4e96c18f8c..6307877b9d 100644 --- a/src/psyclone/domain/lfric/lfric_kern.py +++ b/src/psyclone/domain/lfric/lfric_kern.py @@ -210,7 +210,7 @@ def load_meta(self, ktype): f"data types for a scalar argument but found " f"'{descriptor.data_type}'.") if (descriptor.argument_type.lower() in - const.VALID_ARRAY_NAMES): + const.VALID_ARRAY_NAMES): pre += "array_" else: raise GenerationError( diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index c7437b1b67..01f8a61594 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -134,11 +134,11 @@ def invoke_declarations(self): lscal = [arg.declaration_name for arg in self._logical_scalars[intent]] rscalarr = [arg.declaration_name for - arg in self._real_scalar_arrays[intent]] + arg in self._real_scalar_arrays[intent]] iscalarr = [arg.declaration_name for - arg in self._integer_scalar_arrays[intent]] + arg in self._integer_scalar_arrays[intent]] lscalarr = [arg.declaration_name for - arg in self._logical_scalar_arrays[intent]] + arg in self._logical_scalar_arrays[intent]] # Add "real", "integer" and "logical" scalar lists for checks decl_scal = rscal + iscal + lscal + rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types @@ -311,6 +311,7 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) + # ---------- Documentation utils -------------------------------------------- # # The list of module members that we wish AutoAPI to generate # documentation for. diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 28263f3306..0a08762a01 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -604,6 +604,7 @@ def test_three_scalars(tmpdir): assert expected in generated_code assert LFRicBuild(tmpdir).code_compiles(psy) + def test_scalar_array(tmpdir): ''' Tests that we generate correct code when a kernel has all three types of valid scalar array argument: 'real', 'integer' and 'logical'. diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index ec9a6fa163..3f3133946c 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -137,6 +137,7 @@ def test_stub_generate_with_scalar_sums_err(): "argument but kernel 'simple_with_reduction_type' has a scalar " "argument with 'gh_sum' access." in str(err.value)) + def test_stub_generate_with_scalar_array(): ''' Check that the stub generate produces the expected output when the kernel has ScalarArray arguments. ''' From 136d89e8844625e6082f8a3db640517c06f40ae0 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:56:42 +0100 Subject: [PATCH 020/122] #1312: move dimension array to lfric_scalar_args --- src/psyclone/domain/lfric/arg_ordering.py | 37 ++++++------ .../domain/lfric/lfric_scalar_args.py | 57 +++++++++++++++---- src/psyclone/domain/lfric/lfric_types.py | 1 + 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index becc9eb761..8a6dd92e89 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -777,25 +777,26 @@ def scalar(self, scalar_arg, var_accesses=None): f"but got '{scalar_arg.argument_type}'") if scalar_arg.is_scalar_array: + pass # If it's a ScalarArray append the dimensions array - from psyclone.domain.lfric import LFRicTypes - const = LFRicConstants() - text = ('dims_' + scalar_arg.name) - - dims_sym = self._symtab.find_or_create( - text, tag=text, symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [scalar_arg._array_ndims])) - print(dims_sym) - print(dims_sym.name) - arr_type = LFRicTypes("LFRicIntegerScalarDataType")() - self.append_array_reference(array_name=dims_sym.name, - indices=[":"], - intrinsic_type=arr_type, - tag=dims_sym.name, - symbol=dims_sym) - self.append(dims_sym, var_accesses, mode=AccessType.READ) + # from psyclone.domain.lfric import LFRicTypes + # const = LFRicConstants() + # text = ('dims_' + scalar_arg.name) + + # dims_sym = self._symtab.find_or_create( + # text, tag=text, symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicIntegerScalarDataType")(), + # [scalar_arg._array_ndims])) + # print(dims_sym) + # print(dims_sym.name) + # arr_type = LFRicTypes("LFRicIntegerScalarDataType")() + # self.append_array_reference(array_name=dims_sym.name, + # indices=[":"], + # intrinsic_type=arr_type, + # tag=dims_sym.name, + # symbol=dims_sym) + # self.append(dims_sym, var_accesses, mode=AccessType.READ) else: if scalar_arg.is_literal: # If we have a literal, do not add it to the variable access diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 01f8a61594..42cccdd0cd 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -49,7 +49,10 @@ from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES -from psyclone.psyir.symbols import DataSymbol, ArgumentInterface, ArrayType +from psyclone.psyir.nodes import Reference +from psyclone.psyir.symbols import (DataSymbol, ArgumentInterface, + AutomaticInterface, ArrayType, + ScalarType, UnresolvedType) # pylint: disable=too-many-lines # pylint: disable=too-many-locals @@ -249,15 +252,49 @@ def _create_declarations(self): for intent in FORTRAN_INTENT_NAMES: if self._real_scalar_arrays[intent]: for arg in self._real_scalar_arrays[intent]: - symbol = self.symtab.find_or_create( - arg.declaration_name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - [arg._array_ndims])) - symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(symbol) + if arg._array_ndims > 1: + # Create the dimensions array symbol + dims_symbol_list = [] + dims_name = ('dims_' + arg.name) + dims_symbol = self.symtab.find_or_create( + dims_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_symbol) + for idx in range(1, arg._array_ndims + 1): + # Create symbols to add as dimensions + # to ScalarArray + dims_access_name = dims_name + '(' + str(idx) + ')' + # I'm unsure about the need for this. It was added + # to appease the dims_symbol_access but seems + # unneccessary + kind_sym = self.symtab.find_or_create( + "kind_sym", + symbol_type=DataSymbol, + datatype=UnresolvedType()) + dims_symbol_access = self.symtab.find_or_create( + dims_access_name, + symbol_type=DataSymbol, + datatype=ScalarType( + ScalarType.Intrinsic.INTEGER, + Reference(kind_sym))) + dims_symbol_access.interface = AutomaticInterface() + dims_symbol_list.append(dims_symbol_access) + + # Add the ScalarArray + scalar_array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + [Reference(sym) for sym in dims_symbol_list])) + scalar_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(scalar_array_symbol) # Integer scalar arguments for intent in FORTRAN_INTENT_NAMES: diff --git a/src/psyclone/domain/lfric/lfric_types.py b/src/psyclone/domain/lfric/lfric_types.py index ce8f112edf..217e6e5678 100644 --- a/src/psyclone/domain/lfric/lfric_types.py +++ b/src/psyclone/domain/lfric/lfric_types.py @@ -190,6 +190,7 @@ def _create_generic_scalars(): LFRicTypes("R_DEF")), GenericScalar("LFRicLogicalScalar", ScalarType.Intrinsic.BOOLEAN, LFRicTypes("L_DEF"))] + # TODO: Consider adding ScalarArrays as a generic data type # Generate generic LFRic scalar datatypes and symbols from definitions for info in generic_scalar_datatypes: From fd0d5462f5ef1be16129d87ded2c017a7c1f1719 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 24 Oct 2025 13:59:28 +0100 Subject: [PATCH 021/122] #1312: add declarations for ScalarArray --- .../domain/lfric/lfric_scalar_args.py | 103 +++++++++++++----- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 42cccdd0cd..501cd69257 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -252,7 +252,7 @@ def _create_declarations(self): for intent in FORTRAN_INTENT_NAMES: if self._real_scalar_arrays[intent]: for arg in self._real_scalar_arrays[intent]: - if arg._array_ndims > 1: + if arg._array_ndims >= 1: # Create the dimensions array symbol dims_symbol_list = [] dims_name = ('dims_' + arg.name) @@ -272,16 +272,11 @@ def _create_declarations(self): # I'm unsure about the need for this. It was added # to appease the dims_symbol_access but seems # unneccessary - kind_sym = self.symtab.find_or_create( - "kind_sym", - symbol_type=DataSymbol, - datatype=UnresolvedType()) dims_symbol_access = self.symtab.find_or_create( dims_access_name, symbol_type=DataSymbol, datatype=ScalarType( - ScalarType.Intrinsic.INTEGER, - Reference(kind_sym))) + ScalarType.Intrinsic.INTEGER, 4)) dims_symbol_access.interface = AutomaticInterface() dims_symbol_list.append(dims_symbol_access) @@ -312,15 +307,44 @@ def _create_declarations(self): for intent in FORTRAN_INTENT_NAMES: if self._integer_scalar_arrays[intent]: for arg in self._integer_scalar_arrays[intent]: - symbol = self.symtab.find_or_create( - arg.declaration_name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(symbol) + if arg._array_ndims >= 1: + # Create the dimensions array symbol + dims_symbol_list = [] + dims_name = ('dims_' + arg.name) + dims_symbol = self.symtab.find_or_create( + dims_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_symbol) + for idx in range(1, arg._array_ndims + 1): + # Create symbols to add as dimensions + # to ScalarArray + dims_access_name = dims_name + '(' + str(idx) + ')' + # I'm unsure about the need for this. It was added + # to appease the dims_symbol_access but seems + # unneccessary + dims_symbol_access = self.symtab.find_or_create( + dims_access_name, + symbol_type=DataSymbol, + datatype=ScalarType( + ScalarType.Intrinsic.INTEGER, 4)) + dims_symbol_access.interface = AutomaticInterface() + dims_symbol_list.append(dims_symbol_access) + + # Add the ScalarArray + scalar_array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [Reference(sym) for sym in dims_symbol_list])) + scalar_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(scalar_array_symbol) # Logical scalar arguments for intent in FORTRAN_INTENT_NAMES: @@ -338,15 +362,44 @@ def _create_declarations(self): for intent in FORTRAN_INTENT_NAMES: if self._logical_scalar_arrays[intent]: for arg in self._logical_scalar_arrays[intent]: - symbol = self.symtab.find_or_create( - arg.declaration_name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicLogicalScalarDataType")(), - [arg._array_ndims])) - symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(symbol) + if arg._array_ndims >= 1: + # Create the dimensions array symbol + dims_symbol_list = [] + dims_name = ('dims_' + arg.name) + dims_symbol = self.symtab.find_or_create( + dims_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_symbol) + for idx in range(1, arg._array_ndims + 1): + # Create symbols to add as dimensions + # to ScalarArray + dims_access_name = dims_name + '(' + str(idx) + ')' + # I'm unsure about the need for this. It was added + # to appease the dims_symbol_access but seems + # unneccessary + dims_symbol_access = self.symtab.find_or_create( + dims_access_name, + symbol_type=DataSymbol, + datatype=ScalarType( + ScalarType.Intrinsic.INTEGER, 4)) + dims_symbol_access.interface = AutomaticInterface() + dims_symbol_list.append(dims_symbol_access) + + # Add the ScalarArray + scalar_array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicLogicalScalarDataType")(), + [Reference(sym) for sym in dims_symbol_list])) + scalar_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(scalar_array_symbol) # ---------- Documentation utils -------------------------------------------- # From 50a2c09fd4a687db5a994faf2c788f58acf277aa Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 3 Nov 2025 14:07:48 +0000 Subject: [PATCH 022/122] #1312: Move ScalarArray declarations to its own file --- .../domain/lfric/lfric_scalar_args.py | 198 +---------- .../domain/lfric/lfric_scalar_array_args.py | 323 ++++++++++++++++++ 2 files changed, 339 insertions(+), 182 deletions(-) create mode 100644 src/psyclone/domain/lfric/lfric_scalar_array_args.py diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 501cd69257..ec4631809d 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -49,10 +49,7 @@ from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES -from psyclone.psyir.nodes import Reference -from psyclone.psyir.symbols import (DataSymbol, ArgumentInterface, - AutomaticInterface, ArrayType, - ScalarType, UnresolvedType) +from psyclone.psyir.symbols import DataSymbol, ArgumentInterface # pylint: disable=too-many-lines # pylint: disable=too-many-locals @@ -79,17 +76,11 @@ def __init__(self, node): self._real_scalars = {} self._integer_scalars = {} self._logical_scalars = {} - self._real_scalar_arrays = {} - self._integer_scalar_arrays = {} - self._logical_scalar_arrays = {} for intent in FORTRAN_INTENT_NAMES: self._scalar_args[intent] = [] self._real_scalars[intent] = [] self._integer_scalars[intent] = [] self._logical_scalars[intent] = [] - self._real_scalar_arrays[intent] = [] - self._integer_scalar_arrays[intent] = [] - self._logical_scalar_arrays[intent] = [] def invoke_declarations(self): ''' @@ -118,15 +109,6 @@ def invoke_declarations(self): self._logical_scalars = self._invoke.unique_declns_by_intent( const.VALID_SCALAR_NAMES, intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) - self._real_scalar_arrays = self._invoke.unique_declns_by_intent( - const.VALID_ARRAY_NAMES, - intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) - self._integer_scalar_arrays = self._invoke.unique_declns_by_intent( - const.VALID_ARRAY_NAMES, - intrinsic_type=const.MAPPING_DATA_TYPES["gh_integer"]) - self._logical_scalar_arrays = self._invoke.unique_declns_by_intent( - const.VALID_ARRAY_NAMES, - intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: scal = [arg.declaration_name for arg in self._scalar_args[intent]] @@ -136,14 +118,10 @@ def invoke_declarations(self): arg in self._integer_scalars[intent]] lscal = [arg.declaration_name for arg in self._logical_scalars[intent]] - rscalarr = [arg.declaration_name for - arg in self._real_scalar_arrays[intent]] - iscalarr = [arg.declaration_name for - arg in self._integer_scalar_arrays[intent]] - lscalarr = [arg.declaration_name for - arg in self._logical_scalar_arrays[intent]] + # Add "real", "integer" and "logical" scalar lists for checks - decl_scal = rscal + iscal + lscal + rscalarr + iscalarr + lscalarr + decl_scal = rscal + iscal + lscal + # Check for unsupported intrinsic types scal_inv = sorted(set(scal) - set(decl_scal)) if scal_inv: @@ -186,34 +164,19 @@ def stub_declarations(self): for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_args[intent]: # Distinguish whether they are ScalarArrays - if arg.is_scalar_array: - if arg.descriptor.data_type == "gh_real": - self._real_scalar_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_integer": - self._integer_scalar_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_logical": - self._logical_scalar_arrays[intent].append(arg) - else: - raise InternalError( - f"Found an unsupported data type " - f"'{arg.descriptor.data_type}' for the " - f"ScalarArray argument '{arg.declaration_name}'" - f". Supported types are " - f"{const.VALID_SCALAR_DATA_TYPES}.") + if arg.descriptor.data_type == "gh_real": + self._real_scalars[intent].append(arg) + elif arg.descriptor.data_type == "gh_integer": + self._integer_scalars[intent].append(arg) + elif arg.descriptor.data_type == "gh_logical": + self._logical_scalars[intent].append(arg) else: - if arg.descriptor.data_type == "gh_real": - self._real_scalars[intent].append(arg) - elif arg.descriptor.data_type == "gh_integer": - self._integer_scalars[intent].append(arg) - elif arg.descriptor.data_type == "gh_logical": - self._logical_scalars[intent].append(arg) - else: - raise InternalError( - f"Found an unsupported data type " - f"'{arg.descriptor.data_type}' for the scalar " - f"argument '{arg.declaration_name}'. " - f"Supported types are " - f"{const.VALID_SCALAR_DATA_TYPES}.") + raise InternalError( + f"Found an unsupported data type " + f"'{arg.descriptor.data_type}' for the scalar " + f"argument '{arg.declaration_name}'. " + f"Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() @@ -248,49 +211,6 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) - # Real ScalarArray arguments - for intent in FORTRAN_INTENT_NAMES: - if self._real_scalar_arrays[intent]: - for arg in self._real_scalar_arrays[intent]: - if arg._array_ndims >= 1: - # Create the dimensions array symbol - dims_symbol_list = [] - dims_name = ('dims_' + arg.name) - dims_symbol = self.symtab.find_or_create( - dims_name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_symbol) - for idx in range(1, arg._array_ndims + 1): - # Create symbols to add as dimensions - # to ScalarArray - dims_access_name = dims_name + '(' + str(idx) + ')' - # I'm unsure about the need for this. It was added - # to appease the dims_symbol_access but seems - # unneccessary - dims_symbol_access = self.symtab.find_or_create( - dims_access_name, - symbol_type=DataSymbol, - datatype=ScalarType( - ScalarType.Intrinsic.INTEGER, 4)) - dims_symbol_access.interface = AutomaticInterface() - dims_symbol_list.append(dims_symbol_access) - - # Add the ScalarArray - scalar_array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - [Reference(sym) for sym in dims_symbol_list])) - scalar_array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(scalar_array_symbol) - # Integer scalar arguments for intent in FORTRAN_INTENT_NAMES: if self._integer_scalars[intent]: @@ -303,49 +223,6 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) - # Integer ScalarArray arguments - for intent in FORTRAN_INTENT_NAMES: - if self._integer_scalar_arrays[intent]: - for arg in self._integer_scalar_arrays[intent]: - if arg._array_ndims >= 1: - # Create the dimensions array symbol - dims_symbol_list = [] - dims_name = ('dims_' + arg.name) - dims_symbol = self.symtab.find_or_create( - dims_name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_symbol) - for idx in range(1, arg._array_ndims + 1): - # Create symbols to add as dimensions - # to ScalarArray - dims_access_name = dims_name + '(' + str(idx) + ')' - # I'm unsure about the need for this. It was added - # to appease the dims_symbol_access but seems - # unneccessary - dims_symbol_access = self.symtab.find_or_create( - dims_access_name, - symbol_type=DataSymbol, - datatype=ScalarType( - ScalarType.Intrinsic.INTEGER, 4)) - dims_symbol_access.interface = AutomaticInterface() - dims_symbol_list.append(dims_symbol_access) - - # Add the ScalarArray - scalar_array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [Reference(sym) for sym in dims_symbol_list])) - scalar_array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(scalar_array_symbol) - # Logical scalar arguments for intent in FORTRAN_INTENT_NAMES: if self._logical_scalars[intent]: @@ -358,49 +235,6 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(symbol) - # Logical ScalarArray arguments - for intent in FORTRAN_INTENT_NAMES: - if self._logical_scalar_arrays[intent]: - for arg in self._logical_scalar_arrays[intent]: - if arg._array_ndims >= 1: - # Create the dimensions array symbol - dims_symbol_list = [] - dims_name = ('dims_' + arg.name) - dims_symbol = self.symtab.find_or_create( - dims_name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_symbol) - for idx in range(1, arg._array_ndims + 1): - # Create symbols to add as dimensions - # to ScalarArray - dims_access_name = dims_name + '(' + str(idx) + ')' - # I'm unsure about the need for this. It was added - # to appease the dims_symbol_access but seems - # unneccessary - dims_symbol_access = self.symtab.find_or_create( - dims_access_name, - symbol_type=DataSymbol, - datatype=ScalarType( - ScalarType.Intrinsic.INTEGER, 4)) - dims_symbol_access.interface = AutomaticInterface() - dims_symbol_list.append(dims_symbol_access) - - # Add the ScalarArray - scalar_array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicLogicalScalarDataType")(), - [Reference(sym) for sym in dims_symbol_list])) - scalar_array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(scalar_array_symbol) - # ---------- Documentation utils -------------------------------------------- # # The list of module members that we wish AutoAPI to generate diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py new file mode 100644 index 0000000000..d4fcdf3b46 --- /dev/null +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -0,0 +1,323 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2017-2025, Science and Technology Facilities Council. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- +# Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab +# Modified I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office +# Modified J. Henrichs, Bureau of Meteorology +# Modified A. B. G. Chalk and N. Nobre, STFC Daresbury Lab + +''' +This module contains the LFRicScalarArgs class which handles the +declarations of scalar arguments to the kernel found in either +an Invoke or a Kernel stub. +''' + +# Imports +from collections import OrderedDict, Counter + +from psyclone.psyir.frontend.fparser2 import INTENT_MAPPING +from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes +from psyclone.errors import GenerationError, InternalError +from psyclone.psyGen import FORTRAN_INTENT_NAMES +from psyclone.psyir.nodes import Reference, Literal, ArrayReference +from psyclone.psyir.symbols import (DataSymbol, ArgumentInterface, + AutomaticInterface, ArrayType, + ScalarType, UnresolvedType, + INTEGER_TYPE) + +# pylint: disable=too-many-lines +# pylint: disable=too-many-locals +# pylint: disable=too-many-branches + + +class LFRicScalarArrayArgs(LFRicCollection): + ''' + Handles the declarations of scalar kernel arguments appearing in either + an Invoke or a Kernel stub. + + :param node: the Invoke or Kernel stub for which to manage the scalar \ + arguments. + :type node: :py:class:`psyclone.domain.lfric.LFRicKern` or \ + :py:class:`psyclone.domain.lfric.LFRicInvoke` + + ''' + def __init__(self, node): + super().__init__(node) + + # Initialise dictionaries of 'real', 'integer' and 'logical' + # scalar arguments by data type and intent + self._scalar_args = {} + self._real_scalar_arrays = {} + self._integer_scalar_arrays = {} + self._logical_scalar_arrays = {} + for intent in FORTRAN_INTENT_NAMES: + self._scalar_args[intent] = [] + self._real_scalar_arrays[intent] = [] + self._integer_scalar_arrays[intent] = [] + self._logical_scalar_arrays[intent] = [] + + def invoke_declarations(self): + ''' + Create argument lists and declarations for all scalar arguments + in an Invoke. + + + :raises InternalError: for unsupported argument intrinsic types. + :raises GenerationError: if the same scalar argument has different \ + data types in different Kernel calls \ + within the same Invoke. + + ''' + super().invoke_declarations() + # Create dictionary of all scalar arguments for checks + const = LFRicConstants() + self._scalar_args = self._invoke.unique_declns_by_intent( + const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) + # Filter scalar arguments by intent and intrinsic type + self._real_scalar_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) + self._integer_scalar_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_integer"]) + self._logical_scalar_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) + + for intent in FORTRAN_INTENT_NAMES: + scal = [arg.declaration_name for arg in self._scalar_args[intent]] + rscalarr = [arg.declaration_name for + arg in self._real_scalar_arrays[intent]] + iscalarr = [arg.declaration_name for + arg in self._integer_scalar_arrays[intent]] + lscalarr = [arg.declaration_name for + arg in self._logical_scalar_arrays[intent]] + # Add "real", "integer" and "logical" scalar lists for checks + decl_scal = rscalarr + iscalarr + lscalarr + # Check for unsupported intrinsic types + scal_inv = sorted(set(scal) - set(decl_scal)) + if scal_inv: + raise InternalError( + f"Found unsupported intrinsic types for the scalar " + f"arguments {scal_inv} to Invoke '{self._invoke.name}'. " + f"Supported types are {const.VALID_INTRINSIC_TYPES}.") + # Check that the same scalar name is not found in either of + # 'real', 'integer' or 'logical' scalar lists (for instance if + # passed to one kernel as a 'real' and to another kernel as an + # 'integer' scalar) + scal_multi_type = [item for item, count in + Counter(decl_scal).items() if count > 1] + if scal_multi_type: + raise GenerationError( + f"Scalar argument(s) {scal_multi_type} in Invoke " + f"'{self._invoke.name}' have different metadata for data " + f"type ({list(const.MAPPING_DATA_TYPES.keys())}) in " + f"different kernels. This is invalid.") + + # Create declarations + self._create_declarations() + + def stub_declarations(self): + ''' + Create and add declarations for all scalar arguments in + a Kernel stub. + + :raises InternalError: for an unsupported argument data type. + + ''' + super().stub_declarations() + # Extract all scalar arguments + for arg in self.kernel_calls[0].arguments.args: + if arg.is_scalar or arg.is_scalar_array: + self._scalar_args[arg.intent].append(arg) + + const = LFRicConstants() + # Filter scalar arguments by intent and data type + for intent in FORTRAN_INTENT_NAMES: + for arg in self._scalar_args[intent]: + # Distinguish whether they are ScalarArrays + if arg.is_scalar_array: + if arg.descriptor.data_type == "gh_real": + self._real_scalar_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_integer": + self._integer_scalar_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_logical": + self._logical_scalar_arrays[intent].append(arg) + else: + raise InternalError( + f"Found an unsupported data type " + f"'{arg.descriptor.data_type}' for the " + f"ScalarArray argument '{arg.declaration_name}'" + f". Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}.") + else: + # Throw some kind of exception + continue + + # Create declarations + self._create_declarations() + + def _create_declarations(self): + ''' + Add declarations for the scalar arguments. + + ''' + # Real ScalarArray arguments + for intent in FORTRAN_INTENT_NAMES: + if self._real_scalar_arrays[intent]: + for arg in self._real_scalar_arrays[intent]: + if arg._array_ndims >= 1: + # Create the dimensions array symbol + dims_symbol_list = [] + dims_name = ('dims_' + arg.name) + dims_symbol = self.symtab.find_or_create( + dims_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_symbol) + for idx in range(1, arg._array_ndims + 1): + # Create symbols to add as dimensions + # to ScalarArray + dims_access_name = dims_name + '(' + str(idx) + ')' + # I'm unsure about the need for this. It was added + # to appease the dims_symbol_access but seems + # unneccessary + dims_symbol_access = self.symtab.find_or_create( + dims_access_name, + symbol_type=DataSymbol, + datatype=ScalarType( + ScalarType.Intrinsic.INTEGER, 4)) + dims_symbol_access.interface = AutomaticInterface() + dims_symbol_list.append(dims_symbol_access) + + # Add the ScalarArray + scalar_array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + [Reference(sym) for sym in dims_symbol_list])) + scalar_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(scalar_array_symbol) + + # Integer ScalarArray arguments + for intent in FORTRAN_INTENT_NAMES: + if self._integer_scalar_arrays[intent]: + for arg in self._integer_scalar_arrays[intent]: + if arg._array_ndims >= 1: + dims_array_symbol = self.symtab.find_or_create( + arg.declaration_name, + symbol_type=DataSymbol, + datatype=ArrayType(INTEGER_TYPE, + [arg._array_ndims])) + + dim = [ArrayReference.create(dims_array_symbol, + [Literal(str(idx),INTEGER_TYPE) for idx in range(1,arg._array_ndims+1)])] + # Add the ScalarArray + # data_type = ArrayType(LFRicTypes("LFRicIntegerScalarDataType")(), + # dims=[ArrayReference.create(dims_symbol, [Literal(idx,ArrayType)]) + # for idx in range(1,arg._array_ndims)]) + + # scalar_array_symbol = self.symtab.find_or_create( + # arg.name, + # symbol_type=DataSymbol, + # datatype=data_type) + # scalar_array_symbol.interface = ArgumentInterface( + # INTENT_MAPPING[intent]) + # self.symtab.append_argument(scalar_array_symbol) + + # Create the dimensions array symbol + # dims_name = ('dims_' + arg.name) + # dims_symbol = self.symtab.find_or_create( + # dims_name, + # symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicIntegerScalarDataType")(), + # [arg._array_ndims])) + # dims_symbol.interface = ArgumentInterface( + # INTENT_MAPPING[intent]) + # self.symtab.append_argument(dims_symbol) + + # Logical ScalarArray arguments + for intent in FORTRAN_INTENT_NAMES: + if self._logical_scalar_arrays[intent]: + for arg in self._logical_scalar_arrays[intent]: + if arg._array_ndims >= 1: + # Create the dimensions array symbol + dims_symbol_list = [] + dims_name = ('dims_' + arg.name) + dims_symbol = self.symtab.find_or_create( + dims_name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_symbol) + for idx in range(1, arg._array_ndims + 1): + # Create symbols to add as dimensions + # to ScalarArray + dims_access_name = dims_name + '(' + str(idx) + ')' + # I'm unsure about the need for this. It was added + # to appease the dims_symbol_access but seems + # unneccessary + dims_symbol_access = self.symtab.find_or_create( + dims_access_name, + symbol_type=DataSymbol, + datatype=ScalarType( + ScalarType.Intrinsic.INTEGER, 4)) + dims_symbol_access.interface = AutomaticInterface() + dims_symbol_list.append(dims_symbol_access) + + # Add the ScalarArray + scalar_array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicLogicalScalarDataType")(), + [Reference(sym) for sym in dims_symbol_list])) + scalar_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(scalar_array_symbol) + + +# ---------- Documentation utils -------------------------------------------- # +# The list of module members that we wish AutoAPI to generate +# documentation for. +__all__ = ['LFRicScalarArrayArgs'] From f4c685b5759ab24965df5a25ef5816571a51fc14 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 3 Nov 2025 14:17:07 +0000 Subject: [PATCH 023/122] #1312: correct the type checking in declarations --- .../domain/lfric/lfric_scalar_args.py | 2 +- .../domain/lfric/lfric_scalar_array_args.py | 54 +++++++++---------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index ec4631809d..6c345bfede 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -156,7 +156,7 @@ def stub_declarations(self): super().stub_declarations() # Extract all scalar arguments for arg in self.kernel_calls[0].arguments.args: - if arg.is_scalar or arg.is_scalar_array: + if arg.is_scalar: self._scalar_args[arg.intent].append(arg) const = LFRicConstants() diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index d4fcdf3b46..f7d9799ce8 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -31,14 +31,11 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- -# Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office -# Modified J. Henrichs, Bureau of Meteorology -# Modified A. B. G. Chalk and N. Nobre, STFC Daresbury Lab +# Authors A. Pirrie, Met Office ''' -This module contains the LFRicScalarArgs class which handles the -declarations of scalar arguments to the kernel found in either +This module contains the LFRicScalarArrayArgs class which handles the +declarations of ScalarArray arguments to the kernel found in either an Invoke or a Kernel stub. ''' @@ -76,12 +73,12 @@ def __init__(self, node): # Initialise dictionaries of 'real', 'integer' and 'logical' # scalar arguments by data type and intent - self._scalar_args = {} + self._scalar_array_args = {} self._real_scalar_arrays = {} self._integer_scalar_arrays = {} self._logical_scalar_arrays = {} for intent in FORTRAN_INTENT_NAMES: - self._scalar_args[intent] = [] + self._scalar_array_args[intent] = [] self._real_scalar_arrays[intent] = [] self._integer_scalar_arrays[intent] = [] self._logical_scalar_arrays[intent] = [] @@ -101,7 +98,7 @@ def invoke_declarations(self): super().invoke_declarations() # Create dictionary of all scalar arguments for checks const = LFRicConstants() - self._scalar_args = self._invoke.unique_declns_by_intent( + self._scalar_array_args = self._invoke.unique_declns_by_intent( const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) # Filter scalar arguments by intent and intrinsic type self._real_scalar_arrays = self._invoke.unique_declns_by_intent( @@ -115,7 +112,7 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: - scal = [arg.declaration_name for arg in self._scalar_args[intent]] + scal = [arg.declaration_name for arg in self._scalar_array_args[intent]] rscalarr = [arg.declaration_name for arg in self._real_scalar_arrays[intent]] iscalarr = [arg.declaration_name for @@ -158,31 +155,27 @@ def stub_declarations(self): super().stub_declarations() # Extract all scalar arguments for arg in self.kernel_calls[0].arguments.args: - if arg.is_scalar or arg.is_scalar_array: - self._scalar_args[arg.intent].append(arg) + if arg.is_scalar_array: + self._scalar_array_args[arg.intent].append(arg) const = LFRicConstants() # Filter scalar arguments by intent and data type for intent in FORTRAN_INTENT_NAMES: - for arg in self._scalar_args[intent]: + for arg in self._scalar_array_args[intent]: # Distinguish whether they are ScalarArrays - if arg.is_scalar_array: - if arg.descriptor.data_type == "gh_real": - self._real_scalar_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_integer": - self._integer_scalar_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_logical": - self._logical_scalar_arrays[intent].append(arg) - else: - raise InternalError( - f"Found an unsupported data type " - f"'{arg.descriptor.data_type}' for the " - f"ScalarArray argument '{arg.declaration_name}'" - f". Supported types are " - f"{const.VALID_SCALAR_DATA_TYPES}.") + if arg.descriptor.data_type == "gh_real": + self._real_scalar_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_integer": + self._integer_scalar_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_logical": + self._logical_scalar_arrays[intent].append(arg) else: - # Throw some kind of exception - continue + raise InternalError( + f"Found an unsupported data type " + f"'{arg.descriptor.data_type}' for the " + f"ScalarArray argument '{arg.declaration_name}'" + f". Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() @@ -234,6 +227,9 @@ def _create_declarations(self): scalar_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(scalar_array_symbol) + else: + # Possibly throw exception for wrong dimensions + continue # Integer ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: From cc533903420506dfb7fbf9d102889b347abc388d Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:35:05 +0000 Subject: [PATCH 024/122] #1312: return lfric_scalar_args to original state --- src/psyclone/domain/lfric/lfric_scalar_args.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 6c345bfede..b50d9b54f3 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -98,7 +98,7 @@ def invoke_declarations(self): # Create dictionary of all scalar arguments for checks const = LFRicConstants() self._scalar_args = self._invoke.unique_declns_by_intent( - const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) + const.VALID_SCALAR_NAMES) # Filter scalar arguments by intent and intrinsic type self._real_scalars = self._invoke.unique_declns_by_intent( const.VALID_SCALAR_NAMES, @@ -118,10 +118,8 @@ def invoke_declarations(self): arg in self._integer_scalars[intent]] lscal = [arg.declaration_name for arg in self._logical_scalars[intent]] - # Add "real", "integer" and "logical" scalar lists for checks decl_scal = rscal + iscal + lscal - # Check for unsupported intrinsic types scal_inv = sorted(set(scal) - set(decl_scal)) if scal_inv: @@ -163,7 +161,6 @@ def stub_declarations(self): # Filter scalar arguments by intent and data type for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_args[intent]: - # Distinguish whether they are ScalarArrays if arg.descriptor.data_type == "gh_real": self._real_scalars[intent].append(arg) elif arg.descriptor.data_type == "gh_integer": From f3ee59e1d7b18d8124602bc1c815ea52aa0ef412 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:39:24 +0000 Subject: [PATCH 025/122] #1312: fix if statement to exclude ScalarArray --- src/psyclone/domain/lfric/lfric_scalar_args.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index b50d9b54f3..0038b7c9ea 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -154,7 +154,7 @@ def stub_declarations(self): super().stub_declarations() # Extract all scalar arguments for arg in self.kernel_calls[0].arguments.args: - if arg.is_scalar: + if arg.is_scalar and not arg.is_scalar_array: self._scalar_args[arg.intent].append(arg) const = LFRicConstants() From 140b0225b5bd1bbc5c59fbaf5d26607d5e44e783 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:47:44 +0000 Subject: [PATCH 026/122] #1312: Add LFRicScalarArrayArga to paths --- src/psyclone/domain/lfric/__init__.py | 2 ++ src/psyclone/domain/lfric/lfric_invoke.py | 8 ++++++-- src/psyclone/domain/lfric/lfric_kern.py | 12 ++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/psyclone/domain/lfric/__init__.py b/src/psyclone/domain/lfric/__init__.py index c1dc00cb4c..a713e0516b 100644 --- a/src/psyclone/domain/lfric/__init__.py +++ b/src/psyclone/domain/lfric/__init__.py @@ -71,6 +71,7 @@ from psyclone.domain.lfric.lfric_run_time_checks import LFRicRunTimeChecks from psyclone.domain.lfric.lfric_invokes import LFRicInvokes from psyclone.domain.lfric.lfric_scalar_args import LFRicScalarArgs +from psyclone.domain.lfric.lfric_scalar_array_args import LFRicScalarArrayArgs from psyclone.domain.lfric.lfric_loop_bounds import LFRicLoopBounds from psyclone.domain.lfric.lfric_kern_metadata import LFRicKernMetadata from psyclone.domain.lfric.lfric_psy import LFRicPSy @@ -105,5 +106,6 @@ 'LFRicPSy', 'LFRicRunTimeChecks', 'LFRicScalarArgs', + 'LFRicScalarArrayArgs', 'LFRicStencils', 'LFRicSymbolTable'] diff --git a/src/psyclone/domain/lfric/lfric_invoke.py b/src/psyclone/domain/lfric/lfric_invoke.py index f5a73639fc..fe2a16ec35 100644 --- a/src/psyclone/domain/lfric/lfric_invoke.py +++ b/src/psyclone/domain/lfric/lfric_invoke.py @@ -93,10 +93,13 @@ def __init__(self, alg_invocation, idx, invokes): from psyclone.domain.lfric import ( LFRicCellIterators, LFRicHaloDepths, LFRicLoopBounds, LFRicRunTimeChecks, - LFRicScalarArgs, LFRicFields, LFRicDofmaps, LFRicStencils) + LFRicScalarArgs, LFRicScalarArrayArgs, LFRicFields, LFRicDofmaps, + LFRicStencils) self.scalar_args = LFRicScalarArgs(self) + self.scalar_array_args = LFRicScalarArrayArgs(self) + # Initialise our Invoke stencil information self.stencil = LFRicStencils(self) @@ -274,7 +277,8 @@ def setup_psy_layer_symbols(self): ''' # Declare all quantities required by this PSy routine (Invoke) - for entities in [self.scalar_args, self.fields, self.lma_ops, + for entities in [self.scalar_args, self. scalar_array_args, + self.fields, self.lma_ops, self.stencil, self.meshes, self.function_spaces, self.dofmaps, self.cma_ops, self.boundary_conditions, self.evaluators, diff --git a/src/psyclone/domain/lfric/lfric_kern.py b/src/psyclone/domain/lfric/lfric_kern.py index 6307877b9d..9f6cb6e177 100644 --- a/src/psyclone/domain/lfric/lfric_kern.py +++ b/src/psyclone/domain/lfric/lfric_kern.py @@ -776,17 +776,17 @@ def gen_stub(self) -> Container: # Import here to avoid circular dependency # pylint: disable=import-outside-toplevel from psyclone.domain.lfric import ( - LFRicCellIterators, LFRicScalarArgs, LFRicFields, - LFRicDofmaps, LFRicStencils) + LFRicCellIterators, LFRicScalarArgs, LFRicScalarArrayArgs, + LFRicFields, LFRicDofmaps, LFRicStencils) from psyclone.lfric import ( LFRicFunctionSpaces, LFRicCMAOperators, LFRicBoundaryConditions, LFRicLMAOperators, LFRicMeshProperties, LFRicBasisFunctions, LFRicReferenceElement) for entities in [LFRicCellIterators, LFRicDofmaps, LFRicFunctionSpaces, - LFRicCMAOperators, LFRicScalarArgs, LFRicFields, - LFRicLMAOperators, LFRicStencils, LFRicBasisFunctions, - LFRicBoundaryConditions, LFRicReferenceElement, - LFRicMeshProperties]: + LFRicCMAOperators, LFRicScalarArgs, LFRicScalarArrayArgs, + LFRicFields, LFRicLMAOperators, LFRicStencils, + LFRicBasisFunctions, LFRicBoundaryConditions, + LFRicReferenceElement, LFRicMeshProperties]: entities(self).stub_declarations() # TODO #2874: The declarations above are not in order, we need to use From 8527d01c453d6432394390abe4d46c2399cfa999 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:26:53 +0000 Subject: [PATCH 027/122] #1312: Alter ScalarArray declaration --- .../domain/lfric/lfric_scalar_array_args.py | 142 ++++++------------ src/psyclone/lfric.py | 2 +- 2 files changed, 50 insertions(+), 94 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index f7d9799ce8..bed0d9b3e6 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -47,10 +47,8 @@ from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES from psyclone.psyir.nodes import Reference, Literal, ArrayReference -from psyclone.psyir.symbols import (DataSymbol, ArgumentInterface, - AutomaticInterface, ArrayType, - ScalarType, UnresolvedType, - INTEGER_TYPE) +from psyclone.psyir.symbols import (DataSymbol, ArrayType, ScalarType, + INTEGER_TYPE, ArgumentInterface) # pylint: disable=too-many-lines # pylint: disable=too-many-locals @@ -99,7 +97,7 @@ def invoke_declarations(self): # Create dictionary of all scalar arguments for checks const = LFRicConstants() self._scalar_array_args = self._invoke.unique_declns_by_intent( - const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES) + const.VALID_ARRAY_NAMES) # Filter scalar arguments by intent and intrinsic type self._real_scalar_arrays = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES, @@ -119,7 +117,7 @@ def invoke_declarations(self): arg in self._integer_scalar_arrays[intent]] lscalarr = [arg.declaration_name for arg in self._logical_scalar_arrays[intent]] - # Add "real", "integer" and "logical" scalar lists for checks + # Add "real", "integer" and "logical" ScalarArray lists for checks decl_scal = rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types scal_inv = sorted(set(scal) - set(decl_scal)) @@ -191,45 +189,28 @@ def _create_declarations(self): for arg in self._real_scalar_arrays[intent]: if arg._array_ndims >= 1: # Create the dimensions array symbol - dims_symbol_list = [] - dims_name = ('dims_' + arg.name) - dims_symbol = self.symtab.find_or_create( - dims_name, + dims_array_symbol = self.symtab.find_or_create( + "dims_" + arg.name, symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_symbol.interface = ArgumentInterface( + datatype=ArrayType(INTEGER_TYPE, + [1]*arg._array_ndims)) + dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_symbol) - for idx in range(1, arg._array_ndims + 1): - # Create symbols to add as dimensions - # to ScalarArray - dims_access_name = dims_name + '(' + str(idx) + ')' - # I'm unsure about the need for this. It was added - # to appease the dims_symbol_access but seems - # unneccessary - dims_symbol_access = self.symtab.find_or_create( - dims_access_name, - symbol_type=DataSymbol, - datatype=ScalarType( - ScalarType.Intrinsic.INTEGER, 4)) - dims_symbol_access.interface = AutomaticInterface() - dims_symbol_list.append(dims_symbol_access) + self.symtab.append_argument(dims_array_symbol) + + dim_symbol = [ArrayReference.create(dims_array_symbol, + [Literal(str(idx),INTEGER_TYPE) + for idx in range(1,arg._array_ndims+1)])] - # Add the ScalarArray - scalar_array_symbol = self.symtab.find_or_create( + array_symbol = self.symtab.find_or_create( arg.name, symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicRealScalarDataType")(), - [Reference(sym) for sym in dims_symbol_list])) - scalar_array_symbol.interface = ArgumentInterface( + dim_symbol)) + array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) - self.symtab.append_argument(scalar_array_symbol) - else: - # Possibly throw exception for wrong dimensions - continue + self.symtab.append_argument(array_symbol) # Integer ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: @@ -237,37 +218,27 @@ def _create_declarations(self): for arg in self._integer_scalar_arrays[intent]: if arg._array_ndims >= 1: dims_array_symbol = self.symtab.find_or_create( - arg.declaration_name, + "dims_" + arg.name, symbol_type=DataSymbol, datatype=ArrayType(INTEGER_TYPE, - [arg._array_ndims])) - - dim = [ArrayReference.create(dims_array_symbol, - [Literal(str(idx),INTEGER_TYPE) for idx in range(1,arg._array_ndims+1)])] - # Add the ScalarArray - # data_type = ArrayType(LFRicTypes("LFRicIntegerScalarDataType")(), - # dims=[ArrayReference.create(dims_symbol, [Literal(idx,ArrayType)]) - # for idx in range(1,arg._array_ndims)]) + [1]*arg._array_ndims)) + dims_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_array_symbol) - # scalar_array_symbol = self.symtab.find_or_create( - # arg.name, - # symbol_type=DataSymbol, - # datatype=data_type) - # scalar_array_symbol.interface = ArgumentInterface( - # INTENT_MAPPING[intent]) - # self.symtab.append_argument(scalar_array_symbol) + dim_symbol = [ArrayReference.create(dims_array_symbol, + [Literal(str(idx),INTEGER_TYPE) + for idx in range(1,arg._array_ndims+1)])] - # Create the dimensions array symbol - # dims_name = ('dims_' + arg.name) - # dims_symbol = self.symtab.find_or_create( - # dims_name, - # symbol_type=DataSymbol, - # datatype=ArrayType( - # LFRicTypes("LFRicIntegerScalarDataType")(), - # [arg._array_ndims])) - # dims_symbol.interface = ArgumentInterface( - # INTENT_MAPPING[intent]) - # self.symtab.append_argument(dims_symbol) + array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + dim_symbol)) + array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(array_symbol) # Logical ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: @@ -275,43 +246,28 @@ def _create_declarations(self): for arg in self._logical_scalar_arrays[intent]: if arg._array_ndims >= 1: # Create the dimensions array symbol - dims_symbol_list = [] - dims_name = ('dims_' + arg.name) - dims_symbol = self.symtab.find_or_create( - dims_name, + dims_array_symbol = self.symtab.find_or_create( + "dims_" + arg.name, symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_symbol.interface = ArgumentInterface( + datatype=ArrayType(INTEGER_TYPE, + [1]*arg._array_ndims)) + dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_symbol) - for idx in range(1, arg._array_ndims + 1): - # Create symbols to add as dimensions - # to ScalarArray - dims_access_name = dims_name + '(' + str(idx) + ')' - # I'm unsure about the need for this. It was added - # to appease the dims_symbol_access but seems - # unneccessary - dims_symbol_access = self.symtab.find_or_create( - dims_access_name, - symbol_type=DataSymbol, - datatype=ScalarType( - ScalarType.Intrinsic.INTEGER, 4)) - dims_symbol_access.interface = AutomaticInterface() - dims_symbol_list.append(dims_symbol_access) + self.symtab.append_argument(dims_array_symbol) - # Add the ScalarArray - scalar_array_symbol = self.symtab.find_or_create( + dim_symbol = [ArrayReference.create(dims_array_symbol, + [Literal(str(idx),INTEGER_TYPE) + for idx in range(1,arg._array_ndims+1)])] + + array_symbol = self.symtab.find_or_create( arg.name, symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicLogicalScalarDataType")(), - [Reference(sym) for sym in dims_symbol_list])) - scalar_array_symbol.interface = ArgumentInterface( + dim_symbol)) + array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) - self.symtab.append_argument(scalar_array_symbol) - + self.symtab.append_argument(array_symbol) # ---------- Documentation utils -------------------------------------------- # # The list of module members that we wish AutoAPI to generate diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 1d93653813..9c2632aa02 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -5900,7 +5900,7 @@ def _init_data_type_properties(self, arg_info, check=True): alg_datatype = None # TODO: Check this is correct after is_scalar is fixed - if self.is_scalar: + if self.is_scalar or self.is_scalar_array: self._init_scalar_properties(alg_datatype, alg_precision, check) elif self.is_field: From 39f96fbe29cd10c8a270bb9d33780ffc88d497e5 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:52:40 +0000 Subject: [PATCH 028/122] #1312: Lint fix --- .../domain/lfric/lfric_scalar_array_args.py | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index bed0d9b3e6..c06026dbe2 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -40,14 +40,14 @@ ''' # Imports -from collections import OrderedDict, Counter +from collections import Counter from psyclone.psyir.frontend.fparser2 import INTENT_MAPPING from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES -from psyclone.psyir.nodes import Reference, Literal, ArrayReference -from psyclone.psyir.symbols import (DataSymbol, ArrayType, ScalarType, +from psyclone.psyir.nodes import Literal, ArrayReference +from psyclone.psyir.symbols import (DataSymbol, ArrayType, INTEGER_TYPE, ArgumentInterface) # pylint: disable=too-many-lines @@ -110,7 +110,8 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: - scal = [arg.declaration_name for arg in self._scalar_array_args[intent]] + scal = [arg.declaration_name + for arg in self._scalar_array_args[intent]] rscalarr = [arg.declaration_name for arg in self._real_scalar_arrays[intent]] iscalarr = [arg.declaration_name for @@ -192,15 +193,18 @@ def _create_declarations(self): dims_array_symbol = self.symtab.find_or_create( "dims_" + arg.name, symbol_type=DataSymbol, - datatype=ArrayType(INTEGER_TYPE, + datatype=ArrayType( + INTEGER_TYPE, [1]*arg._array_ndims)) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - dim_symbol = [ArrayReference.create(dims_array_symbol, - [Literal(str(idx),INTEGER_TYPE) - for idx in range(1,arg._array_ndims+1)])] + dim_symbol = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE) + for idx in + range(1, arg._array_ndims+1)])] array_symbol = self.symtab.find_or_create( arg.name, @@ -220,15 +224,18 @@ def _create_declarations(self): dims_array_symbol = self.symtab.find_or_create( "dims_" + arg.name, symbol_type=DataSymbol, - datatype=ArrayType(INTEGER_TYPE, + datatype=ArrayType( + INTEGER_TYPE, [1]*arg._array_ndims)) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - dim_symbol = [ArrayReference.create(dims_array_symbol, - [Literal(str(idx),INTEGER_TYPE) - for idx in range(1,arg._array_ndims+1)])] + dim_symbol = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE) + for idx in + range(1, arg._array_ndims+1)])] array_symbol = self.symtab.find_or_create( arg.name, @@ -249,15 +256,18 @@ def _create_declarations(self): dims_array_symbol = self.symtab.find_or_create( "dims_" + arg.name, symbol_type=DataSymbol, - datatype=ArrayType(INTEGER_TYPE, + datatype=ArrayType( + INTEGER_TYPE, [1]*arg._array_ndims)) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - dim_symbol = [ArrayReference.create(dims_array_symbol, - [Literal(str(idx),INTEGER_TYPE) - for idx in range(1,arg._array_ndims+1)])] + dim_symbol = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE) + for idx in + range(1, arg._array_ndims+1)])] array_symbol = self.symtab.find_or_create( arg.name, @@ -269,6 +279,7 @@ def _create_declarations(self): INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) + # ---------- Documentation utils -------------------------------------------- # # The list of module members that we wish AutoAPI to generate # documentation for. From 3360be3a4b6d9575d566141e795a5466f3225adb Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:13:10 +0000 Subject: [PATCH 029/122] #1312: Lint fix --- src/psyclone/domain/lfric/lfric_kern.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_kern.py b/src/psyclone/domain/lfric/lfric_kern.py index 9f6cb6e177..1b48f0b9bd 100644 --- a/src/psyclone/domain/lfric/lfric_kern.py +++ b/src/psyclone/domain/lfric/lfric_kern.py @@ -783,10 +783,11 @@ def gen_stub(self) -> Container: LFRicLMAOperators, LFRicMeshProperties, LFRicBasisFunctions, LFRicReferenceElement) for entities in [LFRicCellIterators, LFRicDofmaps, LFRicFunctionSpaces, - LFRicCMAOperators, LFRicScalarArgs, LFRicScalarArrayArgs, - LFRicFields, LFRicLMAOperators, LFRicStencils, - LFRicBasisFunctions, LFRicBoundaryConditions, - LFRicReferenceElement, LFRicMeshProperties]: + LFRicCMAOperators, LFRicScalarArgs, + LFRicScalarArrayArgs, LFRicFields, LFRicLMAOperators, + LFRicStencils, LFRicBasisFunctions, + LFRicBoundaryConditions, LFRicReferenceElement, + LFRicMeshProperties]: entities(self).stub_declarations() # TODO #2874: The declarations above are not in order, we need to use From 02a42b2a298f0a1fc85e43b321ad1d13249e205b Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:31:34 +0000 Subject: [PATCH 030/122] #1312: Remove ScalarArrays from is_scalar --- src/psyclone/domain/lfric/arg_ordering.py | 42 +++++++++---------- .../domain/lfric/kern_call_arg_list.py | 39 +++++++++++++++++ .../domain/lfric/lfric_scalar_args.py | 5 ++- .../domain/lfric/lfric_scalar_array_args.py | 2 +- src/psyclone/lfric.py | 11 +++-- src/psyclone/tests/lfric_test.py | 2 +- 6 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 8a6dd92e89..e35f7c6493 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -776,28 +776,26 @@ def scalar(self, scalar_arg, var_accesses=None): f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES} " f"but got '{scalar_arg.argument_type}'") - if scalar_arg.is_scalar_array: - pass - # If it's a ScalarArray append the dimensions array - # from psyclone.domain.lfric import LFRicTypes - # const = LFRicConstants() - # text = ('dims_' + scalar_arg.name) - - # dims_sym = self._symtab.find_or_create( - # text, tag=text, symbol_type=DataSymbol, - # datatype=ArrayType( - # LFRicTypes("LFRicIntegerScalarDataType")(), - # [scalar_arg._array_ndims])) - # print(dims_sym) - # print(dims_sym.name) - # arr_type = LFRicTypes("LFRicIntegerScalarDataType")() - # self.append_array_reference(array_name=dims_sym.name, - # indices=[":"], - # intrinsic_type=arr_type, - # tag=dims_sym.name, - # symbol=dims_sym) - # self.append(dims_sym, var_accesses, mode=AccessType.READ) - else: + # If it's a ScalarArray append the dimensions array + # from psyclone.domain.lfric import LFRicTypes + # const = LFRicConstants() + # text = ('dims_' + scalar_arg.name) + + # dims_sym = self._symtab.find_or_create( + # text, tag=text, symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicIntegerScalarDataType")(), + # [scalar_arg._array_ndims])) + # print(dims_sym) + # print(dims_sym.name) + # arr_type = LFRicTypes("LFRicIntegerScalarDataType")() + # self.append_array_reference(array_name=dims_sym.name, + # indices=[":"], + # intrinsic_type=arr_type, + # tag=dims_sym.name, + # symbol=dims_sym) + # self.append(dims_sym, var_accesses, mode=AccessType.READ) + if not scalar_arg.is_scalar_array: if scalar_arg.is_literal: # If we have a literal, do not add it to the variable access # information. We do this by providing None as var access. diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 81ea67acd0..83d9db1fcb 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -255,6 +255,45 @@ def scalar(self, scalar_arg, sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) + # if scalar_arg.is_scalar_array: + # # Create the dimensions array symbol + # # dims_symbol_list = [] + # dims_name = ('dims_' + scalar_arg.name) + # dims_symbol = self.symtab.find_or_create( + # dims_name, + # symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicIntegerScalarDataType")(), + # [scalar_arg._array_ndims])) + # dims_symbol.interface = ArgumentInterface( + # INTENT_MAPPING[intent]) + # self.symtab.append_argument(dims_symbol) + + # arr_symbol = self.symtab.find_or_create( + # scalar_arg.name, + # symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicIntegerScalarDataType")(), + # [scalar_arg._array_ndims])) + # arr_symbol.interface = ArgumentInterface( + # INTENT_MAPPING[intent]) + # self.symtab.append_argument(arr_symbol) + + # for idx in range(1, scalar_arg._array_ndims + 1): + # # Create symbols to add as dimensions + # # to ScalarArray + # dims_access_name = dims_name + '(' + str(idx) + ')' + # # I'm unsure about the need for this. It was added + # # to appease the dims_symbol_access but seems + # # unneccessary + # dims_symbol_access = self.symtab.find_or_create( + # dims_access_name, + # symbol_type=DataSymbol, + # datatype=ScalarType( + # ScalarType.Intrinsic.INTEGER, 4)) + # dims_symbol_access.interface = AutomaticInterface() + # dims_symbol_list.append(dims_symbol_access) + # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 0038b7c9ea..40a11602d1 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -111,7 +111,8 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: - scal = [arg.declaration_name for arg in self._scalar_args[intent]] + scal = [arg.declaration_name for + arg in self._scalar_args[intent]] rscal = [arg.declaration_name for arg in self._real_scalars[intent]] iscal = [arg.declaration_name for @@ -154,7 +155,7 @@ def stub_declarations(self): super().stub_declarations() # Extract all scalar arguments for arg in self.kernel_calls[0].arguments.args: - if arg.is_scalar and not arg.is_scalar_array: + if arg.is_scalar: self._scalar_args[arg.intent].append(arg) const = LFRicConstants() diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index c06026dbe2..933e8a784b 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -195,7 +195,7 @@ def _create_declarations(self): symbol_type=DataSymbol, datatype=ArrayType( INTEGER_TYPE, - [1]*arg._array_ndims)) + [arg._array_ndims])) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 9c2632aa02..65c0a2916b 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -1484,7 +1484,7 @@ def initialise(self, cursor: int) -> int: init_cursor = cursor for arg in self._invoke.psy_unique_vars: # We don't have proxies for scalars - if arg.is_scalar: + if arg.is_scalar or arg.is_scalar_array: continue const = LFRicConstants() @@ -1938,7 +1938,7 @@ def __init__(self, invoke, unique_psy_vars): # kernels in this invoke. self._first_var = None for var in unique_psy_vars: - if not var.is_scalar: + if not (var.is_scalar or var.is_scalar_array): self._first_var = var break @@ -6157,8 +6157,7 @@ def is_scalar(self): :rtype: bool ''' const = LFRicConstants() - return self._argument_type in (const.VALID_SCALAR_NAMES + - const.VALID_ARRAY_NAMES) + return self._argument_type in const.VALID_SCALAR_NAMES @property def is_scalar_array(self): @@ -6281,7 +6280,7 @@ def psyir_expression(self): # TODO: this needs altering to consider ScalarArrays # Currently, this is adding a ScalarArray as a normal # scalar variable - if self.is_scalar or self.is_scalar_array: + if self.is_scalar and not self.is_scalar_array: try: scalar_sym = symbol_table.lookup(self.name) except KeyError: @@ -6536,7 +6535,7 @@ def _find_or_create_type(mod_name: str, symbol_type=ContainerSymbol) )) - if self.is_scalar: + if self.is_scalar or self.is_scalar_array: # Find or create the DataType for the appropriate scalar type. if self.intrinsic_type == "real": prim_type = ScalarType.Intrinsic.REAL diff --git a/src/psyclone/tests/lfric_test.py b/src/psyclone/tests/lfric_test.py index 3f6224c860..0577c7ff11 100644 --- a/src/psyclone/tests/lfric_test.py +++ b/src/psyclone/tests/lfric_test.py @@ -1709,7 +1709,7 @@ class for a ScalarArray. api=TEST_API) psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) scalar_argument = psy.invokes.invoke_list[0].schedule.args[0] - assert scalar_argument.is_scalar + assert not scalar_argument.is_scalar assert scalar_argument.is_scalar_array From 6cf25bc8317a28ac42e7e4e9bb9cc9d98a4598a7 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:31:16 +0000 Subject: [PATCH 031/122] #1312: Fix is_scalar statement in lfric_loop --- src/psyclone/domain/lfric/lfric_loop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_loop.py b/src/psyclone/domain/lfric/lfric_loop.py index 0676302a36..cc2525e650 100644 --- a/src/psyclone/domain/lfric/lfric_loop.py +++ b/src/psyclone/domain/lfric/lfric_loop.py @@ -714,7 +714,7 @@ def _halo_read_access(self, arg): ''' const = LFRicConstants() - if arg.is_scalar or arg.is_operator: + if arg.is_scalar or arg.is_operator or arg.is_scalar_array: # Scalars and operators do not have halos return False if arg.is_field: From 75692cc5e692bd33b7aad48eeef0ddacd70574fe Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:47:54 +0000 Subject: [PATCH 032/122] #1312: reintroduce ScalarArray if statement in arg_ordering --- src/psyclone/domain/lfric/arg_ordering.py | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index e2a6472454..45e60e8401 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -776,17 +776,21 @@ def scalar(self, scalar_arg, var_accesses=None): f"{const.VALID_SCALAR_NAMES} but got " f"'{scalar_arg.argument_type}'") - if scalar_arg.is_literal: - # If we have a literal, do not add it to the variable access - # information. We do this by providing None as var access. - self.append(scalar_arg.name, None, mode=scalar_arg.access, - metadata_posn=scalar_arg.metadata_index) - if scalar_arg.precision and var_accesses is not None: - var_accesses.add_access(Signature(scalar_arg.precision), - AccessType.CONSTANT, self._kern) + if scalar_arg.is_scalar: + if scalar_arg.is_literal: + # If we have a literal, do not add it to the variable access + # information. We do this by providing None as var access. + self.append(scalar_arg.name, None, mode=scalar_arg.access, + metadata_posn=scalar_arg.metadata_index) + if scalar_arg.precision and var_accesses is not None: + var_accesses.add_access(Signature(scalar_arg.precision), + AccessType.CONSTANT, self._kern) + else: + self.append(scalar_arg.name, var_accesses, mode=scalar_arg.access, + metadata_posn=scalar_arg.metadata_index) else: - self.append(scalar_arg.name, var_accesses, mode=scalar_arg.access, - metadata_posn=scalar_arg.metadata_index) + # It is a ScalarArray + pass def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and From 6edd5f3f43abb8e18c1df2bcedecddf2281d941c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:58:49 +0000 Subject: [PATCH 033/122] #1312: add super scalar call to kern_stub_arg_list --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index f2c2a43a61..974d2e9f10 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -148,6 +148,7 @@ def scalar(self, scalar_arg, var_accesses=None): :raises InternalError: if the argument is not a recognised scalar type. ''' + super().scalar(scalar_arg, var_accesses) def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the From 12b4a74fbc9b1adb3d3f0c9838084d306276c883 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 10 Nov 2025 12:05:49 +0000 Subject: [PATCH 034/122] #1312: lint fix --- src/psyclone/domain/lfric/arg_ordering.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index 45e60e8401..a7a1713ced 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -786,7 +786,8 @@ def scalar(self, scalar_arg, var_accesses=None): var_accesses.add_access(Signature(scalar_arg.precision), AccessType.CONSTANT, self._kern) else: - self.append(scalar_arg.name, var_accesses, mode=scalar_arg.access, + self.append(scalar_arg.name, var_accesses, + mode=scalar_arg.access, metadata_posn=scalar_arg.metadata_index) else: # It is a ScalarArray From c45548223c4bc166389c8a57acee07ec4e844eb1 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:19:41 +0000 Subject: [PATCH 035/122] #1312: fix arg_ordering to include ScalarArrays in assertion --- src/psyclone/domain/lfric/arg_ordering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index a7a1713ced..dd2af966c3 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -773,8 +773,8 @@ def scalar(self, scalar_arg, var_accesses=None): if not (scalar_arg.is_scalar or scalar_arg.is_scalar_array): raise InternalError( f"Expected argument type to be one of " - f"{const.VALID_SCALAR_NAMES} but got " - f"'{scalar_arg.argument_type}'") + f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES}" + f" but got '{scalar_arg.argument_type}'") if scalar_arg.is_scalar: if scalar_arg.is_literal: From 184a624552e7413d9f7bd42d0b594a6dde1662bd Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:25:51 +0000 Subject: [PATCH 036/122] #1312: Fix lfric_test to check ScalarArray rather than field --- src/psyclone/tests/lfric_test.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/lfric_test.py b/src/psyclone/tests/lfric_test.py index 0577c7ff11..62e20d6ae7 100644 --- a/src/psyclone/tests/lfric_test.py +++ b/src/psyclone/tests/lfric_test.py @@ -1708,7 +1708,15 @@ class for a ScalarArray. "28.scalar_array_invoke.f90"), api=TEST_API) psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) - scalar_argument = psy.invokes.invoke_list[0].schedule.args[0] + scalar_argument = psy.invokes.invoke_list[0].schedule.args[1] + assert not scalar_argument.is_scalar + assert scalar_argument.is_scalar_array + + scalar_argument = psy.invokes.invoke_list[0].schedule.args[2] + assert not scalar_argument.is_scalar + assert scalar_argument.is_scalar_array + + scalar_argument = psy.invokes.invoke_list[0].schedule.args[3] assert not scalar_argument.is_scalar assert scalar_argument.is_scalar_array From 20ecf84b9b8c407cb5b57579528215a905bcd02f Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 10 Nov 2025 14:10:21 +0000 Subject: [PATCH 037/122] #1312: change INTEGER_TYPE to LFRic equivalent --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 933e8a784b..05430cd32c 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -31,7 +31,7 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- -# Authors A. Pirrie, Met Office +# Author A. Pirrie, Met Office ''' This module contains the LFRicScalarArrayArgs class which handles the @@ -194,8 +194,8 @@ def _create_declarations(self): "dims_" + arg.name, symbol_type=DataSymbol, datatype=ArrayType( - INTEGER_TYPE, - [arg._array_ndims])) + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims]*arg._array_ndims)) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) @@ -225,7 +225,7 @@ def _create_declarations(self): "dims_" + arg.name, symbol_type=DataSymbol, datatype=ArrayType( - INTEGER_TYPE, + LFRicTypes("LFRicIntegerScalarDataType")(), [1]*arg._array_ndims)) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) @@ -257,7 +257,7 @@ def _create_declarations(self): "dims_" + arg.name, symbol_type=DataSymbol, datatype=ArrayType( - INTEGER_TYPE, + LFRicTypes("LFRicIntegerScalarDataType")(), [1]*arg._array_ndims)) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) From 35bc15a66850f734da13bb26accc967d5c8e4842 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:32:47 +0000 Subject: [PATCH 038/122] #1312: add dims_array dimensions to ScalarArray declarations --- .../domain/lfric/lfric_scalar_array_args.py | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 05430cd32c..2dc1adddd8 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -195,23 +195,24 @@ def _create_declarations(self): symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims]*arg._array_ndims)) + [arg._array_ndims])) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - dim_symbol = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE) - for idx in - range(1, arg._array_ndims+1)])] + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, arg._array_ndims + 1)] + # Create ScalarArray reference array_symbol = self.symtab.find_or_create( - arg.name, + arg.name + "temp", symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicRealScalarDataType")(), - dim_symbol)) + sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -221,28 +222,30 @@ def _create_declarations(self): if self._integer_scalar_arrays[intent]: for arg in self._integer_scalar_arrays[intent]: if arg._array_ndims >= 1: + # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( "dims_" + arg.name, symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), - [1]*arg._array_ndims)) + [arg._array_ndims])) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - dim_symbol = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE) - for idx in - range(1, arg._array_ndims+1)])] + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, arg._array_ndims + 1)] + # Create ScalarArray reference array_symbol = self.symtab.find_or_create( - arg.name, + arg.name + "temp", symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), - dim_symbol)) + sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -258,23 +261,24 @@ def _create_declarations(self): symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), - [1]*arg._array_ndims)) + [arg._array_ndims])) dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - dim_symbol = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE) - for idx in - range(1, arg._array_ndims+1)])] + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, arg._array_ndims + 1)] + # Create ScalarArray reference array_symbol = self.symtab.find_or_create( - arg.name, + arg.name + "temp", symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicLogicalScalarDataType")(), - dim_symbol)) + sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) From 3a6ddc6c472a6c6e32b8908cb36829761d54dd99 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 12 Nov 2025 10:13:31 +0000 Subject: [PATCH 039/122] #1312: change find_or_create to lookup to fix code generation --- .../domain/lfric/lfric_scalar_array_args.py | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 2dc1adddd8..0b770f298b 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -118,6 +118,7 @@ def invoke_declarations(self): arg in self._integer_scalar_arrays[intent]] lscalarr = [arg.declaration_name for arg in self._logical_scalar_arrays[intent]] + print(scal) # Add "real", "integer" and "logical" ScalarArray lists for checks decl_scal = rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types @@ -153,6 +154,7 @@ def stub_declarations(self): ''' super().stub_declarations() # Extract all scalar arguments + print(self.kernel_calls[0].arguments.args) for arg in self.kernel_calls[0].arguments.args: if arg.is_scalar_array: self._scalar_array_args[arg.intent].append(arg) @@ -161,6 +163,7 @@ def stub_declarations(self): # Filter scalar arguments by intent and data type for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_array_args[intent]: + print(arg) # Distinguish whether they are ScalarArrays if arg.descriptor.data_type == "gh_real": self._real_scalar_arrays[intent].append(arg) @@ -175,6 +178,11 @@ def stub_declarations(self): f"ScalarArray argument '{arg.declaration_name}'" f". Supported types are " f"{const.VALID_SCALAR_DATA_TYPES}.") + print(self._real_scalar_arrays[intent]) + print(self._integer_scalar_arrays[intent]) + print(self._logical_scalar_arrays[intent]) + + print(self._scalar_array_args) # Create declarations self._create_declarations() @@ -184,10 +192,24 @@ def _create_declarations(self): Add declarations for the scalar arguments. ''' + # print("symtab - ") + # print(self.symtab) + # print("symtab.tags_dict - ") + # print(self.symtab.tags_dict) # Real ScalarArray arguments + + + # It seems that the symbols are not being added in the stub + # declaration phase in the same way as they are in the invoke + # declaration. LFRicCollections seems to initialise differently + # for these two - could be to do with it. + + for intent in FORTRAN_INTENT_NAMES: if self._real_scalar_arrays[intent]: for arg in self._real_scalar_arrays[intent]: + print(self.symtab) + print(self.symtab.tags_dict) if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -199,28 +221,29 @@ def _create_declarations(self): dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - + print(dims_array_symbol) # Create list of dims_array references sym_list = [ArrayReference.create( dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - - # Create ScalarArray reference - array_symbol = self.symtab.find_or_create( - arg.name + "temp", - symbol_type=DataSymbol, - datatype=ArrayType( + print(sym_list) + # Find ScalarArray tag and convert it to an ArrayType + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( LFRicTypes("LFRicRealScalarDataType")(), - sym_list)) + sym_list) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) + print(array_symbol) # Integer ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: if self._integer_scalar_arrays[intent]: for arg in self._integer_scalar_arrays[intent]: + print(self.symtab) if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -232,28 +255,29 @@ def _create_declarations(self): dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - + print(dims_array_symbol) # Create list of dims_array references sym_list = [ArrayReference.create( dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - - # Create ScalarArray reference - array_symbol = self.symtab.find_or_create( - arg.name + "temp", - symbol_type=DataSymbol, - datatype=ArrayType( + print(sym_list) + # Find ScalarArray tag and convert it to an ArrayType + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), - sym_list)) + sym_list) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) + print(array_symbol) # Logical ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: if self._logical_scalar_arrays[intent]: for arg in self._logical_scalar_arrays[intent]: + print(self.symtab) if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -272,16 +296,16 @@ def _create_declarations(self): [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - # Create ScalarArray reference - array_symbol = self.symtab.find_or_create( - arg.name + "temp", - symbol_type=DataSymbol, - datatype=ArrayType( + # Find ScalarArray tag and convert it to an ArrayType + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( LFRicTypes("LFRicLogicalScalarDataType")(), - sym_list)) + sym_list) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) + print(array_symbol) # ---------- Documentation utils -------------------------------------------- # From e92ca5069ddbdcc81089690bc46440eca78b6305 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:39:53 +0000 Subject: [PATCH 040/122] #1312: lint fix --- src/psyclone/domain/lfric/arg_ordering.py | 32 ++++---- .../domain/lfric/kern_call_arg_list.py | 77 ++++++++----------- 2 files changed, 47 insertions(+), 62 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index dd2af966c3..ea34ee0906 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -776,22 +776,22 @@ def scalar(self, scalar_arg, var_accesses=None): f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES}" f" but got '{scalar_arg.argument_type}'") - if scalar_arg.is_scalar: - if scalar_arg.is_literal: - # If we have a literal, do not add it to the variable access - # information. We do this by providing None as var access. - self.append(scalar_arg.name, None, mode=scalar_arg.access, - metadata_posn=scalar_arg.metadata_index) - if scalar_arg.precision and var_accesses is not None: - var_accesses.add_access(Signature(scalar_arg.precision), - AccessType.CONSTANT, self._kern) - else: - self.append(scalar_arg.name, var_accesses, - mode=scalar_arg.access, - metadata_posn=scalar_arg.metadata_index) - else: - # It is a ScalarArray - pass + # if scalar_arg.is_scalar: + # if scalar_arg.is_literal: + # # If we have a literal, do not add it to the variable access + # # information. We do this by providing None as var access. + # self.append(scalar_arg.name, None, mode=scalar_arg.access, + # metadata_posn=scalar_arg.metadata_index) + # if scalar_arg.precision and var_accesses is not None: + # var_accesses.add_access(Signature(scalar_arg.precision), + # AccessType.CONSTANT, self._kern) + # else: + # self.append(scalar_arg.name, var_accesses, + # mode=scalar_arg.access, + # metadata_posn=scalar_arg.metadata_index) + # else: + # # It is a ScalarArray + # pass def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 83d9db1fcb..7dc1c4ce76 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -52,11 +52,11 @@ from psyclone.domain.lfric.lfric_types import LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyir.nodes import ( - ArrayReference, Reference, StructureReference) + ArrayReference, Reference, StructureReference, Literal) from psyclone.psyir.symbols import ( DataSymbol, DataTypeSymbol, UnresolvedType, ContainerSymbol, ImportInterface, ScalarType, ArrayType, UnsupportedFortranType, - ArgumentInterface) + ArgumentInterface, INTEGER_TYPE) # psyir has classes created at runtime # pylint: disable=no-member @@ -249,51 +249,36 @@ def scalar(self, scalar_arg, ''' super().scalar(scalar_arg, var_accesses) - if scalar_arg.is_literal: - self.psyir_append(scalar_arg.psyir_expression()) + if scalar_arg.is_scalar: + if scalar_arg.is_literal: + self.psyir_append(scalar_arg.psyir_expression()) + else: + sym = self._symtab.lookup(scalar_arg.name) + self.psyir_append(Reference(sym)) else: - sym = self._symtab.lookup(scalar_arg.name) - self.psyir_append(Reference(sym)) - - # if scalar_arg.is_scalar_array: - # # Create the dimensions array symbol - # # dims_symbol_list = [] - # dims_name = ('dims_' + scalar_arg.name) - # dims_symbol = self.symtab.find_or_create( - # dims_name, - # symbol_type=DataSymbol, - # datatype=ArrayType( - # LFRicTypes("LFRicIntegerScalarDataType")(), - # [scalar_arg._array_ndims])) - # dims_symbol.interface = ArgumentInterface( - # INTENT_MAPPING[intent]) - # self.symtab.append_argument(dims_symbol) - - # arr_symbol = self.symtab.find_or_create( - # scalar_arg.name, - # symbol_type=DataSymbol, - # datatype=ArrayType( - # LFRicTypes("LFRicIntegerScalarDataType")(), - # [scalar_arg._array_ndims])) - # arr_symbol.interface = ArgumentInterface( - # INTENT_MAPPING[intent]) - # self.symtab.append_argument(arr_symbol) - - # for idx in range(1, scalar_arg._array_ndims + 1): - # # Create symbols to add as dimensions - # # to ScalarArray - # dims_access_name = dims_name + '(' + str(idx) + ')' - # # I'm unsure about the need for this. It was added - # # to appease the dims_symbol_access but seems - # # unneccessary - # dims_symbol_access = self.symtab.find_or_create( - # dims_access_name, - # symbol_type=DataSymbol, - # datatype=ScalarType( - # ScalarType.Intrinsic.INTEGER, 4)) - # dims_symbol_access.interface = AutomaticInterface() - # dims_symbol_list.append(dims_symbol_access) - + # ScalarArray + dims_array_symbol = self._symtab.find_or_create( + "dims_" + scalar_arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [scalar_arg._array_ndims])) + self._symtab.append_argument(dims_array_symbol) + + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, scalar_arg._array_ndims + 1)] + + # Create ScalarArray reference + array_symbol = self._symtab.find_or_create( + scalar_arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + sym_list)) + self._symtab.append_argument(array_symbol) # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): From a21d57ebe1bdd915c24c722e849adc3c7172c102 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:45:55 +0000 Subject: [PATCH 041/122] #1312: lint fix --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 0b770f298b..7415b57ab5 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -181,7 +181,7 @@ def stub_declarations(self): print(self._real_scalar_arrays[intent]) print(self._integer_scalar_arrays[intent]) print(self._logical_scalar_arrays[intent]) - + print(self._scalar_array_args) # Create declarations @@ -198,13 +198,11 @@ def _create_declarations(self): # print(self.symtab.tags_dict) # Real ScalarArray arguments - # It seems that the symbols are not being added in the stub # declaration phase in the same way as they are in the invoke # declaration. LFRicCollections seems to initialise differently # for these two - could be to do with it. - for intent in FORTRAN_INTENT_NAMES: if self._real_scalar_arrays[intent]: for arg in self._real_scalar_arrays[intent]: From 1d6b212963a8cbe52db40b52681f30c3d8ce55ab Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:12:15 +0000 Subject: [PATCH 042/122] #1312: copy ScalarArray creation into the stub list --- .../domain/lfric/kern_stub_arg_list.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 974d2e9f10..88c7d0aef8 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -149,6 +149,36 @@ def scalar(self, scalar_arg, var_accesses=None): ''' super().scalar(scalar_arg, var_accesses) + if scalar_arg.is_scalar: + if scalar_arg.is_literal: + self.psyir_append(scalar_arg.psyir_expression()) + else: + sym = self._symtab.lookup(scalar_arg.name) + self.psyir_append(Reference(sym)) + else: + # ScalarArray + dims_array_symbol = self._symtab.find_or_create( + "dims_" + scalar_arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [scalar_arg._array_ndims])) + self._symtab.append_argument(dims_array_symbol) + + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, scalar_arg._array_ndims + 1)] + + # Create ScalarArray reference + array_symbol = self._symtab.find_or_create( + scalar_arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + sym_list)) + self._symtab.append_argument(array_symbol) def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the From a73d33bd34afb27217110a198a13dc209d51feff Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:22:18 +0000 Subject: [PATCH 043/122] #1312: Remove the temporary KernStubArgList code --- .../domain/lfric/kern_stub_arg_list.py | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 88c7d0aef8..f2c2a43a61 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -148,37 +148,6 @@ def scalar(self, scalar_arg, var_accesses=None): :raises InternalError: if the argument is not a recognised scalar type. ''' - super().scalar(scalar_arg, var_accesses) - if scalar_arg.is_scalar: - if scalar_arg.is_literal: - self.psyir_append(scalar_arg.psyir_expression()) - else: - sym = self._symtab.lookup(scalar_arg.name) - self.psyir_append(Reference(sym)) - else: - # ScalarArray - dims_array_symbol = self._symtab.find_or_create( - "dims_" + scalar_arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [scalar_arg._array_ndims])) - self._symtab.append_argument(dims_array_symbol) - - # Create list of dims_array references - sym_list = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE)]) - for idx in range(1, scalar_arg._array_ndims + 1)] - - # Create ScalarArray reference - array_symbol = self._symtab.find_or_create( - scalar_arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - sym_list)) - self._symtab.append_argument(array_symbol) def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the From 39b7cb9f76a0659136d3c9a14f61982da7cbb6f2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:17:54 +0000 Subject: [PATCH 044/122] #1312: Alter test cases to have 5 args in testkern to avoid error --- .../tests/test_files/lfric/28.scalar_array_invoke.f90 | 8 +++++--- .../tests/test_files/lfric/testkern_scalar_array_mod.f90 | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 index 33cbcbd1c6..f30f70f5ae 100644 --- a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 +++ b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 @@ -42,21 +42,23 @@ program scalar_array_invoke implicit none + type(field_type) :: afield real(r_def), dimension(50, 100) :: real_array logical(l_def), dimension(10) :: logical_array integer(i_def), dimension(2, 5, 10, 8) :: integer_array - type(field_type) :: afield + integer(i_def) :: a_scalar real_array = 666.0_r_def logical_array = .false. integer_array = -1 + a_scalar = 5 write(*,*) "Driver: shape(real_array) = ", shape(real_array) write(*,*) "Driver: shape(logical_array) = ", shape(logical_array) write(*,*) "Driver: shape(integer_array) = ", shape(integer_array) - call invoke( & - testkern_scalar_array_type(afield,real_array,logical_array,integer_array) & + call invoke( & + testkern_scalar_array_type(afield,real_array,logical_array,integer_array,a_scalar) & ) end program scalar_array_invoke diff --git a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 index 86033962ee..c020537dd2 100644 --- a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 +++ b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 @@ -41,11 +41,12 @@ module testkern_scalar_array_mod implicit none type, extends(kernel_type) :: testkern_scalar_array_type - type(arg_type), dimension(4) :: meta_args = & + type(arg_type), dimension(5) :: meta_args = & (/ arg_type(gh_field, gh_real, gh_inc, w1), & arg_type(gh_scalar_array, gh_real, gh_read, 2 ), & arg_type(gh_scalar_array, gh_logical, gh_read, 1 ), & - arg_type(gh_scalar_array, gh_integer, gh_read, 4 ) & + arg_type(gh_scalar_array, gh_integer, gh_read, 4 ), & + arg_type(gh_scalar, gh_integer, gh_read ) & /) integer :: operates_on = cell_column contains @@ -59,7 +60,7 @@ subroutine testkern_scalar_array_code(nlayers, & dims_rarray, real_array, & dims_larray, logical_array, & dims_iarray, integer_array, & - ) + a_scalar) implicit none integer(kind=i_def), intent(in) :: nlayers @@ -70,6 +71,7 @@ subroutine testkern_scalar_array_code(nlayers, & real(kind=r_def), intent(in), dimension(dims_rarray(1),dims_rarray(2)) :: real_array logical(kind=l_def), intent(in), dimension(dims_larray(1)) :: logical_array integer(kind=i_def), intent(in), dimension(dims_iarray(1),dims_iarray(2),dims_iarray(3),dims_iarray(4)) :: integer_array + integer(kind=i_def), intent(in) :: a_scalar end subroutine testkern_scalar_array_code From 9556c2bd094217e13c9ca59faa6917cbe6cf1d31 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:17:24 +0000 Subject: [PATCH 045/122] #1312: Try comment out changes to see if it fixes errors --- .../domain/lfric/kern_call_arg_list.py | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 7dc1c4ce76..3122be6261 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -249,36 +249,36 @@ def scalar(self, scalar_arg, ''' super().scalar(scalar_arg, var_accesses) - if scalar_arg.is_scalar: - if scalar_arg.is_literal: - self.psyir_append(scalar_arg.psyir_expression()) - else: - sym = self._symtab.lookup(scalar_arg.name) - self.psyir_append(Reference(sym)) + # if scalar_arg.is_scalar: + if scalar_arg.is_literal: + self.psyir_append(scalar_arg.psyir_expression()) else: - # ScalarArray - dims_array_symbol = self._symtab.find_or_create( - "dims_" + scalar_arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [scalar_arg._array_ndims])) - self._symtab.append_argument(dims_array_symbol) - - # Create list of dims_array references - sym_list = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE)]) - for idx in range(1, scalar_arg._array_ndims + 1)] - - # Create ScalarArray reference - array_symbol = self._symtab.find_or_create( - scalar_arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - sym_list)) - self._symtab.append_argument(array_symbol) + sym = self._symtab.lookup(scalar_arg.name) + self.psyir_append(Reference(sym)) + # else: + # # ScalarArray + # dims_array_symbol = self._symtab.find_or_create( + # "dims_" + scalar_arg.name, + # symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicIntegerScalarDataType")(), + # [scalar_arg._array_ndims])) + # self._symtab.append_argument(dims_array_symbol) + + # # Create list of dims_array references + # sym_list = [ArrayReference.create( + # dims_array_symbol, + # [Literal(str(idx), INTEGER_TYPE)]) + # for idx in range(1, scalar_arg._array_ndims + 1)] + + # # Create ScalarArray reference + # array_symbol = self._symtab.find_or_create( + # scalar_arg.name, + # symbol_type=DataSymbol, + # datatype=ArrayType( + # LFRicTypes("LFRicRealScalarDataType")(), + # sym_list)) + # self._symtab.append_argument(array_symbol) # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): From 86d3231e4295a76f2c58faa54769b4da9348f011 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:27:51 +0000 Subject: [PATCH 046/122] #1312: lint fix --- src/psyclone/domain/lfric/kern_call_arg_list.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 94b3656272..bd34f1b22f 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -52,11 +52,13 @@ from psyclone.domain.lfric.lfric_types import LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyir.nodes import ( - ArrayReference, Reference, StructureReference, Literal) + # ArrayReference, Reference, StructureReference, Literal) + ArrayReference, Reference, StructureReference) from psyclone.psyir.symbols import ( DataSymbol, DataTypeSymbol, UnresolvedType, ContainerSymbol, ImportInterface, ScalarType, ArrayType, UnsupportedFortranType, - ArgumentInterface, INTEGER_TYPE) + # ArgumentInterface, INTEGER_TYPE) + ArgumentInterface) # psyir has classes created at runtime # pylint: disable=no-member From 03c600a83b262b2c4a7a84615e486a8b21bad11f Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:08:46 +0000 Subject: [PATCH 047/122] #1312: add conditional to differentiate between code gen and stub gen --- .../domain/lfric/lfric_scalar_array_args.py | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 7415b57ab5..a2ce429316 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -227,11 +227,21 @@ def _create_declarations(self): for idx in range(1, arg._array_ndims + 1)] print(sym_list) # Find ScalarArray tag and convert it to an ArrayType - array_symbol = self.symtab.lookup_with_tag( - "AlgArgs_" + arg.name) - array_symbol.datatype = ArrayType( + if not self._kernel: + # For code generation + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( LFRicTypes("LFRicRealScalarDataType")(), sym_list) + else: + # For stub generation + array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + [arg._array_ndims])) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -261,11 +271,21 @@ def _create_declarations(self): for idx in range(1, arg._array_ndims + 1)] print(sym_list) # Find ScalarArray tag and convert it to an ArrayType - array_symbol = self.symtab.lookup_with_tag( - "AlgArgs_" + arg.name) - array_symbol.datatype = ArrayType( + if not self._kernel: + # For code generation + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), sym_list) + else: + # For stub generation + array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -295,11 +315,21 @@ def _create_declarations(self): for idx in range(1, arg._array_ndims + 1)] # Find ScalarArray tag and convert it to an ArrayType - array_symbol = self.symtab.lookup_with_tag( - "AlgArgs_" + arg.name) - array_symbol.datatype = ArrayType( + if not self._kernel: + # For code generation + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( LFRicTypes("LFRicLogicalScalarDataType")(), sym_list) + else: + # For stub generation + array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicLogicalScalarDataType")(), + [arg._array_ndims])) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) From b8c358f00488b65898325017d35e5273950d7410 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:06:01 +0000 Subject: [PATCH 048/122] #1312: Add partial stub generation code --- .../domain/lfric/kern_call_arg_list.py | 66 +++++++++---------- .../domain/lfric/kern_stub_arg_list.py | 7 ++ 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index bd34f1b22f..271c94dd6e 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -52,13 +52,13 @@ from psyclone.domain.lfric.lfric_types import LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyir.nodes import ( - # ArrayReference, Reference, StructureReference, Literal) - ArrayReference, Reference, StructureReference) + ArrayReference, Reference, StructureReference, Literal) + # ArrayReference, Reference, StructureReference) from psyclone.psyir.symbols import ( DataSymbol, DataTypeSymbol, UnresolvedType, ContainerSymbol, ImportInterface, ScalarType, ArrayType, UnsupportedFortranType, - # ArgumentInterface, INTEGER_TYPE) - ArgumentInterface) + ArgumentInterface, INTEGER_TYPE) + # ArgumentInterface) # psyir has classes created at runtime # pylint: disable=no-member @@ -251,36 +251,36 @@ def scalar(self, scalar_arg, ''' super().scalar(scalar_arg, var_accesses) - # if scalar_arg.is_scalar: - if scalar_arg.is_literal: - self.psyir_append(scalar_arg.psyir_expression()) + if scalar_arg.is_scalar: + if scalar_arg.is_literal: + self.psyir_append(scalar_arg.psyir_expression()) + else: + sym = self._symtab.lookup(scalar_arg.name) + self.psyir_append(Reference(sym)) else: - sym = self._symtab.lookup(scalar_arg.name) - self.psyir_append(Reference(sym)) - # else: - # # ScalarArray - # dims_array_symbol = self._symtab.find_or_create( - # "dims_" + scalar_arg.name, - # symbol_type=DataSymbol, - # datatype=ArrayType( - # LFRicTypes("LFRicIntegerScalarDataType")(), - # [scalar_arg._array_ndims])) - # self._symtab.append_argument(dims_array_symbol) - - # # Create list of dims_array references - # sym_list = [ArrayReference.create( - # dims_array_symbol, - # [Literal(str(idx), INTEGER_TYPE)]) - # for idx in range(1, scalar_arg._array_ndims + 1)] - - # # Create ScalarArray reference - # array_symbol = self._symtab.find_or_create( - # scalar_arg.name, - # symbol_type=DataSymbol, - # datatype=ArrayType( - # LFRicTypes("LFRicRealScalarDataType")(), - # sym_list)) - # self._symtab.append_argument(array_symbol) + # ScalarArray + dims_array_symbol = self._symtab.find_or_create( + "dims_" + scalar_arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [scalar_arg._array_ndims])) + self._symtab.append_argument(dims_array_symbol) + + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, scalar_arg._array_ndims + 1)] + + # Create ScalarArray reference + array_symbol = self._symtab.find_or_create( + scalar_arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + sym_list)) + self._symtab.append_argument(array_symbol) # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index f2c2a43a61..c35bfd7eb0 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -148,6 +148,13 @@ def scalar(self, scalar_arg, var_accesses=None): :raises InternalError: if the argument is not a recognised scalar type. ''' + if scalar_arg.is_scalar: + self.append(scalar_arg.name, var_accesses) + else: + # ScalarArray + self.append(scalar_arg.name, var_accesses) + self.append("dims_"+scalar_arg.name, var_accesses) + def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the From 221699393ff2e534e312548dde5955916e988d5e Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:07:55 +0000 Subject: [PATCH 049/122] #1312: lint fix --- src/psyclone/domain/lfric/kern_call_arg_list.py | 2 -- src/psyclone/domain/lfric/kern_stub_arg_list.py | 1 - 2 files changed, 3 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 271c94dd6e..d7ebff7d54 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -53,12 +53,10 @@ from psyclone.errors import GenerationError, InternalError from psyclone.psyir.nodes import ( ArrayReference, Reference, StructureReference, Literal) - # ArrayReference, Reference, StructureReference) from psyclone.psyir.symbols import ( DataSymbol, DataTypeSymbol, UnresolvedType, ContainerSymbol, ImportInterface, ScalarType, ArrayType, UnsupportedFortranType, ArgumentInterface, INTEGER_TYPE) - # ArgumentInterface) # psyir has classes created at runtime # pylint: disable=no-member diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index c35bfd7eb0..33074d9704 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -155,7 +155,6 @@ def scalar(self, scalar_arg, var_accesses=None): self.append(scalar_arg.name, var_accesses) self.append("dims_"+scalar_arg.name, var_accesses) - def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the argument list. If supplied it also stores these accesses to the From 0d6874b873ca37752536a57d26bd9325687d43e4 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:21:23 +0000 Subject: [PATCH 050/122] #1312: lint fix --- .../domain/lfric/lfric_scalar_array_args.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index a2ce429316..e7b8625049 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -237,11 +237,11 @@ def _create_declarations(self): else: # For stub generation array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - [arg._array_ndims])) + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicRealScalarDataType")(), + [arg._array_ndims])) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -281,11 +281,11 @@ def _create_declarations(self): else: # For stub generation array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -325,11 +325,11 @@ def _create_declarations(self): else: # For stub generation array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicLogicalScalarDataType")(), - [arg._array_ndims])) + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicLogicalScalarDataType")(), + [arg._array_ndims])) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) From 06fbf557c1823e87f93d955af25111c8da38efc1 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:46:01 +0000 Subject: [PATCH 051/122] #1312: reinstate standard scalar behaviour in ArgOrdering --- src/psyclone/domain/lfric/arg_ordering.py | 28 ++++++++++------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index ea34ee0906..a01679af79 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -776,22 +776,18 @@ def scalar(self, scalar_arg, var_accesses=None): f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES}" f" but got '{scalar_arg.argument_type}'") - # if scalar_arg.is_scalar: - # if scalar_arg.is_literal: - # # If we have a literal, do not add it to the variable access - # # information. We do this by providing None as var access. - # self.append(scalar_arg.name, None, mode=scalar_arg.access, - # metadata_posn=scalar_arg.metadata_index) - # if scalar_arg.precision and var_accesses is not None: - # var_accesses.add_access(Signature(scalar_arg.precision), - # AccessType.CONSTANT, self._kern) - # else: - # self.append(scalar_arg.name, var_accesses, - # mode=scalar_arg.access, - # metadata_posn=scalar_arg.metadata_index) - # else: - # # It is a ScalarArray - # pass + if scalar_arg.is_literal: + # If we have a literal, do not add it to the variable access + # information. We do this by providing None as var access. + self.append(scalar_arg.name, None, mode=scalar_arg.access, + metadata_posn=scalar_arg.metadata_index) + if scalar_arg.precision and var_accesses is not None: + var_accesses.add_access(Signature(scalar_arg.precision), + AccessType.CONSTANT, self._kern) + else: + self.append(scalar_arg.name, var_accesses, + mode=scalar_arg.access, + metadata_posn=scalar_arg.metadata_index) def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and From aa7e39be2ca06a64b83fed6a7ba7c72e8b77fb98 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:13:07 +0000 Subject: [PATCH 052/122] #1312: Fix the dimensions pf the ScalarArray stub gen --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 3 ++- .../domain/lfric/lfric_scalar_array_args.py | 14 ++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 33074d9704..86252c8f0b 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -152,8 +152,9 @@ def scalar(self, scalar_arg, var_accesses=None): self.append(scalar_arg.name, var_accesses) else: # ScalarArray + super().scalar(scalar_arg, var_accesses) + self.append("dims_" + scalar_arg.name, var_accesses) self.append(scalar_arg.name, var_accesses) - self.append("dims_"+scalar_arg.name, var_accesses) def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index e7b8625049..fe76859c27 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -154,7 +154,7 @@ def stub_declarations(self): ''' super().stub_declarations() # Extract all scalar arguments - print(self.kernel_calls[0].arguments.args) + # print(self.kernel_calls[0].arguments.args) for arg in self.kernel_calls[0].arguments.args: if arg.is_scalar_array: self._scalar_array_args[arg.intent].append(arg) @@ -241,7 +241,7 @@ def _create_declarations(self): symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicRealScalarDataType")(), - [arg._array_ndims])) + sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) @@ -251,7 +251,6 @@ def _create_declarations(self): for intent in FORTRAN_INTENT_NAMES: if self._integer_scalar_arrays[intent]: for arg in self._integer_scalar_arrays[intent]: - print(self.symtab) if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -263,13 +262,11 @@ def _create_declarations(self): dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - print(dims_array_symbol) # Create list of dims_array references sym_list = [ArrayReference.create( dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - print(sym_list) # Find ScalarArray tag and convert it to an ArrayType if not self._kernel: # For code generation @@ -285,17 +282,15 @@ def _create_declarations(self): symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) + sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) - print(array_symbol) # Logical ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: if self._logical_scalar_arrays[intent]: for arg in self._logical_scalar_arrays[intent]: - print(self.symtab) if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -329,11 +324,10 @@ def _create_declarations(self): symbol_type=DataSymbol, datatype=ArrayType( LFRicTypes("LFRicLogicalScalarDataType")(), - [arg._array_ndims])) + sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) - print(array_symbol) # ---------- Documentation utils -------------------------------------------- # From 0dcd904949d0a764de707e17ff2759f2597a0015 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:58:15 +0000 Subject: [PATCH 053/122] #1312: add correct stub gen test --- .../domain/lfric/lfric_scalar_stubgen_test.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 3f3133946c..5137723534 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -155,17 +155,19 @@ def test_stub_generate_with_scalar_array(): public contains - subroutine testkern_scalar_array_code(nlayers, field_1_w1, \ -rscalar_array_2, lscalar_array_3, iscalar_array_4, ndf_w1, \ -undf_w1, map_w1) + subroutine testkern_scalar_array_code(nlayers, field_1_w1, dims_rscalar_array_2, rscalar_array_2, lscalar_array_3, dims_lscalar_array_3, iscalar_array_4, dims_iscalar_array_4, iscalar_5, ndf_w1, undf_w1, map_w1) use constants_mod integer(kind=i_def), intent(in) :: nlayers integer(kind=i_def), intent(in) :: ndf_w1 integer(kind=i_def), dimension(ndf_w1), intent(in) :: map_w1 integer(kind=i_def), intent(in) :: undf_w1 - real(kind=r_def), intent(in) :: rscalar_array_2 - integer(kind=i_def), intent(in) :: iscalar_array_4 - logical(kind=l_def), intent(in) :: lscalar_array_3 + integer(kind=i_def), intent(in) :: iscalar_5 + integer(kind=i_def), dimension(2), intent(in) :: dims_rscalar_array_2 + real(kind=r_def), dimension(dims_rscalar_array_2(1),dims_rscalar_array_2(2)), intent(in) :: rscalar_array_2 + integer(kind=i_def), dimension(4), intent(in) :: dims_iscalar_array_4 + integer(kind=i_def), dimension(dims_iscalar_array_4(1),dims_iscalar_array_4(2),dims_iscalar_array_4(3),dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 + integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 + logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: lscalar_array_3 real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 From 13bcee01f6f4dba569b924092684eda1fb781efa Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:40:53 +0000 Subject: [PATCH 054/122] #1312: Fix the stub gen to have the correct number of ScalarArray inputs --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 1 - src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 86252c8f0b..fa0d7c3625 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -152,7 +152,6 @@ def scalar(self, scalar_arg, var_accesses=None): self.append(scalar_arg.name, var_accesses) else: # ScalarArray - super().scalar(scalar_arg, var_accesses) self.append("dims_" + scalar_arg.name, var_accesses) self.append(scalar_arg.name, var_accesses) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 5137723534..d69d85f1c2 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -155,7 +155,7 @@ def test_stub_generate_with_scalar_array(): public contains - subroutine testkern_scalar_array_code(nlayers, field_1_w1, dims_rscalar_array_2, rscalar_array_2, lscalar_array_3, dims_lscalar_array_3, iscalar_array_4, dims_iscalar_array_4, iscalar_5, ndf_w1, undf_w1, map_w1) + subroutine testkern_scalar_array_code(nlayers, field_1_w1, dims_rscalar_array_2, rscalar_array_2, dims_lscalar_array_3, lscalar_array_3, dims_iscalar_array_4, iscalar_array_4, iscalar_5, ndf_w1, undf_w1, map_w1) use constants_mod integer(kind=i_def), intent(in) :: nlayers integer(kind=i_def), intent(in) :: ndf_w1 From 0cc24636bcb6e82c87e652fe9e44d15247e7ff94 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:59:14 +0000 Subject: [PATCH 055/122] #1312: lint fix --- .../tests/domain/lfric/lfric_scalar_stubgen_test.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index d69d85f1c2..f137020325 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -155,7 +155,10 @@ def test_stub_generate_with_scalar_array(): public contains - subroutine testkern_scalar_array_code(nlayers, field_1_w1, dims_rscalar_array_2, rscalar_array_2, dims_lscalar_array_3, lscalar_array_3, dims_iscalar_array_4, iscalar_array_4, iscalar_5, ndf_w1, undf_w1, map_w1) + subroutine testkern_scalar_array_code(nlayers, field_1_w1, \ + dims_rscalar_array_2, rscalar_array_2, dims_lscalar_array_3, \ + lscalar_array_3, dims_iscalar_array_4, iscalar_array_4, \ + iscalar_5, ndf_w1, undf_w1, map_w1) use constants_mod integer(kind=i_def), intent(in) :: nlayers integer(kind=i_def), intent(in) :: ndf_w1 @@ -163,9 +166,11 @@ def test_stub_generate_with_scalar_array(): integer(kind=i_def), intent(in) :: undf_w1 integer(kind=i_def), intent(in) :: iscalar_5 integer(kind=i_def), dimension(2), intent(in) :: dims_rscalar_array_2 - real(kind=r_def), dimension(dims_rscalar_array_2(1),dims_rscalar_array_2(2)), intent(in) :: rscalar_array_2 + real(kind=r_def), dimension(dims_rscalar_array_2(1),dims_rscalar_array_2(2))\ + , intent(in) :: rscalar_array_2 integer(kind=i_def), dimension(4), intent(in) :: dims_iscalar_array_4 - integer(kind=i_def), dimension(dims_iscalar_array_4(1),dims_iscalar_array_4(2),dims_iscalar_array_4(3),dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 + integer(kind=i_def), dimension(dims_iscalar_array_4(1),dims_iscalar_array_4(2),\ + dims_iscalar_array_4(3),dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: lscalar_array_3 real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 From 531e18181cd9c9d7ec30fb299a02f6f17849a2ad Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 21 Nov 2025 16:04:04 +0000 Subject: [PATCH 056/122] #1312: Fix test in test to pass lint --- .../tests/domain/lfric/lfric_scalar_stubgen_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index f137020325..ac86a221f8 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -156,9 +156,9 @@ def test_stub_generate_with_scalar_array(): contains subroutine testkern_scalar_array_code(nlayers, field_1_w1, \ - dims_rscalar_array_2, rscalar_array_2, dims_lscalar_array_3, \ - lscalar_array_3, dims_iscalar_array_4, iscalar_array_4, \ - iscalar_5, ndf_w1, undf_w1, map_w1) +dims_rscalar_array_2, rscalar_array_2, dims_lscalar_array_3, \ +lscalar_array_3, dims_iscalar_array_4, iscalar_array_4, \ +iscalar_5, ndf_w1, undf_w1, map_w1) use constants_mod integer(kind=i_def), intent(in) :: nlayers integer(kind=i_def), intent(in) :: ndf_w1 @@ -166,11 +166,11 @@ def test_stub_generate_with_scalar_array(): integer(kind=i_def), intent(in) :: undf_w1 integer(kind=i_def), intent(in) :: iscalar_5 integer(kind=i_def), dimension(2), intent(in) :: dims_rscalar_array_2 - real(kind=r_def), dimension(dims_rscalar_array_2(1),dims_rscalar_array_2(2))\ - , intent(in) :: rscalar_array_2 + real(kind=r_def), dimension(dims_rscalar_array_2(1),dims_rscalar_array_2(2)), \ +intent(in) :: rscalar_array_2 integer(kind=i_def), dimension(4), intent(in) :: dims_iscalar_array_4 integer(kind=i_def), dimension(dims_iscalar_array_4(1),dims_iscalar_array_4(2),\ - dims_iscalar_array_4(3),dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 +dims_iscalar_array_4(3),dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: lscalar_array_3 real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 From 40aaf0e3881c468473298f5ae8e792ec997c4276 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:53:30 +0000 Subject: [PATCH 057/122] #1312: remove code in KernCallArgList to fix the call in code generation --- .../domain/lfric/kern_call_arg_list.py | 33 +++---------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index d7ebff7d54..01ad4191c4 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -249,36 +249,11 @@ def scalar(self, scalar_arg, ''' super().scalar(scalar_arg, var_accesses) - if scalar_arg.is_scalar: - if scalar_arg.is_literal: - self.psyir_append(scalar_arg.psyir_expression()) - else: - sym = self._symtab.lookup(scalar_arg.name) - self.psyir_append(Reference(sym)) + if scalar_arg.is_literal: + self.psyir_append(scalar_arg.psyir_expression()) else: - # ScalarArray - dims_array_symbol = self._symtab.find_or_create( - "dims_" + scalar_arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [scalar_arg._array_ndims])) - self._symtab.append_argument(dims_array_symbol) - - # Create list of dims_array references - sym_list = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE)]) - for idx in range(1, scalar_arg._array_ndims + 1)] - - # Create ScalarArray reference - array_symbol = self._symtab.find_or_create( - scalar_arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - sym_list)) - self._symtab.append_argument(array_symbol) + sym = self._symtab.lookup(scalar_arg.name) + self.psyir_append(Reference(sym)) # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): From 18be0dfb8528220ab120bcb0343411ece4d5678f Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 10:04:37 +0000 Subject: [PATCH 058/122] #1312: fix lint --- .../domain/lfric/kern_call_arg_list.py | 4 +- .../domain/lfric/lfric_scalar_codegen_test.py | 77 ++++++++++++++++++- .../domain/lfric/lfric_scalar_stubgen_test.py | 12 +-- 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 01ad4191c4..4abf2e03cf 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -52,11 +52,11 @@ from psyclone.domain.lfric.lfric_types import LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyir.nodes import ( - ArrayReference, Reference, StructureReference, Literal) + ArrayReference, Reference, StructureReference) from psyclone.psyir.symbols import ( DataSymbol, DataTypeSymbol, UnresolvedType, ContainerSymbol, ImportInterface, ScalarType, ArrayType, UnsupportedFortranType, - ArgumentInterface, INTEGER_TYPE) + ArgumentInterface) # psyir has classes created at runtime # pylint: disable=no-member diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 0a08762a01..79d6d6b0ba 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -616,9 +616,78 @@ def test_scalar_array(tmpdir): psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) generated_code = str(psy.gen) - expected = "test to fail\n" - - print("Generated code - ") - print(generated_code) + expected = ( + "module scalar_array_invoke_psy\n" + " use constants_mod\n" + " use field_mod, only : field_proxy_type, field_type\n" + " implicit none\n" + " public\n" + "\n" + " contains\n" + " subroutine invoke_0_testkern_scalar_array_type(afield, " + "real_array, logical_array, integer_array, a_scalar, " + "dims_real_array, dims_integer_array, dims_logical_array)\n" + " use mesh_mod, only : mesh_type\n" + " use testkern_scalar_array_mod, only : " + "testkern_scalar_array_code\n" + " type(field_type), intent(in) :: afield\n" + " real(kind=r_def), dimension(dims_real_array(1)," + "dims_real_array(2)), intent(in) :: real_array\n" + " logical(kind=l_def), dimension(dims_logical_array(1)), " + "intent(in) :: logical_array\n" + " integer(kind=i_def), dimension(dims_integer_array(1)," + "dims_integer_array(2),dims_integer_array(3),dims_integer_array(4)), " + "intent(in) :: integer_array\n" + " integer(kind=i_def), intent(in) :: a_scalar\n" + " integer(kind=i_def), dimension(2), intent(in) :: " + "dims_real_array\n" + " integer(kind=i_def), dimension(4), intent(in) :: " + "dims_integer_array\n" + " integer(kind=i_def), dimension(1), intent(in) :: " + "dims_logical_array\n" + " integer(kind=i_def) :: cell\n" + " type(mesh_type), pointer :: mesh => null()\n" + " integer(kind=i_def) :: max_halo_depth_mesh\n" + " real(kind=r_def), pointer, dimension(:) :: afield_data => " + "null()\n" + " integer(kind=i_def) :: nlayers_afield\n" + " integer(kind=i_def) :: ndf_w1\n" + " integer(kind=i_def) :: undf_w1\n" + " integer(kind=i_def), pointer :: map_w1(:,:) => null()\n" + " type(field_proxy_type) :: afield_proxy\n" + " integer(kind=i_def) :: loop0_start\n" + " integer(kind=i_def) :: loop0_stop\n" + "\n" + " ! Initialise field and/or operator proxies\n" + " afield_proxy = afield%get_proxy()\n" + " afield_data => afield_proxy%data\n" + "\n" + " ! Initialise number of layers\n" + " nlayers_afield = afield_proxy%vspace%get_nlayers()\n" + "\n" + " ! Create a mesh object\n" + " mesh => afield_proxy%vspace%get_mesh()\n" + " max_halo_depth_mesh = mesh%get_halo_depth()\n" + "\n" + " ! Look-up dofmaps for each function space\n" + " map_w1 => afield_proxy%vspace%get_whole_dofmap()\n" + "\n" + " ! Initialise number of DoFs for w1\n" + " ndf_w1 = afield_proxy%vspace%get_ndf()\n" + " undf_w1 = afield_proxy%vspace%get_undf()\n" + "\n" + " ! Set-up all of the loop bounds\n" + " loop0_start = 1\n" + " loop0_stop = mesh%get_last_halo_cell(1)\n" + "\n" + " ! Call kernels and communication routines\n" + " if (afield_proxy%is_dirty(depth=1)) then\n" + " call afield_proxy%halo_exchange(depth=1)\n" + " end if\n" + " do cell = loop0_start, loop0_stop, 1\n" + " call testkern_scalar_array_code(nlayers_afield, " + "afield_data, real_array, logical_array, integer_array, a_scalar, " + "ndf_w1, undf_w1, map_w1(:,cell))\n" + ) assert expected in generated_code assert LFRicBuild(tmpdir).code_compiles(psy) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index ac86a221f8..b7bb519cce 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -166,13 +166,15 @@ def test_stub_generate_with_scalar_array(): integer(kind=i_def), intent(in) :: undf_w1 integer(kind=i_def), intent(in) :: iscalar_5 integer(kind=i_def), dimension(2), intent(in) :: dims_rscalar_array_2 - real(kind=r_def), dimension(dims_rscalar_array_2(1),dims_rscalar_array_2(2)), \ -intent(in) :: rscalar_array_2 + real(kind=r_def), dimension(dims_rscalar_array_2(1),\ + dims_rscalar_array_2(2)), intent(in) :: rscalar_array_2 integer(kind=i_def), dimension(4), intent(in) :: dims_iscalar_array_4 - integer(kind=i_def), dimension(dims_iscalar_array_4(1),dims_iscalar_array_4(2),\ -dims_iscalar_array_4(3),dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 + integer(kind=i_def), dimension(dims_iscalar_array_4(1),\ + dims_iscalar_array_4(2),dims_iscalar_array_4(3),\ + dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 - logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: lscalar_array_3 + logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) ::\ + lscalar_array_3 real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 From 388d45eac1c8f3ae73fdafc35f6522a85192e9e0 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 10:06:34 +0000 Subject: [PATCH 059/122] #1312: remove print statement from stub_gen test --- src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index b7bb519cce..89343bd6b4 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -145,10 +145,6 @@ def test_stub_generate_with_scalar_array(): os.path.join(BASE_PATH, "testkern_scalar_array_mod.f90"), api=TEST_API) -# I don't think this is actually correct. It doesn't seem to be adding -# the array dimensions (or arrays to hold that information). In fact -# this looks suspiciously like a plain scalar entry - print(result) expected = """\ module testkern_scalar_array_mod implicit none From f8d1a8a3a553cc02844d08e2b17ebca33cd8462c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:12:40 +0000 Subject: [PATCH 060/122] #1312: lint fix --- src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 79d6d6b0ba..7bde8c6c72 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -636,7 +636,7 @@ def test_scalar_array(tmpdir): " logical(kind=l_def), dimension(dims_logical_array(1)), " "intent(in) :: logical_array\n" " integer(kind=i_def), dimension(dims_integer_array(1)," - "dims_integer_array(2),dims_integer_array(3),dims_integer_array(4)), " + "dims_integer_array(2),dims_integer_array(3),dims_integer_array(4)), " "intent(in) :: integer_array\n" " integer(kind=i_def), intent(in) :: a_scalar\n" " integer(kind=i_def), dimension(2), intent(in) :: " From 502b6184e9bcbd433a24f8430b33333bdb0c022a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:43:08 +0000 Subject: [PATCH 061/122] #1312: tidy LFRicScalarArrayArgs --- .../domain/lfric/lfric_scalar_array_args.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index fe76859c27..f22f1b9c30 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -118,7 +118,6 @@ def invoke_declarations(self): arg in self._integer_scalar_arrays[intent]] lscalarr = [arg.declaration_name for arg in self._logical_scalar_arrays[intent]] - print(scal) # Add "real", "integer" and "logical" ScalarArray lists for checks decl_scal = rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types @@ -154,7 +153,6 @@ def stub_declarations(self): ''' super().stub_declarations() # Extract all scalar arguments - # print(self.kernel_calls[0].arguments.args) for arg in self.kernel_calls[0].arguments.args: if arg.is_scalar_array: self._scalar_array_args[arg.intent].append(arg) @@ -163,7 +161,6 @@ def stub_declarations(self): # Filter scalar arguments by intent and data type for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_array_args[intent]: - print(arg) # Distinguish whether they are ScalarArrays if arg.descriptor.data_type == "gh_real": self._real_scalar_arrays[intent].append(arg) @@ -178,11 +175,6 @@ def stub_declarations(self): f"ScalarArray argument '{arg.declaration_name}'" f". Supported types are " f"{const.VALID_SCALAR_DATA_TYPES}.") - print(self._real_scalar_arrays[intent]) - print(self._integer_scalar_arrays[intent]) - print(self._logical_scalar_arrays[intent]) - - print(self._scalar_array_args) # Create declarations self._create_declarations() @@ -192,22 +184,10 @@ def _create_declarations(self): Add declarations for the scalar arguments. ''' - # print("symtab - ") - # print(self.symtab) - # print("symtab.tags_dict - ") - # print(self.symtab.tags_dict) # Real ScalarArray arguments - - # It seems that the symbols are not being added in the stub - # declaration phase in the same way as they are in the invoke - # declaration. LFRicCollections seems to initialise differently - # for these two - could be to do with it. - for intent in FORTRAN_INTENT_NAMES: if self._real_scalar_arrays[intent]: for arg in self._real_scalar_arrays[intent]: - print(self.symtab) - print(self.symtab.tags_dict) if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -219,13 +199,11 @@ def _create_declarations(self): dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - print(dims_array_symbol) # Create list of dims_array references sym_list = [ArrayReference.create( dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - print(sym_list) # Find ScalarArray tag and convert it to an ArrayType if not self._kernel: # For code generation @@ -245,7 +223,6 @@ def _create_declarations(self): array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(array_symbol) - print(array_symbol) # Integer ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: From da0a8d15af3bd2d87d984915276d2c32349e41ec Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:24:56 +0000 Subject: [PATCH 062/122] #1312: fix indentation in stub gen test --- .../tests/domain/lfric/lfric_scalar_stubgen_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 89343bd6b4..7fb0f6a3b2 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -163,14 +163,14 @@ def test_stub_generate_with_scalar_array(): integer(kind=i_def), intent(in) :: iscalar_5 integer(kind=i_def), dimension(2), intent(in) :: dims_rscalar_array_2 real(kind=r_def), dimension(dims_rscalar_array_2(1),\ - dims_rscalar_array_2(2)), intent(in) :: rscalar_array_2 +dims_rscalar_array_2(2)), intent(in) :: rscalar_array_2 integer(kind=i_def), dimension(4), intent(in) :: dims_iscalar_array_4 integer(kind=i_def), dimension(dims_iscalar_array_4(1),\ - dims_iscalar_array_4(2),dims_iscalar_array_4(3),\ - dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 +dims_iscalar_array_4(2),dims_iscalar_array_4(3),\ +dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 - logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) ::\ - lscalar_array_3 + logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: \ +lscalar_array_3 real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 From 013463c09d3e795816665d55ff1d47ea49fcd97d Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:27:08 +0000 Subject: [PATCH 063/122] #1312: Add error message to KernStubArgList because it no longer has the parent behaviour --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index fa0d7c3625..e610a048c0 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -148,6 +148,13 @@ def scalar(self, scalar_arg, var_accesses=None): :raises InternalError: if the argument is not a recognised scalar type. ''' + const = LFRicConstants() + if not (scalar_arg.is_scalar or scalar_arg.is_scalar_array): + raise InternalError( + f"Expected argument type to be one of " + f"{const.VALID_SCALAR_NAMES + const.VALID_ARRAY_NAMES}" + f" but got '{scalar_arg.argument_type}'") + if scalar_arg.is_scalar: self.append(scalar_arg.name, var_accesses) else: From 8249adec3855ebebb6d5de6f2275688faf8b17d2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:46:13 +0000 Subject: [PATCH 064/122] #1312: Add stub declaration data type exception --- .../domain/lfric/lfric_scalar_stubgen_test.py | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 7fb0f6a3b2..e92d1066a4 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -46,7 +46,8 @@ from fparser import api as fpapi from psyclone.domain.lfric import (LFRicConstants, LFRicKern, - LFRicKernMetadata, LFRicScalarArgs) + LFRicKernMetadata, LFRicScalarArgs, + LFRicScalarArrayArgs) from psyclone.errors import InternalError from psyclone.gen_kernel_stub import generate from psyclone.parse.utils import ParseError @@ -82,6 +83,29 @@ def test_lfricscalars_stub_err(): f"{const.VALID_SCALAR_DATA_TYPES}." in str(err.value)) +def test_lfricscalararray_stub_err(): + ''' Check that LFRicScalarArrayArgs.stub_declarations() raises the + expected internal error if it encounters an unrecognised data + type of a scalar argument when generating a kernel stub. + + ''' + ast = fpapi.parse(os.path.join(BASE_PATH, + "testkern_scalar_array_mod.f90"), + ignore_comments=False) + metadata = LFRicKernMetadata(ast) + kernel = LFRicKern() + kernel.load_meta(metadata) + # Sabotage the scalar argument to make it have an invalid data type + arg = kernel.arguments.args[1] + arg.descriptor._data_type = "gh_invalid_scalar" + with pytest.raises(InternalError) as err: + LFRicScalarArrayArgs(kernel).stub_declarations() + const = LFRicConstants() + assert (f"Found an unsupported data type 'gh_invalid_scalar' for the " + f"ScalarArray argument 'rscalar_array_2'. Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}." in str(err.value)) + + def test_stub_generate_with_scalars(): ''' Check that the stub generate produces the expected output when the kernel has scalar arguments. ''' From 4d503fa58afc532d661ec3be81d97f09c89f2a8c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:09:21 +0000 Subject: [PATCH 065/122] #1312: lint fix --- src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index e92d1066a4..8d11cefb2e 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -90,8 +90,8 @@ def test_lfricscalararray_stub_err(): ''' ast = fpapi.parse(os.path.join(BASE_PATH, - "testkern_scalar_array_mod.f90"), - ignore_comments=False) + "testkern_scalar_array_mod.f90"), + ignore_comments=False) metadata = LFRicKernMetadata(ast) kernel = LFRicKern() kernel.load_meta(metadata) From 42ff5b7fa7797778dba719479cafa3f6b2fa9d06 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:16:50 +0000 Subject: [PATCH 066/122] #1312: Add test for ScalarArray intrinsic type --- .../domain/lfric/lfric_scalar_array_args.py | 5 +++- .../domain/lfric/lfric_scalar_mdata_test.py | 26 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index f22f1b9c30..ff1805f02c 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -121,10 +121,13 @@ def invoke_declarations(self): # Add "real", "integer" and "logical" ScalarArray lists for checks decl_scal = rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types + print(decl_scal) + print(scal) scal_inv = sorted(set(scal) - set(decl_scal)) + print(scal_inv) if scal_inv: raise InternalError( - f"Found unsupported intrinsic types for the scalar " + f"Found unsupported intrinsic types for the ScalarArray " f"arguments {scal_inv} to Invoke '{self._invoke.name}'. " f"Supported types are {const.VALID_INTRINSIC_TYPES}.") # Check that the same scalar name is not found in either of diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py index 1d01b65040..c7b024b3d1 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py @@ -48,7 +48,7 @@ from psyclone.domain.lfric import (LFRicArgDescriptor, LFRicConstants, LFRicKern, LFRicKernMetadata, - LFRicScalarArgs) + LFRicScalarArgs, LFRicScalarArrayArgs) from psyclone.errors import InternalError, GenerationError from psyclone.parse.algorithm import parse from psyclone.parse.utils import ParseError @@ -331,6 +331,30 @@ def test_lfricscalars_call_err1(): in str(err.value)) +def test_lfricscalararray_call_err1(): + ''' Check that the LFRicScalarArrayArgs constructor raises the + expected internal error if it encounters an unrecognised + intrinsic type of ScalarArray when generating a kernel call. + + ''' + _, invoke_info = parse( + os.path.join(BASE_PATH, + "28.scalar_array_invoke.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) + invoke = psy.invokes.invoke_list[0] + kernel = invoke.schedule.coded_kernels()[0] + # Sabotage the scalar argument to make it have an invalid intrinsic type + scalar_arr_arg = kernel.arguments.args[1] + scalar_arr_arg._intrinsic_type = "double-type" + with pytest.raises(InternalError) as err: + LFRicScalarArrayArgs(invoke).invoke_declarations() + assert ("Found unsupported intrinsic types for the ScalarArray arguments " + "['real_array'] to Invoke 'invoke_0_testkern_scalar_array_type'. " + "Supported types are ['real', 'integer', 'logical']." + in str(err.value)) + + def test_lfricscalarargs_mp(): '''Check that the precision of a new scalar integer datatype is declared in the psy-layer. From 662ac2e1d04244ba21638936c2de3f3001850e51 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:23:56 +0000 Subject: [PATCH 067/122] #1312: remove print statements --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index ff1805f02c..7b751f36c5 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -121,10 +121,7 @@ def invoke_declarations(self): # Add "real", "integer" and "logical" ScalarArray lists for checks decl_scal = rscalarr + iscalarr + lscalarr # Check for unsupported intrinsic types - print(decl_scal) - print(scal) scal_inv = sorted(set(scal) - set(decl_scal)) - print(scal_inv) if scal_inv: raise InternalError( f"Found unsupported intrinsic types for the ScalarArray " From bfc3e47ba01f4478891b1e58a402b1da84afa3d6 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:32:22 +0000 Subject: [PATCH 068/122] #1312: Remove the KernCallAccArgList empty if statement to appease Codecov --- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index c761f40fc8..7651bddf5e 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -273,10 +273,7 @@ def scalar(self, scalar_arg, var_accesses=None): ''' # TODO: Add implementation of OpenACC data region for ScalarArrays - if scalar_arg.is_scalar_array: - # Need to add the relevant OpenACC information - pass - # Else the argument is a simple scalar value and doesn't need values + # If the argument is a simple scalar value then doesn't need values # added to OpenACC region From 463fcff8b06e37ba678a38fa949936f82bb53d73 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:04:14 +0000 Subject: [PATCH 069/122] #1312: Test whether an exception is raised when a ScalarArray is called with different types --- .../domain/lfric/lfric_scalar_array_args.py | 2 +- .../domain/lfric/lfric_scalar_mdata_test.py | 20 +++++++ ...ltikernel_invokes_scalar_array_invalid.f90 | 58 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 7b751f36c5..3579ddf4ad 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -135,7 +135,7 @@ def invoke_declarations(self): Counter(decl_scal).items() if count > 1] if scal_multi_type: raise GenerationError( - f"Scalar argument(s) {scal_multi_type} in Invoke " + f"ScalarArray argument(s) {scal_multi_type} in Invoke " f"'{self._invoke.name}' have different metadata for data " f"type ({list(const.MAPPING_DATA_TYPES.keys())}) in " f"different kernels. This is invalid.") diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py index c7b024b3d1..fcb7752ca2 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py @@ -537,3 +537,23 @@ def test_scalar_different_data_types_invoke(): f"'invoke_real_and_integer_scalars' have different metadata for " f"data type ({const.VALID_SCALAR_DATA_TYPES}) in different " f"kernels. This is invalid." in str(excinfo.value)) + + +def test_scalar_array_different_data_types_invoke(): + ''' Tests that the same scalar cannot have different data types + in different kernels within the same Invoke. + + ''' + _, invoke_info = parse( + os.path.join(BASE_PATH, + "28.1_multikernel_invokes_scalar_array_invalid.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) + + const = LFRicConstants() + with pytest.raises(GenerationError) as excinfo: + _ = psy.gen + assert (f"ScalarArray argument(s) ['b'] in Invoke " + f"'invoke_real_and_logical_scalars' have different metadata for " + f"data type ({const.VALID_SCALAR_DATA_TYPES}) in different " + f"kernels. This is invalid." in str(excinfo.value)) diff --git a/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 b/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 new file mode 100644 index 0000000000..aa48948536 --- /dev/null +++ b/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 @@ -0,0 +1,58 @@ +! ----------------------------------------------------------------------------- +! BSD 3-Clause License +! +! Copyright (c) 2025, Science and Technology Facilities Council +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! * Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! * Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! * Neither the name of the copyright holder nor the names of its +! contributors may be used to endorse or promote products derived from +! this software without specific prior written permission. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +! POSSIBILITY OF SUCH DAMAGE. +!------------------------------------------------------------------------------- +! Author A. Pirrie, Met Office + +program multikernel_invokes_scalar_array_invalid + + ! Description: single function specified in an invoke call + use constants_mod, only: i_def, r_def, l_def + use field_mod, only: field_type + use testkern_scalar_array_mod, only: testkern_scalar_array_type + + use unknown_mod, only : b + + implicit none + + type(field_type) :: afield + real(r_def), dimension(50, 100) :: real_array + logical(l_def), dimension(10) :: logical_array + integer(i_def), dimension(2, 5, 10, 8) :: integer_array + integer(i_def) :: a_scalar + + call invoke(name = "real_and_logical_scalars", & + testkern_scalar_array_type(afield,b,logical_array,integer_array,a_scalar), & + testkern_scalar_array_type(afield,real_array,b,integer_array,a_scalar) & + ) + +end program multikernel_invokes_scalar_array_invalid From 9828122e5631f4ba39e1a50bc691730c5c672aee Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:31:01 +0000 Subject: [PATCH 070/122] #1312: remove todo --- src/psyclone/domain/lfric/kernel_interface.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel_interface.py b/src/psyclone/domain/lfric/kernel_interface.py index 08296ebcdd..d98eec3a42 100644 --- a/src/psyclone/domain/lfric/kernel_interface.py +++ b/src/psyclone/domain/lfric/kernel_interface.py @@ -423,7 +423,6 @@ def scalar(self, scalar_arg, var_accesses=None): "real": LFRicTypes("LFRicRealScalarDataSymbol"), "logical": LFRicTypes("LFRicLogicalScalarDataSymbol")} try: - # TODO: add the ScalarArray alternative symbol = self._symtab.find_or_create_tag( scalar_arg.name, symbol_type=mapping[scalar_arg.intrinsic_type], From 05b2725dcd5df8d282139ef3d9bf9d5fccf54c2d Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:42:36 +0000 Subject: [PATCH 071/122] #1312: Tidy LFRicScalarArrayArgs --- .../domain/lfric/lfric_scalar_array_args.py | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 3579ddf4ad..798e24f788 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2017-2025, Science and Technology Facilities Council. +# Copyright (c) 2025, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -57,11 +57,11 @@ class LFRicScalarArrayArgs(LFRicCollection): ''' - Handles the declarations of scalar kernel arguments appearing in either - an Invoke or a Kernel stub. + Handles the declarations of ScalarArray kernel arguments appearing in + either an Invoke or a Kernel stub. - :param node: the Invoke or Kernel stub for which to manage the scalar \ - arguments. + :param node: the Invoke or Kernel stub for which to manage the \ + ScalarArray arguments. :type node: :py:class:`psyclone.domain.lfric.LFRicKern` or \ :py:class:`psyclone.domain.lfric.LFRicInvoke` @@ -70,7 +70,7 @@ def __init__(self, node): super().__init__(node) # Initialise dictionaries of 'real', 'integer' and 'logical' - # scalar arguments by data type and intent + # ScalarArray arguments by data type and intent self._scalar_array_args = {} self._real_scalar_arrays = {} self._integer_scalar_arrays = {} @@ -83,22 +83,22 @@ def __init__(self, node): def invoke_declarations(self): ''' - Create argument lists and declarations for all scalar arguments + Create argument lists and declarations for all ScalarArray arguments in an Invoke. :raises InternalError: for unsupported argument intrinsic types. - :raises GenerationError: if the same scalar argument has different \ - data types in different Kernel calls \ - within the same Invoke. + :raises GenerationError: if the same ScalarArray argument has \ + different data types in different Kernel \ + calls within the same Invoke. ''' super().invoke_declarations() - # Create dictionary of all scalar arguments for checks + # Create dictionary of all ScalarArray arguments for checks const = LFRicConstants() self._scalar_array_args = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES) - # Filter scalar arguments by intent and intrinsic type + # Filter ScalarArray arguments by intent and intrinsic type self._real_scalar_arrays = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES, intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) @@ -127,10 +127,10 @@ def invoke_declarations(self): f"Found unsupported intrinsic types for the ScalarArray " f"arguments {scal_inv} to Invoke '{self._invoke.name}'. " f"Supported types are {const.VALID_INTRINSIC_TYPES}.") - # Check that the same scalar name is not found in either of - # 'real', 'integer' or 'logical' scalar lists (for instance if - # passed to one kernel as a 'real' and to another kernel as an - # 'integer' scalar) + # Check that the same ScalarArray name is not found in either of + # 'real', 'integer' or 'logical' ScalarArray lists (for instance + # if passed to one kernel as a 'real' and to another kernel as an + # 'logical' ScalarArray) scal_multi_type = [item for item, count in Counter(decl_scal).items() if count > 1] if scal_multi_type: @@ -145,20 +145,20 @@ def invoke_declarations(self): def stub_declarations(self): ''' - Create and add declarations for all scalar arguments in + Create and add declarations for all ScalarArray arguments in a Kernel stub. :raises InternalError: for an unsupported argument data type. ''' super().stub_declarations() - # Extract all scalar arguments + # Extract all ScalarArray arguments for arg in self.kernel_calls[0].arguments.args: if arg.is_scalar_array: self._scalar_array_args[arg.intent].append(arg) const = LFRicConstants() - # Filter scalar arguments by intent and data type + # Filter ScalarArray arguments by intent and data type for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_array_args[intent]: # Distinguish whether they are ScalarArrays @@ -181,7 +181,7 @@ def stub_declarations(self): def _create_declarations(self): ''' - Add declarations for the scalar arguments. + Add declarations for the ScalarArray arguments. ''' # Real ScalarArray arguments @@ -204,16 +204,16 @@ def _create_declarations(self): dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - # Find ScalarArray tag and convert it to an ArrayType if not self._kernel: - # For code generation + # For code generation, find ScalarArray tag + # and convert it to an ArrayType array_symbol = self.symtab.lookup_with_tag( "AlgArgs_" + arg.name) array_symbol.datatype = ArrayType( LFRicTypes("LFRicRealScalarDataType")(), sym_list) else: - # For stub generation + # For stub generation, create the symbol array_symbol = self.symtab.find_or_create( arg.name, symbol_type=DataSymbol, @@ -244,16 +244,16 @@ def _create_declarations(self): dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - # Find ScalarArray tag and convert it to an ArrayType if not self._kernel: - # For code generation + # For code generation, find ScalarArray tag + # and convert it to an ArrayType array_symbol = self.symtab.lookup_with_tag( "AlgArgs_" + arg.name) array_symbol.datatype = ArrayType( LFRicTypes("LFRicIntegerScalarDataType")(), sym_list) else: - # For stub generation + # For stub generation, create the symbol array_symbol = self.symtab.find_or_create( arg.name, symbol_type=DataSymbol, @@ -286,16 +286,16 @@ def _create_declarations(self): [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - # Find ScalarArray tag and convert it to an ArrayType if not self._kernel: - # For code generation + # For code generation, find ScalarArray tag + # and convert it to an ArrayType array_symbol = self.symtab.lookup_with_tag( "AlgArgs_" + arg.name) array_symbol.datatype = ArrayType( LFRicTypes("LFRicLogicalScalarDataType")(), sym_list) else: - # For stub generation + # For stub generation, create the symbol array_symbol = self.symtab.find_or_create( arg.name, symbol_type=DataSymbol, From abbed542f6631b4886ce0fbe3ac067f69005afdd Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:32:11 +0000 Subject: [PATCH 072/122] #1312: Add consideration for ScalarArrays in lfric.py --- src/psyclone/lfric.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index b30920f8b2..4c5b4295e3 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -5894,7 +5894,6 @@ def _init_data_type_properties(self, arg_info, check=True): # The collection datatype is not recognised or supported. alg_datatype = None - # TODO: Check this is correct after is_scalar is fixed if self.is_scalar or self.is_scalar_array: self._init_scalar_properties(alg_datatype, alg_precision, check) @@ -5936,7 +5935,6 @@ def _init_scalar_properties( not declared with default precision. ''' - # TODO: Check whether this needs scalars and ScalarArray separated const = LFRicConstants() # Check the type of scalar defined in the metadata is supported. if self.intrinsic_type not in const.VALID_INTRINSIC_TYPES: @@ -6272,10 +6270,7 @@ def psyir_expression(self): f"PSyIR contains one or more References.") return lit - # TODO: this needs altering to consider ScalarArrays - # Currently, this is adding a ScalarArray as a normal - # scalar variable - if self.is_scalar and not self.is_scalar_array: + if self.is_scalar or self.is_scalar_array: try: scalar_sym = symbol_table.lookup(self.name) except KeyError: @@ -6560,7 +6555,10 @@ def _find_or_create_type(mod_name: str, kind_name, INTEGER_TYPE, interface=ImportInterface(constants_container)) symtab.add(kind_symbol) - return ScalarType(prim_type, Reference(kind_symbol)) + dts = ScalarType(prim_type, Reference(kind_symbol)) + if self.is_scalar_array and self._array_ndims > 1: + return ArrayType(dts, [self._array_ndims]) + return dts if self.is_field or self.is_operator: # Find or create the DataTypeSymbol for the appropriate From ec152593376d2d790e343099c3f57168cd459051 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:37:29 +0000 Subject: [PATCH 073/122] #1312: tidy scalar_array_invoke.f90 --- .../tests/test_files/lfric/28.scalar_array_invoke.f90 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 index f30f70f5ae..d01dddb0b1 100644 --- a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 +++ b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 @@ -48,15 +48,6 @@ program scalar_array_invoke integer(i_def), dimension(2, 5, 10, 8) :: integer_array integer(i_def) :: a_scalar - real_array = 666.0_r_def - logical_array = .false. - integer_array = -1 - a_scalar = 5 - - write(*,*) "Driver: shape(real_array) = ", shape(real_array) - write(*,*) "Driver: shape(logical_array) = ", shape(logical_array) - write(*,*) "Driver: shape(integer_array) = ", shape(integer_array) - call invoke( & testkern_scalar_array_type(afield,real_array,logical_array,integer_array,a_scalar) & ) From f78a894e0475c8ce32f1d700e663b9ee29b4e8e2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:41:27 +0000 Subject: [PATCH 074/122] #1312: improve the multikernel_invokes_scalar_array_invalid description --- .../lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 b/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 index aa48948536..c6d05387f0 100644 --- a/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 +++ b/src/psyclone/tests/test_files/lfric/28.1_multikernel_invokes_scalar_array_invalid.f90 @@ -35,7 +35,11 @@ program multikernel_invokes_scalar_array_invalid - ! Description: single function specified in an invoke call + ! Description: two kernel calls with the first kernel using a real + ! ScalarArray and the second kernel usign a logical ScalarArray + ! incorrectly passing a ScalarArray that would need to be both real + ! and logical. This is provided from a module to stop PSyclone's type + ! checking from raising an exception. use constants_mod, only: i_def, r_def, l_def use field_mod, only: field_type use testkern_scalar_array_mod, only: testkern_scalar_array_type From dc1bce977bf9cc4d986b39cf808ed743d49660a9 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:53:08 +0000 Subject: [PATCH 075/122] #1312: Add authorship to relevant files --- src/psyclone/domain/lfric/__init__.py | 2 +- src/psyclone/domain/lfric/arg_ordering.py | 2 +- src/psyclone/domain/lfric/kern_stub_arg_list.py | 2 +- src/psyclone/domain/lfric/lfric_invoke.py | 3 ++- src/psyclone/domain/lfric/lfric_kern.py | 3 ++- src/psyclone/lfric.py | 3 ++- src/psyclone/tests/domain/lfric/arg_ordering_test.py | 2 +- src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py | 2 +- src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py | 3 ++- src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py | 3 ++- src/psyclone/tests/lfric_test.py | 3 ++- 11 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/psyclone/domain/lfric/__init__.py b/src/psyclone/domain/lfric/__init__.py index a713e0516b..b90c55e215 100644 --- a/src/psyclone/domain/lfric/__init__.py +++ b/src/psyclone/domain/lfric/__init__.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author J. Henrichs, Bureau of Meteorology -# Modified: I. Kavcic, L. Turner and O. Brunt, Met Office +# Modified: I. Kavcic, L. Turner, O. Brunt and A. Pirrie, Met Office # R. W. Ford and A. R. Porter, STFC Daresbury Lab '''Module for the LFRic domain. diff --git a/src/psyclone/domain/lfric/arg_ordering.py b/src/psyclone/domain/lfric/arg_ordering.py index a01679af79..b122dcf8b7 100644 --- a/src/psyclone/domain/lfric/arg_ordering.py +++ b/src/psyclone/domain/lfric/arg_ordering.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie and L. Turner, Met Office +# Modified I. Kavcic, A. Coughtrie, L. Turner, and A. Pirrie, Met Office # Modified J. Henrichs, Bureau of Meteorology '''This module implements the base class for managing arguments to diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index e610a048c0..4b7e12c505 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie and L. Turner, Met Office +# Modified I. Kavcic, A. Coughtrie, L. Turner and A. Pirrie, Met Office # Modified J. Henrichs, Bureau of Meteorology '''This module implements a class that creates the argument list diff --git a/src/psyclone/domain/lfric/lfric_invoke.py b/src/psyclone/domain/lfric/lfric_invoke.py index fe2a16ec35..6e3bbf5f68 100644 --- a/src/psyclone/domain/lfric/lfric_invoke.py +++ b/src/psyclone/domain/lfric/lfric_invoke.py @@ -32,7 +32,8 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office +# Modified I. Kavcic, A. Coughtrie, L. Turner, O. Brunt +# and A. Pirrie, Met Office # Modified J. Henrichs, Bureau of Meteorology # Modified A. B. G. Chalk and N. Nobre, STFC Daresbury Lab diff --git a/src/psyclone/domain/lfric/lfric_kern.py b/src/psyclone/domain/lfric/lfric_kern.py index 1b48f0b9bd..3987ac735a 100644 --- a/src/psyclone/domain/lfric/lfric_kern.py +++ b/src/psyclone/domain/lfric/lfric_kern.py @@ -32,7 +32,8 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office +# Modified I. Kavcic, A. Coughtrie, L. Turner, O. Brunt +# and A. Pirrie, Met Office # Modified J. Henrichs, Bureau of Meteorology # Modified A. B. G. Chalk and N. Nobre, STFC Daresbury Lab diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 4c5b4295e3..26b216337c 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -32,7 +32,8 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office +# Modified I. Kavcic, A. Coughtrie, L. Turner, O. Brunt +# and A. Pirrie, Met Office # Modified J. Henrichs, Bureau of Meteorology # Modified A. B. G. Chalk and N. Nobre, STFC Daresbury Lab diff --git a/src/psyclone/tests/domain/lfric/arg_ordering_test.py b/src/psyclone/tests/domain/lfric/arg_ordering_test.py index e2d6de7936..68b8816c31 100644 --- a/src/psyclone/tests/domain/lfric/arg_ordering_test.py +++ b/src/psyclone/tests/domain/lfric/arg_ordering_test.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford and A. R. Porter, STFC Daresbury Lab -# Modified I. Kavcic and L. Turner, Met Office +# Modified I. Kavcic, L. Turner and A. Pirrie, Met Office # Modified J. Henrichs, Bureau of Meteorology ''' This module tests the LFric classes based on ArgOrdering.''' diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 7bde8c6c72..63f63f217e 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab; -# I. Kavcic and A. Coughtrie, Met Office; +# I. Kavcic, A. Coughtrie and A. Pirrie, Met Office; # C. M. Maynard, Met Office/University of Reading; # J. Henrichs, Bureau of Meteorology. diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py index fcb7752ca2..b09a444065 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py @@ -32,7 +32,8 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter, S. Siso and N. Nobre, STFC Daresbury Lab; -# I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office; +# I. Kavcic, A. Coughtrie, L. Turner, O. Brunt +# and A. Pirrie, Met Office; # C. M. Maynard, Met Office/University of Reading; # J. Henrichs, Bureau of Meteorology. diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 8d11cefb2e..7aae252ee5 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -32,7 +32,8 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors: R. W. Ford, A. R. Porter, S. Siso and N. Nobre, STFC Daresbury Lab; -# I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office; +# I. Kavcic, A. Coughtrie, L. Turner, O. Brunt, +# and A. Pirrie, Met Office; # C. M. Maynard, Met Office/University of Reading; # J. Henrichs, Bureau of Meteorology. diff --git a/src/psyclone/tests/lfric_test.py b/src/psyclone/tests/lfric_test.py index 62e20d6ae7..55da700679 100644 --- a/src/psyclone/tests/lfric_test.py +++ b/src/psyclone/tests/lfric_test.py @@ -32,7 +32,8 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab -# Modified I. Kavcic, A. Coughtrie, L. Turner and O. Brunt, Met Office, +# Modified I. Kavcic, A. Coughtrie, L. Turner, O. Brunt, +# and A. Pirrie Met Office, # C. M. Maynard, Met Office/University of Reading, # J. Henrichs, Bureau of Meteorology. From 6b265e26fe5c6c8b5b948c09d028d2867906929d Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:05:15 +0000 Subject: [PATCH 076/122] #1312: Add NotImplementedError to KernCallACCArgList --- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 7651bddf5e..55923946ad 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -275,6 +275,10 @@ def scalar(self, scalar_arg, var_accesses=None): # TODO: Add implementation of OpenACC data region for ScalarArrays # If the argument is a simple scalar value then doesn't need values # added to OpenACC region + if scalar_arg.is_scalar_array: + raise NotImplementedError( + f"OpenACC data regions are not currently supported for arrays" + f" of scalars.") # ============================================================================ From 0d1b97ab94e8de67a46d57e883b5e03a1a2c8257 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:12:09 +0000 Subject: [PATCH 077/122] #1312: Revert requested files --- .../domain/lfric/kern_call_arg_list.py | 177 ++++++++++-------- .../domain/lfric/lfric_scalar_args.py | 8 +- 2 files changed, 107 insertions(+), 78 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 4abf2e03cf..205a6e865c 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -175,25 +175,29 @@ def append_structure_reference(self, module_name, user_type, member_list, overwrite_datatype=overwrite_datatype)) return sym - def cell_position(self, var_accesses: Optional[VariablesAccessMap] = None): + def cell_position(self, var_accesses=None): '''Adds a cell argument to the argument list and if supplied stores this access in var_accesses. - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' cell_ref_name, ref = self.cell_ref_name(var_accesses) self.psyir_append(ref) self.append(cell_ref_name) - def cell_map(self, var_accesses: Optional[VariablesAccessMap] = None): + def cell_map(self, var_accesses=None): '''Add cell-map and related cell counts (for inter-grid kernels) to the argument list. If supplied it also stores these accesses to the var_access object. - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' cargs = psyGen.args_filter(self._kern.args, arg_meshes=["gh_coarse"]) @@ -221,12 +225,13 @@ def cell_map(self, var_accesses: Optional[VariablesAccessMap] = None): sym = self.append_integer_reference(base_name) self.append(sym.name, var_accesses) - def mesh_height(self, var_accesses: Optional[VariablesAccessMap] = None): + def mesh_height(self, var_accesses=None): '''Add mesh height (nlayers) to the argument list and if supplied stores this access in var_accesses. :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. + :type var_accesses: :py:class:`psyclone.core.VariablesAccessMap` ''' if self._kern.iterates_over == "dof": @@ -236,16 +241,17 @@ def mesh_height(self, var_accesses: Optional[VariablesAccessMap] = None): self.append(nlayers_symbol.name, var_accesses) self._nlayers_positions.append(self.num_args) - def scalar(self, scalar_arg, - var_accesses: Optional[VariablesAccessMap] = None): + def scalar(self, scalar_arg, var_accesses=None): ''' Add the necessary argument for a scalar quantity as well as an appropriate Symbol to the SymbolTable. :param scalar_arg: the scalar kernel argument. :type scalar_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance that + :param var_accesses: optional VariablesAccessMap instance that \ stores information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' super().scalar(scalar_arg, var_accesses) @@ -254,6 +260,7 @@ def scalar(self, scalar_arg, else: sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) + # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): @@ -263,40 +270,44 @@ def scalar(self, scalar_arg, # root_name="ncell_3d", context="PSyVars", label="ncell3d") # self.append(ncell3d_name) - def _mesh_ncell2d(self, var_accesses: Optional[VariablesAccessMap] = None): + def _mesh_ncell2d(self, var_accesses=None): '''Add the number of columns in the mesh to the argument list and if supplied stores this access in var_accesses. - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' sym = self.append_integer_reference("ncell_2d") self.append(sym.name, var_accesses) - def _mesh_ncell2d_no_halos( - self, var_accesses: Optional[VariablesAccessMap] = None): + def _mesh_ncell2d_no_halos(self, var_accesses=None): '''Add the number of columns in the mesh (excluding those in the halo) to the argument list and store this access in var_accesses (if supplied). - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' ncell_symbol = self.append_integer_reference("ncell_2d_no_halos") self.append(ncell_symbol.name, var_accesses) - def cma_operator(self, arg, - var_accesses: Optional[VariablesAccessMap] = None): + def cma_operator(self, arg, var_accesses=None): '''Add the CMA operator and associated scalars to the argument list and optionally add them to the variable access information. :param arg: the CMA operator argument. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' components = ["matrix"] @@ -340,8 +351,7 @@ def cma_operator(self, arg, self.append(sym.name, var_accesses, mode=mode, metadata_posn=arg.metadata_index) - def field_vector(self, argvect, - var_accesses: Optional[VariablesAccessMap] = None): + def field_vector(self, argvect, var_accesses=None): '''Add the field vector associated with the argument 'argvect' to the argument list. If supplied it also stores these accesses to the var_access object. @@ -350,6 +360,7 @@ def field_vector(self, argvect, :type argvect: :py:class:`psyclone.lfric.LFRicKernelArgument` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. + :type var_accesses: :py:class:`psyclone.core.VariablesAccessMap` ''' suffix = LFRicConstants().ARG_TYPE_SUFFIX_MAPPING[ @@ -385,7 +396,7 @@ def field_vector(self, argvect, var_accesses.add_access(Signature(argvect.name), argvect.access, self._kern) - def field(self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def field(self, arg, var_accesses=None): '''Add the field array associated with the argument 'arg' to the argument list. If supplied it also stores this access in var_accesses. @@ -393,6 +404,7 @@ def field(self, arg, var_accesses: Optional[VariablesAccessMap] = None): :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. + :type var_accesses: :py:class:`psyclone.core.VariablesAccessMap` ''' const = LFRicConstants() @@ -419,16 +431,17 @@ def field(self, arg, var_accesses: Optional[VariablesAccessMap] = None): mode=arg.access, metadata_posn=arg.metadata_index) self.psyir_append(Reference(sym)) - def stencil_unknown_extent( - self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def stencil_unknown_extent(self, arg, var_accesses=None): '''Add stencil information to the argument list associated with the argument 'arg' if the extent is unknown. If supplied it also stores this access in var_accesses. :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # The extent is not specified in the metadata so pass the value in @@ -442,16 +455,17 @@ def stencil_unknown_extent( self.append(f"{var_sym.name}({cell_name})", var_accesses, var_access_name=var_sym.name) - def stencil_2d_unknown_extent( - self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def stencil_2d_unknown_extent(self, arg, var_accesses=None): '''Add 2D stencil information to the argument list associated with the argument 'arg' if the extent is unknown. If supplied it also stores this access in var_accesses. :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # The extent is not specified in the metadata so pass the value in @@ -465,16 +479,17 @@ def stencil_2d_unknown_extent( name = f"{var_sym.name}(:,{cell_name})" self.append(name, var_accesses, var_access_name=var_sym.name) - def stencil_2d_max_extent( - self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def stencil_2d_max_extent(self, arg, var_accesses=None): '''Add the maximum branch extent for a 2D stencil associated with the argument 'arg' to the argument list. If supplied it also stores this in var_accesses. :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariableAccessMap instance to store the - information about variable accesses. + :param var_accesses: optional SingleVariableAccessInfo instance \ + to store the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.SingleVariableAccessInfo` ''' # The maximum branch extent is not specified in the metadata so pass @@ -490,8 +505,7 @@ def stencil_2d_max_extent( sym = self.append_integer_reference(root_name, tag=unique_tag) self.append(sym.name, var_accesses) - def stencil_unknown_direction( - self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def stencil_unknown_direction(self, arg, var_accesses=None): '''Add stencil information to the argument list associated with the argument 'arg' if the direction is unknown (i.e. it's being supplied in a variable). If supplied it also stores this access in @@ -499,8 +513,10 @@ def stencil_unknown_direction( :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # the direction of the stencil is not known so pass the value in @@ -509,16 +525,18 @@ def stencil_unknown_direction( self.append_integer_reference(name, f"AlgArgs_{tag}") self.append(name, var_accesses) - def stencil(self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def stencil(self, arg, var_accesses=None): '''Add general stencil information associated with the argument 'arg' to the argument list. If supplied it also stores this access in var_accesses. - :param arg: the meta-data description of the kernel + :param arg: the meta-data description of the kernel \ argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # add in stencil dofmap @@ -532,17 +550,18 @@ def stencil(self, arg, var_accesses: Optional[VariablesAccessMap] = None): self.append(f"{var_sym.name}(:,:,{cell_name})", var_accesses, var_access_name=var_sym.name) - def stencil_2d( - self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def stencil_2d(self, arg, var_accesses=None): '''Add general 2D stencil information associated with the argument 'arg' to the argument list. If supplied it also stores this access in var_accesses. - :param arg: the meta-data description of the kernel + :param arg: the meta-data description of the kernel \ argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # The stencil_2D differs from the stencil in that the direction @@ -563,14 +582,16 @@ def stencil_2d( name = f"{var_sym.name}(:,:,:,{cell_name})" self.append(name, var_accesses, var_access_name=var_sym.name) - def operator(self, arg, var_accesses: Optional[VariablesAccessMap] = None): + def operator(self, arg, var_accesses=None): '''Add the operator arguments to the argument list. If supplied it also stores this access in var_accesses. :param arg: the meta-data description of the operator. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # TODO we should only be including ncell_3d once in the argument @@ -598,16 +619,17 @@ def operator(self, arg, var_accesses: Optional[VariablesAccessMap] = None): self.append(sym.name, var_accesses, mode=arg.access, metadata_posn=arg.metadata_index) - def fs_common(self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def fs_common(self, function_space, var_accesses=None): '''Add function-space related arguments common to LMA operators and fields. If supplied it also stores this access in var_accesses. - :param function_space: the function space for which the related + :param function_space: the function space for which the related \ arguments common to LMA operators and fields are added. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. + :type var_accesses: + Optional[:py:class:`psyclone.core.VariablesAccessMap`] ''' if self._kern.iterates_over == "dof": @@ -617,9 +639,7 @@ def fs_common(self, function_space, KernCallArgList.NdfInfo(position=self.num_args, function_space=function_space.orig_name)) - def fs_compulsory_field( - self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def fs_compulsory_field(self, function_space, var_accesses=None): '''Add compulsory arguments associated with this function space to the list. If supplied it also stores this access in var_accesses. @@ -628,6 +648,8 @@ def fs_compulsory_field( :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. + :type var_accesses: + :py:class:`psyclone.core.VariablesAccessMap` ''' if self._kern.iterates_over == "dof": @@ -661,15 +683,16 @@ def fs_compulsory_field( self.append(f"{sym.name}(:,{cell_name})", var_accesses, var_access_name=sym.name) - def fs_intergrid(self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def fs_intergrid(self, function_space, var_accesses=None): '''Add function-space related arguments for an intergrid kernel. If supplied it also stores this access in var_accesses. :param function_space: the function space for which to add arguments :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # Is this FS associated with the coarse or fine mesh? (All fields @@ -690,16 +713,17 @@ def fs_intergrid(self, function_space, self.fs_compulsory_field(function_space, var_accesses=var_accesses) - def basis(self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def basis(self, function_space, var_accesses=None): '''Add basis function information for this function space to the argument list and optionally to the variable access information. - :param function_space: the function space for which the basis + :param function_space: the function space for which the basis \ function is required. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' for rule in self._kern.qr_rules.values(): @@ -722,17 +746,18 @@ def basis(self, function_space, sym = self.append_array_reference(basis_name, [":", ":", ":"]) self.append(sym.name, var_accesses) - def diff_basis(self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def diff_basis(self, function_space, var_accesses=None): '''Add differential basis information for the function space to the argument list. If supplied it also stores this access in var_accesses. - :param function_space: the function space for which the differential + :param function_space: the function space for which the differential \ basis functions are required. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' for rule in self._kern.qr_rules.values(): @@ -761,18 +786,19 @@ def diff_basis(self, function_space, LFRicTypes("LFRicRealScalarDataType")()) self.append(sym.name, var_accesses) - def field_bcs_kernel(self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def field_bcs_kernel(self, function_space, var_accesses=None): '''Implement the boundary_dofs array fix for a field. If supplied it also stores this access in var_accesses. - :param function_space: the function space for which boundary dofs + :param function_space: the function space for which boundary dofs \ are required. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` - :raises GenerationError: if the bcs kernel does not contain + :raises GenerationError: if the bcs kernel does not contain \ a field as argument (but e.g. an operator). ''' @@ -794,16 +820,17 @@ def field_bcs_kernel(self, function_space, sym = self.append_array_reference(base_name, [":", ":"]) self.append(sym.name, var_accesses) - def operator_bcs_kernel(self, function_space, - var_accesses: Optional[VariablesAccessMap] = None): + def operator_bcs_kernel(self, function_space, var_accesses=None): '''Supply necessary additional arguments for the kernel that applies boundary conditions to a LMA operator. If supplied it also stores this access in var_accesses. :param function_space: unused, only for consistency with base class. :type function_space: :py:class:`psyclone.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # This kernel has only a single LMA operator as argument. @@ -813,14 +840,15 @@ def operator_bcs_kernel(self, function_space, sym = self.append_array_reference(base_name, [":", ":"]) self.append(sym.name, var_accesses) - def mesh_properties(self, - var_accesses: Optional[VariablesAccessMap] = None): + def mesh_properties(self, var_accesses=None): '''Provide the kernel arguments required for the mesh properties specified in the kernel metadata. If supplied it also stores this access in var_accesses. - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' if self._kern.mesh.properties: @@ -831,13 +859,15 @@ def mesh_properties(self, kern_args(stub=False, var_accesses=var_accesses, kern_call_arg_list=self)) - def quad_rule(self, var_accesses: Optional[VariablesAccessMap] = None): + def quad_rule(self, var_accesses=None): '''Add quadrature-related information to the kernel argument list. Adds the necessary arguments to the argument list, and optionally adds variable access information to the var_accesses object. - :param var_accesses: optional VariablesAccessMap instance to store + :param var_accesses: optional VariablesAccessMap instance to store \ the information about variable accesses. + :type var_accesses: \ + :py:class:`psyclone.core.VariablesAccessMap` ''' # The QR shapes that this routine supports @@ -990,7 +1020,8 @@ def cell_ref_name( if var_accesses is not None: var_accesses.add_access(Signature(array_ref.name), AccessType.READ, - self._kern) + self._kern, + ["colour", "tile", "cell"]) else: symbol = self._kern.colourmap array_ref = ArrayReference.create( @@ -999,7 +1030,7 @@ def cell_ref_name( if var_accesses is not None: var_accesses.add_access(Signature(array_ref.name), AccessType.READ, - self._kern) + self._kern, ["colour", "cell"]) return (array_ref.debug_string(), array_ref) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 40a11602d1..df500f9282 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -111,8 +111,7 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: - scal = [arg.declaration_name for - arg in self._scalar_args[intent]] + scal = [arg.declaration_name for arg in self._scalar_args[intent]] rscal = [arg.declaration_name for arg in self._real_scalars[intent]] iscal = [arg.declaration_name for @@ -172,9 +171,8 @@ def stub_declarations(self): raise InternalError( f"Found an unsupported data type " f"'{arg.descriptor.data_type}' for the scalar " - f"argument '{arg.declaration_name}'. " - f"Supported types are " - f"{const.VALID_SCALAR_DATA_TYPES}.") + f"argument '{arg.declaration_name}'. Supported types " + f"are {const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() From 01f507c38035a31c7927b8862b8bf35cd98cc141 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:52:22 +0000 Subject: [PATCH 078/122] #1312: Create test to check for NotImplementedError for ScalarArrays in OpenACC --- .../lfric/kern_call_acc_arg_list_test.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py b/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py index 1a02fdc16f..e713bf70bc 100644 --- a/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py +++ b/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py @@ -241,3 +241,28 @@ def test_lfric_field(): assert "f2_data: READ" in var_info assert "m1_data: READ" in var_info assert "m2_data: READ" in var_info + + +def test_lfric_scalar(): + '''Check that the scalar method throws a NotImplementedError for + ScalarArrays. + + ''' + # Use the OpenACC transforms to create the required kernels + acc_par_trans = ACCParallelTrans() + acc_enter_trans = ACCEnterDataTrans() + _, invoke = get_invoke("28.scalar_array_invoke.f90", + "lfric", + idx=0, dist_mem=False) + sched = invoke.schedule + acc_par_trans.apply(sched.children) + acc_enter_trans.apply(sched) + + # Find the first kernel: + kern = invoke.schedule.walk(psyGen.CodedKern)[0] + create_acc_arg_list = KernCallAccArgList(kern) + var_accesses = VariablesAccessMap() + with pytest.raises(NotImplementedError) as excinfo: + create_acc_arg_list.generate(var_accesses=var_accesses) + assert (f"OpenACC data regions are not currently supported for arrays" + f" of scalars.") in str(excinfo) From afaebb66ba04ee45d95a58f60b41e4676c022fbc Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 2 Dec 2025 14:40:51 +0000 Subject: [PATCH 079/122] #1312: miscellaneous style changes --- .../domain/lfric/kern_stub_arg_list.py | 10 ++++----- .../domain/lfric/lfric_scalar_array_args.py | 22 ++++++++----------- src/psyclone/lfric.py | 8 +++---- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 4b7e12c505..63b40d5513 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -44,6 +44,7 @@ from psyclone.core import VariablesAccessMap from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants +from psyclone.lfric import LFRicKernelArgument from psyclone.errors import InternalError @@ -133,17 +134,16 @@ def cma_operator(self, arg, var_accesses=None): _local_args += [bandwidth, alpha, beta, gamma_m, gamma_p] self.extend(_local_args, var_accesses) - def scalar(self, scalar_arg, var_accesses=None): + def scalar(self, + scalar_arg: LFRicKernelArgument, + var_accesses: Optional[VariablesAccessMap] = None): '''Add the name associated with the scalar argument to the argument list and optionally add this scalar to the variable access information. :param scalar_arg: the kernel argument. - :type scalar_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance that \ + :param var_accesses: optional VariablesAccessMap instance that stores information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` :raises InternalError: if the argument is not a recognised scalar type. diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 798e24f788..18dc0476fd 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -41,32 +41,29 @@ # Imports from collections import Counter +from typing import Union from psyclone.psyir.frontend.fparser2 import INTENT_MAPPING -from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes +from psyclone.domain.lfric import (LFRicCollection, LFRicConstants, LFRicTypes, + LFRicKern, LFRicInvoke) from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES from psyclone.psyir.nodes import Literal, ArrayReference from psyclone.psyir.symbols import (DataSymbol, ArrayType, INTEGER_TYPE, ArgumentInterface) -# pylint: disable=too-many-lines -# pylint: disable=too-many-locals # pylint: disable=too-many-branches - class LFRicScalarArrayArgs(LFRicCollection): ''' Handles the declarations of ScalarArray kernel arguments appearing in either an Invoke or a Kernel stub. - :param node: the Invoke or Kernel stub for which to manage the \ - ScalarArray arguments. - :type node: :py:class:`psyclone.domain.lfric.LFRicKern` or \ - :py:class:`psyclone.domain.lfric.LFRicInvoke` + :param node: the Invoke or Kernel stub for which to manage the +- ScalarArray arguments. ''' - def __init__(self, node): + def __init__(self, node: Union[LFRicKern, LFRicInvoke]): super().__init__(node) # Initialise dictionaries of 'real', 'integer' and 'logical' @@ -86,10 +83,9 @@ def invoke_declarations(self): Create argument lists and declarations for all ScalarArray arguments in an Invoke. - :raises InternalError: for unsupported argument intrinsic types. - :raises GenerationError: if the same ScalarArray argument has \ - different data types in different Kernel \ + :raises GenerationError: if the same ScalarArray argument has + different data types in different Kernel calls within the same Invoke. ''' @@ -181,7 +177,7 @@ def stub_declarations(self): def _create_declarations(self): ''' - Add declarations for the ScalarArray arguments. + Create the symbols for the ScalarArray arguments. ''' # Real ScalarArray arguments diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 356454b9f4..9a9171d932 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -1480,7 +1480,7 @@ def initialise(self, cursor: int) -> int: ''' init_cursor = cursor for arg in self._invoke.psy_unique_vars: - # We don't have proxies for scalars + # We don't have proxies for scalars or arrays of scalars. if arg.is_scalar or arg.is_scalar_array: continue @@ -5682,6 +5682,7 @@ def __init__(self, kernel_args, arg_meta_data, arg_info, call, check=True): # any-space function spaces. self._kernel_args = kernel_args self._vector_size = arg_meta_data.vector_size + # The number of dimensions (for a ScalarArray) self._array_ndims = arg_meta_data.array_ndims self._argument_type = arg_meta_data.argument_type self._stencil = None @@ -6155,11 +6156,10 @@ def is_scalar(self): return self._argument_type in const.VALID_SCALAR_NAMES @property - def is_scalar_array(self): + def is_scalar_array(self) -> bool: ''' - :returns: True if this kernel argument represents a \ + :returns: True if this kernel argument represents a ScalarArray, False otherwise. - :rtype: bool ''' const = LFRicConstants() return self._argument_type in const.VALID_ARRAY_NAMES From cd61f83f52c95a4f4833d9b600391cd3312d46e2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 2 Dec 2025 14:52:10 +0000 Subject: [PATCH 080/122] #1312: lint fix --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 1 + .../tests/domain/lfric/kern_call_acc_arg_list_test.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 18dc0476fd..85b53c0687 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -54,6 +54,7 @@ # pylint: disable=too-many-branches + class LFRicScalarArrayArgs(LFRicCollection): ''' Handles the declarations of ScalarArray kernel arguments appearing in diff --git a/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py b/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py index e713bf70bc..906f24793f 100644 --- a/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py +++ b/src/psyclone/tests/domain/lfric/kern_call_acc_arg_list_test.py @@ -246,7 +246,7 @@ def test_lfric_field(): def test_lfric_scalar(): '''Check that the scalar method throws a NotImplementedError for ScalarArrays. - + ''' # Use the OpenACC transforms to create the required kernels acc_par_trans = ACCParallelTrans() @@ -264,5 +264,5 @@ def test_lfric_scalar(): var_accesses = VariablesAccessMap() with pytest.raises(NotImplementedError) as excinfo: create_acc_arg_list.generate(var_accesses=var_accesses) - assert (f"OpenACC data regions are not currently supported for arrays" - f" of scalars.") in str(excinfo) + assert ("OpenACC data regions are not currently supported for arrays" + " of scalars.") in str(excinfo) From eca5ad1c5b1517c4f39fe76471e05738b6a65def Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:01:48 +0000 Subject: [PATCH 081/122] #1312: lint fix --- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 55923946ad..f86c80559c 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -277,8 +277,8 @@ def scalar(self, scalar_arg, var_accesses=None): # added to OpenACC region if scalar_arg.is_scalar_array: raise NotImplementedError( - f"OpenACC data regions are not currently supported for arrays" - f" of scalars.") + "OpenACC data regions are not currently supported for arrays" + " of scalars.") # ============================================================================ From 6269aab3f0bcb6b72e93d2cdde27df43b8e2d961 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 3 Dec 2025 11:09:49 +0000 Subject: [PATCH 082/122] #1312: revert typehints temporarily to try identify error --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 85b53c0687..6b6f5e825c 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -44,8 +44,7 @@ from typing import Union from psyclone.psyir.frontend.fparser2 import INTENT_MAPPING -from psyclone.domain.lfric import (LFRicCollection, LFRicConstants, LFRicTypes, - LFRicKern, LFRicInvoke) +from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES from psyclone.psyir.nodes import Literal, ArrayReference @@ -64,7 +63,7 @@ class LFRicScalarArrayArgs(LFRicCollection): - ScalarArray arguments. ''' - def __init__(self, node: Union[LFRicKern, LFRicInvoke]): + def __init__(self, node): super().__init__(node) # Initialise dictionaries of 'real', 'integer' and 'logical' From 5e48f745ec600d5fe2333bbc691bfbf437f5aa2b Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 3 Dec 2025 11:23:33 +0000 Subject: [PATCH 083/122] #1312: lint fix --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 6b6f5e825c..578d76ed27 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -41,7 +41,6 @@ # Imports from collections import Counter -from typing import Union from psyclone.psyir.frontend.fparser2 import INTENT_MAPPING from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes From 53111a9e9452baf76c273c5e4cb1eeb7d284505b Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:35:16 +0000 Subject: [PATCH 084/122] #1312: change imports to try find culprit --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 3 +-- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 63b40d5513..d0f2437f2a 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -44,7 +44,6 @@ from psyclone.core import VariablesAccessMap from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants -from psyclone.lfric import LFRicKernelArgument from psyclone.errors import InternalError @@ -135,7 +134,7 @@ def cma_operator(self, arg, var_accesses=None): self.extend(_local_args, var_accesses) def scalar(self, - scalar_arg: LFRicKernelArgument, + scalar_arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add the name associated with the scalar argument to the argument list and optionally add this scalar to the variable access diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 578d76ed27..85b53c0687 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -41,9 +41,11 @@ # Imports from collections import Counter +from typing import Union from psyclone.psyir.frontend.fparser2 import INTENT_MAPPING -from psyclone.domain.lfric import LFRicCollection, LFRicConstants, LFRicTypes +from psyclone.domain.lfric import (LFRicCollection, LFRicConstants, LFRicTypes, + LFRicKern, LFRicInvoke) from psyclone.errors import GenerationError, InternalError from psyclone.psyGen import FORTRAN_INTENT_NAMES from psyclone.psyir.nodes import Literal, ArrayReference @@ -62,7 +64,7 @@ class LFRicScalarArrayArgs(LFRicCollection): - ScalarArray arguments. ''' - def __init__(self, node): + def __init__(self, node: Union[LFRicKern, LFRicInvoke]): super().__init__(node) # Initialise dictionaries of 'real', 'integer' and 'logical' From 279f88234a3e850b92037147c8855d91a722c51a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:46:13 +0000 Subject: [PATCH 085/122] This reverts commit 0d1b97ab94e8de67a46d57e883b5e03a1a2c8257. --- .../domain/lfric/kern_call_arg_list.py | 177 ++++++++---------- .../domain/lfric/lfric_scalar_args.py | 8 +- 2 files changed, 78 insertions(+), 107 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 205a6e865c..4abf2e03cf 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -175,29 +175,25 @@ def append_structure_reference(self, module_name, user_type, member_list, overwrite_datatype=overwrite_datatype)) return sym - def cell_position(self, var_accesses=None): + def cell_position(self, var_accesses: Optional[VariablesAccessMap] = None): '''Adds a cell argument to the argument list and if supplied stores this access in var_accesses. - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' cell_ref_name, ref = self.cell_ref_name(var_accesses) self.psyir_append(ref) self.append(cell_ref_name) - def cell_map(self, var_accesses=None): + def cell_map(self, var_accesses: Optional[VariablesAccessMap] = None): '''Add cell-map and related cell counts (for inter-grid kernels) to the argument list. If supplied it also stores these accesses to the var_access object. - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' cargs = psyGen.args_filter(self._kern.args, arg_meshes=["gh_coarse"]) @@ -225,13 +221,12 @@ def cell_map(self, var_accesses=None): sym = self.append_integer_reference(base_name) self.append(sym.name, var_accesses) - def mesh_height(self, var_accesses=None): + def mesh_height(self, var_accesses: Optional[VariablesAccessMap] = None): '''Add mesh height (nlayers) to the argument list and if supplied stores this access in var_accesses. :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: :py:class:`psyclone.core.VariablesAccessMap` ''' if self._kern.iterates_over == "dof": @@ -241,17 +236,16 @@ def mesh_height(self, var_accesses=None): self.append(nlayers_symbol.name, var_accesses) self._nlayers_positions.append(self.num_args) - def scalar(self, scalar_arg, var_accesses=None): + def scalar(self, scalar_arg, + var_accesses: Optional[VariablesAccessMap] = None): ''' Add the necessary argument for a scalar quantity as well as an appropriate Symbol to the SymbolTable. :param scalar_arg: the scalar kernel argument. :type scalar_arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance that \ + :param var_accesses: optional VariablesAccessMap instance that stores information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' super().scalar(scalar_arg, var_accesses) @@ -260,7 +254,6 @@ def scalar(self, scalar_arg, var_accesses=None): else: sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) - # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): @@ -270,44 +263,40 @@ def scalar(self, scalar_arg, var_accesses=None): # root_name="ncell_3d", context="PSyVars", label="ncell3d") # self.append(ncell3d_name) - def _mesh_ncell2d(self, var_accesses=None): + def _mesh_ncell2d(self, var_accesses: Optional[VariablesAccessMap] = None): '''Add the number of columns in the mesh to the argument list and if supplied stores this access in var_accesses. - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' sym = self.append_integer_reference("ncell_2d") self.append(sym.name, var_accesses) - def _mesh_ncell2d_no_halos(self, var_accesses=None): + def _mesh_ncell2d_no_halos( + self, var_accesses: Optional[VariablesAccessMap] = None): '''Add the number of columns in the mesh (excluding those in the halo) to the argument list and store this access in var_accesses (if supplied). - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' ncell_symbol = self.append_integer_reference("ncell_2d_no_halos") self.append(ncell_symbol.name, var_accesses) - def cma_operator(self, arg, var_accesses=None): + def cma_operator(self, arg, + var_accesses: Optional[VariablesAccessMap] = None): '''Add the CMA operator and associated scalars to the argument list and optionally add them to the variable access information. :param arg: the CMA operator argument. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' components = ["matrix"] @@ -351,7 +340,8 @@ def cma_operator(self, arg, var_accesses=None): self.append(sym.name, var_accesses, mode=mode, metadata_posn=arg.metadata_index) - def field_vector(self, argvect, var_accesses=None): + def field_vector(self, argvect, + var_accesses: Optional[VariablesAccessMap] = None): '''Add the field vector associated with the argument 'argvect' to the argument list. If supplied it also stores these accesses to the var_access object. @@ -360,7 +350,6 @@ def field_vector(self, argvect, var_accesses=None): :type argvect: :py:class:`psyclone.lfric.LFRicKernelArgument` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: :py:class:`psyclone.core.VariablesAccessMap` ''' suffix = LFRicConstants().ARG_TYPE_SUFFIX_MAPPING[ @@ -396,7 +385,7 @@ def field_vector(self, argvect, var_accesses=None): var_accesses.add_access(Signature(argvect.name), argvect.access, self._kern) - def field(self, arg, var_accesses=None): + def field(self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add the field array associated with the argument 'arg' to the argument list. If supplied it also stores this access in var_accesses. @@ -404,7 +393,6 @@ def field(self, arg, var_accesses=None): :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: :py:class:`psyclone.core.VariablesAccessMap` ''' const = LFRicConstants() @@ -431,17 +419,16 @@ def field(self, arg, var_accesses=None): mode=arg.access, metadata_posn=arg.metadata_index) self.psyir_append(Reference(sym)) - def stencil_unknown_extent(self, arg, var_accesses=None): + def stencil_unknown_extent( + self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add stencil information to the argument list associated with the argument 'arg' if the extent is unknown. If supplied it also stores this access in var_accesses. :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # The extent is not specified in the metadata so pass the value in @@ -455,17 +442,16 @@ def stencil_unknown_extent(self, arg, var_accesses=None): self.append(f"{var_sym.name}({cell_name})", var_accesses, var_access_name=var_sym.name) - def stencil_2d_unknown_extent(self, arg, var_accesses=None): + def stencil_2d_unknown_extent( + self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add 2D stencil information to the argument list associated with the argument 'arg' if the extent is unknown. If supplied it also stores this access in var_accesses. :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # The extent is not specified in the metadata so pass the value in @@ -479,17 +465,16 @@ def stencil_2d_unknown_extent(self, arg, var_accesses=None): name = f"{var_sym.name}(:,{cell_name})" self.append(name, var_accesses, var_access_name=var_sym.name) - def stencil_2d_max_extent(self, arg, var_accesses=None): + def stencil_2d_max_extent( + self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add the maximum branch extent for a 2D stencil associated with the argument 'arg' to the argument list. If supplied it also stores this in var_accesses. :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional SingleVariableAccessInfo instance \ - to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.SingleVariableAccessInfo` + :param var_accesses: optional VariableAccessMap instance to store the + information about variable accesses. ''' # The maximum branch extent is not specified in the metadata so pass @@ -505,7 +490,8 @@ def stencil_2d_max_extent(self, arg, var_accesses=None): sym = self.append_integer_reference(root_name, tag=unique_tag) self.append(sym.name, var_accesses) - def stencil_unknown_direction(self, arg, var_accesses=None): + def stencil_unknown_direction( + self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add stencil information to the argument list associated with the argument 'arg' if the direction is unknown (i.e. it's being supplied in a variable). If supplied it also stores this access in @@ -513,10 +499,8 @@ def stencil_unknown_direction(self, arg, var_accesses=None): :param arg: the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # the direction of the stencil is not known so pass the value in @@ -525,18 +509,16 @@ def stencil_unknown_direction(self, arg, var_accesses=None): self.append_integer_reference(name, f"AlgArgs_{tag}") self.append(name, var_accesses) - def stencil(self, arg, var_accesses=None): + def stencil(self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add general stencil information associated with the argument 'arg' to the argument list. If supplied it also stores this access in var_accesses. - :param arg: the meta-data description of the kernel \ + :param arg: the meta-data description of the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # add in stencil dofmap @@ -550,18 +532,17 @@ def stencil(self, arg, var_accesses=None): self.append(f"{var_sym.name}(:,:,{cell_name})", var_accesses, var_access_name=var_sym.name) - def stencil_2d(self, arg, var_accesses=None): + def stencil_2d( + self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add general 2D stencil information associated with the argument 'arg' to the argument list. If supplied it also stores this access in var_accesses. - :param arg: the meta-data description of the kernel \ + :param arg: the meta-data description of the kernel argument with which the stencil is associated. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # The stencil_2D differs from the stencil in that the direction @@ -582,16 +563,14 @@ def stencil_2d(self, arg, var_accesses=None): name = f"{var_sym.name}(:,:,:,{cell_name})" self.append(name, var_accesses, var_access_name=var_sym.name) - def operator(self, arg, var_accesses=None): + def operator(self, arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add the operator arguments to the argument list. If supplied it also stores this access in var_accesses. :param arg: the meta-data description of the operator. :type arg: :py:class:`psyclone.lfric.LFRicKernelArgument` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # TODO we should only be including ncell_3d once in the argument @@ -619,17 +598,16 @@ def operator(self, arg, var_accesses=None): self.append(sym.name, var_accesses, mode=arg.access, metadata_posn=arg.metadata_index) - def fs_common(self, function_space, var_accesses=None): + def fs_common(self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Add function-space related arguments common to LMA operators and fields. If supplied it also stores this access in var_accesses. - :param function_space: the function space for which the related \ + :param function_space: the function space for which the related arguments common to LMA operators and fields are added. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: - Optional[:py:class:`psyclone.core.VariablesAccessMap`] ''' if self._kern.iterates_over == "dof": @@ -639,7 +617,9 @@ def fs_common(self, function_space, var_accesses=None): KernCallArgList.NdfInfo(position=self.num_args, function_space=function_space.orig_name)) - def fs_compulsory_field(self, function_space, var_accesses=None): + def fs_compulsory_field( + self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Add compulsory arguments associated with this function space to the list. If supplied it also stores this access in var_accesses. @@ -648,8 +628,6 @@ def fs_compulsory_field(self, function_space, var_accesses=None): :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: - :py:class:`psyclone.core.VariablesAccessMap` ''' if self._kern.iterates_over == "dof": @@ -683,16 +661,15 @@ def fs_compulsory_field(self, function_space, var_accesses=None): self.append(f"{sym.name}(:,{cell_name})", var_accesses, var_access_name=sym.name) - def fs_intergrid(self, function_space, var_accesses=None): + def fs_intergrid(self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Add function-space related arguments for an intergrid kernel. If supplied it also stores this access in var_accesses. :param function_space: the function space for which to add arguments :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # Is this FS associated with the coarse or fine mesh? (All fields @@ -713,17 +690,16 @@ def fs_intergrid(self, function_space, var_accesses=None): self.fs_compulsory_field(function_space, var_accesses=var_accesses) - def basis(self, function_space, var_accesses=None): + def basis(self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Add basis function information for this function space to the argument list and optionally to the variable access information. - :param function_space: the function space for which the basis \ + :param function_space: the function space for which the basis function is required. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' for rule in self._kern.qr_rules.values(): @@ -746,18 +722,17 @@ def basis(self, function_space, var_accesses=None): sym = self.append_array_reference(basis_name, [":", ":", ":"]) self.append(sym.name, var_accesses) - def diff_basis(self, function_space, var_accesses=None): + def diff_basis(self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Add differential basis information for the function space to the argument list. If supplied it also stores this access in var_accesses. - :param function_space: the function space for which the differential \ + :param function_space: the function space for which the differential basis functions are required. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' for rule in self._kern.qr_rules.values(): @@ -786,19 +761,18 @@ def diff_basis(self, function_space, var_accesses=None): LFRicTypes("LFRicRealScalarDataType")()) self.append(sym.name, var_accesses) - def field_bcs_kernel(self, function_space, var_accesses=None): + def field_bcs_kernel(self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Implement the boundary_dofs array fix for a field. If supplied it also stores this access in var_accesses. - :param function_space: the function space for which boundary dofs \ + :param function_space: the function space for which boundary dofs are required. :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` - :raises GenerationError: if the bcs kernel does not contain \ + :raises GenerationError: if the bcs kernel does not contain a field as argument (but e.g. an operator). ''' @@ -820,17 +794,16 @@ def field_bcs_kernel(self, function_space, var_accesses=None): sym = self.append_array_reference(base_name, [":", ":"]) self.append(sym.name, var_accesses) - def operator_bcs_kernel(self, function_space, var_accesses=None): + def operator_bcs_kernel(self, function_space, + var_accesses: Optional[VariablesAccessMap] = None): '''Supply necessary additional arguments for the kernel that applies boundary conditions to a LMA operator. If supplied it also stores this access in var_accesses. :param function_space: unused, only for consistency with base class. :type function_space: :py:class:`psyclone.lfric.FunctionSpace` - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # This kernel has only a single LMA operator as argument. @@ -840,15 +813,14 @@ def operator_bcs_kernel(self, function_space, var_accesses=None): sym = self.append_array_reference(base_name, [":", ":"]) self.append(sym.name, var_accesses) - def mesh_properties(self, var_accesses=None): + def mesh_properties(self, + var_accesses: Optional[VariablesAccessMap] = None): '''Provide the kernel arguments required for the mesh properties specified in the kernel metadata. If supplied it also stores this access in var_accesses. - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' if self._kern.mesh.properties: @@ -859,15 +831,13 @@ def mesh_properties(self, var_accesses=None): kern_args(stub=False, var_accesses=var_accesses, kern_call_arg_list=self)) - def quad_rule(self, var_accesses=None): + def quad_rule(self, var_accesses: Optional[VariablesAccessMap] = None): '''Add quadrature-related information to the kernel argument list. Adds the necessary arguments to the argument list, and optionally adds variable access information to the var_accesses object. - :param var_accesses: optional VariablesAccessMap instance to store \ + :param var_accesses: optional VariablesAccessMap instance to store the information about variable accesses. - :type var_accesses: \ - :py:class:`psyclone.core.VariablesAccessMap` ''' # The QR shapes that this routine supports @@ -1020,8 +990,7 @@ def cell_ref_name( if var_accesses is not None: var_accesses.add_access(Signature(array_ref.name), AccessType.READ, - self._kern, - ["colour", "tile", "cell"]) + self._kern) else: symbol = self._kern.colourmap array_ref = ArrayReference.create( @@ -1030,7 +999,7 @@ def cell_ref_name( if var_accesses is not None: var_accesses.add_access(Signature(array_ref.name), AccessType.READ, - self._kern, ["colour", "cell"]) + self._kern) return (array_ref.debug_string(), array_ref) diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index df500f9282..40a11602d1 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -111,7 +111,8 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: - scal = [arg.declaration_name for arg in self._scalar_args[intent]] + scal = [arg.declaration_name for + arg in self._scalar_args[intent]] rscal = [arg.declaration_name for arg in self._real_scalars[intent]] iscal = [arg.declaration_name for @@ -171,8 +172,9 @@ def stub_declarations(self): raise InternalError( f"Found an unsupported data type " f"'{arg.descriptor.data_type}' for the scalar " - f"argument '{arg.declaration_name}'. Supported types " - f"are {const.VALID_SCALAR_DATA_TYPES}.") + f"argument '{arg.declaration_name}'. " + f"Supported types are " + f"{const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() From b4d2647235c53591c0827cd89382104b43d00ba7 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:51:52 +0000 Subject: [PATCH 086/122] #1312: revert KernCallArgList and LFRicScalarArgs to original state --- src/psyclone/domain/lfric/kern_call_arg_list.py | 1 + src/psyclone/domain/lfric/lfric_scalar_args.py | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 4abf2e03cf..1e55430d91 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -254,6 +254,7 @@ def scalar(self, scalar_arg, else: sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) + # TODO uncomment this method when ensuring we only pass ncell3d once # to any given kernel. # def mesh_ncell3d(self): diff --git a/src/psyclone/domain/lfric/lfric_scalar_args.py b/src/psyclone/domain/lfric/lfric_scalar_args.py index 40a11602d1..df500f9282 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_args.py @@ -111,8 +111,7 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: - scal = [arg.declaration_name for - arg in self._scalar_args[intent]] + scal = [arg.declaration_name for arg in self._scalar_args[intent]] rscal = [arg.declaration_name for arg in self._real_scalars[intent]] iscal = [arg.declaration_name for @@ -172,9 +171,8 @@ def stub_declarations(self): raise InternalError( f"Found an unsupported data type " f"'{arg.descriptor.data_type}' for the scalar " - f"argument '{arg.declaration_name}'. " - f"Supported types are " - f"{const.VALID_SCALAR_DATA_TYPES}.") + f"argument '{arg.declaration_name}'. Supported types " + f"are {const.VALID_SCALAR_DATA_TYPES}.") # Create declarations self._create_declarations() From 7be0fa6e41afedbcdd9af62508f843ffa25751ec Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:11:06 +0000 Subject: [PATCH 087/122] #1312: potentially fix LFRicScalarArrayArgs doc build error --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 85b53c0687..b722d0fd6c 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -60,9 +60,6 @@ class LFRicScalarArrayArgs(LFRicCollection): Handles the declarations of ScalarArray kernel arguments appearing in either an Invoke or a Kernel stub. - :param node: the Invoke or Kernel stub for which to manage the -- ScalarArray arguments. - ''' def __init__(self, node: Union[LFRicKern, LFRicInvoke]): super().__init__(node) From 72b3026af802e0dda1349c2e92f0ac215e94f4d1 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 4 Dec 2025 10:19:24 +0000 Subject: [PATCH 088/122] #1312: add typehint to KernStubArgList --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index d0f2437f2a..b2ecc3d2c4 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -42,6 +42,7 @@ from typing import Optional from psyclone.core import VariablesAccessMap +from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError @@ -134,7 +135,7 @@ def cma_operator(self, arg, var_accesses=None): self.extend(_local_args, var_accesses) def scalar(self, - scalar_arg, + scalar_arg: LFRicKernelArgument, var_accesses: Optional[VariablesAccessMap] = None): '''Add the name associated with the scalar argument to the argument list and optionally add this scalar to the variable access From 699aeacd5556d0b905675eea8f0deaaa6661e9ba Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 4 Dec 2025 10:28:22 +0000 Subject: [PATCH 089/122] #1312: remove typehint from KernStubArgList --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index b2ecc3d2c4..d0f2437f2a 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -42,7 +42,6 @@ from typing import Optional from psyclone.core import VariablesAccessMap -from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError @@ -135,7 +134,7 @@ def cma_operator(self, arg, var_accesses=None): self.extend(_local_args, var_accesses) def scalar(self, - scalar_arg: LFRicKernelArgument, + scalar_arg, var_accesses: Optional[VariablesAccessMap] = None): '''Add the name associated with the scalar argument to the argument list and optionally add this scalar to the variable access From d10b34fac8cb10519902e3b9fbaaa7d0e478b5cf Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:04:49 +0000 Subject: [PATCH 090/122] #1312: potential fix for import build failure --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 3 ++- src/psyclone/lfric.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index d0f2437f2a..b2ecc3d2c4 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -42,6 +42,7 @@ from typing import Optional from psyclone.core import VariablesAccessMap +from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError @@ -134,7 +135,7 @@ def cma_operator(self, arg, var_accesses=None): self.extend(_local_args, var_accesses) def scalar(self, - scalar_arg, + scalar_arg: LFRicKernelArgument, var_accesses: Optional[VariablesAccessMap] = None): '''Add the name associated with the scalar argument to the argument list and optionally add this scalar to the variable access diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 9a9171d932..f9076af5c2 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -56,9 +56,10 @@ from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn from psyclone.domain.lfric import ( - FunctionSpace, KernCallAccArgList, KernCallArgList, LFRicCollection, + FunctionSpace, KernCallArgList, LFRicCollection, LFRicConstants, LFRicSymbolTable, LFRicKern, LFRicTypes, LFRicLoop) +from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From cee1d488a390d7b7f95ae15ae310b5e8b32a4bb4 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:08:22 +0000 Subject: [PATCH 091/122] #1312: continuing the potential fix --- src/psyclone/lfric.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index f9076af5c2..da7c3a02e9 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -56,9 +56,9 @@ from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn from psyclone.domain.lfric import ( - FunctionSpace, KernCallArgList, LFRicCollection, - LFRicConstants, LFRicSymbolTable, LFRicKern, - LFRicTypes, LFRicLoop) + FunctionSpace, LFRicCollection, LFRicConstants, + LFRicSymbolTable, LFRicKern, LFRicTypes, LFRicLoop) +from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError From cc617812bf0ce274cef7234d07e5072613f95cbe Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:37:05 +0000 Subject: [PATCH 092/122] #1312: continue trying to fix circular import --- src/psyclone/lfric.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index da7c3a02e9..8fddbbfe69 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -56,10 +56,11 @@ from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn from psyclone.domain.lfric import ( - FunctionSpace, LFRicCollection, LFRicConstants, - LFRicSymbolTable, LFRicKern, LFRicTypes, LFRicLoop) + FunctionSpace, LFRicConstants, LFRicSymbolTable, LFRicKern, + LFRicTypes, LFRicLoop) from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList +from psyclone.domain.lfric.lfric_collection import LFRicCollection from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From c58d7cf0ec6d51e5f1415f6c61d7699dd367339c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:46:46 +0000 Subject: [PATCH 093/122] #1312: continue trying to fix circular import --- src/psyclone/lfric.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 8fddbbfe69..43b42a29dd 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -56,11 +56,11 @@ from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn from psyclone.domain.lfric import ( - FunctionSpace, LFRicConstants, LFRicSymbolTable, LFRicKern, - LFRicTypes, LFRicLoop) + FunctionSpace, LFRicConstants, LFRicKern, LFRicTypes, LFRicLoop) from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_collection import LFRicCollection +from psyclone.domain.lfric.lfric)symbol_table import LFRicSymbolTable from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From c2f572a31df94481986ca9ac213ec647d722424f Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:54:09 +0000 Subject: [PATCH 094/122] #1312: lint fix --- src/psyclone/lfric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 43b42a29dd..3d7147119e 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -60,7 +60,7 @@ from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_collection import LFRicCollection -from psyclone.domain.lfric.lfric)symbol_table import LFRicSymbolTable +from psyclone.domain.lfric.lfric_symbol_table import LFRicSymbolTable from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From 8bdf4d1a158e2adea228d31696cadb56d473d201 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:01:03 +0000 Subject: [PATCH 095/122] #1312: continue trying to fix circular import --- src/psyclone/lfric.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 3d7147119e..af0105ace9 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -56,11 +56,12 @@ from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn from psyclone.domain.lfric import ( - FunctionSpace, LFRicConstants, LFRicKern, LFRicTypes, LFRicLoop) + FunctionSpace, LFRicConstants, LFRicTypes, LFRicLoop) from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_collection import LFRicCollection from psyclone.domain.lfric.lfric_symbol_table import LFRicSymbolTable +from psyclone.domain.lfric.lfric_kern import LFRicKern from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From efca80bc2bc046f796680a0d8c47d7d27fc30907 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:18:12 +0000 Subject: [PATCH 096/122] #1312: continue trying to fix circular import --- src/psyclone/lfric.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index af0105ace9..7741382daf 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -56,12 +56,13 @@ from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn from psyclone.domain.lfric import ( - FunctionSpace, LFRicConstants, LFRicTypes, LFRicLoop) + FunctionSpace, LFRicConstants, LFRicLoop) from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_collection import LFRicCollection from psyclone.domain.lfric.lfric_symbol_table import LFRicSymbolTable from psyclone.domain.lfric.lfric_kern import LFRicKern +from psyclone.domain.lfric.lfric_types import LFRicTypes from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From 553a610ef030764c6a500c20425c18dd31d5724b Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:30:02 +0000 Subject: [PATCH 097/122] #1312: continue trying to fix circular import --- src/psyclone/lfric.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 7741382daf..f0f4788410 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -55,14 +55,14 @@ from psyclone.configuration import Config from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn -from psyclone.domain.lfric import ( - FunctionSpace, LFRicConstants, LFRicLoop) +from psyclone.domain.lfric import FunctionSpace, LFRicConstants from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList from psyclone.domain.lfric.lfric_collection import LFRicCollection from psyclone.domain.lfric.lfric_symbol_table import LFRicSymbolTable from psyclone.domain.lfric.lfric_kern import LFRicKern from psyclone.domain.lfric.lfric_types import LFRicTypes +from psyclone.domain.lfric.lfric_loop import LFRicLoop from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From 8cd4dbbbaf840a1b80c1a2c9ebb4ad6400706b10 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 12:28:43 +0000 Subject: [PATCH 098/122] #1312: revert the splitting of imports --- src/psyclone/lfric.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index f0f4788410..3bb3cadca4 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -55,14 +55,9 @@ from psyclone.configuration import Config from psyclone.core import AccessType, Signature, SymbolicMaths from psyclone.domain.lfric.lfric_builtins import LFRicBuiltIn -from psyclone.domain.lfric import FunctionSpace, LFRicConstants -from psyclone.domain.lfric.kern_call_arg_list import KernCallArgList -from psyclone.domain.lfric.kern_call_acc_arg_list import KernCallAccArgList -from psyclone.domain.lfric.lfric_collection import LFRicCollection -from psyclone.domain.lfric.lfric_symbol_table import LFRicSymbolTable -from psyclone.domain.lfric.lfric_kern import LFRicKern -from psyclone.domain.lfric.lfric_types import LFRicTypes -from psyclone.domain.lfric.lfric_loop import LFRicLoop +from psyclone.domain.lfric import ( + FunctionSpace, KernCallAccArgList, KernCallArgList, LFRicCollection, + LFRicConstants, LFRicSymbolTable, LFRicKern, LFRicTypes, LFRicLoop) from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule from psyclone.errors import GenerationError, InternalError, FieldNotFoundError from psyclone.parse.kernel import getkerneldescriptors From 03ea2f8f59b1464d582e7f5c6558cd06193cc099 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:12:42 +0000 Subject: [PATCH 099/122] #1312: Fix the typehinting in KernStubArgList --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index b2ecc3d2c4..9396cec975 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -39,10 +39,11 @@ for a kernel subroutine. ''' -from typing import Optional +from typing import Optional, TYPE_CHECKING from psyclone.core import VariablesAccessMap -from psyclone.lfric import LFRicKernelArgument +if TYPE_CHECKING: + from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError From d5468411c67a5b49f71ad7bd185763fa581bfc9c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:04:23 +0000 Subject: [PATCH 100/122] #1312: test inverting the if statement --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 9396cec975..6ad1c71b34 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -42,7 +42,7 @@ from typing import Optional, TYPE_CHECKING from psyclone.core import VariablesAccessMap -if TYPE_CHECKING: +if not TYPE_CHECKING: from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants From 8b4618256b56321151679974d10d9aa49f08564b Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:35:13 +0000 Subject: [PATCH 101/122] #1312: change typehinting in KernStubArgList to be a comment --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 6ad1c71b34..986bb43b64 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -39,11 +39,9 @@ for a kernel subroutine. ''' -from typing import Optional, TYPE_CHECKING +from typing import Optional from psyclone.core import VariablesAccessMap -if not TYPE_CHECKING: - from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError @@ -136,7 +134,7 @@ def cma_operator(self, arg, var_accesses=None): self.extend(_local_args, var_accesses) def scalar(self, - scalar_arg: LFRicKernelArgument, + scalar_arg: 'LFRicKernelArgument', var_accesses: Optional[VariablesAccessMap] = None): '''Add the name associated with the scalar argument to the argument list and optionally add this scalar to the variable access From a1e51113ad002926e7ae2580e54b00184a2bc0f0 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:47:55 +0000 Subject: [PATCH 102/122] #1312: hopefully fix the typehinting --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 986bb43b64..1d3f8e399c 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -39,9 +39,11 @@ for a kernel subroutine. ''' -from typing import Optional +from typing import Optional, TYPE_CHECKING from psyclone.core import VariablesAccessMap +if TYPE_CHECKING: + from psyclone.domain.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError From 5ccffeee019f162d359c8f1753b97ce6048b7aba Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:22:05 +0000 Subject: [PATCH 103/122] #1312: correct the import --- src/psyclone/domain/lfric/kern_stub_arg_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kern_stub_arg_list.py b/src/psyclone/domain/lfric/kern_stub_arg_list.py index 1d3f8e399c..635839ac48 100644 --- a/src/psyclone/domain/lfric/kern_stub_arg_list.py +++ b/src/psyclone/domain/lfric/kern_stub_arg_list.py @@ -43,7 +43,7 @@ from psyclone.core import VariablesAccessMap if TYPE_CHECKING: - from psyclone.domain.lfric import LFRicKernelArgument + from psyclone.lfric import LFRicKernelArgument from psyclone.domain.lfric.arg_ordering import ArgOrdering from psyclone.domain.lfric.lfric_constants import LFRicConstants from psyclone.errors import InternalError From bd82d2901d47fc61d958eeff1a0e361516cf1dd5 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:24:21 +0000 Subject: [PATCH 104/122] #1312: Cut down LFRicScalarArrayArgs to do multiple types at once --- .../domain/lfric/lfric_scalar_array_args.py | 95 ++----------------- 1 file changed, 8 insertions(+), 87 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index b722d0fd6c..303d8dc3ac 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -178,90 +178,13 @@ def _create_declarations(self): Create the symbols for the ScalarArray arguments. ''' - # Real ScalarArray arguments + type_map = {"gh_real": LFRicTypes("LFRicRealScalarDataType")(), + "gh_integer": LFRicTypes("LFRicIntegerScalarDataType")(), + "gh_logical": LFRicTypes("LFRicLogicalScalarDataType")()} + # ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: - if self._real_scalar_arrays[intent]: - for arg in self._real_scalar_arrays[intent]: - if arg._array_ndims >= 1: - # Create the dimensions array symbol - dims_array_symbol = self.symtab.find_or_create( - "dims_" + arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_array_symbol) - # Create list of dims_array references - sym_list = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE)]) - for idx in range(1, arg._array_ndims + 1)] - if not self._kernel: - # For code generation, find ScalarArray tag - # and convert it to an ArrayType - array_symbol = self.symtab.lookup_with_tag( - "AlgArgs_" + arg.name) - array_symbol.datatype = ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - sym_list) - else: - # For stub generation, create the symbol - array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicRealScalarDataType")(), - sym_list)) - array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(array_symbol) - - # Integer ScalarArray arguments - for intent in FORTRAN_INTENT_NAMES: - if self._integer_scalar_arrays[intent]: - for arg in self._integer_scalar_arrays[intent]: - if arg._array_ndims >= 1: - # Create the dimensions array symbol - dims_array_symbol = self.symtab.find_or_create( - "dims_" + arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_array_symbol) - # Create list of dims_array references - sym_list = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE)]) - for idx in range(1, arg._array_ndims + 1)] - if not self._kernel: - # For code generation, find ScalarArray tag - # and convert it to an ArrayType - array_symbol = self.symtab.lookup_with_tag( - "AlgArgs_" + arg.name) - array_symbol.datatype = ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - sym_list) - else: - # For stub generation, create the symbol - array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - sym_list)) - array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(array_symbol) - - # Logical ScalarArray arguments - for intent in FORTRAN_INTENT_NAMES: - if self._logical_scalar_arrays[intent]: - for arg in self._logical_scalar_arrays[intent]: + for arg in self._scalar_array_args[intent]: + if arg.intent in FORTRAN_INTENT_NAMES: if arg._array_ndims >= 1: # Create the dimensions array symbol dims_array_symbol = self.symtab.find_or_create( @@ -273,20 +196,18 @@ def _create_declarations(self): dims_array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) self.symtab.append_argument(dims_array_symbol) - # Create list of dims_array references sym_list = [ArrayReference.create( dims_array_symbol, [Literal(str(idx), INTEGER_TYPE)]) for idx in range(1, arg._array_ndims + 1)] - if not self._kernel: # For code generation, find ScalarArray tag # and convert it to an ArrayType array_symbol = self.symtab.lookup_with_tag( "AlgArgs_" + arg.name) array_symbol.datatype = ArrayType( - LFRicTypes("LFRicLogicalScalarDataType")(), + type_map[arg.intent], sym_list) else: # For stub generation, create the symbol @@ -294,7 +215,7 @@ def _create_declarations(self): arg.name, symbol_type=DataSymbol, datatype=ArrayType( - LFRicTypes("LFRicLogicalScalarDataType")(), + type_map[arg.intent], sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) From 3b167fc37c93d4bfd1040007c58e7cb7d29c6e2c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:29:35 +0000 Subject: [PATCH 105/122] #1312: Use intrinsic_type rather than intent in LFRicScalarArrayArgs and fix relevant test ordering --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 10 +++++----- .../tests/domain/lfric/lfric_scalar_codegen_test.py | 6 +++--- .../tests/domain/lfric/lfric_scalar_stubgen_test.py | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 303d8dc3ac..df27ad66cb 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -178,9 +178,9 @@ def _create_declarations(self): Create the symbols for the ScalarArray arguments. ''' - type_map = {"gh_real": LFRicTypes("LFRicRealScalarDataType")(), - "gh_integer": LFRicTypes("LFRicIntegerScalarDataType")(), - "gh_logical": LFRicTypes("LFRicLogicalScalarDataType")()} + type_map = {"real": LFRicTypes("LFRicRealScalarDataType")(), + "integer": LFRicTypes("LFRicIntegerScalarDataType")(), + "logical": LFRicTypes("LFRicLogicalScalarDataType")()} # ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_array_args[intent]: @@ -207,7 +207,7 @@ def _create_declarations(self): array_symbol = self.symtab.lookup_with_tag( "AlgArgs_" + arg.name) array_symbol.datatype = ArrayType( - type_map[arg.intent], + type_map[arg.intrinsic_type], sym_list) else: # For stub generation, create the symbol @@ -215,7 +215,7 @@ def _create_declarations(self): arg.name, symbol_type=DataSymbol, datatype=ArrayType( - type_map[arg.intent], + type_map[arg.intrinsic_type], sym_list)) array_symbol.interface = ArgumentInterface( INTENT_MAPPING[intent]) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 63f63f217e..d0c4fc88b8 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -626,7 +626,7 @@ def test_scalar_array(tmpdir): " contains\n" " subroutine invoke_0_testkern_scalar_array_type(afield, " "real_array, logical_array, integer_array, a_scalar, " - "dims_real_array, dims_integer_array, dims_logical_array)\n" + "dims_real_array, dims_logical_array, dims_integer_array)\n" " use mesh_mod, only : mesh_type\n" " use testkern_scalar_array_mod, only : " "testkern_scalar_array_code\n" @@ -641,10 +641,10 @@ def test_scalar_array(tmpdir): " integer(kind=i_def), intent(in) :: a_scalar\n" " integer(kind=i_def), dimension(2), intent(in) :: " "dims_real_array\n" - " integer(kind=i_def), dimension(4), intent(in) :: " - "dims_integer_array\n" " integer(kind=i_def), dimension(1), intent(in) :: " "dims_logical_array\n" + " integer(kind=i_def), dimension(4), intent(in) :: " + "dims_integer_array\n" " integer(kind=i_def) :: cell\n" " type(mesh_type), pointer :: mesh => null()\n" " integer(kind=i_def) :: max_halo_depth_mesh\n" diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py index 7aae252ee5..79bac15248 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_stubgen_test.py @@ -189,13 +189,13 @@ def test_stub_generate_with_scalar_array(): integer(kind=i_def), dimension(2), intent(in) :: dims_rscalar_array_2 real(kind=r_def), dimension(dims_rscalar_array_2(1),\ dims_rscalar_array_2(2)), intent(in) :: rscalar_array_2 + integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 + logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: \ +lscalar_array_3 integer(kind=i_def), dimension(4), intent(in) :: dims_iscalar_array_4 integer(kind=i_def), dimension(dims_iscalar_array_4(1),\ dims_iscalar_array_4(2),dims_iscalar_array_4(3),\ dims_iscalar_array_4(4)), intent(in) :: iscalar_array_4 - integer(kind=i_def), dimension(1), intent(in) :: dims_lscalar_array_3 - logical(kind=l_def), dimension(dims_lscalar_array_3(1)), intent(in) :: \ -lscalar_array_3 real(kind=r_def), dimension(undf_w1), intent(inout) :: field_1_w1 From 889fefabb15872296f3bc4773f9d3cdb20981b72 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 9 Dec 2025 16:08:02 +0000 Subject: [PATCH 106/122] #1312: Condense argument dictionaries into one where possible --- .../domain/lfric/lfric_scalar_array_args.py | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index df27ad66cb..532ff52f65 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -67,14 +67,8 @@ def __init__(self, node: Union[LFRicKern, LFRicInvoke]): # Initialise dictionaries of 'real', 'integer' and 'logical' # ScalarArray arguments by data type and intent self._scalar_array_args = {} - self._real_scalar_arrays = {} - self._integer_scalar_arrays = {} - self._logical_scalar_arrays = {} for intent in FORTRAN_INTENT_NAMES: self._scalar_array_args[intent] = [] - self._real_scalar_arrays[intent] = [] - self._integer_scalar_arrays[intent] = [] - self._logical_scalar_arrays[intent] = [] def invoke_declarations(self): ''' @@ -88,32 +82,33 @@ def invoke_declarations(self): ''' super().invoke_declarations() - # Create dictionary of all ScalarArray arguments for checks + # Create dictionary of all ScalarArray arguments for validation. + # The dictionary keys are intent values, i.e., 'in', 'out', and + # 'inout', with the values being arrays of ScalarArray arguments. const = LFRicConstants() self._scalar_array_args = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES) # Filter ScalarArray arguments by intent and intrinsic type - self._real_scalar_arrays = self._invoke.unique_declns_by_intent( + real_scalar_arrays = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES, intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) - self._integer_scalar_arrays = self._invoke.unique_declns_by_intent( + integer_scalar_arrays = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES, intrinsic_type=const.MAPPING_DATA_TYPES["gh_integer"]) - self._logical_scalar_arrays = self._invoke.unique_declns_by_intent( + logical_scalar_arrays = self._invoke.unique_declns_by_intent( const.VALID_ARRAY_NAMES, intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: scal = [arg.declaration_name for arg in self._scalar_array_args[intent]] - rscalarr = [arg.declaration_name for - arg in self._real_scalar_arrays[intent]] - iscalarr = [arg.declaration_name for - arg in self._integer_scalar_arrays[intent]] - lscalarr = [arg.declaration_name for - arg in self._logical_scalar_arrays[intent]] - # Add "real", "integer" and "logical" ScalarArray lists for checks - decl_scal = rscalarr + iscalarr + lscalarr + decl_scal = [arg.declaration_name for arg in + real_scalar_arrays[intent]] + decl_scal += [arg.declaration_name for arg in + integer_scalar_arrays[intent]] + decl_scal += [arg.declaration_name for arg in + logical_scalar_arrays[intent]] + # Check for unsupported intrinsic types scal_inv = sorted(set(scal) - set(decl_scal)) if scal_inv: @@ -156,13 +151,8 @@ def stub_declarations(self): for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_array_args[intent]: # Distinguish whether they are ScalarArrays - if arg.descriptor.data_type == "gh_real": - self._real_scalar_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_integer": - self._integer_scalar_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_logical": - self._logical_scalar_arrays[intent].append(arg) - else: + if (arg.descriptor.data_type not in + const.VALID_SCALAR_DATA_TYPES): raise InternalError( f"Found an unsupported data type " f"'{arg.descriptor.data_type}' for the " From 58ba124e68dbf485ff5cacf06df540d00609660d Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 9 Dec 2025 16:47:10 +0000 Subject: [PATCH 107/122] #1312: Improve comments to distinguish between scal and decl_scal --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 532ff52f65..658fd91832 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -100,6 +100,9 @@ def invoke_declarations(self): intrinsic_type=const.MAPPING_DATA_TYPES["gh_logical"]) for intent in FORTRAN_INTENT_NAMES: + # scal contains all ScalarArray arguments of all intents and + # intrinsic types whereas decl_scal contains all ScalarArray + # arguments of all intents with valid intrinsic types. scal = [arg.declaration_name for arg in self._scalar_array_args[intent]] decl_scal = [arg.declaration_name for arg in From e9c7b77093c1f15cf2a7dc24b6c2399e11410cf5 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 10 Dec 2025 13:51:13 +0000 Subject: [PATCH 108/122] #1312: Include the dimensions array in the kernel call list --- src/psyclone/domain/lfric/kern_call_arg_list.py | 5 +++++ src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kern_call_arg_list.py b/src/psyclone/domain/lfric/kern_call_arg_list.py index 1e55430d91..4bfd9b348f 100644 --- a/src/psyclone/domain/lfric/kern_call_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_arg_list.py @@ -252,6 +252,11 @@ def scalar(self, scalar_arg, if scalar_arg.is_literal: self.psyir_append(scalar_arg.psyir_expression()) else: + if scalar_arg.is_scalar_array: + # If it's a ScalarArray we need to add the dimensions + # array to the call + dims_sym = self._symtab.lookup("dims_" + scalar_arg.name) + self.psyir_append(Reference(dims_sym)) sym = self._symtab.lookup(scalar_arg.name) self.psyir_append(Reference(sym)) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index d0c4fc88b8..b7e28ed5dd 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -686,7 +686,8 @@ def test_scalar_array(tmpdir): " end if\n" " do cell = loop0_start, loop0_stop, 1\n" " call testkern_scalar_array_code(nlayers_afield, " - "afield_data, real_array, logical_array, integer_array, a_scalar, " + "afield_data, dims_real_array, real_array, dims_logical_array, " + "logical_array, dims_integer_array, integer_array, a_scalar, " "ndf_w1, undf_w1, map_w1(:,cell))\n" ) assert expected in generated_code From 3febeb743df4c83bf5b009245ed6abf03b81cb93 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:18:48 +0000 Subject: [PATCH 109/122] #1312: remove old todo --- src/psyclone/domain/lfric/lfric_types.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_types.py b/src/psyclone/domain/lfric/lfric_types.py index 217e6e5678..ce8f112edf 100644 --- a/src/psyclone/domain/lfric/lfric_types.py +++ b/src/psyclone/domain/lfric/lfric_types.py @@ -190,7 +190,6 @@ def _create_generic_scalars(): LFRicTypes("R_DEF")), GenericScalar("LFRicLogicalScalar", ScalarType.Intrinsic.BOOLEAN, LFRicTypes("L_DEF"))] - # TODO: Consider adding ScalarArrays as a generic data type # Generate generic LFRic scalar datatypes and symbols from definitions for info in generic_scalar_datatypes: From 6af9a5585192ead4fda1128c553d85228fc87fe7 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:25:53 +0000 Subject: [PATCH 110/122] #1312: Change the _array_ndims to be >=1 --- src/psyclone/lfric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 3bb3cadca4..0e46e94cbb 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -6557,7 +6557,7 @@ def _find_or_create_type(mod_name: str, interface=ImportInterface(constants_container)) symtab.add(kind_symbol) dts = ScalarType(prim_type, Reference(kind_symbol)) - if self.is_scalar_array and self._array_ndims > 1: + if self.is_scalar_array and self._array_ndims >= 1: return ArrayType(dts, [self._array_ndims]) return dts From a7f3e982a0545004c17d8f8e3f79e899c5b81806 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:03:20 +0000 Subject: [PATCH 111/122] #1312: Add comment to _array_ndims --- src/psyclone/lfric.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/psyclone/lfric.py b/src/psyclone/lfric.py index 0e46e94cbb..366c1201e9 100644 --- a/src/psyclone/lfric.py +++ b/src/psyclone/lfric.py @@ -6558,6 +6558,8 @@ def _find_or_create_type(mod_name: str, symtab.add(kind_symbol) dts = ScalarType(prim_type, Reference(kind_symbol)) if self.is_scalar_array and self._array_ndims >= 1: + # ScalarArray needs to have a number of dimensions + # greater than or equal to one return ArrayType(dts, [self._array_ndims]) return dts From 9c8499dbf418084a66eadaab58a5fa0abf9140ac Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 18 Dec 2025 12:30:44 +0000 Subject: [PATCH 112/122] #1312: change the test codegen to use get_invoke --- .../tests/domain/lfric/lfric_scalar_codegen_test.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index b7e28ed5dd..4b378b6ce8 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -45,6 +45,7 @@ from psyclone.parse.algorithm import parse from psyclone.psyGen import PSyFactory from psyclone.tests.lfric_build import LFRicBuild +from psyclone.tests.utilities import get_invoke # Constants BASE_PATH = os.path.join( @@ -610,10 +611,7 @@ def test_scalar_array(tmpdir): types of valid scalar array argument: 'real', 'integer' and 'logical'. ''' - _, invoke_info = parse(os.path.join(BASE_PATH, - "28.scalar_array_invoke.f90"), - api=TEST_API) - psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) + psy, invoke = get_invoke("28.scalar_array_invoke.f90", TEST_API, idx=0) generated_code = str(psy.gen) expected = ( From 49d89e53dd42eb7c54a1d2d9be0c14853f41d22b Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 18 Dec 2025 12:33:21 +0000 Subject: [PATCH 113/122] #1312: add field related parameters to the testkern --- .../tests/test_files/lfric/testkern_scalar_array_mod.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 index c020537dd2..eafb6a0410 100644 --- a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 +++ b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 @@ -60,10 +60,14 @@ subroutine testkern_scalar_array_code(nlayers, & dims_rarray, real_array, & dims_larray, logical_array, & dims_iarray, integer_array, & - a_scalar) + a_scalar, ndf_w1, undf_w1, & + map_w1) implicit none integer(kind=i_def), intent(in) :: nlayers + integer(kind=i_def), intent(in) :: ndf_w1 + integer(kind=i_def), intent(in) :: undf_w1 + integer(kind=i_def), intent(in), dimension(ndf_w1) :: map_w1 real(kind=r_def), intent(inout) :: afield integer(kind=i_def), intent(in), dimension(2) :: dims_rarray integer(kind=i_def), intent(in), dimension(1) :: dims_larray From 2741a4b5f8adee4b0eaf6c89a7cfaa4913f7ea30 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 15 Jan 2026 17:23:08 +0000 Subject: [PATCH 114/122] #1312: Swap the order of dims_array and ScalarArray declarations --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 658fd91832..317a2c05d7 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -202,6 +202,10 @@ def _create_declarations(self): array_symbol.datatype = ArrayType( type_map[arg.intrinsic_type], sym_list) + # Replace the symbol with itself to ensure + # the ScalarArray is generated after the + # dimensions array to avoid compilation errors + self.symtab.swap(array_symbol,array_symbol) else: # For stub generation, create the symbol array_symbol = self.symtab.find_or_create( From 444d99af85aa40c69b79994bcaff1e942dcfab1d Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 15 Jan 2026 17:28:57 +0000 Subject: [PATCH 115/122] #1312: Update ScalarArray tests to match declaration order --- .../domain/lfric/lfric_scalar_codegen_test.py | 14 +++++++------- .../test_files/lfric/28.scalar_array_invoke.f90 | 10 +++++----- .../lfric/testkern_scalar_array_mod.f90 | 15 +++++++-------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 4b378b6ce8..1ebc574d4d 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -629,20 +629,20 @@ def test_scalar_array(tmpdir): " use testkern_scalar_array_mod, only : " "testkern_scalar_array_code\n" " type(field_type), intent(in) :: afield\n" - " real(kind=r_def), dimension(dims_real_array(1)," - "dims_real_array(2)), intent(in) :: real_array\n" - " logical(kind=l_def), dimension(dims_logical_array(1)), " - "intent(in) :: logical_array\n" - " integer(kind=i_def), dimension(dims_integer_array(1)," - "dims_integer_array(2),dims_integer_array(3),dims_integer_array(4)), " - "intent(in) :: integer_array\n" " integer(kind=i_def), intent(in) :: a_scalar\n" " integer(kind=i_def), dimension(2), intent(in) :: " "dims_real_array\n" + " real(kind=r_def), dimension(dims_real_array(1)," + "dims_real_array(2)), intent(in) :: real_array\n" " integer(kind=i_def), dimension(1), intent(in) :: " "dims_logical_array\n" + " logical(kind=l_def), dimension(dims_logical_array(1)), " + "intent(in) :: logical_array\n" " integer(kind=i_def), dimension(4), intent(in) :: " "dims_integer_array\n" + " integer(kind=i_def), dimension(dims_integer_array(1)," + "dims_integer_array(2),dims_integer_array(3),dims_integer_array(4)), " + "intent(in) :: integer_array\n" " integer(kind=i_def) :: cell\n" " type(mesh_type), pointer :: mesh => null()\n" " integer(kind=i_def) :: max_halo_depth_mesh\n" diff --git a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 index d01dddb0b1..94900c9352 100644 --- a/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 +++ b/src/psyclone/tests/test_files/lfric/28.scalar_array_invoke.f90 @@ -42,11 +42,11 @@ program scalar_array_invoke implicit none - type(field_type) :: afield - real(r_def), dimension(50, 100) :: real_array - logical(l_def), dimension(10) :: logical_array - integer(i_def), dimension(2, 5, 10, 8) :: integer_array - integer(i_def) :: a_scalar + type(field_type) :: afield + real(kind=r_def), dimension(50, 100) :: real_array + logical(kind=l_def), dimension(10) :: logical_array + integer(kind=i_def), dimension(2, 5, 10, 8) :: integer_array + integer(kind=i_def) :: a_scalar call invoke( & testkern_scalar_array_type(afield,real_array,logical_array,integer_array,a_scalar) & diff --git a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 index eafb6a0410..5bf16d0100 100644 --- a/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 +++ b/src/psyclone/tests/test_files/lfric/testkern_scalar_array_mod.f90 @@ -55,8 +55,7 @@ module testkern_scalar_array_mod contains - subroutine testkern_scalar_array_code(nlayers, & - afield, & + subroutine testkern_scalar_array_code(nlayers, afield, & dims_rarray, real_array, & dims_larray, logical_array, & dims_iarray, integer_array, & @@ -65,17 +64,17 @@ subroutine testkern_scalar_array_code(nlayers, & implicit none integer(kind=i_def), intent(in) :: nlayers - integer(kind=i_def), intent(in) :: ndf_w1 - integer(kind=i_def), intent(in) :: undf_w1 - integer(kind=i_def), intent(in), dimension(ndf_w1) :: map_w1 - real(kind=r_def), intent(inout) :: afield integer(kind=i_def), intent(in), dimension(2) :: dims_rarray - integer(kind=i_def), intent(in), dimension(1) :: dims_larray - integer(kind=i_def), intent(in), dimension(4) :: dims_iarray real(kind=r_def), intent(in), dimension(dims_rarray(1),dims_rarray(2)) :: real_array + integer(kind=i_def), intent(in), dimension(1) :: dims_larray logical(kind=l_def), intent(in), dimension(dims_larray(1)) :: logical_array + integer(kind=i_def), intent(in), dimension(4) :: dims_iarray integer(kind=i_def), intent(in), dimension(dims_iarray(1),dims_iarray(2),dims_iarray(3),dims_iarray(4)) :: integer_array integer(kind=i_def), intent(in) :: a_scalar + integer(kind=i_def), intent(in) :: ndf_w1 + integer(kind=i_def), intent(in) :: undf_w1 + real(kind=r_def), intent(inout), dimension(undf_w1) :: afield + integer(kind=i_def), intent(in), dimension(ndf_w1) :: map_w1 end subroutine testkern_scalar_array_code From b2d45535bf8743d1d1b0d28d53c80347a8c1d0c5 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:42:17 +0000 Subject: [PATCH 116/122] #1312: Add GH_SCALAR_ARRAY as an LFRic argument --- .../lfric_infrastructure/src/kernel_metadata/argument_mod.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/external/lfric_infrastructure/src/kernel_metadata/argument_mod.f90 b/external/lfric_infrastructure/src/kernel_metadata/argument_mod.f90 index 134d5a3b78..a5bf654350 100644 --- a/external/lfric_infrastructure/src/kernel_metadata/argument_mod.f90 +++ b/external/lfric_infrastructure/src/kernel_metadata/argument_mod.f90 @@ -60,6 +60,7 @@ module argument_mod integer, public, parameter :: GH_FIELD = 507 integer, public, parameter :: GH_OPERATOR = 735 integer, public, parameter :: GH_COLUMNWISE_OPERATOR = 841 + integer, public, parameter :: GH_SCALAR_ARRAY = 973 !> @} !> @defgroup data_type Enumeration of argument data type property descriptors. From adcdb3779f750ddeacd0fd9ca130b2d1bdf53426 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 16 Jan 2026 10:05:26 +0000 Subject: [PATCH 117/122] #1312: lint fix --- src/psyclone/domain/lfric/lfric_scalar_array_args.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index 317a2c05d7..d8c4fe174f 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -205,7 +205,7 @@ def _create_declarations(self): # Replace the symbol with itself to ensure # the ScalarArray is generated after the # dimensions array to avoid compilation errors - self.symtab.swap(array_symbol,array_symbol) + self.symtab.swap(array_symbol, array_symbol) else: # For stub generation, create the symbol array_symbol = self.symtab.find_or_create( From dd53db7989c1f9f8195ca769eae47caf1a9edb03 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:38:50 +0000 Subject: [PATCH 118/122] #1312: remove TODO and add raise to dcumentation --- src/psyclone/domain/lfric/kern_call_acc_arg_list.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py index 276500ae69..6f1d46dabb 100644 --- a/src/psyclone/domain/lfric/kern_call_acc_arg_list.py +++ b/src/psyclone/domain/lfric/kern_call_acc_arg_list.py @@ -271,10 +271,10 @@ def scalar(self, scalar_arg, var_accesses=None): :type var_accesses: Optional[ :py:class:`psyclone.core.VariablesAccessMap`] + :raises NotImplementedError: OpenACC data regions are not currently + supported for arrays os scalars. + ''' - # TODO: Add implementation of OpenACC data region for ScalarArrays - # If the argument is a simple scalar value then doesn't need values - # added to OpenACC region if scalar_arg.is_scalar_array: raise NotImplementedError( "OpenACC data regions are not currently supported for arrays" From d5315aec0e56809a5cedddc6dcbae6988cd28e86 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:09:20 +0000 Subject: [PATCH 119/122] #1312: Add dist_mem and condense generated code --- .../domain/lfric/lfric_scalar_codegen_test.py | 66 ++++--------------- 1 file changed, 11 insertions(+), 55 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py index 338103419c..821533fd7f 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_codegen_test.py @@ -606,30 +606,21 @@ def test_three_scalars(tmpdir): assert LFRicBuild(tmpdir).code_compiles(psy) -def test_scalar_array(tmpdir): +def test_scalar_array(tmpdir, dist_mem): ''' Tests that we generate correct code when a kernel has all three types of valid scalar array argument: 'real', 'integer' and 'logical'. ''' - psy, invoke = get_invoke("28.scalar_array_invoke.f90", TEST_API, idx=0) + psy, invoke = get_invoke("28.scalar_array_invoke.f90", TEST_API, + dist_mem=dist_mem, idx=0) generated_code = str(psy.gen) - expected = ( - "module scalar_array_invoke_psy\n" - " use constants_mod\n" - " use field_mod, only : field_proxy_type, field_type\n" - " implicit none\n" - " public\n" - "\n" - " contains\n" + expected_subroutine = ( " subroutine invoke_0_testkern_scalar_array_type(afield, " "real_array, logical_array, integer_array, a_scalar, " "dims_real_array, dims_logical_array, dims_integer_array)\n" - " use mesh_mod, only : mesh_type\n" - " use testkern_scalar_array_mod, only : " - "testkern_scalar_array_code\n" - " type(field_type), intent(in) :: afield\n" - " integer(kind=i_def), intent(in) :: a_scalar\n" + ) + expected_declarations = ( " integer(kind=i_def), dimension(2), intent(in) :: " "dims_real_array\n" " real(kind=r_def), dimension(dims_real_array(1)," @@ -643,50 +634,15 @@ def test_scalar_array(tmpdir): " integer(kind=i_def), dimension(dims_integer_array(1)," "dims_integer_array(2),dims_integer_array(3),dims_integer_array(4)), " "intent(in) :: integer_array\n" - " integer(kind=i_def) :: cell\n" - " type(mesh_type), pointer :: mesh => null()\n" - " integer(kind=i_def) :: max_halo_depth_mesh\n" - " real(kind=r_def), pointer, dimension(:) :: afield_data => " - "null()\n" - " integer(kind=i_def) :: nlayers_afield\n" - " integer(kind=i_def) :: ndf_w1\n" - " integer(kind=i_def) :: undf_w1\n" - " integer(kind=i_def), pointer :: map_w1(:,:) => null()\n" - " type(field_proxy_type) :: afield_proxy\n" - " integer(kind=i_def) :: loop0_start\n" - " integer(kind=i_def) :: loop0_stop\n" - "\n" - " ! Initialise field and/or operator proxies\n" - " afield_proxy = afield%get_proxy()\n" - " afield_data => afield_proxy%data\n" - "\n" - " ! Initialise number of layers\n" - " nlayers_afield = afield_proxy%vspace%get_nlayers()\n" - "\n" - " ! Create a mesh object\n" - " mesh => afield_proxy%vspace%get_mesh()\n" - " max_halo_depth_mesh = mesh%get_halo_depth()\n" - "\n" - " ! Look-up dofmaps for each function space\n" - " map_w1 => afield_proxy%vspace%get_whole_dofmap()\n" - "\n" - " ! Initialise number of DoFs for w1\n" - " ndf_w1 = afield_proxy%vspace%get_ndf()\n" - " undf_w1 = afield_proxy%vspace%get_undf()\n" - "\n" - " ! Set-up all of the loop bounds\n" - " loop0_start = 1\n" - " loop0_stop = mesh%get_last_halo_cell(1)\n" - "\n" - " ! Call kernels and communication routines\n" - " if (afield_proxy%is_dirty(depth=1)) then\n" - " call afield_proxy%halo_exchange(depth=1)\n" - " end if\n" + ) + expected_call = ( " do cell = loop0_start, loop0_stop, 1\n" " call testkern_scalar_array_code(nlayers_afield, " "afield_data, dims_real_array, real_array, dims_logical_array, " "logical_array, dims_integer_array, integer_array, a_scalar, " "ndf_w1, undf_w1, map_w1(:,cell))\n" ) - assert expected in generated_code + assert expected_subroutine in generated_code + assert expected_declarations in generated_code + assert expected_call in generated_code assert LFRicBuild(tmpdir).code_compiles(psy) From 9fd41fb89b750a189356e3851dbc82404895d381 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 20 Jan 2026 17:13:57 +0000 Subject: [PATCH 120/122] #1312: refactor stub_declarations and tidy code --- .../domain/lfric/lfric_scalar_array_args.py | 125 ++++++++++-------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_scalar_array_args.py b/src/psyclone/domain/lfric/lfric_scalar_array_args.py index d8c4fe174f..bb3e32caaf 100644 --- a/src/psyclone/domain/lfric/lfric_scalar_array_args.py +++ b/src/psyclone/domain/lfric/lfric_scalar_array_args.py @@ -64,8 +64,8 @@ class LFRicScalarArrayArgs(LFRicCollection): def __init__(self, node: Union[LFRicKern, LFRicInvoke]): super().__init__(node) - # Initialise dictionaries of 'real', 'integer' and 'logical' - # ScalarArray arguments by data type and intent + # Initialise a dictionary keyed by intent ('in', 'out', 'inout') + # with values to be populated with lists of ScalarArray arguments self._scalar_array_args = {} for intent in FORTRAN_INTENT_NAMES: self._scalar_array_args[intent] = [] @@ -128,9 +128,9 @@ def invoke_declarations(self): if scal_multi_type: raise GenerationError( f"ScalarArray argument(s) {scal_multi_type} in Invoke " - f"'{self._invoke.name}' have different metadata for data " - f"type ({list(const.MAPPING_DATA_TYPES.keys())}) in " - f"different kernels. This is invalid.") + f"'{self._invoke.name}' is/are passed to more than one " + f"kernel and the kernel metadata for the corresponding " + f"arguments specifies different intrinsic types.") # Create declarations self._create_declarations() @@ -144,16 +144,16 @@ def stub_declarations(self): ''' super().stub_declarations() + const = LFRicConstants() + type_map = {"real": LFRicTypes("LFRicRealScalarDataType")(), + "integer": LFRicTypes("LFRicIntegerScalarDataType")(), + "logical": LFRicTypes("LFRicLogicalScalarDataType")()} + # Extract all ScalarArray arguments for arg in self.kernel_calls[0].arguments.args: if arg.is_scalar_array: - self._scalar_array_args[arg.intent].append(arg) - - const = LFRicConstants() - # Filter ScalarArray arguments by intent and data type - for intent in FORTRAN_INTENT_NAMES: - for arg in self._scalar_array_args[intent]: - # Distinguish whether they are ScalarArrays + # Check whether the ScalarArrays are of a supported data + # type if (arg.descriptor.data_type not in const.VALID_SCALAR_DATA_TYPES): raise InternalError( @@ -162,9 +162,37 @@ def stub_declarations(self): f"ScalarArray argument '{arg.declaration_name}'" f". Supported types are " f"{const.VALID_SCALAR_DATA_TYPES}.") + self._scalar_array_args[arg.intent].append(arg) # Create declarations - self._create_declarations() + for intent in FORTRAN_INTENT_NAMES: + for arg in self._scalar_array_args[intent]: + if arg._array_ndims >= 1: + # Create the dimensions array symbol + dims_array_symbol = self.symtab.find_or_create( + "dims_" + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_array_symbol) + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, arg._array_ndims + 1)] + # Create the symbol + array_symbol = self.symtab.find_or_create( + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + type_map[arg.intrinsic_type], + sym_list)) + array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(array_symbol) def _create_declarations(self): ''' @@ -174,49 +202,40 @@ def _create_declarations(self): type_map = {"real": LFRicTypes("LFRicRealScalarDataType")(), "integer": LFRicTypes("LFRicIntegerScalarDataType")(), "logical": LFRicTypes("LFRicLogicalScalarDataType")()} + # ScalarArray arguments for intent in FORTRAN_INTENT_NAMES: for arg in self._scalar_array_args[intent]: - if arg.intent in FORTRAN_INTENT_NAMES: - if arg._array_ndims >= 1: - # Create the dimensions array symbol - dims_array_symbol = self.symtab.find_or_create( - "dims_" + arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - LFRicTypes("LFRicIntegerScalarDataType")(), - [arg._array_ndims])) - dims_array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(dims_array_symbol) - # Create list of dims_array references - sym_list = [ArrayReference.create( - dims_array_symbol, - [Literal(str(idx), INTEGER_TYPE)]) - for idx in range(1, arg._array_ndims + 1)] - if not self._kernel: - # For code generation, find ScalarArray tag - # and convert it to an ArrayType - array_symbol = self.symtab.lookup_with_tag( - "AlgArgs_" + arg.name) - array_symbol.datatype = ArrayType( - type_map[arg.intrinsic_type], - sym_list) - # Replace the symbol with itself to ensure - # the ScalarArray is generated after the - # dimensions array to avoid compilation errors - self.symtab.swap(array_symbol, array_symbol) - else: - # For stub generation, create the symbol - array_symbol = self.symtab.find_or_create( - arg.name, - symbol_type=DataSymbol, - datatype=ArrayType( - type_map[arg.intrinsic_type], - sym_list)) - array_symbol.interface = ArgumentInterface( - INTENT_MAPPING[intent]) - self.symtab.append_argument(array_symbol) + if arg._array_ndims >= 1: + # Create the dimensions array symbol + dims_array_symbol = self.symtab.find_or_create( + "dims_" + arg.name, + symbol_type=DataSymbol, + datatype=ArrayType( + LFRicTypes("LFRicIntegerScalarDataType")(), + [arg._array_ndims])) + dims_array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(dims_array_symbol) + # Create list of dims_array references + sym_list = [ArrayReference.create( + dims_array_symbol, + [Literal(str(idx), INTEGER_TYPE)]) + for idx in range(1, arg._array_ndims + 1)] + # Find the ScalarArray tag and convert it to an ArrayType + array_symbol = self.symtab.lookup_with_tag( + "AlgArgs_" + arg.name) + array_symbol.datatype = ArrayType( + type_map[arg.intrinsic_type], + sym_list) + # Replace the symbol with itself to ensure + # the ScalarArray is generated after the + # dimensions array to avoid compilation errors + # TODO: #2202 may allow this to be removed + self.symtab.swap(array_symbol, array_symbol) + array_symbol.interface = ArgumentInterface( + INTENT_MAPPING[intent]) + self.symtab.append_argument(array_symbol) # ---------- Documentation utils -------------------------------------------- # From 172466d57c005ebc8c77ed99a0e1df7d29aa0e69 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:38:25 +0000 Subject: [PATCH 121/122] #1312: fix metadata test to match change in lfric_scalar_array_args --- src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py index 24872e7d91..8ad04b46bf 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py @@ -555,6 +555,6 @@ def test_scalar_array_different_data_types_invoke(): with pytest.raises(GenerationError) as excinfo: _ = psy.gen assert (f"ScalarArray argument(s) ['b'] in Invoke " - f"'invoke_real_and_logical_scalars' have different metadata for " - f"data type ({const.VALID_SCALAR_DATA_TYPES}) in different " - f"kernels. This is invalid." in str(excinfo.value)) + f"'invoke_real_and_logical_scalars' is/are passed to more than " + f"one kernel and the kernel metadata for the corresponding " + f"arguments specifies different intrinsic types.") From c4a4cdef9d542ccedd79209c66528dbaf4c0ce73 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:41:15 +0000 Subject: [PATCH 122/122] #1312: remove unnecessary variables for lint fix --- .../tests/domain/lfric/lfric_scalar_mdata_test.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py index 8ad04b46bf..934e210509 100644 --- a/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_scalar_mdata_test.py @@ -551,10 +551,9 @@ def test_scalar_array_different_data_types_invoke(): api=TEST_API) psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) - const = LFRicConstants() - with pytest.raises(GenerationError) as excinfo: + with pytest.raises(GenerationError): _ = psy.gen - assert (f"ScalarArray argument(s) ['b'] in Invoke " - f"'invoke_real_and_logical_scalars' is/are passed to more than " - f"one kernel and the kernel metadata for the corresponding " - f"arguments specifies different intrinsic types.") + assert ("ScalarArray argument(s) ['b'] in Invoke " + "'invoke_real_and_logical_scalars' is/are passed to more than " + "one kernel and the kernel metadata for the corresponding " + "arguments specifies different intrinsic types.")