From a9f4f6f352fa13b626f23faf39f22cf28aee9003 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 12 Jun 2023 15:24:52 +0100 Subject: [PATCH 001/119] #1312: starting on adding the metadata for arrays --- .../domain/lfric/lfric_arg_descriptor.py | 141 +++++++++++++++++- src/psyclone/domain/lfric/lfric_constants.py | 7 +- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index af4cf95a4b..4308b71f68 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2017-2022, Science and Technology Facilities Council. +# Copyright (c) 2017-2023, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Authors R. W. Ford, A. R. Porter, S. Siso and N. Nobre, STFC Daresbury Lab -# Modified I. Kavcic and A. Coughtrie, Met Office +# Modified I. Kavcic, A. Coughtrie and L. Turner, Met Office # Modified by J. Henrichs, Bureau of Meteorology ''' @@ -102,6 +102,7 @@ def __init__(self, arg_type, operates_on, metadata_index): self._function_spaces = [] # Set vector size to 1 (scalars set it to 0 in their validation) self._vector_size = 1 + self._array_size = 1 # Initialise other internal arguments self._access_type = None self._function_space1 = None @@ -270,6 +271,63 @@ def _validate_vector_size(self, separator, arg_type): f"{const.VALID_FIELD_NAMES} argument types but found " f"'{arg_type.args[0]}'.") + def _validate_array_size(self, separator, arg_type): + ''' + Validates descriptors for scalar array arguments and populates + vector properties accordingly. + + :param str separator: operator in a binary expression. + :param arg_type: LFRic API array argument type. + :type arg_type: :py:class:`psyclone.expression.FunctionVar` + + :raises ParseError: if the array notation does not use \ + the '*' operator. + :raises ParseError: if the array notation is not in the \ + correct format '(NRANKS*n)' where 'n' is \ + an integer. + :raises ParseError: if the array notation is used for the \ + array size of less than 1. + :raises ParseError: if the array notation is used for an \ + argument that is not an array. + + ''' + # Check that the operator is correct + if separator != "*": + raise ParseError( + f"In the LFRic API the 1st argument of a 'meta_arg' " + f"entry may be an array but if so must use '*' as " + f"the separator in the format 'NRANKS*n', but found " + f"'{separator}' in '{arg_type}'.") + + # Now try to find the array size for a scalar array and return + # an error if it is not an integer number... + try: + arraysize = int(arg_type.args[0].toks[2]) + except TypeError as err: + raise ParseError( + f"In the LFRic API, the array notation must be in the " + f"format 'NRANKS*n' where 'n' is an integer, but the following " + f"'{arg_type.args[0].toks[2]}' was found in " + f"'{arg_type}'.") from err + + # ... or it is less than 1 (1 is the default for all fields)... + const = LFRicConstants() + if arraysize < 1: + raise ParseError( + f"In the LFRic API the 1st argument of a 'meta_arg' entry may " + f"be a field vector with format 'NRANKS*n' where n is an " + f"integer >= 1. However, found n = {vectsize} in '{arg_type}'.") + # ... and set the array size if all checks pass + self._array_size = arraysize + + # Check that no other arguments than fields use array notation + if self._argument_type not in \ + const.VALID_FIELD_NAMES and self._array_size: + raise ParseError( + f"In the LFRic API, array notation is only supported for " + f"{const.VALID_FIELD_NAMES} argument types but found " + f"'{arg_type.args[0]}'.") + def _init_field(self, arg_type, operates_on): ''' Validates metadata descriptors for field arguments and @@ -599,7 +657,71 @@ def _init_scalar(self, arg_type): f"with a real scalar argument, but a scalar argument with " f"'{self._data_type}' data type was found in '{arg_type}'.") - # Scalars don't have vector size + # Scalars don't have vector size or array size + self._vector_size = 0 + self._array_size = 0 + + def _init_array(self, arg_type): + ''' + Validates metadata descriptors for scalar array arguments and + initialises scalar array argument properties accordingly. + + :param arg_type: LFRic API scalar array argument type. + :type arg_type: :py:class:`psyclone.expression.FunctionVar` + + :raises InternalError: if argument type other than an array is \ + passed in. + :raises ParseError: if there are not exactly 4 metadata arguments. + :raises InternalError: if an array argument has an invalid data type. + :raises ParseError: if array arguments do not have read-only access. + :raises ParseError: if a scalar argument that is not a real \ + scalar has a reduction access. + + ''' + const = LFRicConstants() + # Check whether something other than a scalar is passed in + if self._argument_type not in const.VALID_ARRAY_NAMES: + raise InternalError( + f"Expected a scalar argument but got an argument of type " + f"'{arg_type.args[0]}'.") + + # There must be 4 argument descriptors to describe a scalar array. + nargs_array = 4 + if self._nargs != nargs_array: + raise ParseError( + f"In the LFRic API each 'meta_arg' entry must have " + f"{nargs_array} arguments if its first argument is " + f"'gh_array', but found {self._nargs} in '{arg_type}'.") + + # Check whether an invalid data type for a scalar argument is passed + # in. Valid data types for scalars are valid data types in LFRic API. + if self._data_type not in const.VALID_ARRAY_DATA_TYPES: + raise InternalError( + f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " + f"scalar data type but got '{self._data_type}'.") + + # Test allowed accesses for arrays (read_only) + array_accesses = [AccessType.READ] + # Convert generic access types to GH_* names for error messages + api_config = Config.get().api_conf(API) + rev_access_mapping = api_config.get_reverse_access_mapping() + if self._access_type not in array_accesses: + api_specific_name = rev_access_mapping[self._access_type] + valid_reductions = AccessType.get_valid_reduction_names() + raise ParseError( + f"In the LFRic API array arguments must have read-only " + f"('gh_read') access but found '{api_specific_name}' " + f"in '{arg_type}'.") + # Reduction access is currently only valid for real scalar arguments + if self._data_type != "gh_real" and self._access_type in \ + AccessType.get_valid_reduction_modes(): + raise ParseError( + f"In the LFRic API a reduction access " + f"'{self._access_type.api_specific_name()}' is only valid " + f"with a real scalar argument, but a scalar argument with " + f"'{self._data_type}' data type was found in '{arg_type}'.") + + # Arrays don't have vector size self._vector_size = 0 @property @@ -713,6 +835,19 @@ def vector_size(self): ''' return self._vector_size + @property + def array_size(self): + ''' + Returns the array size of the argument. This will be 1 if ``*n`` + has not been specified for all argument types except scalars + (their array size is set to 0). + + :returns: array size of the argument. + :rtype: int + + ''' + return self._array_size + def __str__(self): ''' Creates a string representation of the argument descriptor. This diff --git a/src/psyclone/domain/lfric/lfric_constants.py b/src/psyclone/domain/lfric/lfric_constants.py index ad337f6419..45a1436e6a 100644 --- a/src/psyclone/domain/lfric/lfric_constants.py +++ b/src/psyclone/domain/lfric/lfric_constants.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author: J. Henrichs, Bureau of Meteorology -# Modified: I. Kavcic, Met Office +# Modified: I. Kavcic and L, Turner, Met Office # A. R. Porter, STFC Daresbury Laboratory # R. W. Ford, STFC Daresbury Laboratory @@ -78,12 +78,14 @@ def __init__(self): # Supported LFRic API argument types (scalars, fields, operators) LFRicConstants.VALID_SCALAR_NAMES = ["gh_scalar"] + LFRicConstants.VALID_ARRAY_NAMES = ["gh_array"] LFRicConstants.VALID_FIELD_NAMES = ["gh_field"] LFRicConstants.VALID_OPERATOR_NAMES = ["gh_operator", "gh_columnwise_operator"] LFRicConstants.VALID_ARG_TYPE_NAMES = \ LFRicConstants.VALID_FIELD_NAMES + \ LFRicConstants.VALID_OPERATOR_NAMES + \ + LFRicConstants.VALID_ARRAY_NAMES + \ LFRicConstants.VALID_SCALAR_NAMES # Supported API argument data types ('gh_real', 'gh_integer' @@ -92,6 +94,8 @@ def __init__(self): ["gh_real", "gh_integer", "gh_logical"] LFRicConstants.VALID_SCALAR_DATA_TYPES = \ LFRicConstants.VALID_ARG_DATA_TYPES + LFRicConstants.VALID_ARRAY_DATA_TYPES = \ + LFRicConstants.VALID_ARG_DATA_TYPES LFRicConstants.VALID_FIELD_DATA_TYPES = ["gh_real", "gh_integer"] LFRicConstants.VALID_OPERATOR_DATA_TYPES = ["gh_real"] @@ -100,6 +104,7 @@ def __init__(self): # Supported access types # gh_sum for scalars is restricted to iterates_over == 'dof' LFRicConstants.VALID_SCALAR_ACCESS_TYPES = ["gh_read", "gh_sum"] + LFRicConstants.VALID_ARRAY_ACCESS_TYPES = ["gh_read"] LFRicConstants.VALID_FIELD_ACCESS_TYPES = [ "gh_read", "gh_write", "gh_readwrite", "gh_inc", "gh_readinc"] LFRicConstants.VALID_OPERATOR_ACCESS_TYPES = [ From 721e7eb8352cb1b09d9c94c14c1030501a3cdb3b Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 12 Jun 2023 15:38:54 +0100 Subject: [PATCH 002/119] #1312 missed a name change oops --- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 4308b71f68..2ee2e7edd5 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -316,7 +316,7 @@ def _validate_array_size(self, separator, arg_type): raise ParseError( f"In the LFRic API the 1st argument of a 'meta_arg' entry may " f"be a field vector with format 'NRANKS*n' where n is an " - f"integer >= 1. However, found n = {vectsize} in '{arg_type}'.") + f"integer >= 1. However, found n = {arraysize} in '{arg_type}'.") # ... and set the array size if all checks pass self._array_size = arraysize From 694dd102bb83add1cce24d95b3a7ad860aedaa42 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 12 Jun 2023 15:55:14 +0100 Subject: [PATCH 003/119] #1312 list in test file needed to be updated --- src/psyclone/tests/domain/constants_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/psyclone/tests/domain/constants_test.py b/src/psyclone/tests/domain/constants_test.py index 9c0c794960..dc6baa929d 100644 --- a/src/psyclone/tests/domain/constants_test.py +++ b/src/psyclone/tests/domain/constants_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2021-2022, Science and Technology Facilities Council. +# Copyright (c) 2021-2023, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ---------------------------------------------------------------------------- # Author: J. Henrichs, Bureau of Meteorology -# Modified: I. Kavcic, Met Office +# Modified: I. Kavcic and L. Turner, Met Office # Modified: R. W. Ford, STFC Daresbury Lab @@ -57,7 +57,7 @@ def test_lfric_const(): # Don't test intrinsic_types, which comes from the config file assert lfric_const.VALID_ARG_TYPE_NAMES == ["gh_field", "gh_operator", "gh_columnwise_operator", - "gh_scalar"] + "gh_array", "gh_scalar"] assert lfric_const.VALID_SCALAR_NAMES == ["gh_scalar"] @@ -69,7 +69,7 @@ def test_lfric_const(): assert lfric_const.VALID_INTRINSIC_TYPES == "INVALID" assert lfric_const.VALID_ARG_TYPE_NAMES == ["gh_field", "gh_operator", "gh_columnwise_operator", - "gh_scalar"] + "gh_array", "gh_scalar"] assert lfric_const.VALID_SCALAR_NAMES == ["gh_scalar"] assert lfric_const.VALID_ARG_DATA_TYPES == ["gh_real", "gh_integer", "gh_logical"] From f866583463f8d27c607c4b37869e7d06e5a8e9ae Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 14 Jun 2023 17:04:55 +0100 Subject: [PATCH 004/119] #1312 adding tests, some not yet working --- .../domain/lfric/lfric_arg_descriptor.py | 48 +- .../domain/lfric/lfric_array_mdata_test.py | 565 ++++++++++++++++++ 2 files changed, 604 insertions(+), 9 deletions(-) create mode 100644 src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 2ee2e7edd5..a4b97499dc 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -202,6 +202,10 @@ def __init__(self, arg_type, operates_on, metadata_index): # Validate scalar arguments self._init_scalar(arg_type) + elif self._argument_type in const.VALID_ARRAY_NAMES: + # Validate array arguments + self._init_array(arg_type) + else: # We should never get to here if the checks are tight enough raise InternalError( @@ -682,23 +686,32 @@ def _init_array(self, arg_type): # Check whether something other than a scalar is passed in if self._argument_type not in const.VALID_ARRAY_NAMES: raise InternalError( - f"Expected a scalar argument but got an argument of type " + f"Expected an array argument but got an argument of type " f"'{arg_type.args[0]}'.") - # There must be 4 argument descriptors to describe a scalar array. - nargs_array = 4 - if self._nargs != nargs_array: + # There must be at least 4 arguments + nargs_array_min = 4 + if self._nargs < nargs_array_min: raise ParseError( - f"In the LFRic API each 'meta_arg' entry must have " - f"{nargs_array} arguments if its first argument is " - f"'gh_array', but found {self._nargs} in '{arg_type}'.") + "In the LFRic API each 'meta_arg' entry must have at least " + f"{nargs_array_min} arguments if its first argument is of " + f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " + f"'{arg_type}'.") + # There must be at most 5 arguments + nargs_array_max = 5 + if self._nargs > nargs_array_max: + raise ParseError( + f"In the LFRic API each 'meta_arg' entry must have at most " + f"{nargs_array_max} arguments if its first argument is of " + f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " + f"'{arg_type}'.") # Check whether an invalid data type for a scalar argument is passed # in. Valid data types for scalars are valid data types in LFRic API. if self._data_type not in const.VALID_ARRAY_DATA_TYPES: raise InternalError( f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " - f"scalar data type but got '{self._data_type}'.") + f"array data type but got '{self._data_type}'.") # Test allowed accesses for arrays (read_only) array_accesses = [AccessType.READ] @@ -720,7 +733,17 @@ def _init_array(self, arg_type): f"'{self._access_type.api_specific_name()}' is only valid " f"with a real scalar argument, but a scalar argument with " f"'{self._data_type}' data type was found in '{arg_type}'.") - + # The 4th argument must be a valid function-space name + prop_ind = 3 + if arg_type.args[prop_ind].name not in \ + const.VALID_FUNCTION_SPACE_NAMES: + raise ParseError( + f"In the LFRic API argument {prop_ind+1} of a 'meta_arg' " + f"array entry must be a valid function-space name (one of " + f"{const.VALID_FUNCTION_SPACE_NAMES}) if its first argument " + f"is of {const.VALID_ARRAY_NAMES} type, but found " + f"'{arg_type.args[prop_ind].name}' in '{arg_type}'.") + self._function_space1 = arg_type.args[prop_ind].name # Arrays don't have vector size self._vector_size = 0 @@ -792,6 +815,8 @@ def function_space(self): return self._function_space1 if self._argument_type in const.VALID_OPERATOR_NAMES: return self._function_space2 + if self._argument_type in const.VALID_ARRAY_NAMES: + return self._function_space1 if self._argument_type in const.VALID_SCALAR_NAMES: return None raise InternalError(f"Expected a valid argument type but got " @@ -817,6 +842,8 @@ def function_spaces(self): if self._argument_type in const.VALID_OPERATOR_NAMES: # Return to before from to maintain expected ordering return [self.function_space_to, self.function_space_from] + if self._argument_type in const.VALID_ARRAY_NAMES: + return [self.function_space] if self._argument_type in const.VALID_SCALAR_NAMES: return [] raise InternalError(f"Expected a valid argument type but got " @@ -873,6 +900,9 @@ def __str__(self): if self._argument_type in const.VALID_FIELD_NAMES: res += (f" function_space[3]='{self._function_space1}'" + os.linesep) + elif self._argument_type in const.VALID_ARRAY_NAMES: + res += (f" function_space[3]='{self._function_space1}'" + + os.linesep) elif self._argument_type in const.VALID_OPERATOR_NAMES: res += (f" function_space_to[3]='{self._function_space1}'" + os.linesep) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py new file mode 100644 index 0000000000..d56ce0694e --- /dev/null +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -0,0 +1,565 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2017-2023, 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, S. Siso and N. Nobre, STFC Daresbury Lab; +# I. Kavcic, A. Coughtrie and L. Turner, Met Office; +# C. M. Maynard, Met Office/University of Reading; +# J. Henrichs, Bureau of Meteorology. + +''' +Module containing pytest tests for the general LFRic array arguments +functionality (e.g. metadata, parsing, invoke calls). +''' + +import os +import pytest +import fparser +from fparser import api as fpapi +from psyclone.domain.lfric import LFRicArgDescriptor +from psyclone.dynamo0p3 import (DynKern, DynKernMetadata, + LFRicScalarArgs, LFRicConstants) +from psyclone.errors import InternalError, GenerationError +from psyclone.f2pygen import ModuleGen +from psyclone.parse.algorithm import parse +from psyclone.parse.utils import ParseError +from psyclone.psyGen import FORTRAN_INTENT_NAMES, PSyFactory + +# Constants +BASE_PATH = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname( + os.path.abspath(__file__)))), + "test_files", "dynamo0p3") +TEST_API = "dynamo0.3" + + +ARRAY_CODE = ''' +module testkern_mod + + type, extends(kernel_type) :: testkern_array_type + type(arg_type), meta_args(5) = & + (/ arg_type(gh_array, gh_real, gh_read, NRANKS*1), & + arg_type(gh_array, gh_integer, gh_read, NRANKS*2), & + arg_type(gh_array, gh_logical, gh_read, NRANKS*4), & + arg_type(gh_operator, gh_real, gh_read, w2, w2), & + arg_type(gh_field, gh_real, gh_write, w3) & + /) + integer :: operates_on = cell_column + contains + procedure, nopass :: code => testkern_code + end type testkern_array_type +contains + subroutine testkern_code(a, b, c, d) + end subroutine testkern_code +end module testkern_mod +''' + + +def test_ad_array_init_wrong_argument_type(): + ''' Test that an error is raised if something other than an array + is passed to the LFRicArgDescriptor._init_array() method. ''' + ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) + name = "testkern_array_type" + metadata = DynKernMetadata(ast, name=name) + # Get an argument which is not an array + wrong_arg = metadata._inits[3] + with pytest.raises(InternalError) as excinfo: + LFRicArgDescriptor( + wrong_arg, metadata.iterates_over, 0)._init_array(wrong_arg) + assert ("Expected an array argument but got an argument of type " + "'gh_operator'." in str(excinfo.value)) + + +def test_ad_array_type_too_few_args(): + ''' Tests that an error is raised when the array argument descriptor + metadata for an array has fewer than 3 args. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_read)", 1) + ast = fpapi.parse(code, ignore_comments=False) + name = "testkern_array_type" + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("each 'meta_arg' entry must have at least 4 arguments if its " + "first argument is of ['gh_array'] type" in str(excinfo.value)) + + +def test_ad_array_type_too_many_args(): + ''' Tests that an error is raised when the field argument descriptor + metadata has more than 4 args. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_read, w1, w1, w2)", 1) + ast = fpapi.parse(code, ignore_comments=False) + name = "testkern_array_type" + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("each 'meta_arg' entry must have at most 5 arguments if its " + "first argument is of ['gh_array'] type" in str(excinfo.value)) + + +def test_ad_array_invalid_data_type(): + ''' Tests that an error is raised when the argument descriptor + metadata for a scalar has an invalid data type. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + # check real array + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_unreal, gh_read, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + const = LFRicConstants() + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " + f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " + f"but found 'gh_unreal' in 'arg_type(gh_array, gh_unreal, " + f"gh_read, nranks * 1)'." in str(excinfo.value)) + # check integer array + code = ARRAY_CODE.replace("arg_type(gh_array, gh_integer, gh_read, NRANKS*2)", + "arg_type(gh_array, gh_frac, gh_read, NRANKS*2)", 1) + ast = fpapi.parse(code, ignore_comments=False) + const = LFRicConstants() + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " + f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " + f"but found 'gh_frac' in 'arg_type(gh_array, gh_frac, " + f"gh_read, nranks * 2)'." in str(excinfo.value)) + # check logical array + code = ARRAY_CODE.replace("arg_type(gh_array, gh_logical, gh_read, NRANKS*4)", + "arg_type(gh_array, gh_illogical, gh_read, NRANKS*4)", 1) + ast = fpapi.parse(code, ignore_comments=False) + const = LFRicConstants() + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " + f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " + f"but found 'gh_illogical' in 'arg_type(gh_array, gh_illogical, " + f"gh_read, nranks * 4)'." in str(excinfo.value)) + + +def test_ad_array_init_wrong_data_type(monkeypatch): + ''' Test that an error is raised if an invalid data type + is passed to the LFRicArgDescriptor._init_array() method. ''' + ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) + name = "testkern_array_type" + metadata = DynKernMetadata(ast, name=name) + # Get an array argument descriptor and set a wrong data type + scalar_arg = metadata._inits[0] + scalar_arg.args[1].name = "gh_double" + const = LFRicConstants() + # Now try to trip the error by making the initial test think + # that 'gh_double' is actually a valid data type + monkeypatch.setattr( + target=LFRicConstants, name="VALID_ARG_DATA_TYPES", + value=LFRicConstants.VALID_ARG_DATA_TYPES + ["gh_double"]) + with pytest.raises(InternalError) as excinfo: + LFRicArgDescriptor( + scalar_arg, metadata.iterates_over, 0)._init_scalar(scalar_arg) + assert (f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the array " + f"data type but got 'gh_double'." in str(excinfo.value)) + + +def test_ad_array_type_no_write(): + ''' Tests that an error is raised when the argument descriptor + metadata for a scalar specifies 'GH_WRITE' access. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_write, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_write'" in str(excinfo.value)) + + +def test_ad_array_type_no_inc(): + ''' Tests that an error is raised when the argument descriptor + metadata for a scalar specifies 'GH_INC' access. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_inc, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_inc'" in str(excinfo.value)) + + +def test_ad_array_type_no_readwrite(): + ''' Tests that an error is raised when the argument descriptor + metadata for an array specifies 'GH_READWRITE' access. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_readwrite, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_readwrite'" in str(excinfo.value)) + + +def test_ad_array_type_no_sum(): + ''' Tests that an error is raised when the argument descriptor + metadata for an array specifies 'GH_SUM' access (reduction). ''' + fparser.logging.disable(fparser.logging.CRITICAL) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_sum, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + name = "testkern_array_type" + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_sum'" in str(excinfo.value)) + + +def test_no_vector_array(): + ''' Tests that we raise an error when kernel metadata erroneously + specifies a vector scalar argument. ''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array*3, gh_real, gh_read, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert (f"vector notation is only supported for ['gh_field'] argument " + f"types but found 'gh_array * 3'" in str(excinfo.value)) + +# here be dragons (ignore test below) + +@pytest.mark.parametrize("array_ind, array_type, array_ranks", [ + (0, "gh_real", "nranks*1"), (1, "gh_integer", "nranks*2"), (2, "gh_logical", "nranks*4")]) +def test_arg_descriptor_array(array_ind, array_type, array_ranks): + ''' Test that the LFRicArgDescriptor argument representation works + as expected for all three types of valid array argument: + 'real', 'integer' and 'logical'. + + ''' + fparser.logging.disable(fparser.logging.CRITICAL) + ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) + metadata = DynKernMetadata(ast, name="testkern_array_type") + array_descriptor = metadata.arg_descriptors[array_ind] + + # Assert correct string representation from LFRicArgDescriptor + result = str(array_descriptor) + expected_output = ( + f"LFRicArgDescriptor object\n" + f" argument_type[0]='gh_array'\n" + f" data_type[1]='{array_type}'\n" + f" access_descriptor[2]='gh_read'\n" + f" function_space[3]='{array_ranks}'") + assert expected_output in result + + # Check LFRicArgDescriptor argument properties + assert array_descriptor.argument_type == "gh_array" + assert array_descriptor.data_type == array_type + assert array_descriptor.function_space == array_ranks + assert array_descriptor.function_spaces == [{array_ranks}] + assert str(array_descriptor.access) == "READ" + assert array_descriptor.mesh is None + assert array_descriptor.stencil is None + assert array_descriptor.vector_size == 0 + +# here be dragons (below) (LFRicScalarArgs) + +def test_lfricarrays_call_err1(): + ''' Check that the LFRicScalarArgs constructor raises the expected + internal error if it encounters an unrecognised intrinsic type of + scalar when generating a kernel call. + + ''' + _, invoke_info = parse( + os.path.join(BASE_PATH, + "1.7_single_invoke_3scalar.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 + array_arg = kernel.arguments.args[0] + array_arg._intrinsic_type = "double-type" + with pytest.raises(InternalError) as err: + LFRicScalarArgs(invoke)._invoke_declarations(ModuleGen(name="my_mod")) + assert ("Found unsupported intrinsic types for the scalar arguments " + "['a'] to Invoke 'invoke_0_testkern_three_scalars_type'. " + "Supported types are ['real', 'integer', 'logical']." + in str(err.value)) + +# here be dragons (below) (LFRicScalarArgs) + +def test_lfricscalars_call_err2(): + '''Check that LFRicScalarArgs _create_declarations method raises the + expected internal errors for real, integer and logical scalars if + neither invoke nor kernel is set. + + ''' + _, invoke_info = parse( + os.path.join(BASE_PATH, + "1.7_single_invoke_3scalar.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) + invoke = psy.invokes.invoke_list[0] + scalar_args = LFRicScalarArgs(invoke) + node = ModuleGen("prog") + # Set up information that _create_declarations requires. Note, + # this method also calls _create_declarations. + scalar_args._invoke_declarations(node) + + # Sabotage code so that a call to _create declarations raises the + # required exceptions. + scalar_args._invoke = None + + # The first exception comes from real scalars. + with pytest.raises(InternalError) as error: + scalar_args._create_declarations(node) + assert ("Expected the declaration of real scalar kernel arguments to be " + "for either an invoke or a kernel stub, but it is neither." + in str(error.value)) + + # Remove real scalars so we get the exception for integer scalars. + for intent in FORTRAN_INTENT_NAMES: + scalar_args._real_scalars[intent] = None + with pytest.raises(InternalError) as error: + scalar_args._create_declarations(node) + assert ("Expected the declaration of integer scalar kernel arguments to " + "be for either an invoke or a kernel stub, but it is neither." + in str(error.value)) + + # Remove integer scalars so we get the exception for logical scalars. + for intent in FORTRAN_INTENT_NAMES: + scalar_args._integer_scalars[intent] = None + with pytest.raises(InternalError) as error: + scalar_args._create_declarations(node) + assert ("Expected the declaration of logical scalar kernel arguments to " + "be for either an invoke or a kernel stub, but it is neither." + in str(error.value)) + +# here be dragons (below) (LFRicScalarArgs) + +def test_lfricscalarargs_mp(): + '''Check that the precision of a new scalar integer datatype is + declared in the psy-layer. + + ''' + _, invoke_info = parse( + os.path.join(BASE_PATH, + "1.6.4_scalar_mixed_prec.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) + code = str(psy.gen) + assert "USE constants_mod, ONLY: roo_def, i_def" in code + +# here be sea monsters (below) (working point) + +def test_lfricinvoke_uniq_declns_intent_array(): + ''' Tests that LFRicInvoke.unique_declns_by_intent() returns the correct + list of arguments for 'gh_array' argument type. ''' + _, invoke_info = parse(os.path.join(BASE_PATH, + "1.7_single_invoke_3scalar.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) + + # Test 'real' array arguments + real_args = psy.invokes.invoke_list[0].unique_declns_by_intent( + ["gh_array"], intrinsic_type="real") + assert real_args['inout'] == [] + assert real_args['out'] == [] + assert real_args['in'] == [] + + # Test 'integer' array arguments + integer_args = psy.invokes.invoke_list[0].unique_declns_by_intent( + ["gh_array"], intrinsic_type="integer") + assert integer_args['inout'] == [] + assert integer_args['out'] == [] + assert integer_args['in'] == [] + + # Test 'logical' array arguments + logical_args = psy.invokes.invoke_list[0].unique_declns_by_intent( + ["gh_array"], intrinsic_type="logical") + assert logical_args['inout'] == [] + assert logical_args['out'] == [] + assert logical_args['in'] == [] + + +def test_array_invoke_uniq_declns_valid_intrinsic(): + ''' Tests that all valid intrinsic types for user-defined scalar + arguments ('real', 'integer' and 'logical') are accepted by + Invoke.unique_declarations(). + + ''' + _, invoke_info = parse(os.path.join(BASE_PATH, + "1.7_single_invoke_3scalar.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) + invoke = psy.invokes.invoke_list[0] + + # Test 'real' scalars + const = LFRicConstants() + arrays_real_args = invoke.unique_declarations( + const.VALID_ARRAY_NAMES, intrinsic_type="real") + arrays_real = [arg.declaration_name for arg in arrays_real_args] + assert arrays_real == ["a"] + + # Test 'integer' scalars + arrays_integer_args = invoke.unique_declarations( + const.VALID_ARRAY_NAMES, intrinsic_type="integer") + arrays_integer = [arg.declaration_name for arg in arrays_integer_args] + assert arrays_integer == ["istep"] + + # Test 'logical' scalars + arrays_logical_args = invoke.unique_declarations( + const.VALID_ARRAY_NAMES, intrinsic_type="logical") + arrays_logical = [arg.declaration_name for arg in arrays_logical_args] + assert arrays_logical == ["lswitch"] + + +def test_scalar_arg_lfricconst_properties(monkeypatch): + ''' Tests that properties of all supported types of user-defined, + read-only, scalar arguments ('real', 'integer' and 'logical') defined + in LFRicConstants are correctly set up in the DynKernelArgument class. + + ''' + fparser.logging.disable(fparser.logging.CRITICAL) + ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) + name = "testkern_array_type" + metadata = DynKernMetadata(ast, name=name) + kernel = DynKern() + kernel.load_meta(metadata) + + # Test 'real' scalars + scalar_arg = kernel.arguments.args[0] + assert scalar_arg.module_name is None + assert scalar_arg.data_type is None + assert scalar_arg.proxy_data_type is None + assert scalar_arg.intrinsic_type == "real" + assert scalar_arg.precision == "r_def" + + # Test 'integer' scalars + scalar_arg = kernel.arguments.args[6] + assert scalar_arg.module_name is None + assert scalar_arg.data_type is None + assert scalar_arg.proxy_data_type is None + assert scalar_arg.intrinsic_type == "integer" + assert scalar_arg.precision == "i_def" + + # Test 'logical' scalars + scalar_arg = kernel.arguments.args[5] + assert scalar_arg.module_name is None + assert scalar_arg.data_type is None + assert scalar_arg.proxy_data_type is None + assert scalar_arg.intrinsic_type == "logical" + assert scalar_arg.precision == "l_def" + + # Monkeypatch to check with an invalid intrinsic type of a + # scalar argument + const = LFRicConstants() + monkeypatch.setattr(scalar_arg, "_intrinsic_type", "tabby") + with pytest.raises(InternalError) as err: + scalar_arg._init_data_type_properties(None) + assert (f"Expected one of {const.VALID_INTRINSIC_TYPES} intrinsic types " + f"for a scalar argument but found 'tabby' in the metadata of " + f"kernel testkern_qr_code for argument lscalar_6." + in str(err.value)) + + +def test_scalar_reduction_lfricconst_properties(): + ''' Tests that properties of 'real' scalar reduction arguments defined + in LFRicConstants are correctly set up in the DynKernelArgument class. + + ''' + _, invoke_info = parse( + os.path.join(BASE_PATH, "15.9.1_X_innerproduct_Y_builtin.f90"), + api=TEST_API) + psy = PSyFactory(TEST_API, + distributed_memory=True).create(invoke_info) + schedule = psy.invokes.invoke_list[0].schedule + kernel = schedule.kernels()[0] + reduction_arg = kernel.arguments.args[0] + + assert reduction_arg.module_name == "scalar_mod" + assert reduction_arg.data_type == "scalar_type" + assert reduction_arg.proxy_data_type is None + assert reduction_arg.intrinsic_type == "real" + assert reduction_arg.precision == "r_def" + + +def test_multiple_updated_scalar_args(): + ''' Check that we raise the expected exception when we encounter a + kernel that writes to more than one of its field and scalar arguments ''' + fparser.logging.disable(fparser.logging.CRITICAL) + code = ARRAY_CODE.replace("arg_type(gh_scalar, gh_real, gh_read)", + "arg_type(gh_scalar, gh_real, gh_sum)", 1) + ast = fpapi.parse(code, ignore_comments=False) + name = "testkern_array_type" + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("A user-supplied LFRic kernel must not write/update a scalar " + "argument but kernel 'testkern_array_type' has a scalar " + "argument with 'gh_sum' access." in str(excinfo.value)) + + +def test_scalar_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, + "4.16_multikernel_invokes_real_int_scalar_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"Scalar argument(s) ['b'] in 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)) From f18c0eb0b73b0648ed19ee6d8c2a9d6e09d91072 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 15 Jun 2023 14:46:37 +0100 Subject: [PATCH 005/119] #1312 making more tests work and adding LFRicArrayArgs --- src/psyclone/domain/lfric/__init__.py | 4 +- .../domain/lfric/lfric_arg_descriptor.py | 82 +++--- src/psyclone/domain/lfric/lfric_array_args.py | 275 ++++++++++++++++++ .../domain/lfric/lfric_array_mdata_test.py | 41 +-- 4 files changed, 325 insertions(+), 77 deletions(-) create mode 100644 src/psyclone/domain/lfric/lfric_array_args.py diff --git a/src/psyclone/domain/lfric/__init__.py b/src/psyclone/domain/lfric/__init__.py index edd04efca5..f3c308f1da 100644 --- a/src/psyclone/domain/lfric/__init__.py +++ b/src/psyclone/domain/lfric/__init__.py @@ -63,6 +63,7 @@ from psyclone.domain.lfric.arg_index_to_metadata_index import \ ArgIndexToMetadataIndex from psyclone.domain.lfric.lfric_collection import LFRicCollection +from psyclone.domain.lfric.lfric_array_args import LFRicArrayArgs __all__ = [ @@ -77,4 +78,5 @@ 'LFRicConstants', 'LFRicExtractDriverCreator', 'LFRicInvoke', - 'LFRicSymbolTable'] + 'LFRicSymbolTable', + 'LFRicArrayArgs'] diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index a4b97499dc..bb074b0984 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -102,7 +102,7 @@ def __init__(self, arg_type, operates_on, metadata_index): self._function_spaces = [] # Set vector size to 1 (scalars set it to 0 in their validation) self._vector_size = 1 - self._array_size = 1 + self._array_nranks = 1 # Initialise other internal arguments self._access_type = None self._function_space1 = None @@ -275,7 +275,7 @@ def _validate_vector_size(self, separator, arg_type): f"{const.VALID_FIELD_NAMES} argument types but found " f"'{arg_type.args[0]}'.") - def _validate_array_size(self, separator, arg_type): + def _validate_array_nranks(self, arg_type): ''' Validates descriptors for scalar array arguments and populates vector properties accordingly. @@ -295,23 +295,33 @@ def _validate_array_size(self, separator, arg_type): argument that is not an array. ''' + print(arg_type.args[3].toks[0]) + if arg_type.args[3].toks[0].name != "NRANKS".lower(): + raise ParseError( + f"In the LFRic API the 4th argument of a 'meta_arg' " + f"entry may give the number of ranks in an array but " + f"if so it must use 'NRANKS' as the keyword in the format " + f"'NRANKS*n', but found '{arg_type.args[3].toks[0]}' as the " + f"keyword in '{arg_type}'.") + # Check that the operator is correct - if separator != "*": + if arg_type.args[3].toks[1] != "*": raise ParseError( - f"In the LFRic API the 1st argument of a 'meta_arg' " + f"In the LFRic API the 4th argument of a 'meta_arg' " f"entry may be an array but if so must use '*' as " f"the separator in the format 'NRANKS*n', but found " - f"'{separator}' in '{arg_type}'.") + f"'{arg_type.args[3].toks[1]}' in '{arg_type}'.") + print(arg_type.args[3]) # Now try to find the array size for a scalar array and return # an error if it is not an integer number... try: - arraysize = int(arg_type.args[0].toks[2]) + arraysize = int(arg_type.args[3].toks[2]) except TypeError as err: raise ParseError( f"In the LFRic API, the array notation must be in the " f"format 'NRANKS*n' where 'n' is an integer, but the following " - f"'{arg_type.args[0].toks[2]}' was found in " + f"'{arg_type.args[3].toks[2]}' was found in " f"'{arg_type}'.") from err # ... or it is less than 1 (1 is the default for all fields)... @@ -322,14 +332,14 @@ def _validate_array_size(self, separator, arg_type): f"be a field vector with format 'NRANKS*n' where n is an " f"integer >= 1. However, found n = {arraysize} in '{arg_type}'.") # ... and set the array size if all checks pass - self._array_size = arraysize + self._array_nranks = arraysize # Check that no other arguments than fields use array notation if self._argument_type not in \ - const.VALID_FIELD_NAMES and self._array_size: + const.VALID_ARRAY_NAMES and self._array_nranks: raise ParseError( f"In the LFRic API, array notation is only supported for " - f"{const.VALID_FIELD_NAMES} argument types but found " + f"{const.VALID_ARRAY_NAMES} argument types but found " f"'{arg_type.args[0]}'.") def _init_field(self, arg_type, operates_on): @@ -663,7 +673,7 @@ def _init_scalar(self, arg_type): # Scalars don't have vector size or array size self._vector_size = 0 - self._array_size = 0 + self._array_nranks = 0 def _init_array(self, arg_type): ''' @@ -689,25 +699,17 @@ def _init_array(self, arg_type): f"Expected an array argument but got an argument of type " f"'{arg_type.args[0]}'.") - # There must be at least 4 arguments - nargs_array_min = 4 - if self._nargs < nargs_array_min: - raise ParseError( - "In the LFRic API each 'meta_arg' entry must have at least " - f"{nargs_array_min} arguments if its first argument is of " - f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " - f"'{arg_type}'.") - # There must be at most 5 arguments - nargs_array_max = 5 - if self._nargs > nargs_array_max: + # There must be 4 arguments + nargs_array = 4 + if self._nargs != nargs_array: raise ParseError( - f"In the LFRic API each 'meta_arg' entry must have at most " - f"{nargs_array_max} arguments if its first argument is of " + "In the LFRic API each 'meta_arg' entry must have " + f"{nargs_array} arguments if its first argument is of " f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " f"'{arg_type}'.") - # Check whether an invalid data type for a scalar argument is passed - # in. Valid data types for scalars are valid data types in LFRic API. + # Check whether an invalid data type for an array argument is passed + # in. Valid data types for arrays are valid data types in LFRic API. if self._data_type not in const.VALID_ARRAY_DATA_TYPES: raise InternalError( f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " @@ -725,25 +727,9 @@ def _init_array(self, arg_type): f"In the LFRic API array arguments must have read-only " f"('gh_read') access but found '{api_specific_name}' " f"in '{arg_type}'.") - # Reduction access is currently only valid for real scalar arguments - if self._data_type != "gh_real" and self._access_type in \ - AccessType.get_valid_reduction_modes(): - raise ParseError( - f"In the LFRic API a reduction access " - f"'{self._access_type.api_specific_name()}' is only valid " - f"with a real scalar argument, but a scalar argument with " - f"'{self._data_type}' data type was found in '{arg_type}'.") - # The 4th argument must be a valid function-space name - prop_ind = 3 - if arg_type.args[prop_ind].name not in \ - const.VALID_FUNCTION_SPACE_NAMES: - raise ParseError( - f"In the LFRic API argument {prop_ind+1} of a 'meta_arg' " - f"array entry must be a valid function-space name (one of " - f"{const.VALID_FUNCTION_SPACE_NAMES}) if its first argument " - f"is of {const.VALID_ARRAY_NAMES} type, but found " - f"'{arg_type.args[prop_ind].name}' in '{arg_type}'.") - self._function_space1 = arg_type.args[prop_ind].name + + self._validate_array_nranks(arg_type) + # Arrays don't have vector size self._vector_size = 0 @@ -863,7 +849,7 @@ def vector_size(self): return self._vector_size @property - def array_size(self): + def array_nranks(self): ''' Returns the array size of the argument. This will be 1 if ``*n`` has not been specified for all argument types except scalars @@ -873,7 +859,7 @@ def array_size(self): :rtype: int ''' - return self._array_size + return self._array_nranks def __str__(self): ''' @@ -901,7 +887,7 @@ def __str__(self): res += (f" function_space[3]='{self._function_space1}'" + os.linesep) elif self._argument_type in const.VALID_ARRAY_NAMES: - res += (f" function_space[3]='{self._function_space1}'" + res += (f" array_nranks[3]='{self._array_nranks}'" + os.linesep) elif self._argument_type in const.VALID_OPERATOR_NAMES: res += (f" function_space_to[3]='{self._function_space1}'" diff --git a/src/psyclone/domain/lfric/lfric_array_args.py b/src/psyclone/domain/lfric/lfric_array_args.py new file mode 100644 index 0000000000..5ba492713e --- /dev/null +++ b/src/psyclone/domain/lfric/lfric_array_args.py @@ -0,0 +1,275 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2023, 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 L. Turner, Met Office + +''' This module handles the declarations of array kernel arguments appearing in either + an Invoke or a Kernel stub.''' + +# Imports +from collections import OrderedDict, Counter + +from psyclone.domain.lfric import LFRicCollection, LFRicConstants +from psyclone.errors import GenerationError, InternalError +from psyclone.f2pygen import DeclGen +from psyclone.psyGen import FORTRAN_INTENT_NAMES + + +class LFRicArrayArgs(LFRicCollection): + ''' + Handles the declarations of array kernel arguments appearing in either + an Invoke or a Kernel stub. + + :param node: the Invoke or Kernel stub for which to manage the array \ + arguments. + :type node: :py:class:`psyclone.dynamo0p3.DynKern` or \ + :py:class:`psyclone.dynamo0p3.LFRicInvoke` + + ''' + def __init__(self, node): + super(LFRicArrayArgs, self).__init__(node) + + # Initialise dictionaries of 'real', 'integer' and 'logical' + # array arguments by data type and intent + self._array_args = {} + self._real_arrays = {} + self._integer_arrays = {} + self._logical_arrays = {} + for intent in FORTRAN_INTENT_NAMES: + self._array_args[intent] = [] + self._real_arrays[intent] = [] + self._integer_arrays[intent] = [] + self._logical_arrays[intent] = [] + + def _invoke_declarations(self, parent): + ''' + Create argument lists and declarations for all array arguments + in an Invoke. + + :param parent: the f2pygen node representing the PSy-layer routine \ + to which to add declarations. + :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` + + :raises InternalError: for unsupported argument intrinsic types. + :raises GenerationError: if the same array argument has different \ + data types in different Kernel calls \ + within the same Invoke. + + ''' + # Create dictionary of all array arguments for checks + const = LFRicConstants() + self._array_args = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES) + # Filter array arguments by intent and intrinsic type + self._real_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) + self._integer_arrays = self._invoke.unique_declns_by_intent( + const.VALID_ARRAY_NAMES, + intrinsic_type=const.MAPPING_DATA_TYPES["gh_integer"]) + self._logical_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._array_args[intent]] + rscal = [arg.declaration_name for + arg in self._real_arrays[intent]] + iscal = [arg.declaration_name for + arg in self._integer_arrays[intent]] + lscal = [arg.declaration_name for + arg in self._logical_arrays[intent]] + # Add "real", "integer" and "logical" array lists for checks + decl_scal = rscal + iscal + lscal + # 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 array " + f"arguments {scal_inv} to Invoke '{self._invoke.name}'. " + f"Supported types are {const.VALID_INTRINSIC_TYPES}.") + # Check that the same array name is not found in either of + # 'real', 'integer' or 'logical' array lists (for instance if + # passed to one kernel as a 'real' and to another kernel as an + # 'integer' array) + 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(parent) + + def _stub_declarations(self, parent): + ''' + Create and add declarations for all array arguments in + a Kernel stub. + + :param parent: node in the f2pygen AST representing the Kernel stub \ + to which to add declarations. + :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` + + :raises InternalError: for an unsupported argument data type. + + ''' + # Extract all array arguments + for arg in self._calls[0].arguments.args: + if arg.is_array: + self._array_args[arg.intent].append(arg) + + const = LFRicConstants() + # Filter array arguments by intent and data type + for intent in FORTRAN_INTENT_NAMES: + for arg in self._array_args[intent]: + if arg.descriptor.data_type == "gh_real": + self._real_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_integer": + self._integer_arrays[intent].append(arg) + elif arg.descriptor.data_type == "gh_logical": + self._logical_arrays[intent].append(arg) + else: + raise InternalError( + f"Found an unsupported data type " + f"'{arg.descriptor.data_type}' for the array " + f"argument '{arg.declaration_name}'. Supported types " + f"are {const.VALID_ARRAY_DATA_TYPES}.") + + # Create declarations + self._create_declarations(parent) + + def _create_declarations(self, parent): + '''Add declarations for the array arguments. + + :param parent: the f2pygen node in which to insert declarations \ + (Invoke or Kernel). + :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` + + :raises InternalError: if neither self._invoke nor \ + self._kernel are set. + + ''' + const = LFRicConstants() + const_mod = const.UTILITIES_MOD_MAP["constants"]["module"] + const_mod_list = None + if self._invoke: + const_mod_list = self._invoke.invokes.psy. \ + infrastructure_modules[const_mod] + # Real array arguments + for intent in FORTRAN_INTENT_NAMES: + if self._real_arrays[intent]: + # Filter arrays based on precision + real_arrays_precision_map = OrderedDict() + for real_array in self._real_arrays[intent]: + try: + real_arrays_precision_map[ + real_array.precision].append(real_array) + except KeyError: + # This precision has not been seen before so + # create a new entry + real_arrays_precision_map[ + real_array.precision] = [real_array] + # Declare arrays + for real_array_kind, real_arrays_list in \ + real_arrays_precision_map.items(): + real_array_type = real_arrays_list[0].intrinsic_type + real_array_names = [arg.declaration_name for arg + in real_arrays_list] + parent.add( + DeclGen(parent, datatype=real_array_type, + kind=real_array_kind, + entity_decls=real_array_names, + intent=intent)) + if self._invoke: + if real_array_kind not in const_mod_list: + const_mod_list.append(real_array_kind) + elif self._kernel: + self._kernel.argument_kinds.add(real_array_kind) + else: + raise InternalError( + "Expected the declaration of real array kernel " + "arguments to be for either an invoke or a " + "kernel stub, but it is neither.") + + # Integer array arguments + for intent in FORTRAN_INTENT_NAMES: + if self._integer_arrays[intent]: + dtype = self._integer_arrays[intent][0].intrinsic_type + dkind = self._integer_arrays[intent][0].precision + integer_array_names = [arg.declaration_name for arg + in self._integer_arrays[intent]] + parent.add( + DeclGen(parent, datatype=dtype, kind=dkind, + entity_decls=integer_array_names, + intent=intent)) + if self._invoke: + if dkind not in const_mod_list: + const_mod_list.append(dkind) + elif self._kernel: + self._kernel.argument_kinds.add(dkind) + else: + raise InternalError( + "Expected the declaration of integer array kernel " + "arguments to be for either an invoke or a " + "kernel stub, but it is neither.") + + # Logical array arguments + for intent in FORTRAN_INTENT_NAMES: + if self._logical_arrays[intent]: + dtype = self._logical_arrays[intent][0].intrinsic_type + dkind = self._logical_arrays[intent][0].precision + logical_array_names = [arg.declaration_name for arg + in self._logical_arrays[intent]] + parent.add( + DeclGen(parent, datatype=dtype, kind=dkind, + entity_decls=logical_array_names, + intent=intent)) + if self._invoke: + if dkind not in const_mod_list: + const_mod_list.append(dkind) + elif self._kernel: + self._kernel.argument_kinds.add(dkind) + else: + raise InternalError( + "Expected the declaration of logical array kernel " + "arguments to be for either an invoke or a " + "kernel stub, but it is neither.") + + +# ---------- Documentation utils -------------------------------------------- # +# The list of module members that we wish AutoAPI to generate +# documentation for. (See https://psyclone-ref.readthedocs.io) +__all__ = ['LFRicArrayArgs'] diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index d56ce0694e..8662d698b4 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -45,9 +45,9 @@ import pytest import fparser from fparser import api as fpapi -from psyclone.domain.lfric import LFRicArgDescriptor +from psyclone.domain.lfric import LFRicArrayArgs, LFRicArgDescriptor from psyclone.dynamo0p3 import (DynKern, DynKernMetadata, - LFRicScalarArgs, LFRicConstants) + LFRicConstants) from psyclone.errors import InternalError, GenerationError from psyclone.f2pygen import ModuleGen from psyclone.parse.algorithm import parse @@ -99,7 +99,7 @@ def test_ad_array_init_wrong_argument_type(): "'gh_operator'." in str(excinfo.value)) -def test_ad_array_type_too_few_args(): +def test_ad_array_type_wrong_num_of_args(): ''' Tests that an error is raised when the array argument descriptor metadata for an array has fewer than 3 args. ''' fparser.logging.disable(fparser.logging.CRITICAL) @@ -110,23 +110,8 @@ def test_ad_array_type_too_few_args(): name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: _ = DynKernMetadata(ast, name=name) - assert ("each 'meta_arg' entry must have at least 4 arguments if its " - "first argument is of ['gh_array'] type" in str(excinfo.value)) - - -def test_ad_array_type_too_many_args(): - ''' Tests that an error is raised when the field argument descriptor - metadata has more than 4 args. ''' - fparser.logging.disable(fparser.logging.CRITICAL) - code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_read, w1, w1, w2)", 1) - ast = fpapi.parse(code, ignore_comments=False) - name = "testkern_array_type" - with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) - assert ("each 'meta_arg' entry must have at most 5 arguments if its " - "first argument is of ['gh_array'] type" in str(excinfo.value)) + assert ("each 'meta_arg' entry must have 4 arguments if its first " + "argument is of ['gh_array'] type" in str(excinfo.value)) def test_ad_array_invalid_data_type(): @@ -272,10 +257,9 @@ def test_no_vector_array(): assert (f"vector notation is only supported for ['gh_field'] argument " f"types but found 'gh_array * 3'" in str(excinfo.value)) -# here be dragons (ignore test below) @pytest.mark.parametrize("array_ind, array_type, array_ranks", [ - (0, "gh_real", "nranks*1"), (1, "gh_integer", "nranks*2"), (2, "gh_logical", "nranks*4")]) + (0, "gh_real", 1), (1, "gh_integer", 2), (2, "gh_logical", 4)]) def test_arg_descriptor_array(array_ind, array_type, array_ranks): ''' Test that the LFRicArgDescriptor argument representation works as expected for all three types of valid array argument: @@ -294,23 +278,24 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): f" argument_type[0]='gh_array'\n" f" data_type[1]='{array_type}'\n" f" access_descriptor[2]='gh_read'\n" - f" function_space[3]='{array_ranks}'") + f" array_nranks[3]='{array_ranks}'") + print({array_ranks}) + print(result) assert expected_output in result # Check LFRicArgDescriptor argument properties assert array_descriptor.argument_type == "gh_array" assert array_descriptor.data_type == array_type - assert array_descriptor.function_space == array_ranks - assert array_descriptor.function_spaces == [{array_ranks}] + assert array_descriptor._array_nranks == array_ranks + assert array_descriptor.function_spaces == [None] assert str(array_descriptor.access) == "READ" assert array_descriptor.mesh is None assert array_descriptor.stencil is None - assert array_descriptor.vector_size == 0 # here be dragons (below) (LFRicScalarArgs) def test_lfricarrays_call_err1(): - ''' Check that the LFRicScalarArgs constructor raises the expected + ''' Check that the LFRicArrayArgs constructor raises the expected internal error if it encounters an unrecognised intrinsic type of scalar when generating a kernel call. @@ -326,7 +311,7 @@ def test_lfricarrays_call_err1(): array_arg = kernel.arguments.args[0] array_arg._intrinsic_type = "double-type" with pytest.raises(InternalError) as err: - LFRicScalarArgs(invoke)._invoke_declarations(ModuleGen(name="my_mod")) + LFRicArrayArgs(invoke)._invoke_declarations(ModuleGen(name="my_mod")) assert ("Found unsupported intrinsic types for the scalar arguments " "['a'] to Invoke 'invoke_0_testkern_three_scalars_type'. " "Supported types are ['real', 'integer', 'logical']." From e240d71d462f50dce6b5f28adee0a5062aeac779 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 15 Jun 2023 17:12:30 +0100 Subject: [PATCH 006/119] #1312 more test changes --- src/psyclone/domain/lfric/lfric_constants.py | 5 +++ .../domain/lfric/lfric_array_mdata_test.py | 44 +++++++++---------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_constants.py b/src/psyclone/domain/lfric/lfric_constants.py index 53ecf5c771..2473151787 100644 --- a/src/psyclone/domain/lfric/lfric_constants.py +++ b/src/psyclone/domain/lfric/lfric_constants.py @@ -150,6 +150,11 @@ def __init__(self): LFRicConstants.VALID_FIELD_INTRINSIC_TYPES = ["real", "integer", "logical"] + # Valid intrinsic types for array kernel argument data + # ('real', 'integer', and 'logical'). + LFRicConstants.VALID_ARRAY_INTRINSIC_TYPES = ["real", "integer", + "logical"] + # ---------- Mapping from metadata data_type to Fortran intrinsic type LFRicConstants.MAPPING_DATA_TYPES = \ OrderedDict(zip(LFRicConstants.VALID_ARG_DATA_TYPES, diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 8662d698b4..dfa11cdab9 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -279,8 +279,6 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): f" data_type[1]='{array_type}'\n" f" access_descriptor[2]='gh_read'\n" f" array_nranks[3]='{array_ranks}'") - print({array_ranks}) - print(result) assert expected_output in result # Check LFRicArgDescriptor argument properties @@ -292,7 +290,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): assert array_descriptor.mesh is None assert array_descriptor.stencil is None -# here be dragons (below) (LFRicScalarArgs) +# here be dragons (below) (LFRicArrayArgs) def test_lfricarrays_call_err1(): ''' Check that the LFRicArrayArgs constructor raises the expected @@ -307,20 +305,20 @@ def test_lfricarrays_call_err1(): 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 + # Sabotage the array argument to make it have an invalid intrinsic type array_arg = kernel.arguments.args[0] - array_arg._intrinsic_type = "double-type" + array_arg._intrinsic_type = "triple-type" with pytest.raises(InternalError) as err: LFRicArrayArgs(invoke)._invoke_declarations(ModuleGen(name="my_mod")) - assert ("Found unsupported intrinsic types for the scalar arguments " - "['a'] to Invoke 'invoke_0_testkern_three_scalars_type'. " - "Supported types are ['real', 'integer', 'logical']." - in str(err.value)) + test_str = str(err.value) + assert ("Found unsupported intrinsic types for the array arguments ['a'] " + "to Invoke 'invoke_0_testkern_three_arrays_type'. Supported " + "types are ['real', 'integer', 'logical']." in test_str) -# here be dragons (below) (LFRicScalarArgs) +# here be dragons (below) (LFRicArrayArgs) -def test_lfricscalars_call_err2(): - '''Check that LFRicScalarArgs _create_declarations method raises the +def test_lfricarrays_call_err2(): + '''Check that LFRicArrayArgs _create_declarations method raises the expected internal errors for real, integer and logical scalars if neither invoke nor kernel is set. @@ -331,45 +329,45 @@ def test_lfricscalars_call_err2(): api=TEST_API) psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) invoke = psy.invokes.invoke_list[0] - scalar_args = LFRicScalarArgs(invoke) + array_args = LFRicArrayArgs(invoke) node = ModuleGen("prog") # Set up information that _create_declarations requires. Note, # this method also calls _create_declarations. - scalar_args._invoke_declarations(node) + array_args._invoke_declarations(node) # Sabotage code so that a call to _create declarations raises the # required exceptions. - scalar_args._invoke = None + array_args._invoke = None # The first exception comes from real scalars. with pytest.raises(InternalError) as error: - scalar_args._create_declarations(node) + array_args._create_declarations(node) assert ("Expected the declaration of real scalar kernel arguments to be " "for either an invoke or a kernel stub, but it is neither." in str(error.value)) # Remove real scalars so we get the exception for integer scalars. for intent in FORTRAN_INTENT_NAMES: - scalar_args._real_scalars[intent] = None + array_args._real_arrays[intent] = None with pytest.raises(InternalError) as error: - scalar_args._create_declarations(node) + array_args._create_declarations(node) assert ("Expected the declaration of integer scalar kernel arguments to " "be for either an invoke or a kernel stub, but it is neither." in str(error.value)) # Remove integer scalars so we get the exception for logical scalars. for intent in FORTRAN_INTENT_NAMES: - scalar_args._integer_scalars[intent] = None + array_args._integer_arrays[intent] = None with pytest.raises(InternalError) as error: - scalar_args._create_declarations(node) + array_args._create_declarations(node) assert ("Expected the declaration of logical scalar kernel arguments to " "be for either an invoke or a kernel stub, but it is neither." in str(error.value)) -# here be dragons (below) (LFRicScalarArgs) +# here be dragons (below) (LFRicArrayArgs) -def test_lfricscalarargs_mp(): - '''Check that the precision of a new scalar integer datatype is +def test_lfricarrayargs_mp(): + '''Check that the precision of a new array integer datatype is declared in the psy-layer. ''' From eb1e9fc83f1a6101057403213e2d7b3ae828181b Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 16 Jun 2023 11:53:16 +0100 Subject: [PATCH 007/119] #1312 more changes for tests --- .../tests/domain/lfric/lfric_array_mdata_test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index dfa11cdab9..eb69cad740 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -379,7 +379,7 @@ def test_lfricarrayargs_mp(): code = str(psy.gen) assert "USE constants_mod, ONLY: roo_def, i_def" in code -# here be sea monsters (below) (working point) +#here be dragons - I'm not sure what is supposed to result from inout/out/in def test_lfricinvoke_uniq_declns_intent_array(): ''' Tests that LFRicInvoke.unique_declns_by_intent() returns the correct @@ -410,6 +410,7 @@ def test_lfricinvoke_uniq_declns_intent_array(): assert logical_args['out'] == [] assert logical_args['in'] == [] +# here be sea monsters (below) (working point) def test_array_invoke_uniq_declns_valid_intrinsic(): ''' Tests that all valid intrinsic types for user-defined scalar @@ -423,20 +424,20 @@ def test_array_invoke_uniq_declns_valid_intrinsic(): psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) invoke = psy.invokes.invoke_list[0] - # Test 'real' scalars + # Test 'real' arrays const = LFRicConstants() arrays_real_args = invoke.unique_declarations( const.VALID_ARRAY_NAMES, intrinsic_type="real") arrays_real = [arg.declaration_name for arg in arrays_real_args] assert arrays_real == ["a"] - # Test 'integer' scalars + # Test 'integer' arrays arrays_integer_args = invoke.unique_declarations( const.VALID_ARRAY_NAMES, intrinsic_type="integer") arrays_integer = [arg.declaration_name for arg in arrays_integer_args] assert arrays_integer == ["istep"] - # Test 'logical' scalars + # Test 'logical' arrays arrays_logical_args = invoke.unique_declarations( const.VALID_ARRAY_NAMES, intrinsic_type="logical") arrays_logical = [arg.declaration_name for arg in arrays_logical_args] From 6285ad1a20cceea2dbfaef202d181cf39377c212 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 19 Jun 2023 15:50:26 +0100 Subject: [PATCH 008/119] #1312 removing lfric_array_args and relevant tests as was getting ahead of myself --- src/psyclone/domain/lfric/__init__.py | 4 +- src/psyclone/domain/lfric/lfric_array_args.py | 275 ------------------ .../domain/lfric/lfric_array_mdata_test.py | 266 +---------------- 3 files changed, 4 insertions(+), 541 deletions(-) delete mode 100644 src/psyclone/domain/lfric/lfric_array_args.py diff --git a/src/psyclone/domain/lfric/__init__.py b/src/psyclone/domain/lfric/__init__.py index f3c308f1da..edd04efca5 100644 --- a/src/psyclone/domain/lfric/__init__.py +++ b/src/psyclone/domain/lfric/__init__.py @@ -63,7 +63,6 @@ from psyclone.domain.lfric.arg_index_to_metadata_index import \ ArgIndexToMetadataIndex from psyclone.domain.lfric.lfric_collection import LFRicCollection -from psyclone.domain.lfric.lfric_array_args import LFRicArrayArgs __all__ = [ @@ -78,5 +77,4 @@ 'LFRicConstants', 'LFRicExtractDriverCreator', 'LFRicInvoke', - 'LFRicSymbolTable', - 'LFRicArrayArgs'] + 'LFRicSymbolTable'] diff --git a/src/psyclone/domain/lfric/lfric_array_args.py b/src/psyclone/domain/lfric/lfric_array_args.py deleted file mode 100644 index 5ba492713e..0000000000 --- a/src/psyclone/domain/lfric/lfric_array_args.py +++ /dev/null @@ -1,275 +0,0 @@ -# ----------------------------------------------------------------------------- -# BSD 3-Clause License -# -# Copyright (c) 2023, 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 L. Turner, Met Office - -''' This module handles the declarations of array kernel arguments appearing in either - an Invoke or a Kernel stub.''' - -# Imports -from collections import OrderedDict, Counter - -from psyclone.domain.lfric import LFRicCollection, LFRicConstants -from psyclone.errors import GenerationError, InternalError -from psyclone.f2pygen import DeclGen -from psyclone.psyGen import FORTRAN_INTENT_NAMES - - -class LFRicArrayArgs(LFRicCollection): - ''' - Handles the declarations of array kernel arguments appearing in either - an Invoke or a Kernel stub. - - :param node: the Invoke or Kernel stub for which to manage the array \ - arguments. - :type node: :py:class:`psyclone.dynamo0p3.DynKern` or \ - :py:class:`psyclone.dynamo0p3.LFRicInvoke` - - ''' - def __init__(self, node): - super(LFRicArrayArgs, self).__init__(node) - - # Initialise dictionaries of 'real', 'integer' and 'logical' - # array arguments by data type and intent - self._array_args = {} - self._real_arrays = {} - self._integer_arrays = {} - self._logical_arrays = {} - for intent in FORTRAN_INTENT_NAMES: - self._array_args[intent] = [] - self._real_arrays[intent] = [] - self._integer_arrays[intent] = [] - self._logical_arrays[intent] = [] - - def _invoke_declarations(self, parent): - ''' - Create argument lists and declarations for all array arguments - in an Invoke. - - :param parent: the f2pygen node representing the PSy-layer routine \ - to which to add declarations. - :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` - - :raises InternalError: for unsupported argument intrinsic types. - :raises GenerationError: if the same array argument has different \ - data types in different Kernel calls \ - within the same Invoke. - - ''' - # Create dictionary of all array arguments for checks - const = LFRicConstants() - self._array_args = self._invoke.unique_declns_by_intent( - const.VALID_ARRAY_NAMES) - # Filter array arguments by intent and intrinsic type - self._real_arrays = self._invoke.unique_declns_by_intent( - const.VALID_ARRAY_NAMES, - intrinsic_type=const.MAPPING_DATA_TYPES["gh_real"]) - self._integer_arrays = self._invoke.unique_declns_by_intent( - const.VALID_ARRAY_NAMES, - intrinsic_type=const.MAPPING_DATA_TYPES["gh_integer"]) - self._logical_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._array_args[intent]] - rscal = [arg.declaration_name for - arg in self._real_arrays[intent]] - iscal = [arg.declaration_name for - arg in self._integer_arrays[intent]] - lscal = [arg.declaration_name for - arg in self._logical_arrays[intent]] - # Add "real", "integer" and "logical" array lists for checks - decl_scal = rscal + iscal + lscal - # 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 array " - f"arguments {scal_inv} to Invoke '{self._invoke.name}'. " - f"Supported types are {const.VALID_INTRINSIC_TYPES}.") - # Check that the same array name is not found in either of - # 'real', 'integer' or 'logical' array lists (for instance if - # passed to one kernel as a 'real' and to another kernel as an - # 'integer' array) - 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(parent) - - def _stub_declarations(self, parent): - ''' - Create and add declarations for all array arguments in - a Kernel stub. - - :param parent: node in the f2pygen AST representing the Kernel stub \ - to which to add declarations. - :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` - - :raises InternalError: for an unsupported argument data type. - - ''' - # Extract all array arguments - for arg in self._calls[0].arguments.args: - if arg.is_array: - self._array_args[arg.intent].append(arg) - - const = LFRicConstants() - # Filter array arguments by intent and data type - for intent in FORTRAN_INTENT_NAMES: - for arg in self._array_args[intent]: - if arg.descriptor.data_type == "gh_real": - self._real_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_integer": - self._integer_arrays[intent].append(arg) - elif arg.descriptor.data_type == "gh_logical": - self._logical_arrays[intent].append(arg) - else: - raise InternalError( - f"Found an unsupported data type " - f"'{arg.descriptor.data_type}' for the array " - f"argument '{arg.declaration_name}'. Supported types " - f"are {const.VALID_ARRAY_DATA_TYPES}.") - - # Create declarations - self._create_declarations(parent) - - def _create_declarations(self, parent): - '''Add declarations for the array arguments. - - :param parent: the f2pygen node in which to insert declarations \ - (Invoke or Kernel). - :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` - - :raises InternalError: if neither self._invoke nor \ - self._kernel are set. - - ''' - const = LFRicConstants() - const_mod = const.UTILITIES_MOD_MAP["constants"]["module"] - const_mod_list = None - if self._invoke: - const_mod_list = self._invoke.invokes.psy. \ - infrastructure_modules[const_mod] - # Real array arguments - for intent in FORTRAN_INTENT_NAMES: - if self._real_arrays[intent]: - # Filter arrays based on precision - real_arrays_precision_map = OrderedDict() - for real_array in self._real_arrays[intent]: - try: - real_arrays_precision_map[ - real_array.precision].append(real_array) - except KeyError: - # This precision has not been seen before so - # create a new entry - real_arrays_precision_map[ - real_array.precision] = [real_array] - # Declare arrays - for real_array_kind, real_arrays_list in \ - real_arrays_precision_map.items(): - real_array_type = real_arrays_list[0].intrinsic_type - real_array_names = [arg.declaration_name for arg - in real_arrays_list] - parent.add( - DeclGen(parent, datatype=real_array_type, - kind=real_array_kind, - entity_decls=real_array_names, - intent=intent)) - if self._invoke: - if real_array_kind not in const_mod_list: - const_mod_list.append(real_array_kind) - elif self._kernel: - self._kernel.argument_kinds.add(real_array_kind) - else: - raise InternalError( - "Expected the declaration of real array kernel " - "arguments to be for either an invoke or a " - "kernel stub, but it is neither.") - - # Integer array arguments - for intent in FORTRAN_INTENT_NAMES: - if self._integer_arrays[intent]: - dtype = self._integer_arrays[intent][0].intrinsic_type - dkind = self._integer_arrays[intent][0].precision - integer_array_names = [arg.declaration_name for arg - in self._integer_arrays[intent]] - parent.add( - DeclGen(parent, datatype=dtype, kind=dkind, - entity_decls=integer_array_names, - intent=intent)) - if self._invoke: - if dkind not in const_mod_list: - const_mod_list.append(dkind) - elif self._kernel: - self._kernel.argument_kinds.add(dkind) - else: - raise InternalError( - "Expected the declaration of integer array kernel " - "arguments to be for either an invoke or a " - "kernel stub, but it is neither.") - - # Logical array arguments - for intent in FORTRAN_INTENT_NAMES: - if self._logical_arrays[intent]: - dtype = self._logical_arrays[intent][0].intrinsic_type - dkind = self._logical_arrays[intent][0].precision - logical_array_names = [arg.declaration_name for arg - in self._logical_arrays[intent]] - parent.add( - DeclGen(parent, datatype=dtype, kind=dkind, - entity_decls=logical_array_names, - intent=intent)) - if self._invoke: - if dkind not in const_mod_list: - const_mod_list.append(dkind) - elif self._kernel: - self._kernel.argument_kinds.add(dkind) - else: - raise InternalError( - "Expected the declaration of logical array kernel " - "arguments to be for either an invoke or a " - "kernel stub, but it is neither.") - - -# ---------- Documentation utils -------------------------------------------- # -# The list of module members that we wish AutoAPI to generate -# documentation for. (See https://psyclone-ref.readthedocs.io) -__all__ = ['LFRicArrayArgs'] diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index eb69cad740..461c2a1a4c 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2017-2023, Science and Technology Facilities Council. +# Copyright (c) 2023, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,10 +31,7 @@ # 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, S. Siso and N. Nobre, STFC Daresbury Lab; -# I. Kavcic, A. Coughtrie and L. Turner, Met Office; -# C. M. Maynard, Met Office/University of Reading; -# J. Henrichs, Bureau of Meteorology. +# Author L. Turner, Met Office ''' Module containing pytest tests for the general LFRic array arguments @@ -45,7 +42,7 @@ import pytest import fparser from fparser import api as fpapi -from psyclone.domain.lfric import LFRicArrayArgs, LFRicArgDescriptor +from psyclone.domain.lfric import LFRicArgDescriptor from psyclone.dynamo0p3 import (DynKern, DynKernMetadata, LFRicConstants) from psyclone.errors import InternalError, GenerationError @@ -290,260 +287,3 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): assert array_descriptor.mesh is None assert array_descriptor.stencil is None -# here be dragons (below) (LFRicArrayArgs) - -def test_lfricarrays_call_err1(): - ''' Check that the LFRicArrayArgs constructor raises the expected - internal error if it encounters an unrecognised intrinsic type of - scalar when generating a kernel call. - - ''' - _, invoke_info = parse( - os.path.join(BASE_PATH, - "1.7_single_invoke_3scalar.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 array argument to make it have an invalid intrinsic type - array_arg = kernel.arguments.args[0] - array_arg._intrinsic_type = "triple-type" - with pytest.raises(InternalError) as err: - LFRicArrayArgs(invoke)._invoke_declarations(ModuleGen(name="my_mod")) - test_str = str(err.value) - assert ("Found unsupported intrinsic types for the array arguments ['a'] " - "to Invoke 'invoke_0_testkern_three_arrays_type'. Supported " - "types are ['real', 'integer', 'logical']." in test_str) - -# here be dragons (below) (LFRicArrayArgs) - -def test_lfricarrays_call_err2(): - '''Check that LFRicArrayArgs _create_declarations method raises the - expected internal errors for real, integer and logical scalars if - neither invoke nor kernel is set. - - ''' - _, invoke_info = parse( - os.path.join(BASE_PATH, - "1.7_single_invoke_3scalar.f90"), - api=TEST_API) - psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) - invoke = psy.invokes.invoke_list[0] - array_args = LFRicArrayArgs(invoke) - node = ModuleGen("prog") - # Set up information that _create_declarations requires. Note, - # this method also calls _create_declarations. - array_args._invoke_declarations(node) - - # Sabotage code so that a call to _create declarations raises the - # required exceptions. - array_args._invoke = None - - # The first exception comes from real scalars. - with pytest.raises(InternalError) as error: - array_args._create_declarations(node) - assert ("Expected the declaration of real scalar kernel arguments to be " - "for either an invoke or a kernel stub, but it is neither." - in str(error.value)) - - # Remove real scalars so we get the exception for integer scalars. - for intent in FORTRAN_INTENT_NAMES: - array_args._real_arrays[intent] = None - with pytest.raises(InternalError) as error: - array_args._create_declarations(node) - assert ("Expected the declaration of integer scalar kernel arguments to " - "be for either an invoke or a kernel stub, but it is neither." - in str(error.value)) - - # Remove integer scalars so we get the exception for logical scalars. - for intent in FORTRAN_INTENT_NAMES: - array_args._integer_arrays[intent] = None - with pytest.raises(InternalError) as error: - array_args._create_declarations(node) - assert ("Expected the declaration of logical scalar kernel arguments to " - "be for either an invoke or a kernel stub, but it is neither." - in str(error.value)) - -# here be dragons (below) (LFRicArrayArgs) - -def test_lfricarrayargs_mp(): - '''Check that the precision of a new array integer datatype is - declared in the psy-layer. - - ''' - _, invoke_info = parse( - os.path.join(BASE_PATH, - "1.6.4_scalar_mixed_prec.f90"), - api=TEST_API) - psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) - code = str(psy.gen) - assert "USE constants_mod, ONLY: roo_def, i_def" in code - -#here be dragons - I'm not sure what is supposed to result from inout/out/in - -def test_lfricinvoke_uniq_declns_intent_array(): - ''' Tests that LFRicInvoke.unique_declns_by_intent() returns the correct - list of arguments for 'gh_array' argument type. ''' - _, invoke_info = parse(os.path.join(BASE_PATH, - "1.7_single_invoke_3scalar.f90"), - api=TEST_API) - psy = PSyFactory(TEST_API, distributed_memory=True).create(invoke_info) - - # Test 'real' array arguments - real_args = psy.invokes.invoke_list[0].unique_declns_by_intent( - ["gh_array"], intrinsic_type="real") - assert real_args['inout'] == [] - assert real_args['out'] == [] - assert real_args['in'] == [] - - # Test 'integer' array arguments - integer_args = psy.invokes.invoke_list[0].unique_declns_by_intent( - ["gh_array"], intrinsic_type="integer") - assert integer_args['inout'] == [] - assert integer_args['out'] == [] - assert integer_args['in'] == [] - - # Test 'logical' array arguments - logical_args = psy.invokes.invoke_list[0].unique_declns_by_intent( - ["gh_array"], intrinsic_type="logical") - assert logical_args['inout'] == [] - assert logical_args['out'] == [] - assert logical_args['in'] == [] - -# here be sea monsters (below) (working point) - -def test_array_invoke_uniq_declns_valid_intrinsic(): - ''' Tests that all valid intrinsic types for user-defined scalar - arguments ('real', 'integer' and 'logical') are accepted by - Invoke.unique_declarations(). - - ''' - _, invoke_info = parse(os.path.join(BASE_PATH, - "1.7_single_invoke_3scalar.f90"), - api=TEST_API) - psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info) - invoke = psy.invokes.invoke_list[0] - - # Test 'real' arrays - const = LFRicConstants() - arrays_real_args = invoke.unique_declarations( - const.VALID_ARRAY_NAMES, intrinsic_type="real") - arrays_real = [arg.declaration_name for arg in arrays_real_args] - assert arrays_real == ["a"] - - # Test 'integer' arrays - arrays_integer_args = invoke.unique_declarations( - const.VALID_ARRAY_NAMES, intrinsic_type="integer") - arrays_integer = [arg.declaration_name for arg in arrays_integer_args] - assert arrays_integer == ["istep"] - - # Test 'logical' arrays - arrays_logical_args = invoke.unique_declarations( - const.VALID_ARRAY_NAMES, intrinsic_type="logical") - arrays_logical = [arg.declaration_name for arg in arrays_logical_args] - assert arrays_logical == ["lswitch"] - - -def test_scalar_arg_lfricconst_properties(monkeypatch): - ''' Tests that properties of all supported types of user-defined, - read-only, scalar arguments ('real', 'integer' and 'logical') defined - in LFRicConstants are correctly set up in the DynKernelArgument class. - - ''' - fparser.logging.disable(fparser.logging.CRITICAL) - ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) - name = "testkern_array_type" - metadata = DynKernMetadata(ast, name=name) - kernel = DynKern() - kernel.load_meta(metadata) - - # Test 'real' scalars - scalar_arg = kernel.arguments.args[0] - assert scalar_arg.module_name is None - assert scalar_arg.data_type is None - assert scalar_arg.proxy_data_type is None - assert scalar_arg.intrinsic_type == "real" - assert scalar_arg.precision == "r_def" - - # Test 'integer' scalars - scalar_arg = kernel.arguments.args[6] - assert scalar_arg.module_name is None - assert scalar_arg.data_type is None - assert scalar_arg.proxy_data_type is None - assert scalar_arg.intrinsic_type == "integer" - assert scalar_arg.precision == "i_def" - - # Test 'logical' scalars - scalar_arg = kernel.arguments.args[5] - assert scalar_arg.module_name is None - assert scalar_arg.data_type is None - assert scalar_arg.proxy_data_type is None - assert scalar_arg.intrinsic_type == "logical" - assert scalar_arg.precision == "l_def" - - # Monkeypatch to check with an invalid intrinsic type of a - # scalar argument - const = LFRicConstants() - monkeypatch.setattr(scalar_arg, "_intrinsic_type", "tabby") - with pytest.raises(InternalError) as err: - scalar_arg._init_data_type_properties(None) - assert (f"Expected one of {const.VALID_INTRINSIC_TYPES} intrinsic types " - f"for a scalar argument but found 'tabby' in the metadata of " - f"kernel testkern_qr_code for argument lscalar_6." - in str(err.value)) - - -def test_scalar_reduction_lfricconst_properties(): - ''' Tests that properties of 'real' scalar reduction arguments defined - in LFRicConstants are correctly set up in the DynKernelArgument class. - - ''' - _, invoke_info = parse( - os.path.join(BASE_PATH, "15.9.1_X_innerproduct_Y_builtin.f90"), - api=TEST_API) - psy = PSyFactory(TEST_API, - distributed_memory=True).create(invoke_info) - schedule = psy.invokes.invoke_list[0].schedule - kernel = schedule.kernels()[0] - reduction_arg = kernel.arguments.args[0] - - assert reduction_arg.module_name == "scalar_mod" - assert reduction_arg.data_type == "scalar_type" - assert reduction_arg.proxy_data_type is None - assert reduction_arg.intrinsic_type == "real" - assert reduction_arg.precision == "r_def" - - -def test_multiple_updated_scalar_args(): - ''' Check that we raise the expected exception when we encounter a - kernel that writes to more than one of its field and scalar arguments ''' - fparser.logging.disable(fparser.logging.CRITICAL) - code = ARRAY_CODE.replace("arg_type(gh_scalar, gh_real, gh_read)", - "arg_type(gh_scalar, gh_real, gh_sum)", 1) - ast = fpapi.parse(code, ignore_comments=False) - name = "testkern_array_type" - with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) - assert ("A user-supplied LFRic kernel must not write/update a scalar " - "argument but kernel 'testkern_array_type' has a scalar " - "argument with 'gh_sum' access." in str(excinfo.value)) - - -def test_scalar_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, - "4.16_multikernel_invokes_real_int_scalar_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"Scalar argument(s) ['b'] in 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)) From 705d38ea4eb60c145f20e2d36df29c71b09e3b57 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 20 Jun 2023 13:58:35 +0100 Subject: [PATCH 009/119] #1312 adding metadata in the new style --- .../domain/lfric/kernel/array_arg_metadata.py | 202 ++++++++++++++++++ .../domain/lfric/lfric_arg_descriptor.py | 14 +- 2 files changed, 209 insertions(+), 7 deletions(-) create mode 100644 src/psyclone/domain/lfric/kernel/array_arg_metadata.py diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py new file mode 100644 index 0000000000..e5b83d6893 --- /dev/null +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -0,0 +1,202 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2023, 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 L. Turner, Met Office + +'''Module containing the ArrayArgMetadata class which captures the metadata +associated with a field argument. Supports the creation, modification +and Fortran output of an Array argument. + +''' +from psyclone.domain.lfric import LFRicConstants +from psyclone.domain.lfric.kernel.scalar_arg_metadata import \ + ScalarArgMetadata + + +class ArrayArgMetadata(ScalarArgMetadata): + '''Class to capture LFRic kernel metadata information for an array + argument. + + :param str datatype: the datatype of this array (GH_INTEGER, ...). + :param str access: the way the kernel accesses this array (GH_WRITE, ...). + :param str function_space: the function space that this field is \ + on (W0, ...). + + ''' + # The name used to specify a field argument in LFRic metadata. + form = "gh_array" + # The relative positions of LFRic metadata. Metadata for a field + # argument is provided in the following format 'arg_type(form, + # datatype, access, function_space)'. Therefore, for example, the + # index of the form argument (form_arg_index) is 0. + form_arg_index = 0 + datatype_arg_index = 1 + access_arg_index = 2 + array_nranks_arg_index = 3 + # The name to use for any exceptions. + check_name = "array" + # The number of arguments in the language-level metadata (min and + # max values). + nargs = (4) + + def __init__(self, datatype, access, array_nranks): + super().__init__(datatype, access) + self.array_nranks = array_nranks + + @classmethod + def _get_metadata(cls, fparser2_tree): + '''Extract the required metadata from the fparser2 tree and return it + as strings. Also check that the metadata is in the expected + form (but do not check the metadata values as that is done + separately). + + :param fparser2_tree: fparser2 tree containing the metadata \ + for this argument. + :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ + :py:class:`fparser.two.Fortran2003.Structure_Constructor` + + :returns: a tuple containing the datatype, access and array nranks \ + metadata. + :rtype: Tuple[str, str, str, Optional[str]] + + ''' + datatype, access = super()._get_metadata(fparser2_tree) + array_nranks = cls.get_arg( + fparser2_tree, cls.array_nranks_arg_index) + return (datatype, access, array_nranks) + + @classmethod + def get_stencil(cls, fparser2_tree): + '''Retrieves the stencil metadata value found within the supplied + fparser2 tree (if there is one) and checks that it is valid. + + :param fparser2_tree: fparser2 tree capturing the required metadata. + :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` + + :returns: the stencil value extracted from the fparser2 tree \ + if there is one, or None if not. + :rtype: Optional[str] + + :raises TypeError: if the stencil metadata is not in the \ + expected form. + + ''' + raw_stencil_text = FieldArgMetadata.get_arg( + fparser2_tree, cls.stencil_arg_index) + if not raw_stencil_text: + return None + raw_stencil_text = raw_stencil_text.strip().lower() + if not (raw_stencil_text.startswith("stencil(") and + raw_stencil_text.endswith(")") and len(raw_stencil_text) > 9): + raise TypeError(f"The stencil metadata should be in the form " + f"'stencil(type)' but found '{raw_stencil_text}'.") + stencil = raw_stencil_text[8:-1] + return stencil + + def fortran_string(self): + ''' + :returns: the metadata represented by this class as Fortran. + :rtype: str + ''' + if self.stencil: + return (f"arg_type({self.form}, {self.datatype}, {self.access}, " + f"{self.function_space}, stencil({self.stencil}))") + return (f"arg_type({self.form}, {self.datatype}, {self.access}, " + f"{self.function_space})") + + @staticmethod + def check_datatype(value): + ''' + :param str value: the datatype to check for validity. + + :raises ValueError: if the provided value is not a valid \ + datatype descriptor. + + ''' + const = LFRicConstants() + FieldArgMetadata.validate_scalar_value( + value, const.VALID_FIELD_DATA_TYPES, "datatype descriptor") + + @staticmethod + def check_access(value): + ''' + :param str value: the access descriptor to validate. + ''' + const = LFRicConstants() + FieldArgMetadata.validate_scalar_value( + value, const.VALID_FIELD_ACCESS_TYPES, "access descriptor") + + @property + def function_space(self): + ''' + :returns: the function space for this field argument. + :rtype: str + ''' + return self._function_space + + @function_space.setter + def function_space(self, value): + ''' + :param str value: set the function space to the \ + specified value. + ''' + const = LFRicConstants() + FieldArgMetadata.validate_scalar_value( + value, const.VALID_FUNCTION_SPACE_NAMES, "function space") + self._function_space = value.lower() + + @property + def stencil(self): + ''' + :returns: the stencil for this field argument, or None if there + isn't one. + :rtype: Optional[str] + + ''' + return self._stencil + + @stencil.setter + def stencil(self, value): + ''' + :param str value: set the stencil to the specified value. + ''' + if value is None: + self._stencil = None + else: + const = LFRicConstants() + FieldArgMetadata.validate_scalar_value( + value, const.VALID_STENCIL_TYPES, "stencil") + self._stencil = value.lower() + + +__all__ = ["ArrayArgMetadata"] diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index bb074b0984..c74486479f 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -297,7 +297,7 @@ def _validate_array_nranks(self, arg_type): ''' print(arg_type.args[3].toks[0]) if arg_type.args[3].toks[0].name != "NRANKS".lower(): - raise ParseError( + raise ParseError( #SHARKS (needs test coverage) f"In the LFRic API the 4th argument of a 'meta_arg' " f"entry may give the number of ranks in an array but " f"if so it must use 'NRANKS' as the keyword in the format " @@ -306,7 +306,7 @@ def _validate_array_nranks(self, arg_type): # Check that the operator is correct if arg_type.args[3].toks[1] != "*": - raise ParseError( + raise ParseError( #SHARKS (needs test coverage) f"In the LFRic API the 4th argument of a 'meta_arg' " f"entry may be an array but if so must use '*' as " f"the separator in the format 'NRANKS*n', but found " @@ -317,8 +317,8 @@ def _validate_array_nranks(self, arg_type): # an error if it is not an integer number... try: arraysize = int(arg_type.args[3].toks[2]) - except TypeError as err: - raise ParseError( + except TypeError as err: #SHARKS (needs test coverage) + raise ParseError( #SHARKS (needs test coverage) f"In the LFRic API, the array notation must be in the " f"format 'NRANKS*n' where 'n' is an integer, but the following " f"'{arg_type.args[3].toks[2]}' was found in " @@ -327,7 +327,7 @@ def _validate_array_nranks(self, arg_type): # ... or it is less than 1 (1 is the default for all fields)... const = LFRicConstants() if arraysize < 1: - raise ParseError( + raise ParseError( #SHARKS (needs test coverage) f"In the LFRic API the 1st argument of a 'meta_arg' entry may " f"be a field vector with format 'NRANKS*n' where n is an " f"integer >= 1. However, found n = {arraysize} in '{arg_type}'.") @@ -337,7 +337,7 @@ def _validate_array_nranks(self, arg_type): # Check that no other arguments than fields use array notation if self._argument_type not in \ const.VALID_ARRAY_NAMES and self._array_nranks: - raise ParseError( + raise ParseError( #SHARKS (needs test coverage) f"In the LFRic API, array notation is only supported for " f"{const.VALID_ARRAY_NAMES} argument types but found " f"'{arg_type.args[0]}'.") @@ -859,7 +859,7 @@ def array_nranks(self): :rtype: int ''' - return self._array_nranks + return self._array_nranks #SHARKS (needs test coverage) def __str__(self): ''' From c3f45a5d2ac62ca21364768e23c042df063a82d1 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 20 Jun 2023 14:11:41 +0100 Subject: [PATCH 010/119] #1312 changes in new metadata --- .../domain/lfric/kernel/array_arg_metadata.py | 105 +++++------------- 1 file changed, 25 insertions(+), 80 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index e5b83d6893..6ee66b4fe1 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -34,7 +34,7 @@ # Author L. Turner, Met Office '''Module containing the ArrayArgMetadata class which captures the metadata -associated with a field argument. Supports the creation, modification +associated with an array argument. Supports the creation, modification and Fortran output of an Array argument. ''' @@ -49,13 +49,13 @@ class ArrayArgMetadata(ScalarArgMetadata): :param str datatype: the datatype of this array (GH_INTEGER, ...). :param str access: the way the kernel accesses this array (GH_WRITE, ...). - :param str function_space: the function space that this field is \ + :param str function_space: the function space that this array is \ on (W0, ...). ''' - # The name used to specify a field argument in LFRic metadata. + # The name used to specify an array argument in LFRic metadata. form = "gh_array" - # The relative positions of LFRic metadata. Metadata for a field + # The relative positions of LFRic metadata. Metadata for an array # argument is provided in the following format 'arg_type(form, # datatype, access, function_space)'. Therefore, for example, the # index of the form argument (form_arg_index) is 0. @@ -87,52 +87,20 @@ def _get_metadata(cls, fparser2_tree): :returns: a tuple containing the datatype, access and array nranks \ metadata. - :rtype: Tuple[str, str, str, Optional[str]] + :rtype: Tuple[str, str, str] ''' datatype, access = super()._get_metadata(fparser2_tree) - array_nranks = cls.get_arg( - fparser2_tree, cls.array_nranks_arg_index) + array_nranks = cls.get_vector_length(fparser2_tree) return (datatype, access, array_nranks) - @classmethod - def get_stencil(cls, fparser2_tree): - '''Retrieves the stencil metadata value found within the supplied - fparser2 tree (if there is one) and checks that it is valid. - - :param fparser2_tree: fparser2 tree capturing the required metadata. - :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` - - :returns: the stencil value extracted from the fparser2 tree \ - if there is one, or None if not. - :rtype: Optional[str] - - :raises TypeError: if the stencil metadata is not in the \ - expected form. - - ''' - raw_stencil_text = FieldArgMetadata.get_arg( - fparser2_tree, cls.stencil_arg_index) - if not raw_stencil_text: - return None - raw_stencil_text = raw_stencil_text.strip().lower() - if not (raw_stencil_text.startswith("stencil(") and - raw_stencil_text.endswith(")") and len(raw_stencil_text) > 9): - raise TypeError(f"The stencil metadata should be in the form " - f"'stencil(type)' but found '{raw_stencil_text}'.") - stencil = raw_stencil_text[8:-1] - return stencil - def fortran_string(self): ''' :returns: the metadata represented by this class as Fortran. :rtype: str ''' - if self.stencil: - return (f"arg_type({self.form}, {self.datatype}, {self.access}, " - f"{self.function_space}, stencil({self.stencil}))") return (f"arg_type({self.form}, {self.datatype}, {self.access}, " - f"{self.function_space})") + f"{self.array_nranks})") @staticmethod def check_datatype(value): @@ -144,8 +112,8 @@ def check_datatype(value): ''' const = LFRicConstants() - FieldArgMetadata.validate_scalar_value( - value, const.VALID_FIELD_DATA_TYPES, "datatype descriptor") + ArrayArgMetadata.validate_scalar_value( + value, const.VALID_ARRAY_DATA_TYPES, "datatype descriptor") @staticmethod def check_access(value): @@ -153,50 +121,27 @@ def check_access(value): :param str value: the access descriptor to validate. ''' const = LFRicConstants() - FieldArgMetadata.validate_scalar_value( - value, const.VALID_FIELD_ACCESS_TYPES, "access descriptor") + ArrayArgMetadata.validate_scalar_value( + value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") @property - def function_space(self): + def array_nranks(self): ''' - :returns: the function space for this field argument. + :returns: the function space for this array argument. :rtype: str ''' - return self._function_space - - @function_space.setter - def function_space(self, value): - ''' - :param str value: set the function space to the \ - specified value. - ''' - const = LFRicConstants() - FieldArgMetadata.validate_scalar_value( - value, const.VALID_FUNCTION_SPACE_NAMES, "function space") - self._function_space = value.lower() - - @property - def stencil(self): - ''' - :returns: the stencil for this field argument, or None if there - isn't one. - :rtype: Optional[str] - - ''' - return self._stencil - - @stencil.setter - def stencil(self, value): - ''' - :param str value: set the stencil to the specified value. - ''' - if value is None: - self._stencil = None - else: - const = LFRicConstants() - FieldArgMetadata.validate_scalar_value( - value, const.VALID_STENCIL_TYPES, "stencil") - self._stencil = value.lower() + return self._array_nranks + +# @array_nranks.setter +# def array_nranks(self, value): +# ''' +# :param str value: set the function space to the \ +# specified value. +# ''' +# const = LFRicConstants() +# ArrayArgMetadata.validate_scalar_value( +# value, const.VALID_FUNCTION_SPACE_NAMES, "array nranks") +# self._array_nranks = value.lower() __all__ = ["ArrayArgMetadata"] From bc4bbc0d854c232de08407d3fa846d0ddb2621b9 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 20 Jun 2023 16:44:46 +0100 Subject: [PATCH 011/119] #1312 removing unneeded commmented out code --- .../domain/lfric/kernel/array_arg_metadata.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 6ee66b4fe1..73dce7f70c 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -132,16 +132,4 @@ def array_nranks(self): ''' return self._array_nranks -# @array_nranks.setter -# def array_nranks(self, value): -# ''' -# :param str value: set the function space to the \ -# specified value. -# ''' -# const = LFRicConstants() -# ArrayArgMetadata.validate_scalar_value( -# value, const.VALID_FUNCTION_SPACE_NAMES, "array nranks") -# self._array_nranks = value.lower() - - __all__ = ["ArrayArgMetadata"] From 7ca546caf577abecf836ae807776dd7f1f12e374 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 21 Jun 2023 16:40:15 +0100 Subject: [PATCH 012/119] #1312 changing get_vector_length to get_array_dimension --- .../domain/lfric/kernel/array_arg_metadata.py | 2 +- .../lfric/kernel/common_meta_arg_metadata.py | 25 +++++++++++++------ .../lfric/kernel/field_vector_arg_metadata.py | 3 ++- .../kernel/inter_grid_vector_arg_metadata.py | 3 ++- .../kernel/common_meta_arg_metadata_test.py | 13 +++++----- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 73dce7f70c..013c5d9b0b 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -91,7 +91,7 @@ def _get_metadata(cls, fparser2_tree): ''' datatype, access = super()._get_metadata(fparser2_tree) - array_nranks = cls.get_vector_length(fparser2_tree) + array_nranks = cls.get_array_dimension(fparser2_tree) return (datatype, access, array_nranks) def fortran_string(self): diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 8503b2ca30..e57c8d24cc 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022, Science and Technology Facilities Council +# Copyright (c) 2022-2023, Science and Technology Facilities Council # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modified L. Turner, Met Office '''Module containing the abstract CommonMetaArgMetadata class which captures the metadata associated with an LFRic meta_arg @@ -176,9 +177,10 @@ def check_nargs(cls, fparser2_tree): # pylint: enable=arguments-differ @classmethod - def get_vector_length(cls, fparser2_tree): - '''Retrieves the vector length metadata value found within the - supplied fparser2 tree and checks that it is valid. + def get_array_dimension(cls, fparser2_tree): + '''Retrieves the field vector length (for gh_field metadata value) or + number of ranks in a scalar array (for gh_array) metadata values found + within the supplied fparser2 tree and checks that it is valid. :param fparser2_tree: fparser2 tree capturing the required metadata. :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` @@ -195,10 +197,17 @@ def get_vector_length(cls, fparser2_tree): components = vector_datatype.split("*") if len(components) != 2: raise TypeError( - f"The vector length metadata should be in the form " - f"'form*vector_length' but found '{vector_datatype}'.") - vector_length = components[1].strip() - return vector_length + f"The vector_length or array_nranks metadata should be in the form " + f"'form*integer' but found '{vector_datatype}'.") + acceptable_forms = ['gh_field', 'nranks'] + if components[0] not in acceptable_forms: + raise ParseError( + f"In the LFRic API, array dimension notation is given in the form " + f"'form*integer', where form is one of '{acceptable_forms}' but " + f"found '{compontents[0]}'." + ) + array_dimension = components[1].strip() + return array_dimension @property def datatype(self): diff --git a/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py b/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py index 01ec6fceed..88f1c34e9a 100644 --- a/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modified L. Turner, Met Office '''Module containing the FieldVector Arg class which captures the metadata associated with a field vector argument. Supports the creation, modification @@ -90,7 +91,7 @@ def _get_metadata(cls, fparser2_tree): ''' datatype, access, function_space, stencil = super()._get_metadata( fparser2_tree) - vector_length = cls.get_vector_length(fparser2_tree) + vector_length = cls.get_array_dimension(fparser2_tree) return (datatype, access, function_space, vector_length, stencil) def fortran_string(self): diff --git a/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py b/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py index 33193a96fe..b941e6c24a 100644 --- a/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modified L. Turner, Met Office '''Module containing the InterGridVectorArgMetadata class which captures the metadata associated with a intergrid vector argument. Supports the @@ -98,7 +99,7 @@ def _get_metadata(cls, fparser2_tree): ''' datatype, access, function_space, mesh_arg, stencil = \ super()._get_metadata(fparser2_tree) - vector_length = cls.get_vector_length(fparser2_tree) + vector_length = cls.get_array_dimension(fparser2_tree) return (datatype, access, function_space, mesh_arg, vector_length, stencil) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 44e2df3497..8963f8bfef 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022, Science and Technology Facilities Council +# Copyright (c) 2022-2023, Science and Technology Facilities Council # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modified L. Turner, Met Office '''Module containing tests for the CommonMetaArgMetadata class. @@ -232,22 +233,22 @@ def test_check_nargs(): CheckArg.check_nargs(fparser2_tree) -def test_get_vector_length(): - '''Test that the get_vector_length method in the +def test_get_array_dimension(): + '''Test that the get_array_dimension method in the CommonMetaArgMetadata class works as expected. ''' fparser_tree = CheckArg.create_fparser2( "arg_type(GH_FIELD, GH_REAL, GH_READ, W0)", Fortran2003.Part_Ref) with pytest.raises(TypeError) as info: - _ = CheckArg.get_vector_length(fparser_tree) + _ = CheckArg.get(fparser_tree) assert ("The vector length metadata should be in the form " - "'form*vector_length' but found 'GH_FIELD'." + "'form*integer' but found 'GH_FIELD'." in str(info.value)) fparser_tree = CheckArg.create_fparser2( "arg_type(GH_FIELD*3, GH_REAL, GH_READ, W0)", Fortran2003.Part_Ref) - vector_length = CheckArg.get_vector_length(fparser_tree) + vector_length = CheckArg.get_array_dimension(fparser_tree) assert vector_length == "3" From 32db8f54afd8298726a2c8bfae8223fddbae3c94 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 21 Jun 2023 18:11:42 +0100 Subject: [PATCH 013/119] #1312 test for incorrect operator added --- .../domain/lfric/lfric_arg_descriptor.py | 2 +- .../tests/domain/lfric/lfric_array_mdata_test.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index c74486479f..3d4f07bc76 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -307,7 +307,7 @@ def _validate_array_nranks(self, arg_type): # Check that the operator is correct if arg_type.args[3].toks[1] != "*": raise ParseError( #SHARKS (needs test coverage) - f"In the LFRic API the 4th argument of a 'meta_arg' " + f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry may be an array but if so must use '*' as " f"the separator in the format 'NRANKS*n', but found " f"'{arg_type.args[3].toks[1]}' in '{arg_type}'.") diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 461c2a1a4c..88ed0bf2f3 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -287,3 +287,19 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): assert array_descriptor.mesh is None assert array_descriptor.stencil is None +def test_incorrect_operator(): + ''' Tests that we raise an error when the operator is incorrect''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_read, NRANKS+1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert (f"the 4th argument of a 'meta_arg' entry may be an " + f"array but if so must use '*' as the separator " + f"in the format 'NRANKS*n', but found '+' in " + f"'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." + in str(excinfo.value)) From aeebec2689cc13ae0fd9094f330a8d1710e0d040 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 22 Jun 2023 15:08:46 +0100 Subject: [PATCH 014/119] #1312 tidying up mistakes and pylint --- .../domain/lfric/kernel/array_arg_metadata.py | 2 +- .../lfric/kernel/common_meta_arg_metadata.py | 11 ++--- .../domain/lfric/lfric_arg_descriptor.py | 2 +- .../domain/lfric/lfric_array_mdata_test.py | 45 ++++++++++--------- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 013c5d9b0b..24a69fb00b 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -130,6 +130,6 @@ def array_nranks(self): :returns: the function space for this array argument. :rtype: str ''' - return self._array_nranks + return self.array_nranks __all__ = ["ArrayArgMetadata"] diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index e57c8d24cc..8f554251ac 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -44,6 +44,7 @@ from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.errors import InternalError +from psyclone.parse.utils import ParseError class CommonMetaArgMetadata(CommonArgMetadata, ABC): @@ -197,14 +198,14 @@ def get_array_dimension(cls, fparser2_tree): components = vector_datatype.split("*") if len(components) != 2: raise TypeError( - f"The vector_length or array_nranks metadata should be in the form " - f"'form*integer' but found '{vector_datatype}'.") + f"The vector_length or array_nranks metadata should be in " + f"the form 'form*integer' but found '{vector_datatype}'.") acceptable_forms = ['gh_field', 'nranks'] if components[0] not in acceptable_forms: raise ParseError( - f"In the LFRic API, array dimension notation is given in the form " - f"'form*integer', where form is one of '{acceptable_forms}' but " - f"found '{compontents[0]}'." + f"In the LFRic API, array dimension notation is given " + f"in the form 'form*integer', where form is one of " + f"'{acceptable_forms}' but found '{components[0]}'." ) array_dimension = components[1].strip() return array_dimension diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 3d4f07bc76..8cc7d0e413 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -306,7 +306,7 @@ def _validate_array_nranks(self, arg_type): # Check that the operator is correct if arg_type.args[3].toks[1] != "*": - raise ParseError( #SHARKS (needs test coverage) + raise ParseError( #SHARKS (test works!) f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry may be an array but if so must use '*' as " f"the separator in the format 'NRANKS*n', but found " diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 88ed0bf2f3..9b48f07431 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -43,13 +43,9 @@ import fparser from fparser import api as fpapi from psyclone.domain.lfric import LFRicArgDescriptor -from psyclone.dynamo0p3 import (DynKern, DynKernMetadata, - LFRicConstants) -from psyclone.errors import InternalError, GenerationError -from psyclone.f2pygen import ModuleGen -from psyclone.parse.algorithm import parse +from psyclone.dynamo0p3 import DynKernMetadata, LFRicConstants +from psyclone.errors import InternalError from psyclone.parse.utils import ParseError -from psyclone.psyGen import FORTRAN_INTENT_NAMES, PSyFactory # Constants BASE_PATH = os.path.join( @@ -117,8 +113,9 @@ def test_ad_array_invalid_data_type(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" # check real array - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_unreal, gh_read, NRANKS*1)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_unreal, gh_read, " + "NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -128,8 +125,9 @@ def test_ad_array_invalid_data_type(): f"but found 'gh_unreal' in 'arg_type(gh_array, gh_unreal, " f"gh_read, nranks * 1)'." in str(excinfo.value)) # check integer array - code = ARRAY_CODE.replace("arg_type(gh_array, gh_integer, gh_read, NRANKS*2)", - "arg_type(gh_array, gh_frac, gh_read, NRANKS*2)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_integer, gh_read, " + "NRANKS*2)", "arg_type(gh_array, gh_frac, gh_read, " + "NRANKS*2)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -139,8 +137,9 @@ def test_ad_array_invalid_data_type(): f"but found 'gh_frac' in 'arg_type(gh_array, gh_frac, " f"gh_read, nranks * 2)'." in str(excinfo.value)) # check logical array - code = ARRAY_CODE.replace("arg_type(gh_array, gh_logical, gh_read, NRANKS*4)", - "arg_type(gh_array, gh_illogical, gh_read, NRANKS*4)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_logical, gh_read, " + "NRANKS*4)", "arg_type(gh_array, gh_illogical, " + "gh_read, NRANKS*4)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -246,13 +245,14 @@ def test_no_vector_array(): name = "testkern_array_type" const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array*3, gh_real, gh_read, NRANKS*1)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array*3, gh_real, " + "gh_read, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = DynKernMetadata(ast, name=name) - assert (f"vector notation is only supported for ['gh_field'] argument " - f"types but found 'gh_array * 3'" in str(excinfo.value)) + assert ("vector notation is only supported for ['gh_field'] argument " + "types but found 'gh_array * 3'" in str(excinfo.value)) @pytest.mark.parametrize("array_ind, array_type, array_ranks", [ @@ -293,13 +293,14 @@ def test_incorrect_operator(): name = "testkern_array_type" const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_read, NRANKS+1)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS+1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = DynKernMetadata(ast, name=name) - assert (f"the 4th argument of a 'meta_arg' entry may be an " - f"array but if so must use '*' as the separator " - f"in the format 'NRANKS*n', but found '+' in " - f"'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." + assert ("the 4th argument of a 'meta_arg' entry may be an " + "array but if so must use '*' as the separator " + "in the format 'NRANKS*n', but found '+' in " + "'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." in str(excinfo.value)) From 8fb098a6aec1c81a95639863898248f85ac009ea Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 26 Jun 2023 12:02:06 +0100 Subject: [PATCH 015/119] #1312 temp hopeful fix for get_array_dimension --- src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 8f554251ac..79e9e3cf4d 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -204,8 +204,9 @@ def get_array_dimension(cls, fparser2_tree): if components[0] not in acceptable_forms: raise ParseError( f"In the LFRic API, array dimension notation is given " - f"in the form 'form*integer', where form is one of " - f"'{acceptable_forms}' but found '{components[0]}'." + f"in the form 'form*integer', where form is "#one of " + f"'gh_field' "#or '{acceptable_forms[1]}' " + f"but found '{components[0]}'." ) array_dimension = components[1].strip() return array_dimension From 597228968895e2c249dfa22b60d83c417daf9e87 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 28 Jun 2023 10:17:23 +0100 Subject: [PATCH 016/119] 1312 reverting changes to get_array_dimension --- .../lfric/kernel/common_meta_arg_metadata.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 79e9e3cf4d..3684d8513c 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -179,9 +179,8 @@ def check_nargs(cls, fparser2_tree): @classmethod def get_array_dimension(cls, fparser2_tree): - '''Retrieves the field vector length (for gh_field metadata value) or - number of ranks in a scalar array (for gh_array) metadata values found - within the supplied fparser2 tree and checks that it is valid. + '''Retrieves the vector length metadata value found within the + supplied fparser2 tree and checks that it is valid. :param fparser2_tree: fparser2 tree capturing the required metadata. :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` @@ -198,16 +197,8 @@ def get_array_dimension(cls, fparser2_tree): components = vector_datatype.split("*") if len(components) != 2: raise TypeError( - f"The vector_length or array_nranks metadata should be in " - f"the form 'form*integer' but found '{vector_datatype}'.") - acceptable_forms = ['gh_field', 'nranks'] - if components[0] not in acceptable_forms: - raise ParseError( - f"In the LFRic API, array dimension notation is given " - f"in the form 'form*integer', where form is "#one of " - f"'gh_field' "#or '{acceptable_forms[1]}' " - f"but found '{components[0]}'." - ) + f"The vector length metadata should be in the form " + f"'form*vector_length' but found '{vector_datatype}'.") array_dimension = components[1].strip() return array_dimension From a1c0774d7360a45ca296fa9d12a09538afa363e5 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 29 Jun 2023 13:54:19 +0100 Subject: [PATCH 017/119] #1312: *facepalm* --- .../tests/domain/lfric/kernel/common_meta_arg_metadata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 8963f8bfef..55f76c5a42 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -241,7 +241,7 @@ def test_get_array_dimension(): fparser_tree = CheckArg.create_fparser2( "arg_type(GH_FIELD, GH_REAL, GH_READ, W0)", Fortran2003.Part_Ref) with pytest.raises(TypeError) as info: - _ = CheckArg.get(fparser_tree) + _ = CheckArg.get_array_dimension(fparser_tree) assert ("The vector length metadata should be in the form " "'form*integer' but found 'GH_FIELD'." in str(info.value)) From f07e02a70842c3ad56952997ec7832380a0e402f Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 29 Jun 2023 14:21:11 +0100 Subject: [PATCH 018/119] #1312 more facepalming (should work now!) --- src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 3684d8513c..745a0aa567 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -198,7 +198,7 @@ def get_array_dimension(cls, fparser2_tree): if len(components) != 2: raise TypeError( f"The vector length metadata should be in the form " - f"'form*vector_length' but found '{vector_datatype}'.") + f"'form*integer' but found '{vector_datatype}'.") array_dimension = components[1].strip() return array_dimension From dca477d82f8ccb7c3ddc3820046cf25493097f0c Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 6 Jul 2023 11:13:25 +0100 Subject: [PATCH 019/119] #1312 writing more tests --- .../domain/lfric/lfric_arg_descriptor.py | 38 +++++++------- .../domain/lfric/lfric_array_mdata_test.py | 52 +++++++++++++++++++ 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 8cc7d0e413..844cdf3d84 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -297,16 +297,16 @@ def _validate_array_nranks(self, arg_type): ''' print(arg_type.args[3].toks[0]) if arg_type.args[3].toks[0].name != "NRANKS".lower(): - raise ParseError( #SHARKS (needs test coverage) - f"In the LFRic API the 4th argument of a 'meta_arg' " - f"entry may give the number of ranks in an array but " - f"if so it must use 'NRANKS' as the keyword in the format " - f"'NRANKS*n', but found '{arg_type.args[3].toks[0]}' as the " - f"keyword in '{arg_type}'.") + raise ParseError( + f"In the LFRic API, the 4th argument of a 'meta_arg' " + f"entry must use 'NRANKS' as the keyword in the format " + f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " + f"found '{arg_type.args[3].toks[0]}' as the keyword " + f"in '{arg_type}'.") # Check that the operator is correct if arg_type.args[3].toks[1] != "*": - raise ParseError( #SHARKS (test works!) + raise ParseError( f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry may be an array but if so must use '*' as " f"the separator in the format 'NRANKS*n', but found " @@ -317,30 +317,30 @@ def _validate_array_nranks(self, arg_type): # an error if it is not an integer number... try: arraysize = int(arg_type.args[3].toks[2]) - except TypeError as err: #SHARKS (needs test coverage) - raise ParseError( #SHARKS (needs test coverage) - f"In the LFRic API, the array notation must be in the " - f"format 'NRANKS*n' where 'n' is an integer, but the following " - f"'{arg_type.args[3].toks[2]}' was found in " + except ValueError as err: + raise ParseError( + f"In the LFRic API, the array notation must be in " + f"the format 'NRANKS*n' where 'n' is an integer, " + f"but '{arg_type.args[3].toks[2]}' was found in " f"'{arg_type}'.") from err # ... or it is less than 1 (1 is the default for all fields)... const = LFRicConstants() if arraysize < 1: - raise ParseError( #SHARKS (needs test coverage) - f"In the LFRic API the 1st argument of a 'meta_arg' entry may " - f"be a field vector with format 'NRANKS*n' where n is an " - f"integer >= 1. However, found n = {arraysize} in '{arg_type}'.") + raise ParseError( + f"In the LFRic API, the array notation must be in " + f"the format 'NRANKS*n' where 'n' is an integer >= 1. " + f"However, found n = '{arraysize}' in '{arg_type}'.") # ... and set the array size if all checks pass self._array_nranks = arraysize - # Check that no other arguments than fields use array notation + # Check that no other arguments than arrays use array notation if self._argument_type not in \ const.VALID_ARRAY_NAMES and self._array_nranks: raise ParseError( #SHARKS (needs test coverage) f"In the LFRic API, array notation is only supported for " - f"{const.VALID_ARRAY_NAMES} argument types but found " - f"'{arg_type.args[0]}'.") + f"'{const.VALID_ARRAY_NAMES}' argument types but found " + f"'{arg_type.args[0]}' in '{arg_type}'.") def _init_field(self, arg_type, operates_on): ''' diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 9b48f07431..341c3c0e8b 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -287,6 +287,24 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): assert array_descriptor.mesh is None assert array_descriptor.stencil is None +def test_keyword_not_nranks(): + ''' Tests that we raise an error when the keyword is not nranks''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, SKNARN*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("the 4th argument of a 'meta_arg' entry must use 'NRANKS' as " + "the keyword in the format 'NRANKS*n' if the 1st argument " + "is 'GH_ARRAY', but found 'sknarn' as the keyword in " + "'arg_type(gh_array, gh_real, gh_read, sknarn * 1)'." + in str(excinfo.value)) + def test_incorrect_operator(): ''' Tests that we raise an error when the operator is incorrect''' fparser.logging.disable(fparser.logging.CRITICAL) @@ -304,3 +322,37 @@ def test_incorrect_operator(): "in the format 'NRANKS*n', but found '+' in " "'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." in str(excinfo.value)) + +def test_n_not_integer(): + ''' Tests that we raise an error when n is not an integer''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS*0.5)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("the array notation must be in the format 'NRANKS*n' " + "where 'n' is an integer, but '0.5' was found in " + "'arg_type(gh_array, gh_real, gh_read, nranks * 0.5)'." + in str(excinfo.value)) + +def test_n_less_than_one(): + ''' Tests that we raise an error when n is less than 1''' + fparser.logging.disable(fparser.logging.CRITICAL) + name = "testkern_array_type" + const = LFRicConstants() + for argname in const.VALID_ARRAY_NAMES: + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS*0)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = DynKernMetadata(ast, name=name) + assert ("the array notation must be in the format 'NRANKS*n' " + "where 'n' is an integer >= 1. However, found n = '0' in " + "'arg_type(gh_array, gh_real, gh_read, nranks * 0)'." + in str(excinfo.value)) From 9ee4fe0be473d13d5bdb84bacb65f6d5e128c6c6 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 25 Sep 2023 12:53:41 +0100 Subject: [PATCH 020/119] #1312 returning get_array_dimensions to get_vector_length in preparation for writing an array-specific version rather than a generic version. --- .../domain/lfric/kernel/array_arg_metadata.py | 40 +++++++++---------- .../lfric/kernel/common_meta_arg_metadata.py | 8 ++-- .../lfric/kernel/field_vector_arg_metadata.py | 3 +- .../kernel/inter_grid_vector_arg_metadata.py | 3 +- .../kernel/common_meta_arg_metadata_test.py | 10 ++--- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 24a69fb00b..75d3967017 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -73,26 +73,26 @@ def __init__(self, datatype, access, array_nranks): super().__init__(datatype, access) self.array_nranks = array_nranks - @classmethod - def _get_metadata(cls, fparser2_tree): - '''Extract the required metadata from the fparser2 tree and return it - as strings. Also check that the metadata is in the expected - form (but do not check the metadata values as that is done - separately). - - :param fparser2_tree: fparser2 tree containing the metadata \ - for this argument. - :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ - :py:class:`fparser.two.Fortran2003.Structure_Constructor` - - :returns: a tuple containing the datatype, access and array nranks \ - metadata. - :rtype: Tuple[str, str, str] - - ''' - datatype, access = super()._get_metadata(fparser2_tree) - array_nranks = cls.get_array_dimension(fparser2_tree) - return (datatype, access, array_nranks) +# @classmethod +# def _get_metadata(cls, fparser2_tree): +# '''Extract the required metadata from the fparser2 tree and return it +# as strings. Also check that the metadata is in the expected +# form (but do not check the metadata values as that is done +# separately). +# +# :param fparser2_tree: fparser2 tree containing the metadata \ +# for this argument. +# :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ +# :py:class:`fparser.two.Fortran2003.Structure_Constructor` +# +# :returns: a tuple containing the datatype, access and array nranks \ +# metadata. +# :rtype: Tuple[str, str, str] +# +# ''' +# datatype, access = super()._get_metadata(fparser2_tree) +# # array_nranks = cls.get_array_dimension(fparser2_tree) +# return (datatype, access, array_nranks) def fortran_string(self): ''' diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 745a0aa567..dc8bf47b8d 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -178,7 +178,7 @@ def check_nargs(cls, fparser2_tree): # pylint: enable=arguments-differ @classmethod - def get_array_dimension(cls, fparser2_tree): + def get_vector_length(cls, fparser2_tree): '''Retrieves the vector length metadata value found within the supplied fparser2 tree and checks that it is valid. @@ -198,9 +198,9 @@ def get_array_dimension(cls, fparser2_tree): if len(components) != 2: raise TypeError( f"The vector length metadata should be in the form " - f"'form*integer' but found '{vector_datatype}'.") - array_dimension = components[1].strip() - return array_dimension + f"'form*vector_length' but found '{vector_datatype}'.") + vector_length = components[1].strip() + return vector_length @property def datatype(self): diff --git a/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py b/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py index 88f1c34e9a..01ec6fceed 100644 --- a/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/field_vector_arg_metadata.py @@ -32,7 +32,6 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab -# Modified L. Turner, Met Office '''Module containing the FieldVector Arg class which captures the metadata associated with a field vector argument. Supports the creation, modification @@ -91,7 +90,7 @@ def _get_metadata(cls, fparser2_tree): ''' datatype, access, function_space, stencil = super()._get_metadata( fparser2_tree) - vector_length = cls.get_array_dimension(fparser2_tree) + vector_length = cls.get_vector_length(fparser2_tree) return (datatype, access, function_space, vector_length, stencil) def fortran_string(self): diff --git a/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py b/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py index b941e6c24a..33193a96fe 100644 --- a/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/inter_grid_vector_arg_metadata.py @@ -32,7 +32,6 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab -# Modified L. Turner, Met Office '''Module containing the InterGridVectorArgMetadata class which captures the metadata associated with a intergrid vector argument. Supports the @@ -99,7 +98,7 @@ def _get_metadata(cls, fparser2_tree): ''' datatype, access, function_space, mesh_arg, stencil = \ super()._get_metadata(fparser2_tree) - vector_length = cls.get_array_dimension(fparser2_tree) + vector_length = cls.get_vector_length(fparser2_tree) return (datatype, access, function_space, mesh_arg, vector_length, stencil) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 55f76c5a42..c40445e2f2 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -233,22 +233,22 @@ def test_check_nargs(): CheckArg.check_nargs(fparser2_tree) -def test_get_array_dimension(): - '''Test that the get_array_dimension method in the +def test_get_vector_length(): + '''Test that the get_vector_length method in the CommonMetaArgMetadata class works as expected. ''' fparser_tree = CheckArg.create_fparser2( "arg_type(GH_FIELD, GH_REAL, GH_READ, W0)", Fortran2003.Part_Ref) with pytest.raises(TypeError) as info: - _ = CheckArg.get_array_dimension(fparser_tree) + _ = CheckArg.get_vector_length(fparser_tree) assert ("The vector length metadata should be in the form " - "'form*integer' but found 'GH_FIELD'." + "'form*vector_length' but found 'GH_FIELD'." in str(info.value)) fparser_tree = CheckArg.create_fparser2( "arg_type(GH_FIELD*3, GH_REAL, GH_READ, W0)", Fortran2003.Part_Ref) - vector_length = CheckArg.get_array_dimension(fparser_tree) + vector_length = CheckArg.get_vector_length(fparser_tree) assert vector_length == "3" From cc0ca8b4b0835adbe823d5ec2cfeb17f3b8ebb05 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 25 Sep 2023 12:56:09 +0100 Subject: [PATCH 021/119] #1312 removing name from modifier list and reinstating previous copyright date --- .../tests/domain/lfric/kernel/common_meta_arg_metadata_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index c40445e2f2..44e2df3497 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022-2023, Science and Technology Facilities Council +# Copyright (c) 2022, Science and Technology Facilities Council # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,6 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab -# Modified L. Turner, Met Office '''Module containing tests for the CommonMetaArgMetadata class. From c9e73570bae2fea45fc2f2556abc2da34325e937 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 25 Sep 2023 12:58:48 +0100 Subject: [PATCH 022/119] #1312 cleaning up pylint &c --- src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index dc8bf47b8d..8503b2ca30 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022-2023, Science and Technology Facilities Council +# Copyright (c) 2022, Science and Technology Facilities Council # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,6 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab -# Modified L. Turner, Met Office '''Module containing the abstract CommonMetaArgMetadata class which captures the metadata associated with an LFRic meta_arg @@ -44,7 +43,6 @@ from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.errors import InternalError -from psyclone.parse.utils import ParseError class CommonMetaArgMetadata(CommonArgMetadata, ABC): From 5433b4fce8f9a0a500775cb07c5850e88a575719 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 18 Jan 2024 17:05:20 +0000 Subject: [PATCH 023/119] #1312 DynKernMetadata -> LFRicKernMetadata, plus labelling untested lines --- .../domain/lfric/kernel/array_arg_metadata.py | 18 +++++----- .../domain/lfric/lfric_array_mdata_test.py | 36 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 75d3967017..632517ac4b 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2023, Science and Technology Facilities Council +# Copyright (c) 2023-2024, Science and Technology Facilities Council # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -70,8 +70,8 @@ class ArrayArgMetadata(ScalarArgMetadata): nargs = (4) def __init__(self, datatype, access, array_nranks): - super().__init__(datatype, access) - self.array_nranks = array_nranks + super().__init__(datatype, access) #SHARKS (needs test coverage) + self.array_nranks = array_nranks #SHARKS (needs test coverage) # @classmethod # def _get_metadata(cls, fparser2_tree): @@ -99,7 +99,7 @@ def fortran_string(self): :returns: the metadata represented by this class as Fortran. :rtype: str ''' - return (f"arg_type({self.form}, {self.datatype}, {self.access}, " + return (f"arg_type({self.form}, {self.datatype}, {self.access}, " #SHARKS (needs test coverage) f"{self.array_nranks})") @staticmethod @@ -111,8 +111,8 @@ def check_datatype(value): datatype descriptor. ''' - const = LFRicConstants() - ArrayArgMetadata.validate_scalar_value( + const = LFRicConstants() #SHARKS (needs test coverage) + ArrayArgMetadata.validate_scalar_value( #SHARKS (needs test coverage) value, const.VALID_ARRAY_DATA_TYPES, "datatype descriptor") @staticmethod @@ -120,8 +120,8 @@ def check_access(value): ''' :param str value: the access descriptor to validate. ''' - const = LFRicConstants() - ArrayArgMetadata.validate_scalar_value( + const = LFRicConstants() #SHARKS (needs test coverage) + ArrayArgMetadata.validate_scalar_value( #SHARKS (needs test coverage) value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") @property @@ -130,6 +130,6 @@ def array_nranks(self): :returns: the function space for this array argument. :rtype: str ''' - return self.array_nranks + return self.array_nranks #SHARKS (needs test coverage) __all__ = ["ArrayArgMetadata"] diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 341c3c0e8b..1b425d0999 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -42,8 +42,8 @@ import pytest import fparser from fparser import api as fpapi -from psyclone.domain.lfric import LFRicArgDescriptor -from psyclone.dynamo0p3 import DynKernMetadata, LFRicConstants +from psyclone.domain.lfric import LFRicArgDescriptor, LFRicKernMetadata +from psyclone.dynamo0p3 import LFRicConstants from psyclone.errors import InternalError from psyclone.parse.utils import ParseError @@ -82,7 +82,7 @@ def test_ad_array_init_wrong_argument_type(): is passed to the LFRicArgDescriptor._init_array() method. ''' ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) name = "testkern_array_type" - metadata = DynKernMetadata(ast, name=name) + metadata = LFRicKernMetadata(ast, name=name) # Get an argument which is not an array wrong_arg = metadata._inits[3] with pytest.raises(InternalError) as excinfo: @@ -102,7 +102,7 @@ def test_ad_array_type_wrong_num_of_args(): ast = fpapi.parse(code, ignore_comments=False) name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("each 'meta_arg' entry must have 4 arguments if its first " "argument is of ['gh_array'] type" in str(excinfo.value)) @@ -119,7 +119,7 @@ def test_ad_array_invalid_data_type(): ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " f"but found 'gh_unreal' in 'arg_type(gh_array, gh_unreal, " @@ -131,7 +131,7 @@ def test_ad_array_invalid_data_type(): ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " f"but found 'gh_frac' in 'arg_type(gh_array, gh_frac, " @@ -143,7 +143,7 @@ def test_ad_array_invalid_data_type(): ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " f"but found 'gh_illogical' in 'arg_type(gh_array, gh_illogical, " @@ -155,7 +155,7 @@ def test_ad_array_init_wrong_data_type(monkeypatch): is passed to the LFRicArgDescriptor._init_array() method. ''' ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) name = "testkern_array_type" - metadata = DynKernMetadata(ast, name=name) + metadata = LFRicKernMetadata(ast, name=name) # Get an array argument descriptor and set a wrong data type scalar_arg = metadata._inits[0] scalar_arg.args[1].name = "gh_double" @@ -184,7 +184,7 @@ def test_ad_array_type_no_write(): "arg_type(gh_array, gh_real, gh_write, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("array arguments must have read-only ('gh_read') " "access but found 'gh_write'" in str(excinfo.value)) @@ -201,7 +201,7 @@ def test_ad_array_type_no_inc(): "arg_type(gh_array, gh_real, gh_inc, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("array arguments must have read-only ('gh_read') " "access but found 'gh_inc'" in str(excinfo.value)) @@ -218,7 +218,7 @@ def test_ad_array_type_no_readwrite(): "arg_type(gh_array, gh_real, gh_readwrite, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("array arguments must have read-only ('gh_read') " "access but found 'gh_readwrite'" in str(excinfo.value)) @@ -233,7 +233,7 @@ def test_ad_array_type_no_sum(): ast = fpapi.parse(code, ignore_comments=False) name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("array arguments must have read-only ('gh_read') " "access but found 'gh_sum'" in str(excinfo.value)) @@ -250,7 +250,7 @@ def test_no_vector_array(): "gh_read, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("vector notation is only supported for ['gh_field'] argument " "types but found 'gh_array * 3'" in str(excinfo.value)) @@ -265,7 +265,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): ''' fparser.logging.disable(fparser.logging.CRITICAL) ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) - metadata = DynKernMetadata(ast, name="testkern_array_type") + metadata = LFRicKernMetadata(ast, name="testkern_array_type") array_descriptor = metadata.arg_descriptors[array_ind] # Assert correct string representation from LFRicArgDescriptor @@ -298,7 +298,7 @@ def test_keyword_not_nranks(): "gh_read, SKNARN*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("the 4th argument of a 'meta_arg' entry must use 'NRANKS' as " "the keyword in the format 'NRANKS*n' if the 1st argument " "is 'GH_ARRAY', but found 'sknarn' as the keyword in " @@ -316,7 +316,7 @@ def test_incorrect_operator(): "gh_read, NRANKS+1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("the 4th argument of a 'meta_arg' entry may be an " "array but if so must use '*' as the separator " "in the format 'NRANKS*n', but found '+' in " @@ -334,7 +334,7 @@ def test_n_not_integer(): "gh_read, NRANKS*0.5)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("the array notation must be in the format 'NRANKS*n' " "where 'n' is an integer, but '0.5' was found in " "'arg_type(gh_array, gh_real, gh_read, nranks * 0.5)'." @@ -351,7 +351,7 @@ def test_n_less_than_one(): "gh_read, NRANKS*0)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: - _ = DynKernMetadata(ast, name=name) + _ = LFRicKernMetadata(ast, name=name) assert ("the array notation must be in the format 'NRANKS*n' " "where 'n' is an integer >= 1. However, found n = '0' in " "'arg_type(gh_array, gh_real, gh_read, nranks * 0)'." From 255113dddf5b04d72544046fb3e5f8d58ca16dfd Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 18 Jan 2024 17:06:29 +0000 Subject: [PATCH 024/119] #1312 removing ParseError that is impossible to trigger --- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 8c609ca47e..06342d454e 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -334,14 +334,6 @@ def _validate_array_nranks(self, arg_type): # ... and set the array size if all checks pass self._array_nranks = arraysize - # Check that no other arguments than arrays use array notation - if self._argument_type not in \ - const.VALID_ARRAY_NAMES and self._array_nranks: - raise ParseError( #SHARKS (needs test coverage) - f"In the LFRic API, array notation is only supported for " - f"'{const.VALID_ARRAY_NAMES}' argument types but found " - f"'{arg_type.args[0]}' in '{arg_type}'.") - def _init_field(self, arg_type, operates_on): ''' Validates metadata descriptors for field arguments and From 2e7b8efcb90eea9aa712af2f2740023484ddf1ed Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 19 Jan 2024 15:15:55 +0000 Subject: [PATCH 025/119] #1312 some tidying and adding a new file for the tests --- .../lfric/kernel/array_arg_metadata_test.py | 43 +++++++++++++++++++ .../domain/lfric/lfric_array_mdata_test.py | 4 +- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py new file mode 100644 index 0000000000..f7bfecc2b2 --- /dev/null +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -0,0 +1,43 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022-2024, 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: L. Turner, Met Office + +'''Module containing tests for the ArrayArgMetadata class. + +''' +import pytest + +from fparser.two import Fortran2003 + +from psyclone.domain.lfric.kernel import ArrayArgMetadata \ No newline at end of file diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 1b425d0999..b3f467545c 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -42,8 +42,8 @@ import pytest import fparser from fparser import api as fpapi -from psyclone.domain.lfric import LFRicArgDescriptor, LFRicKernMetadata -from psyclone.dynamo0p3 import LFRicConstants +from psyclone.domain.lfric import LFRicArgDescriptor, LFRicConstants, + LFRicKernMetadata from psyclone.errors import InternalError from psyclone.parse.utils import ParseError From e8da6d0e5f56a93c9726668ba1af70437abb3e0f Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 23 Jan 2024 17:34:59 +0000 Subject: [PATCH 026/119] #1312 uncommenting section and distinguising array_size (prev array_nranks, NRANKS*n) from array_ndims (prev also array_nranks, n) --- src/psyclone/domain/lfric/kernel/__init__.py | 1 + .../domain/lfric/kernel/array_arg_metadata.py | 56 +++++++++---------- .../domain/lfric/lfric_arg_descriptor.py | 20 +++---- .../domain/lfric/lfric_array_mdata_test.py | 8 +-- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/__init__.py b/src/psyclone/domain/lfric/kernel/__init__.py index 150b5e5a02..e11847c738 100644 --- a/src/psyclone/domain/lfric/kernel/__init__.py +++ b/src/psyclone/domain/lfric/kernel/__init__.py @@ -36,6 +36,7 @@ '''Module for Kernels in the LFRic domain.''' +from psyclone.domain.lfric.kernel.array_arg_metadata import ArrayArgMetadata from psyclone.domain.lfric.kernel.columnwise_operator_arg_metadata import \ ColumnwiseOperatorArgMetadata from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 632517ac4b..c63c583d89 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -62,37 +62,37 @@ class ArrayArgMetadata(ScalarArgMetadata): form_arg_index = 0 datatype_arg_index = 1 access_arg_index = 2 - array_nranks_arg_index = 3 + array_size_arg_index = 3 # The name to use for any exceptions. check_name = "array" # The number of arguments in the language-level metadata (min and # max values). nargs = (4) - def __init__(self, datatype, access, array_nranks): + def __init__(self, datatype, access, array_size): super().__init__(datatype, access) #SHARKS (needs test coverage) - self.array_nranks = array_nranks #SHARKS (needs test coverage) - -# @classmethod -# def _get_metadata(cls, fparser2_tree): -# '''Extract the required metadata from the fparser2 tree and return it -# as strings. Also check that the metadata is in the expected -# form (but do not check the metadata values as that is done -# separately). -# -# :param fparser2_tree: fparser2 tree containing the metadata \ -# for this argument. -# :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ -# :py:class:`fparser.two.Fortran2003.Structure_Constructor` -# -# :returns: a tuple containing the datatype, access and array nranks \ -# metadata. -# :rtype: Tuple[str, str, str] -# -# ''' -# datatype, access = super()._get_metadata(fparser2_tree) -# # array_nranks = cls.get_array_dimension(fparser2_tree) -# return (datatype, access, array_nranks) + self.array_size = array_size #SHARKS (needs test coverage) + + @classmethod + def _get_metadata(cls, fparser2_tree): + '''Extract the required metadata from the fparser2 tree and return it + as strings. Also check that the metadata is in the expected + form (but do not check the metadata values as that is done + separately). + + :param fparser2_tree: fparser2 tree containing the metadata \ + for this argument. + :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ + :py:class:`fparser.two.Fortran2003.Structure_Constructor` + + :returns: a tuple containing the datatype, access and array nranks \ + metadata. + :rtype: Tuple[str, str, str] + + ''' + datatype, access = super()._get_metadata(fparser2_tree) + array_size = cls.get_array_dimension(fparser2_tree) + return (datatype, access, array_size) def fortran_string(self): ''' @@ -100,7 +100,7 @@ def fortran_string(self): :rtype: str ''' return (f"arg_type({self.form}, {self.datatype}, {self.access}, " #SHARKS (needs test coverage) - f"{self.array_nranks})") + f"{self.array_size})") @staticmethod def check_datatype(value): @@ -125,11 +125,11 @@ def check_access(value): value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") @property - def array_nranks(self): + def array_size(self): ''' - :returns: the function space for this array argument. + :returns: the array size for this array argument. :rtype: str ''' - return self.array_nranks #SHARKS (needs test coverage) + return self.array_size #SHARKS (needs test coverage) __all__ = ["ArrayArgMetadata"] diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 06342d454e..e7eeb87f71 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -102,7 +102,7 @@ def __init__(self, arg_type, operates_on, metadata_index): self._function_spaces = [] # Set vector size to 1 (scalars set it to 0 in their validation) self._vector_size = 1 - self._array_nranks = 1 + self._array_ndims = 1 # Initialise other internal arguments self._access_type = None self._function_space1 = None @@ -275,7 +275,7 @@ def _validate_vector_size(self, separator, arg_type): f"{const.VALID_FIELD_NAMES} argument types but found " f"'{arg_type.args[0]}'.") - def _validate_array_nranks(self, arg_type): + def _validate_array_ndims(self, arg_type): ''' Validates descriptors for scalar array arguments and populates vector properties accordingly. @@ -316,7 +316,7 @@ def _validate_array_nranks(self, arg_type): # Now try to find the array size for a scalar array and return # an error if it is not an integer number... try: - arraysize = int(arg_type.args[3].toks[2]) + array_ndims = int(arg_type.args[3].toks[2]) except ValueError as err: raise ParseError( f"In the LFRic API, the array notation must be in " @@ -326,13 +326,13 @@ def _validate_array_nranks(self, arg_type): # ... or it is less than 1 (1 is the default for all fields)... const = LFRicConstants() - if arraysize < 1: + if array_ndims < 1: raise ParseError( f"In the LFRic API, the array notation must be in " f"the format 'NRANKS*n' where 'n' is an integer >= 1. " f"However, found n = '{arraysize}' in '{arg_type}'.") # ... and set the array size if all checks pass - self._array_nranks = arraysize + self._array_ndims = array_ndims def _init_field(self, arg_type, operates_on): ''' @@ -665,7 +665,7 @@ def _init_scalar(self, arg_type): # Scalars don't have vector size or array size self._vector_size = 0 - self._array_nranks = 0 + self._array_ndims = 0 def _init_array(self, arg_type): ''' @@ -720,7 +720,7 @@ def _init_array(self, arg_type): f"('gh_read') access but found '{api_specific_name}' " f"in '{arg_type}'.") - self._validate_array_nranks(arg_type) + self._validate_array_ndims(arg_type) # Arrays don't have vector size self._vector_size = 0 @@ -841,7 +841,7 @@ def vector_size(self): return self._vector_size @property - def array_nranks(self): + def array_ndims(self): ''' Returns the array size of the argument. This will be 1 if ``*n`` has not been specified for all argument types except scalars @@ -851,7 +851,7 @@ def array_nranks(self): :rtype: int ''' - return self._array_nranks #SHARKS (needs test coverage) + return self._array_ndims #SHARKS (needs test coverage) def __str__(self): ''' @@ -879,7 +879,7 @@ def __str__(self): res += (f" function_space[3]='{self._function_space1}'" + os.linesep) elif self._argument_type in const.VALID_ARRAY_NAMES: - res += (f" array_nranks[3]='{self._array_nranks}'" + res += (f" array_ndims[3]='{self._array_ndims}'" + os.linesep) elif self._argument_type in const.VALID_OPERATOR_NAMES: res += (f" function_space_to[3]='{self._function_space1}'" diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index b3f467545c..88bfe7d1f6 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -255,9 +255,9 @@ def test_no_vector_array(): "types but found 'gh_array * 3'" in str(excinfo.value)) -@pytest.mark.parametrize("array_ind, array_type, array_ranks", [ +@pytest.mark.parametrize("array_ind, array_type, array_ndims", [ (0, "gh_real", 1), (1, "gh_integer", 2), (2, "gh_logical", 4)]) -def test_arg_descriptor_array(array_ind, array_type, array_ranks): +def test_arg_descriptor_array(array_ind, array_type, array_ndims): ''' Test that the LFRicArgDescriptor argument representation works as expected for all three types of valid array argument: 'real', 'integer' and 'logical'. @@ -275,13 +275,13 @@ def test_arg_descriptor_array(array_ind, array_type, array_ranks): f" argument_type[0]='gh_array'\n" f" data_type[1]='{array_type}'\n" f" access_descriptor[2]='gh_read'\n" - f" array_nranks[3]='{array_ranks}'") + f" array_ndims[3]='{array_ndims}'") assert expected_output in result # Check LFRicArgDescriptor argument properties assert array_descriptor.argument_type == "gh_array" assert array_descriptor.data_type == array_type - assert array_descriptor._array_nranks == array_ranks + assert array_descriptor._array_ndims == array_ndims assert array_descriptor.function_spaces == [None] assert str(array_descriptor.access) == "READ" assert array_descriptor.mesh is None From 0400ae057c3ff3c049afd2346b6f5f90eafbd83b Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 23 Jan 2024 17:39:36 +0000 Subject: [PATCH 027/119] #1312 missed one --- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index e7eeb87f71..11e13b3b19 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -330,7 +330,7 @@ def _validate_array_ndims(self, arg_type): raise ParseError( f"In the LFRic API, the array notation must be in " f"the format 'NRANKS*n' where 'n' is an integer >= 1. " - f"However, found n = '{arraysize}' in '{arg_type}'.") + f"However, found n = '{array_ndims}' in '{arg_type}'.") # ... and set the array size if all checks pass self._array_ndims = array_ndims From d9f4f601b890e32e39a83ffd8a1fbeaa6397fcef Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 23 Jan 2024 17:43:29 +0000 Subject: [PATCH 028/119] #1312 forgot some brackets! --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 88bfe7d1f6..09c80ebe53 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -42,8 +42,8 @@ import pytest import fparser from fparser import api as fpapi -from psyclone.domain.lfric import LFRicArgDescriptor, LFRicConstants, - LFRicKernMetadata +from psyclone.domain.lfric import (LFRicArgDescriptor, LFRicConstants, + LFRicKernMetadata) from psyclone.errors import InternalError from psyclone.parse.utils import ParseError From 2a0586593f94d59120c9eb09b1f57045dcc9bf7b Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 23 Jan 2024 17:54:31 +0000 Subject: [PATCH 029/119] #1312 pycodestyle changes --- .../domain/lfric/kernel/array_arg_metadata.py | 1 + .../domain/lfric/lfric_array_mdata_test.py | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index c63c583d89..497f728adb 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -132,4 +132,5 @@ def array_size(self): ''' return self.array_size #SHARKS (needs test coverage) + __all__ = ["ArrayArgMetadata"] diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 09c80ebe53..3e13600cea 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -114,8 +114,8 @@ def test_ad_array_invalid_data_type(): name = "testkern_array_type" # check real array code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_unreal, gh_read, " - "NRANKS*1)", 1) + "NRANKS*1)", "arg_type(gh_array, gh_unreal, " + "gh_read, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -126,8 +126,8 @@ def test_ad_array_invalid_data_type(): f"gh_read, nranks * 1)'." in str(excinfo.value)) # check integer array code = ARRAY_CODE.replace("arg_type(gh_array, gh_integer, gh_read, " - "NRANKS*2)", "arg_type(gh_array, gh_frac, gh_read, " - "NRANKS*2)", 1) + "NRANKS*2)", "arg_type(gh_array, gh_frac, " + "gh_read, NRANKS*2)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -138,8 +138,8 @@ def test_ad_array_invalid_data_type(): f"gh_read, nranks * 2)'." in str(excinfo.value)) # check logical array code = ARRAY_CODE.replace("arg_type(gh_array, gh_logical, gh_read, " - "NRANKS*4)", "arg_type(gh_array, gh_illogical, " - "gh_read, NRANKS*4)", 1) + "NRANKS*4)", "arg_type(gh_array, gh_illogical, " + "gh_read, NRANKS*4)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -246,8 +246,8 @@ def test_no_vector_array(): const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array*3, gh_real, " - "gh_read, NRANKS*1)", 1) + "NRANKS*1)", "arg_type(gh_array*3, gh_real, " + "gh_read, NRANKS*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -287,6 +287,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): assert array_descriptor.mesh is None assert array_descriptor.stencil is None + def test_keyword_not_nranks(): ''' Tests that we raise an error when the keyword is not nranks''' fparser.logging.disable(fparser.logging.CRITICAL) @@ -294,8 +295,8 @@ def test_keyword_not_nranks(): const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, SKNARN*1)", 1) + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, SKNARN*1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -305,6 +306,7 @@ def test_keyword_not_nranks(): "'arg_type(gh_array, gh_real, gh_read, sknarn * 1)'." in str(excinfo.value)) + def test_incorrect_operator(): ''' Tests that we raise an error when the operator is incorrect''' fparser.logging.disable(fparser.logging.CRITICAL) @@ -312,8 +314,8 @@ def test_incorrect_operator(): const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS+1)", 1) + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS+1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -323,6 +325,7 @@ def test_incorrect_operator(): "'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." in str(excinfo.value)) + def test_n_not_integer(): ''' Tests that we raise an error when n is not an integer''' fparser.logging.disable(fparser.logging.CRITICAL) @@ -330,8 +333,8 @@ def test_n_not_integer(): const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS*0.5)", 1) + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS*0.5)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -340,6 +343,7 @@ def test_n_not_integer(): "'arg_type(gh_array, gh_real, gh_read, nranks * 0.5)'." in str(excinfo.value)) + def test_n_less_than_one(): ''' Tests that we raise an error when n is less than 1''' fparser.logging.disable(fparser.logging.CRITICAL) @@ -347,8 +351,8 @@ def test_n_less_than_one(): const = LFRicConstants() for argname in const.VALID_ARRAY_NAMES: code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS*0)", 1) + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS*0)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) From e42c51b8bcd3bd4c88f7ac4a5a16896dcb4c42e0 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 2 Feb 2024 16:47:40 +0000 Subject: [PATCH 030/119] #1312 finally managed to get all but one of the array_arg_metadata tests working --- .../domain/lfric/kernel/array_arg_metadata.py | 59 ++++++++-- .../lfric/kernel/common_meta_arg_metadata.py | 34 ++++++ .../lfric/kernel/array_arg_metadata_test.py | 101 +++++++++++++++++- 3 files changed, 185 insertions(+), 9 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 497f728adb..40b2dd8fb8 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -48,7 +48,7 @@ class ArrayArgMetadata(ScalarArgMetadata): argument. :param str datatype: the datatype of this array (GH_INTEGER, ...). - :param str access: the way the kernel accesses this array (GH_WRITE, ...). + :param str access: the way the kernel accesses this array (GH_READ). :param str function_space: the function space that this array is \ on (W0, ...). @@ -69,9 +69,10 @@ class ArrayArgMetadata(ScalarArgMetadata): # max values). nargs = (4) - def __init__(self, datatype, access, array_size): - super().__init__(datatype, access) #SHARKS (needs test coverage) - self.array_size = array_size #SHARKS (needs test coverage) + def __init__(self, datatype, access, array_ndims): #the information that is given + super().__init__(datatype, access) #SHARKS (needs test coverage) + # self.array_size = array_size #SHARKS (needs test coverage) + self.array_ndims = array_ndims @classmethod def _get_metadata(cls, fparser2_tree): @@ -91,8 +92,8 @@ def _get_metadata(cls, fparser2_tree): ''' datatype, access = super()._get_metadata(fparser2_tree) - array_size = cls.get_array_dimension(fparser2_tree) - return (datatype, access, array_size) + array_ndims = cls.get_array_ndims(fparser2_tree) + return (datatype, access, array_ndims) def fortran_string(self): ''' @@ -100,7 +101,7 @@ def fortran_string(self): :rtype: str ''' return (f"arg_type({self.form}, {self.datatype}, {self.access}, " #SHARKS (needs test coverage) - f"{self.array_size})") + f"{self.array_ndims})") # how to check for full NRANKS*n here? @staticmethod def check_datatype(value): @@ -130,7 +131,49 @@ def array_size(self): :returns: the array size for this array argument. :rtype: str ''' - return self.array_size #SHARKS (needs test coverage) + return self._array_size #SHARKS (needs test coverage) + + @array_size.setter + def array_size(self, value): + ''' + :param str value: set the function space to the \ + specified value. + ''' + #const = LFRicConstants() + #FieldArgMetadata.validate_scalar_value( + # value, const.VALID_FUNCTION_SPACE_NAMES, "function space") + #self._array_ndims = cls.get_array_ndims(fparser2_tree) + self._array_size = value.lower() + + @property + def array_ndims(self): + ''' + :returns: the array size for this array argument. + :rtype: str + ''' + return self._array_ndims #SHARKS (needs test coverage) + + @array_ndims.setter + def array_ndims(self, value): + ''' + :param str value: set the function space to the \ + specified value. + ''' + if not isinstance(value, str): + raise TypeError(f"The 'array_size' value should be of type str, " + f"but found '{type(value).__name__}'.") + try: + int_value = int(value) + except ValueError as info: + raise ValueError( + f"The array size should be a string containing an integer, " + f"but found '{value}'.") from info + + if int_value < 1: + raise ValueError(f"The array size should be an integer greater " + f"than or equal to 1 but found {value}.") +# self._array_size = value.lower() + self._array_ndims = value __all__ = ["ArrayArgMetadata"] diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index b3d4af9d00..b209c329c9 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -61,6 +61,7 @@ class CommonMetaArgMetadata(CommonArgMetadata, ABC): datatype_arg_index = 1 access_arg_index = 2 function_space_arg_index = 3 + array_size_arg_index = 3 form = "" check_name = "" nargs = 1 @@ -200,6 +201,39 @@ def get_vector_length(cls, fparser2_tree): vector_length = components[1].strip() return vector_length + @classmethod + def get_array_ndims(cls, fparser2_tree): + '''Retrieves the array ndims metadata value found within the + supplied fparser2 tree and checks that it is valid. + + :param fparser2_tree: fparser2 tree capturing the required metadata. + :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` + + :returns: the array ndims value extracted from the fparser2 tree. + :rtype: str + + :raises TypeError: if the array ndims metadata is not in the \ + expected form. + + ''' + array_datatype = CommonArgMetadata.get_arg( + fparser2_tree, cls.array_size_arg_index) + components = array_datatype.split("*") + print(components) + if len(components) != 2: + raise TypeError( + f"The array size metadata should be in the form " + f"'keyword*array_ndims' but found '{array_datatype}'.") + if components[0].lower().strip() != "NRANKS".lower(): + raise ParseError( + f"In the LFRic API, the 4th argument of a 'meta_arg' " + f"entry must use 'NRANKS' as the keyword in the format " + f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " + f"found '{components[0]}' as the keyword " + f"in '{arg_type}'.") + array_ndims = components[1].strip() + return array_ndims + @property def datatype(self): ''' diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index f7bfecc2b2..c9263166a3 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -40,4 +40,103 @@ from fparser.two import Fortran2003 -from psyclone.domain.lfric.kernel import ArrayArgMetadata \ No newline at end of file +from psyclone.domain.lfric.kernel import ArrayArgMetadata + + +@pytest.mark.parametrize("datatype, access, array_ndims", [ + ("GH_REAL", "GH_READ", "1"), ("gh_real", "gh_read", "1")]) +def test_create(datatype, access, array_ndims): + '''Test that an instance of ArrayArgMetadata can be created + successfully. Also test that the arguments are case insensitive. + + ''' + array_arg = ArrayArgMetadata(datatype, access, array_ndims) + assert isinstance(array_arg, ArrayArgMetadata) + assert array_arg.form == "gh_array" + assert array_arg._datatype == "gh_real" + assert array_arg._access == "gh_read" + assert array_arg._array_ndims == "1" + + +def test_init_invalid_an(): + '''Test that an invalid array_size supplied to the constructor + raises the expected exception. + + ''' + with pytest.raises(TypeError) as info: + _ = ArrayArgMetadata("GH_REAL", "GH_READ", None) + assert ("The 'array_size' value should be of type str, but found " + "'NoneType'." in str(info.value)) + + +@pytest.mark.parametrize( + "metadata", + [("arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)")]) +def test_get_metadata(metadata): + '''Test that the _get_metadata class method works as expected + + ''' + fparser2_tree = ArrayArgMetadata.create_fparser2( + metadata, Fortran2003.Part_Ref) + datatype, access, array_ndims = ArrayArgMetadata._get_metadata( + fparser2_tree) + assert datatype == "GH_REAL" + assert access == "GH_READ" + assert array_ndims == "2" + + +@pytest.mark.parametrize("fortran_string", [ + "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) +def test_fortran_string(fortran_string): + '''Test that the fortran_string method works as expected. Test with + and without a stencil. + + ''' + array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) + result = array_arg.fortran_string() + assert result == fortran_string.lower() + + +def test_check_datatype(): + '''Test the check_datatype method works as expected.''' #expand to test gh_integer and gh_logical + ArrayArgMetadata.check_datatype("GH_REAL") + with pytest.raises(ValueError) as info: + ArrayArgMetadata.check_datatype("invalid") + assert ("The 'datatype descriptor' metadata should be a recognised value " + "(one of ['gh_real', 'gh_integer', 'gh_logical']) but found " + "'invalid'." in str(info.value)) + + +def test_check_access(): + '''Test the check_access method works as expected.''' + ArrayArgMetadata.check_access("GH_READ") + with pytest.raises(ValueError) as info: + ArrayArgMetadata.check_access("invalid") + assert ("The 'access descriptor' metadata should be a recognised value " + "(one of ['gh_read']) but found 'invalid'." in str(info.value)) + + +# def test_function_space_setter_getter(): +# '''Test that the function space setter and getter work as expected, +# including raising an exception if the value is invalid. + +# ''' +# array_arg = ArrayArgMetadata("GH_REAL", "GH_READ", "W0") +# with pytest.raises(ValueError) as info: +# array_arg.function_space = "invalid" +# assert ("The 'function space' metadata should be a recognised value (one " +# "of ['w3', 'wtheta', 'w2v', 'w2vtrace', 'w2broken', 'w0', 'w1', " +# "'w2', 'w2trace', 'w2h', 'w2htrace', 'any_w2', 'wchi', " +# "'any_space_1', 'any_space_2', 'any_space_3', 'any_space_4', " +# "'any_space_5', 'any_space_6', 'any_space_7', 'any_space_8', " +# "'any_space_9', 'any_space_10', 'any_discontinuous_space_1', " +# "'any_discontinuous_space_2', 'any_discontinuous_space_3', " +# "'any_discontinuous_space_4', 'any_discontinuous_space_5', " +# "'any_discontinuous_space_6', 'any_discontinuous_space_7', " +# "'any_discontinuous_space_8', 'any_discontinuous_space_9', " +# "'any_discontinuous_space_10']) but found 'invalid'." +# in str(info.value)) +# array_arg.function_space = "w3" +# assert array_arg.function_space == "w3" +# array_arg.function_space = "W3" +# assert array_arg.function_space == "w3" From 351c4d1f14c58db8352b8b32b6e0bd255db717c3 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 2 Feb 2024 16:50:29 +0000 Subject: [PATCH 031/119] #1312 commenting out non-working test to check nothing else is broken --- .../lfric/kernel/array_arg_metadata_test.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index c9263166a3..8e282eb6fa 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -84,17 +84,17 @@ def test_get_metadata(metadata): assert access == "GH_READ" assert array_ndims == "2" +#GET THIS WORKING +# @pytest.mark.parametrize("fortran_string", [ +# "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) +# def test_fortran_string(fortran_string): +# '''Test that the fortran_string method works as expected. Test with +# and without a stencil. -@pytest.mark.parametrize("fortran_string", [ - "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) -def test_fortran_string(fortran_string): - '''Test that the fortran_string method works as expected. Test with - and without a stencil. - - ''' - array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) - result = array_arg.fortran_string() - assert result == fortran_string.lower() +# ''' +# array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) +# result = array_arg.fortran_string() +# assert result == fortran_string.lower() def test_check_datatype(): From 2e039125a8013b34ee8833540fb397058985a9b5 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 5 Feb 2024 11:29:51 +0000 Subject: [PATCH 032/119] #1312 missing ParseError import --- src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index b209c329c9..15531e5d51 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -43,6 +43,7 @@ from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.errors import InternalError +from psyclone.parse.utils import ParseError class CommonMetaArgMetadata(CommonArgMetadata, ABC): From d0fe57cf1f06e6945cae1af6d4f23192d54c12d7 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 5 Feb 2024 11:42:43 +0000 Subject: [PATCH 033/119] #1312 more fixing for tests + adding name to file --- .../domain/lfric/kernel/common_meta_arg_metadata.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 15531e5d51..b6a3e419f9 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modifier L. Turner, Met Office '''Module containing the abstract CommonMetaArgMetadata class which captures the metadata associated with an LFRic meta_arg @@ -224,14 +225,14 @@ def get_array_ndims(cls, fparser2_tree): if len(components) != 2: raise TypeError( f"The array size metadata should be in the form " - f"'keyword*array_ndims' but found '{array_datatype}'.") + f"'NRANKS*array_ndims' but found '{array_datatype}'.") if components[0].lower().strip() != "NRANKS".lower(): raise ParseError( f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry must use 'NRANKS' as the keyword in the format " f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " - f"found '{components[0]}' as the keyword " - f"in '{arg_type}'.") + f"found '{components[0]}' as the keyword in " + f"'{array_datatype}'.") array_ndims = components[1].strip() return array_ndims From e12aefa9c5b69c20855f10101e5167e18ff36fa6 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 5 Feb 2024 11:57:43 +0000 Subject: [PATCH 034/119] #1312 tidying for pylint and pycodestyle --- .../domain/lfric/kernel/array_arg_metadata.py | 32 +++++++++---------- .../domain/lfric/lfric_arg_descriptor.py | 2 -- .../lfric/kernel/array_arg_metadata_test.py | 4 +-- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 40b2dd8fb8..eb1a463559 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -69,9 +69,9 @@ class ArrayArgMetadata(ScalarArgMetadata): # max values). nargs = (4) - def __init__(self, datatype, access, array_ndims): #the information that is given - super().__init__(datatype, access) #SHARKS (needs test coverage) - # self.array_size = array_size #SHARKS (needs test coverage) + def __init__(self, datatype, access, array_ndims): # the information that is given + super().__init__(datatype, access) # SHARKS (needs test coverage) + # self.array_size = array_size # SHARKS (needs test coverage) self.array_ndims = array_ndims @classmethod @@ -100,8 +100,8 @@ def fortran_string(self): :returns: the metadata represented by this class as Fortran. :rtype: str ''' - return (f"arg_type({self.form}, {self.datatype}, {self.access}, " #SHARKS (needs test coverage) - f"{self.array_ndims})") # how to check for full NRANKS*n here? + return (f"arg_type({self.form}, {self.datatype}, {self.access}, " # SHARKS (needs test coverage) + f"{self.array_ndims})") # how to check for full NRANKS*n here? @staticmethod def check_datatype(value): @@ -112,8 +112,8 @@ def check_datatype(value): datatype descriptor. ''' - const = LFRicConstants() #SHARKS (needs test coverage) - ArrayArgMetadata.validate_scalar_value( #SHARKS (needs test coverage) + const = LFRicConstants() # SHARKS (needs test coverage) + ArrayArgMetadata.validate_scalar_value( # SHARKS (needs test coverage) value, const.VALID_ARRAY_DATA_TYPES, "datatype descriptor") @staticmethod @@ -121,8 +121,8 @@ def check_access(value): ''' :param str value: the access descriptor to validate. ''' - const = LFRicConstants() #SHARKS (needs test coverage) - ArrayArgMetadata.validate_scalar_value( #SHARKS (needs test coverage) + const = LFRicConstants() # SHARKS (needs test coverage) + ArrayArgMetadata.validate_scalar_value( # SHARKS (needs test coverage) value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") @property @@ -131,7 +131,7 @@ def array_size(self): :returns: the array size for this array argument. :rtype: str ''' - return self._array_size #SHARKS (needs test coverage) + return self._array_size # SHARKS (needs test coverage) @array_size.setter def array_size(self, value): @@ -139,10 +139,10 @@ def array_size(self, value): :param str value: set the function space to the \ specified value. ''' - #const = LFRicConstants() - #FieldArgMetadata.validate_scalar_value( - # value, const.VALID_FUNCTION_SPACE_NAMES, "function space") - #self._array_ndims = cls.get_array_ndims(fparser2_tree) + # const = LFRicConstants() + # FieldArgMetadata.validate_scalar_value( + # value, const.VALID_FUNCTION_SPACE_NAMES, "function space") + # self._array_ndims = cls.get_array_ndims(fparser2_tree) self._array_size = value.lower() @property @@ -151,8 +151,8 @@ def array_ndims(self): :returns: the array size for this array argument. :rtype: str ''' - return self._array_ndims #SHARKS (needs test coverage) - + return self._array_ndims # SHARKS (needs test coverage) + @array_ndims.setter def array_ndims(self, value): ''' diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 11e13b3b19..0eba431e47 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -325,7 +325,6 @@ def _validate_array_ndims(self, arg_type): f"'{arg_type}'.") from err # ... or it is less than 1 (1 is the default for all fields)... - const = LFRicConstants() if array_ndims < 1: raise ParseError( f"In the LFRic API, the array notation must be in " @@ -714,7 +713,6 @@ def _init_array(self, arg_type): rev_access_mapping = api_config.get_reverse_access_mapping() if self._access_type not in array_accesses: api_specific_name = rev_access_mapping[self._access_type] - valid_reductions = AccessType.get_valid_reduction_names() raise ParseError( f"In the LFRic API array arguments must have read-only " f"('gh_read') access but found '{api_specific_name}' " diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 8e282eb6fa..129da08c88 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -84,7 +84,7 @@ def test_get_metadata(metadata): assert access == "GH_READ" assert array_ndims == "2" -#GET THIS WORKING +# GET THIS WORKING # @pytest.mark.parametrize("fortran_string", [ # "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) # def test_fortran_string(fortran_string): @@ -98,7 +98,7 @@ def test_get_metadata(metadata): def test_check_datatype(): - '''Test the check_datatype method works as expected.''' #expand to test gh_integer and gh_logical + '''Test the check_datatype method works as expected.''' # expand to test gh_integer and gh_logical ArrayArgMetadata.check_datatype("GH_REAL") with pytest.raises(ValueError) as info: ArrayArgMetadata.check_datatype("invalid") From d40d01b0a7d11537fc9decc0b88cd6948201ab73 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 5 Feb 2024 13:31:04 +0000 Subject: [PATCH 035/119] #1312 adding test for get_array_ndims --- .../lfric/kernel/common_meta_arg_metadata.py | 4 +++- .../kernel/common_meta_arg_metadata_test.py | 18 ++++++++++++++++++ .../domain/lfric/lfric_array_mdata_test.py | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index b6a3e419f9..3df1aa30ff 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -214,8 +214,10 @@ def get_array_ndims(cls, fparser2_tree): :returns: the array ndims value extracted from the fparser2 tree. :rtype: str - :raises TypeError: if the array ndims metadata is not in the \ + :raises TypeError: if the array ndims metadata is not in the expected form. + :raises ParseError: if the array ndims metadata does not use the + expected keyword. ''' array_datatype = CommonArgMetadata.get_arg( diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index d1bd90b6bf..24b44564be 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -257,6 +257,24 @@ def test_get_vector_length(): assert vector_length == "3" +def test_get_array_ndims(): + '''Test that the get_array_ndims method in the + CommonMetaArgMetadata class works as expected. + + ''' + fparser_tree = CheckArg.create_fparser2( + "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS2)", Fortran2003.Part_Ref) + with pytest.raises(TypeError) as info: + _ = CheckArg.get_array_ndims(fparser_tree) + assert ("The array size metadata should be in the form " + "'NRANKS*array_ndims' but found 'NRANKS2'." + in str(info.value)) + + fparser_tree = CheckArg.create_fparser2( + "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*3)", Fortran2003.Part_Ref) + vector_length = CheckArg.get_array_ndims(fparser_tree) + assert vector_length == "3" + def test_setter_getter(): '''Test that the setters and getters in the CommonMetaArgMetadata class work as expected. diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 3e13600cea..54450beb99 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -281,7 +281,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): # Check LFRicArgDescriptor argument properties assert array_descriptor.argument_type == "gh_array" assert array_descriptor.data_type == array_type - assert array_descriptor._array_ndims == array_ndims + assert array_descriptor.array_ndims == array_ndims assert array_descriptor.function_spaces == [None] assert str(array_descriptor.access) == "READ" assert array_descriptor.mesh is None From fe4baf9c33637536b45d9f4bb00ed9b2a654271c Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Mon, 5 Feb 2024 16:26:05 +0000 Subject: [PATCH 036/119] #1312 adding test for the array_ndims setter --- .../domain/lfric/kernel/array_arg_metadata.py | 17 +++++----- .../lfric/kernel/common_meta_arg_metadata.py | 2 +- .../lfric/kernel/array_arg_metadata_test.py | 33 +++++++++++++++---- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index eb1a463559..f7578a93a8 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -112,8 +112,8 @@ def check_datatype(value): datatype descriptor. ''' - const = LFRicConstants() # SHARKS (needs test coverage) - ArrayArgMetadata.validate_scalar_value( # SHARKS (needs test coverage) + const = LFRicConstants() + ArrayArgMetadata.validate_scalar_value( value, const.VALID_ARRAY_DATA_TYPES, "datatype descriptor") @staticmethod @@ -121,8 +121,8 @@ def check_access(value): ''' :param str value: the access descriptor to validate. ''' - const = LFRicConstants() # SHARKS (needs test coverage) - ArrayArgMetadata.validate_scalar_value( # SHARKS (needs test coverage) + const = LFRicConstants() + ArrayArgMetadata.validate_scalar_value( value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") @property @@ -143,7 +143,7 @@ def array_size(self, value): # FieldArgMetadata.validate_scalar_value( # value, const.VALID_FUNCTION_SPACE_NAMES, "function space") # self._array_ndims = cls.get_array_ndims(fparser2_tree) - self._array_size = value.lower() + self._array_size = value.lower() # SHARKS (needs test coverage) @property def array_ndims(self): @@ -165,12 +165,11 @@ def array_ndims(self, value): try: int_value = int(value) except ValueError as info: - raise ValueError( - f"The array size should be a string containing an integer, " - f"but found '{value}'.") from info + raise ValueError(f"The array size should be a string containing " # SHARKS (needs test coverage) + f"an integer, but found '{value}'.") from info if int_value < 1: - raise ValueError(f"The array size should be an integer greater " + raise ValueError(f"The array size should be an integer greater " # SHARKS (needs test coverage) f"than or equal to 1 but found {value}.") # self._array_size = value.lower() self._array_ndims = value diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 3df1aa30ff..b7f5712aa9 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -229,7 +229,7 @@ def get_array_ndims(cls, fparser2_tree): f"The array size metadata should be in the form " f"'NRANKS*array_ndims' but found '{array_datatype}'.") if components[0].lower().strip() != "NRANKS".lower(): - raise ParseError( + raise ParseError( # SHARKS (needs test coverage) f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry must use 'NRANKS' as the keyword in the format " f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 129da08c88..07dd3e1920 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -73,9 +73,7 @@ def test_init_invalid_an(): "metadata", [("arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)")]) def test_get_metadata(metadata): - '''Test that the _get_metadata class method works as expected - - ''' + '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ArrayArgMetadata.create_fparser2( metadata, Fortran2003.Part_Ref) datatype, access, array_ndims = ArrayArgMetadata._get_metadata( @@ -88,10 +86,7 @@ def test_get_metadata(metadata): # @pytest.mark.parametrize("fortran_string", [ # "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) # def test_fortran_string(fortran_string): -# '''Test that the fortran_string method works as expected. Test with -# and without a stencil. - -# ''' +# '''Test that the fortran_string method works as expected.''' # array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) # result = array_arg.fortran_string() # assert result == fortran_string.lower() @@ -116,6 +111,30 @@ def test_check_access(): "(one of ['gh_read']) but found 'invalid'." in str(info.value)) +# def test_array_size_setter(): + + +def test_array_ndims_setter_getter(): + '''Test that the array_ndims setter and getter work as expected, + including raising an exception if the value is invalid. + + ''' + array_arg = ArrayArgMetadata("GH_REAL", "GH_READ", "2") + + with pytest.raises(ValueError) as info: + array_arg.array_ndims = "invalid" + assert ("The array size should be a string containing an integer, " + "but found 'invalid'." in str(info.value)) + + with pytest.raises(ValueError) as info: + array_arg.array_ndims = "0" + assert ("The array size should be an integer greater than or equal to " + "1 but found 0." in str(info.value)) + + array_arg.array_ndims = "3" + assert array_arg.array_ndims == "3" + + # def test_function_space_setter_getter(): # '''Test that the function space setter and getter work as expected, # including raising an exception if the value is invalid. From 0d2eae604ff0493b15b5d9848aec0184b266203d Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 13:54:50 +0000 Subject: [PATCH 037/119] #1312 fixing fortran_string test --- .../domain/lfric/kernel/array_arg_metadata.py | 25 +++++----- .../lfric/kernel/array_arg_metadata_test.py | 49 +++++-------------- 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index f7578a93a8..1a73930d67 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -70,8 +70,7 @@ class ArrayArgMetadata(ScalarArgMetadata): nargs = (4) def __init__(self, datatype, access, array_ndims): # the information that is given - super().__init__(datatype, access) # SHARKS (needs test coverage) - # self.array_size = array_size # SHARKS (needs test coverage) + super().__init__(datatype, access) self.array_ndims = array_ndims @classmethod @@ -86,7 +85,7 @@ def _get_metadata(cls, fparser2_tree): :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ :py:class:`fparser.two.Fortran2003.Structure_Constructor` - :returns: a tuple containing the datatype, access and array nranks \ + :returns: a tuple containing the datatype, access and array ndims \ metadata. :rtype: Tuple[str, str, str] @@ -101,7 +100,7 @@ def fortran_string(self): :rtype: str ''' return (f"arg_type({self.form}, {self.datatype}, {self.access}, " # SHARKS (needs test coverage) - f"{self.array_ndims})") # how to check for full NRANKS*n here? + f"nranks*{self.array_ndims})") # how to check for full NRANKS*n here? @staticmethod def check_datatype(value): @@ -120,6 +119,10 @@ def check_datatype(value): def check_access(value): ''' :param str value: the access descriptor to validate. + + :raises ValueError: if the provided value is not a valid \ + access descriptor. + ''' const = LFRicConstants() ArrayArgMetadata.validate_scalar_value( @@ -139,10 +142,9 @@ def array_size(self, value): :param str value: set the function space to the \ specified value. ''' - # const = LFRicConstants() - # FieldArgMetadata.validate_scalar_value( - # value, const.VALID_FUNCTION_SPACE_NAMES, "function space") - # self._array_ndims = cls.get_array_ndims(fparser2_tree) + if not isinstance(value, str): + raise TypeError(f"The 'array_size' value should be of type str, " + f"but found '{type(value).__name__}'.") self._array_size = value.lower() # SHARKS (needs test coverage) @property @@ -151,7 +153,7 @@ def array_ndims(self): :returns: the array size for this array argument. :rtype: str ''' - return self._array_ndims # SHARKS (needs test coverage) + return self._array_ndims @array_ndims.setter def array_ndims(self, value): @@ -165,13 +167,12 @@ def array_ndims(self, value): try: int_value = int(value) except ValueError as info: - raise ValueError(f"The array size should be a string containing " # SHARKS (needs test coverage) + raise ValueError(f"The array size should be a string containing " f"an integer, but found '{value}'.") from info if int_value < 1: - raise ValueError(f"The array size should be an integer greater " # SHARKS (needs test coverage) + raise ValueError(f"The array size should be an integer greater " f"than or equal to 1 but found {value}.") -# self._array_size = value.lower() self._array_ndims = value diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 07dd3e1920..116939880d 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -53,9 +53,9 @@ def test_create(datatype, access, array_ndims): array_arg = ArrayArgMetadata(datatype, access, array_ndims) assert isinstance(array_arg, ArrayArgMetadata) assert array_arg.form == "gh_array" - assert array_arg._datatype == "gh_real" - assert array_arg._access == "gh_read" - assert array_arg._array_ndims == "1" + assert array_arg.datatype == "gh_real" + assert array_arg.access == "gh_read" + assert array_arg.array_ndims == "1" def test_init_invalid_an(): @@ -71,7 +71,7 @@ def test_init_invalid_an(): @pytest.mark.parametrize( "metadata", - [("arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)")]) + ["arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)"]) def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ArrayArgMetadata.create_fparser2( @@ -83,13 +83,14 @@ def test_get_metadata(metadata): assert array_ndims == "2" # GET THIS WORKING -# @pytest.mark.parametrize("fortran_string", [ -# "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) -# def test_fortran_string(fortran_string): -# '''Test that the fortran_string method works as expected.''' -# array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) -# result = array_arg.fortran_string() -# assert result == fortran_string.lower() +@pytest.mark.parametrize("fortran_string", [ + "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) +def test_fortran_string(fortran_string): + '''Test that the fortran_string method works as expected.''' + array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) + result = array_arg.fortran_string() + fortranstring = fortran_string + assert result == fortran_string.lower() def test_check_datatype(): @@ -133,29 +134,3 @@ def test_array_ndims_setter_getter(): array_arg.array_ndims = "3" assert array_arg.array_ndims == "3" - - -# def test_function_space_setter_getter(): -# '''Test that the function space setter and getter work as expected, -# including raising an exception if the value is invalid. - -# ''' -# array_arg = ArrayArgMetadata("GH_REAL", "GH_READ", "W0") -# with pytest.raises(ValueError) as info: -# array_arg.function_space = "invalid" -# assert ("The 'function space' metadata should be a recognised value (one " -# "of ['w3', 'wtheta', 'w2v', 'w2vtrace', 'w2broken', 'w0', 'w1', " -# "'w2', 'w2trace', 'w2h', 'w2htrace', 'any_w2', 'wchi', " -# "'any_space_1', 'any_space_2', 'any_space_3', 'any_space_4', " -# "'any_space_5', 'any_space_6', 'any_space_7', 'any_space_8', " -# "'any_space_9', 'any_space_10', 'any_discontinuous_space_1', " -# "'any_discontinuous_space_2', 'any_discontinuous_space_3', " -# "'any_discontinuous_space_4', 'any_discontinuous_space_5', " -# "'any_discontinuous_space_6', 'any_discontinuous_space_7', " -# "'any_discontinuous_space_8', 'any_discontinuous_space_9', " -# "'any_discontinuous_space_10']) but found 'invalid'." -# in str(info.value)) -# array_arg.function_space = "w3" -# assert array_arg.function_space == "w3" -# array_arg.function_space = "W3" -# assert array_arg.function_space == "w3" From 9fa6093217b6fc75cfc6c7827aab1d84be90d6dd Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 14:28:09 +0000 Subject: [PATCH 038/119] 1312 tidying of comments and strings --- .../domain/lfric/kernel/array_arg_metadata.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 1a73930d67..3fa64918ce 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -39,8 +39,7 @@ ''' from psyclone.domain.lfric import LFRicConstants -from psyclone.domain.lfric.kernel.scalar_arg_metadata import \ - ScalarArgMetadata +from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata class ArrayArgMetadata(ScalarArgMetadata): @@ -69,7 +68,7 @@ class ArrayArgMetadata(ScalarArgMetadata): # max values). nargs = (4) - def __init__(self, datatype, access, array_ndims): # the information that is given + def __init__(self, datatype, access, array_ndims): super().__init__(datatype, access) self.array_ndims = array_ndims @@ -80,12 +79,12 @@ def _get_metadata(cls, fparser2_tree): form (but do not check the metadata values as that is done separately). - :param fparser2_tree: fparser2 tree containing the metadata \ + :param fparser2_tree: fparser2 tree containing the metadata for this argument. - :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \ + :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | :py:class:`fparser.two.Fortran2003.Structure_Constructor` - :returns: a tuple containing the datatype, access and array ndims \ + :returns: a tuple containing the datatype, access and array ndims metadata. :rtype: Tuple[str, str, str] @@ -100,14 +99,14 @@ def fortran_string(self): :rtype: str ''' return (f"arg_type({self.form}, {self.datatype}, {self.access}, " # SHARKS (needs test coverage) - f"nranks*{self.array_ndims})") # how to check for full NRANKS*n here? + f"nranks*{self.array_ndims})") @staticmethod def check_datatype(value): ''' :param str value: the datatype to check for validity. - :raises ValueError: if the provided value is not a valid \ + :raises ValueError: if the provided value is not a valid datatype descriptor. ''' @@ -120,7 +119,7 @@ def check_access(value): ''' :param str value: the access descriptor to validate. - :raises ValueError: if the provided value is not a valid \ + :raises ValueError: if the provided value is not a valid access descriptor. ''' @@ -139,7 +138,7 @@ def array_size(self): @array_size.setter def array_size(self, value): ''' - :param str value: set the function space to the \ + :param str value: set the function space to the specified value. ''' if not isinstance(value, str): @@ -158,7 +157,7 @@ def array_ndims(self): @array_ndims.setter def array_ndims(self, value): ''' - :param str value: set the function space to the \ + :param str value: set the function space to the specified value. ''' if not isinstance(value, str): From 23b4b2540e6d113663c0c5a982bc355f9957d1c3 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 14:49:46 +0000 Subject: [PATCH 039/119] #1312 removing unused code --- .../domain/lfric/kernel/array_arg_metadata.py | 21 +------------------ .../lfric/kernel/array_arg_metadata_test.py | 8 ++----- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 3fa64918ce..dbb8ec56f7 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -98,7 +98,7 @@ def fortran_string(self): :returns: the metadata represented by this class as Fortran. :rtype: str ''' - return (f"arg_type({self.form}, {self.datatype}, {self.access}, " # SHARKS (needs test coverage) + return (f"arg_type({self.form}, {self.datatype}, {self.access}, " f"nranks*{self.array_ndims})") @staticmethod @@ -127,25 +127,6 @@ def check_access(value): ArrayArgMetadata.validate_scalar_value( value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") - @property - def array_size(self): - ''' - :returns: the array size for this array argument. - :rtype: str - ''' - return self._array_size # SHARKS (needs test coverage) - - @array_size.setter - def array_size(self, value): - ''' - :param str value: set the function space to the - specified value. - ''' - if not isinstance(value, str): - raise TypeError(f"The 'array_size' value should be of type str, " - f"but found '{type(value).__name__}'.") - self._array_size = value.lower() # SHARKS (needs test coverage) - @property def array_ndims(self): ''' diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 116939880d..14483e512d 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -69,8 +69,7 @@ def test_init_invalid_an(): "'NoneType'." in str(info.value)) -@pytest.mark.parametrize( - "metadata", +@pytest.mark.parametrize("metadata", ["arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)"]) def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' @@ -82,7 +81,7 @@ def test_get_metadata(metadata): assert access == "GH_READ" assert array_ndims == "2" -# GET THIS WORKING + @pytest.mark.parametrize("fortran_string", [ "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) def test_fortran_string(fortran_string): @@ -112,9 +111,6 @@ def test_check_access(): "(one of ['gh_read']) but found 'invalid'." in str(info.value)) -# def test_array_size_setter(): - - def test_array_ndims_setter_getter(): '''Test that the array_ndims setter and getter work as expected, including raising an exception if the value is invalid. From 5df7abb25908a6878e084586d7f1f90a08923af8 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 15:22:27 +0000 Subject: [PATCH 040/119] #1312 adding test for get_array_dims ParseError --- .../domain/lfric/kernel/common_meta_arg_metadata.py | 2 +- .../lfric/kernel/common_meta_arg_metadata_test.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index b7f5712aa9..2eb0e2bb89 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -233,7 +233,7 @@ def get_array_ndims(cls, fparser2_tree): f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry must use 'NRANKS' as the keyword in the format " f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " - f"found '{components[0]}' as the keyword in " + f"found '{components[0].strip()}' as the keyword in " f"'{array_datatype}'.") array_ndims = components[1].strip() return array_ndims diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 24b44564be..b578f2b248 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -43,6 +43,7 @@ from psyclone.domain.lfric.kernel import ( CommonMetaArgMetadata, ScalarArgMetadata) from psyclone.errors import InternalError +from psyclone.parse.utils import ParseError # pylint: disable=abstract-class-instantiated @@ -270,6 +271,16 @@ def test_get_array_ndims(): "'NRANKS*array_ndims' but found 'NRANKS2'." in str(info.value)) + fparser_tree = CheckArg.create_fparser2( + "arg_type(GH_ARRAY, GH_REAL, GH_READ, SKARN*2)", Fortran2003.Part_Ref) + with pytest.raises(ParseError) as info: + _ = CheckArg.get_array_ndims(fparser_tree) + assert ("In the LFRic API, the 4th argument of a 'meta_arg' entry must " + "use 'NRANKS' as the keyword in the format 'NRANKS*n' if the 1st " + "argument is 'GH_ARRAY', but found 'SKARN' as the keyword in " + "'SKARN * 2'." in + str(info.value)) + fparser_tree = CheckArg.create_fparser2( "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*3)", Fortran2003.Part_Ref) vector_length = CheckArg.get_array_ndims(fparser_tree) From 2223df2f0cbe13010b5a78ee749bef6dc5576dc3 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 16:08:20 +0000 Subject: [PATCH 041/119] #1312 expanding check_datatype to test gh_integer and gh_logical --- .../tests/domain/lfric/kernel/array_arg_metadata_test.py | 7 ++++--- .../domain/lfric/kernel/common_meta_arg_metadata_test.py | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 14483e512d..95302ace0e 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -92,9 +92,10 @@ def test_fortran_string(fortran_string): assert result == fortran_string.lower() -def test_check_datatype(): - '''Test the check_datatype method works as expected.''' # expand to test gh_integer and gh_logical - ArrayArgMetadata.check_datatype("GH_REAL") +@pytest.mark.parametrize("datatype", ["GH_REAL", "GH_INTEGER", "GH_LOGICAL"]) +def test_check_datatype(datatype): + '''Test the check_datatype method works as expected.''' # expand to test gh_integer and gh_logical + ArrayArgMetadata.check_datatype(datatype) with pytest.raises(ValueError) as info: ArrayArgMetadata.check_datatype("invalid") assert ("The 'datatype descriptor' metadata should be a recognised value " diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index b578f2b248..df69505ffd 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -286,6 +286,7 @@ def test_get_array_ndims(): vector_length = CheckArg.get_array_ndims(fparser_tree) assert vector_length == "3" + def test_setter_getter(): '''Test that the setters and getters in the CommonMetaArgMetadata class work as expected. From 8d2a37aeeb3309bd1cb7e9d28b14308cf3e09874 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 16:28:20 +0000 Subject: [PATCH 042/119] #1312 changes for pylint and pycodestyle --- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 2 +- .../tests/domain/lfric/kernel/array_arg_metadata_test.py | 7 +++---- .../domain/lfric/kernel/common_meta_arg_metadata_test.py | 9 +++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 0eba431e47..e02267c85e 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -849,7 +849,7 @@ def array_ndims(self): :rtype: int ''' - return self._array_ndims #SHARKS (needs test coverage) + return self._array_ndims def __str__(self): ''' diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 95302ace0e..4d73a1cbe2 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -70,12 +70,12 @@ def test_init_invalid_an(): @pytest.mark.parametrize("metadata", - ["arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)"]) + ["arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)"]) def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ArrayArgMetadata.create_fparser2( metadata, Fortran2003.Part_Ref) - datatype, access, array_ndims = ArrayArgMetadata._get_metadata( + datatype, access, array_ndims = ArrayArgMetadata._get_metadata( fparser2_tree) assert datatype == "GH_REAL" assert access == "GH_READ" @@ -88,13 +88,12 @@ def test_fortran_string(fortran_string): '''Test that the fortran_string method works as expected.''' array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) result = array_arg.fortran_string() - fortranstring = fortran_string assert result == fortran_string.lower() @pytest.mark.parametrize("datatype", ["GH_REAL", "GH_INTEGER", "GH_LOGICAL"]) def test_check_datatype(datatype): - '''Test the check_datatype method works as expected.''' # expand to test gh_integer and gh_logical + '''Test the check_datatype method works as expected.''' ArrayArgMetadata.check_datatype(datatype) with pytest.raises(ValueError) as info: ArrayArgMetadata.check_datatype("invalid") diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index df69505ffd..7083138e8c 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modifier L. Turner, Met Office '''Module containing tests for the CommonMetaArgMetadata class. @@ -59,10 +60,10 @@ def test_init_error(): # We split the check to accomodate for this. assert ("Can't instantiate abstract class CommonMetaArgMetadata with" in str(info.value)) - assert ("abstract methods" in str(info.value)) - assert ("_get_metadata" in str(info.value)) - assert ("check_access" in str(info.value)) - assert ("check_datatype" in str(info.value)) + assert "abstract methods" in str(info.value) + assert "_get_metadata" in str(info.value) + assert "check_access" in str(info.value) + assert "check_datatype" in str(info.value) # pylint: enable=abstract-class-instantiated From c530e6943c3fe754c777a719efa4a2188ad538ae Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 6 Feb 2024 16:59:55 +0000 Subject: [PATCH 043/119] #1312 removing unnecessary 'for' loops for pylint --- .../domain/lfric/lfric_array_mdata_test.py | 164 ++++++++---------- 1 file changed, 74 insertions(+), 90 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 54450beb99..0b644bd9c3 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -177,16 +177,14 @@ def test_ad_array_type_no_write(): metadata for a scalar specifies 'GH_WRITE' access. ''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_write, NRANKS*1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " - "access but found 'gh_write'" in str(excinfo.value)) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_write, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_write'" in str(excinfo.value)) def test_ad_array_type_no_inc(): @@ -194,16 +192,14 @@ def test_ad_array_type_no_inc(): metadata for a scalar specifies 'GH_INC' access. ''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_inc, NRANKS*1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " - "access but found 'gh_inc'" in str(excinfo.value)) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_inc, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_inc'" in str(excinfo.value)) def test_ad_array_type_no_readwrite(): @@ -211,16 +207,14 @@ def test_ad_array_type_no_readwrite(): metadata for an array specifies 'GH_READWRITE' access. ''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_readwrite, NRANKS*1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " - "access but found 'gh_readwrite'" in str(excinfo.value)) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", + "arg_type(gh_array, gh_real, gh_readwrite, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("array arguments must have read-only ('gh_read') " + "access but found 'gh_readwrite'" in str(excinfo.value)) def test_ad_array_type_no_sum(): @@ -243,16 +237,14 @@ def test_no_vector_array(): specifies a vector scalar argument. ''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array*3, gh_real, " - "gh_read, NRANKS*1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("vector notation is only supported for ['gh_field'] argument " - "types but found 'gh_array * 3'" in str(excinfo.value)) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array*3, gh_real, " + "gh_read, NRANKS*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("vector notation is only supported for ['gh_field'] argument " + "types but found 'gh_array * 3'" in str(excinfo.value)) @pytest.mark.parametrize("array_ind, array_type, array_ndims", [ @@ -292,71 +284,63 @@ def test_keyword_not_nranks(): ''' Tests that we raise an error when the keyword is not nranks''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, SKNARN*1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("the 4th argument of a 'meta_arg' entry must use 'NRANKS' as " - "the keyword in the format 'NRANKS*n' if the 1st argument " - "is 'GH_ARRAY', but found 'sknarn' as the keyword in " - "'arg_type(gh_array, gh_real, gh_read, sknarn * 1)'." - in str(excinfo.value)) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, SKNARN*1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("the 4th argument of a 'meta_arg' entry must use 'NRANKS' as " + "the keyword in the format 'NRANKS*n' if the 1st argument " + "is 'GH_ARRAY', but found 'sknarn' as the keyword in " + "'arg_type(gh_array, gh_real, gh_read, sknarn * 1)'." + in str(excinfo.value)) def test_incorrect_operator(): ''' Tests that we raise an error when the operator is incorrect''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS+1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("the 4th argument of a 'meta_arg' entry may be an " - "array but if so must use '*' as the separator " - "in the format 'NRANKS*n', but found '+' in " - "'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." - in str(excinfo.value)) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS+1)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("the 4th argument of a 'meta_arg' entry may be an " + "array but if so must use '*' as the separator " + "in the format 'NRANKS*n', but found '+' in " + "'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." + in str(excinfo.value)) def test_n_not_integer(): ''' Tests that we raise an error when n is not an integer''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS*0.5)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("the array notation must be in the format 'NRANKS*n' " - "where 'n' is an integer, but '0.5' was found in " - "'arg_type(gh_array, gh_real, gh_read, nranks * 0.5)'." - in str(excinfo.value)) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS*0.5)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("the array notation must be in the format 'NRANKS*n' " + "where 'n' is an integer, but '0.5' was found in " + "'arg_type(gh_array, gh_real, gh_read, nranks * 0.5)'." + in str(excinfo.value)) def test_n_less_than_one(): ''' Tests that we raise an error when n is less than 1''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - const = LFRicConstants() - for argname in const.VALID_ARRAY_NAMES: - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS*0)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("the array notation must be in the format 'NRANKS*n' " - "where 'n' is an integer >= 1. However, found n = '0' in " - "'arg_type(gh_array, gh_real, gh_read, nranks * 0)'." - in str(excinfo.value)) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " + "NRANKS*1)", "arg_type(gh_array, gh_real, " + "gh_read, NRANKS*0)", 1) + ast = fpapi.parse(code, ignore_comments=False) + with pytest.raises(ParseError) as excinfo: + _ = LFRicKernMetadata(ast, name=name) + assert ("the array notation must be in the format 'NRANKS*n' " + "where 'n' is an integer >= 1. However, found n = '0' in " + "'arg_type(gh_array, gh_real, gh_read, nranks * 0)'." + in str(excinfo.value)) From 9d75b5e25ea982b3cae243402680a33a244f43ee Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 7 Feb 2024 16:09:57 +0000 Subject: [PATCH 044/119] #1312 adding flags to where docs need adding to --- doc/user_guide/dynamo0p3.rst | 55 ++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index 096921aa67..22689fa677 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -32,7 +32,7 @@ .. POSSIBILITY OF SUCH DAMAGE. .. ----------------------------------------------------------------------------- .. Written by R. W. Ford and A. R. Porter, STFC Daresbury Lab -.. Modified by I. Kavcic, A. Coughtrie and O. Brunt Met Office +.. Modified by I. Kavcic, A. Coughtrie, O. Brunt and L. Turner, Met Office .. highlight:: fortran @@ -133,6 +133,13 @@ in the :ref:`LFRic Built-ins `). .. _lfric-field: +Array ++++++ +LFRic API scalar arrays, identified with ``GH_ARRAY`` metadata, represent. +Array arguments can have ``real``, ``integer`` or ``logical`` data type in +:ref:`user-defined Kernels ` +#SHARKS + Field +++++ @@ -404,7 +411,7 @@ have different precision. The table below gives the currently supported datatypes, their associated kernel metadata description and their precision: -.. tabularcolumns:: |l|l|l| +.. tabularcolumns:: |l|l|l| #SHARKS update table to include GH_ARRAY +--------------------------+---------------------------------+-----------+ | Data Type | Kernel Metadata | Precision | @@ -423,6 +430,12 @@ associated kernel metadata description and their precision: +--------------------------+---------------------------------+-----------+ | LOGICAL(L_DEF) | GH_SCALAR, GH_LOGICAL | L_DEF | +--------------------------+---------------------------------+-----------+ +| | GH_ARRAY, GH_REAL | | #SHARKS ++--------------------------+---------------------------------+-----------+ +| | GH_ARRAY, GH_INTEGER | | #SHARKS ++--------------------------+---------------------------------+-----------+ +| | GH_ARRAY, GH_LOGICAL | | #SHARKS ++--------------------------+---------------------------------+-----------+ | FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | +--------------------------+---------------------------------+-----------+ | R_BL_FIELD_TYPE | GH_FIELD, GH_REAL | R_BL | @@ -538,6 +551,11 @@ layer. The rules for whether PSyclone requires information for particular LFRic datatypes and what it does with or without this information are given below: +Arrays +++++++ + +#SHARKS + .. _lfric-mixed-precision-fields: Fields @@ -1003,20 +1021,20 @@ meta_args ######### The ``meta_args`` array specifies information about data that the -kernel code expects to be passed to it via its argument list. There is -one entry in the ``meta_args`` array for each **scalar**, **field**, +kernel code expects to be passed to it via its argument list. There is one +entry in the ``meta_args`` array for each **scalar**, **array**, **field**, or **operator** passed into the Kernel and the order that these occur in the ``meta_args`` array must be the same as they are expected in the kernel code argument list. The entry must be of ``arg_type`` which -itself contains metadata about the associated argument. The size of -the ``meta_args`` array must correspond to the number of **scalars**, +itself contains metadata about the associated argument. The size of the +``meta_args`` array must correspond to the number of **scalars**, **arrays** **fields** and **operators** passed into the Kernel. -.. note:: It makes no sense for a Kernel to have only **scalar** arguments - (because the PSy layer will call a Kernel for each point in the - spatial domain) and PSyclone will reject such Kernels. +.. note:: It makes no sense for a Kernel to have only **scalar** or **array** #SHARKS scalar or scalar array + arguments (because the PSy layer will call a Kernel for each point + in the spatial domain) and PSyclone will reject such Kernels. -For example, if there are a total of 2 **scalar** / **field** / +For example, if there are a total of 2 **scalar** / **array** / **field** / **operator** entities being passed to the Kernel then the ``meta_args`` array will be of size 2 and there will be two ``arg_type`` entries:: @@ -1030,7 +1048,7 @@ Argument metadata (information contained within the brackets of an **operator** (either LMA or CMA). The first argument-metadata entry describes whether the data that is -being passed is for a scalar (``GH_SCALAR``), a field (``GH_FIELD``) or +being passed is for a scalar (``GH_SCALAR``), a field (``GH_FIELD``) or # SHARKS add array an operator (either ``GH_OPERATOR`` for LMA or ``GH_COLUMNWISE_OPERATOR`` for CMA). This information is mandatory. @@ -1043,7 +1061,7 @@ entries, the first is a scalar, the next two are fields and the fourth is an operator. The third entry is a field vector of size 3. :: - +# SHARKS add array type(arg_type) :: meta_args(4) = (/ & arg_type(GH_SCALAR, GH_REAL, ...), & arg_type(GH_FIELD, GH_INTEGER, ... ), & @@ -1098,7 +1116,7 @@ combinations are specified later in this section (see are summed over calls to Kernel code. For example:: - +# SHARKS add array type(arg_type) :: meta_args(6) = (/ & arg_type(GH_OPERATOR, GH_REAL, GH_READ, ... ), & arg_type(GH_FIELD*3, GH_REAL, GH_WRITE, ... ), & @@ -1236,7 +1254,7 @@ argument type are given in the table below (please note that the :ref:`LFRic fields `): .. tabularcolumns:: |l|l| - +# SHARKS add gh_array +------------------------+---------------------------------+ | Argument Type | Data Type | +========================+=================================+ @@ -1257,7 +1275,8 @@ Valid Access Modes As mentioned earlier, not all combinations of metadata are valid. Valid combinations for each argument type in user-defined Kernels are summarised here. All argument types -(``GH_SCALAR``, ``GH_FIELD``, ``GH_OPERATOR`` and +(``GH_SCALAR``, ``GH_FIELD``, ``GH_OPERATOR`` and# SHARKS add gh_array + ``GH_COLUMNWISE_OPERATOR``) may be read within a Kernel and this is specified in metadata using ``GH_READ``. At least one kernel argument must be listed as being modified. When data is *modified* @@ -1267,6 +1286,7 @@ in a user-supplied Kernel (i.e. a Kernel that operates on a modes depend upon the argument type and the function space it is on: .. tabularcolumns:: |l|l|l| +# SHARKS add gh_array +------------------------+------------------------------+--------------------+ | Argument Type | Function Space | Access Type | @@ -1343,6 +1363,11 @@ checks (when generating the PSy layer) that any kernels which read operator values do not do so beyond the level-1 halo. If any such accesses are found then PSyclone aborts. +Array sizes +^^^^^^^^^^^ +# SHARKS + + .. _lfric-function-space: Supported Function Spaces From d64234524dbc953c4f74f044207c6a283b06802d Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 7 Feb 2024 17:00:39 +0000 Subject: [PATCH 045/119] #1312 more docs changes --- doc/user_guide/dynamo0p3.rst | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index 22689fa677..a202f2c028 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -1044,26 +1044,28 @@ array will be of size 2 and there will be two ``arg_type`` entries:: /) Argument metadata (information contained within the brackets of an -``arg_type`` entry), describes either a **scalar**, a **field** or an -**operator** (either LMA or CMA). +``arg_type`` entry), describes either a **scalar**, an **array**, a **field** +or an **operator** (either LMA or CMA). The first argument-metadata entry describes whether the data that is -being passed is for a scalar (``GH_SCALAR``), a field (``GH_FIELD``) or # SHARKS add array -an operator (either ``GH_OPERATOR`` for LMA or ``GH_COLUMNWISE_OPERATOR`` -for CMA). This information is mandatory. +being passed is for a scalar (``GH_SCALAR``), an array (``GH_ARRAY``), a # SHARKS add array +field (``GH_FIELD``) or an operator (either ``GH_OPERATOR`` for LMA or +``GH_COLUMNWISE_OPERATOR`` for CMA). This information is mandatory. Additionally, argument metadata can be used to describe a vector of fields (see the :ref:`lfric-field-vector` section for more details). -As an example, the following ``meta_args`` metadata describes 4 -entries, the first is a scalar, the next two are fields and the -fourth is an operator. The third entry is a field vector of size 3. +As an example, the following ``meta_args`` metadata describes 5 +entries, the first is a scalar, the second is an array, the next two +are fields and the fifth is an operator. The third entry is a field vector +of size 3. :: # SHARKS add array - type(arg_type) :: meta_args(4) = (/ & + type(arg_type) :: meta_args(5) = (/ & arg_type(GH_SCALAR, GH_REAL, ...), & + arg_type(GH_ARRAY, GH_LOGICAL, ...), & arg_type(GH_FIELD, GH_INTEGER, ... ), & arg_type(GH_FIELD*3, GH_REAL, ... ), & arg_type(GH_OPERATOR, GH_REAL, ...) & From e24d286cd0b2778432b3a0ee5436dc4fa88a1dca Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 7 Feb 2024 17:05:09 +0000 Subject: [PATCH 046/119] #1312 more docs changes --- doc/user_guide/dynamo0p3.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index a202f2c028..2fb59353cf 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -1119,12 +1119,13 @@ combinations are specified later in this section (see For example:: # SHARKS add array - type(arg_type) :: meta_args(6) = (/ & + type(arg_type) :: meta_args(7) = (/ & arg_type(GH_OPERATOR, GH_REAL, GH_READ, ... ), & arg_type(GH_FIELD*3, GH_REAL, GH_WRITE, ... ), & arg_type(GH_FIELD, GH_REAL, GH_READWRITE, ... ), & arg_type(GH_FIELD, GH_INTEGER, GH_INC, ... ), & arg_type(GH_FIELD, GH_REAL, GH_READINC, ... ), & + arg_type(GH_ARRAY, GH_LOGICAL, GH_READ, ... ), & arg_type(GH_SCALAR, GH_REAL, GH_SUM) & /) @@ -1256,12 +1257,14 @@ argument type are given in the table below (please note that the :ref:`LFRic fields `): .. tabularcolumns:: |l|l| -# SHARKS add gh_array + +------------------------+---------------------------------+ | Argument Type | Data Type | +========================+=================================+ | GH_SCALAR | GH_REAL, GH_INTEGER, GH_LOGICAL | +------------------------+---------------------------------+ +| GH_ARRAY | GH_REAL, GH_INTEGER, GH_LOGICAL | ++------------------------+---------------------------------+ | GH_FIELD | GH_REAL, GH_INTEGER | +------------------------+---------------------------------+ | GH_OPERATOR | GH_REAL | @@ -1288,13 +1291,14 @@ in a user-supplied Kernel (i.e. a Kernel that operates on a modes depend upon the argument type and the function space it is on: .. tabularcolumns:: |l|l|l| -# SHARKS add gh_array +------------------------+------------------------------+--------------------+ | Argument Type | Function Space | Access Type | +========================+==============================+====================+ | GH_SCALAR | n/a | GH_READ | +------------------------+------------------------------+--------------------+ +| GH_ARRAY | n/a #SHARKS | GH_READ | ++------------------------+------------------------------+--------------------+ | GH_FIELD | Discontinuous | GH_READ, GH_WRITE, | | | | GH_READWRITE | +------------------------+------------------------------+--------------------+ From 5867a305f8115e5105a31956bc1e1d37227e810d Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 7 Feb 2024 17:20:00 +0000 Subject: [PATCH 047/119] #1312 clearing up of flags addressed --- doc/user_guide/dynamo0p3.rst | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index 2fb59353cf..cbf1d23c60 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -554,7 +554,7 @@ information are given below: Arrays ++++++ -#SHARKS +#SHARKS - array of scalars .. _lfric-mixed-precision-fields: @@ -1030,7 +1030,7 @@ itself contains metadata about the associated argument. The size of the ``meta_args`` array must correspond to the number of **scalars**, **arrays** **fields** and **operators** passed into the Kernel. -.. note:: It makes no sense for a Kernel to have only **scalar** or **array** #SHARKS scalar or scalar array +.. note:: It makes no sense for a Kernel to have only **scalar** or **array** arguments (because the PSy layer will call a Kernel for each point in the spatial domain) and PSyclone will reject such Kernels. @@ -1048,7 +1048,7 @@ Argument metadata (information contained within the brackets of an or an **operator** (either LMA or CMA). The first argument-metadata entry describes whether the data that is -being passed is for a scalar (``GH_SCALAR``), an array (``GH_ARRAY``), a # SHARKS add array +being passed is for a scalar (``GH_SCALAR``), an array (``GH_ARRAY``), a field (``GH_FIELD``) or an operator (either ``GH_OPERATOR`` for LMA or ``GH_COLUMNWISE_OPERATOR`` for CMA). This information is mandatory. @@ -1062,13 +1062,13 @@ are fields and the fifth is an operator. The third entry is a field vector of size 3. :: -# SHARKS add array + type(arg_type) :: meta_args(5) = (/ & - arg_type(GH_SCALAR, GH_REAL, ...), & - arg_type(GH_ARRAY, GH_LOGICAL, ...), & - arg_type(GH_FIELD, GH_INTEGER, ... ), & - arg_type(GH_FIELD*3, GH_REAL, ... ), & - arg_type(GH_OPERATOR, GH_REAL, ...) & + arg_type(GH_SCALAR, GH_REAL, ... ), & + arg_type(GH_ARRAY, GH_LOGICAL, ... ), & + arg_type(GH_FIELD, GH_INTEGER, ... ), & + arg_type(GH_FIELD*3, GH_REAL, ... ), & + arg_type(GH_OPERATOR, GH_REAL, ... ) & /) The second item in a metadata entry describes the Fortran primitive @@ -1118,7 +1118,7 @@ combinations are specified later in this section (see are summed over calls to Kernel code. For example:: -# SHARKS add array + type(arg_type) :: meta_args(7) = (/ & arg_type(GH_OPERATOR, GH_REAL, GH_READ, ... ), & arg_type(GH_FIELD*3, GH_REAL, GH_WRITE, ... ), & @@ -1280,8 +1280,7 @@ Valid Access Modes As mentioned earlier, not all combinations of metadata are valid. Valid combinations for each argument type in user-defined Kernels are summarised here. All argument types -(``GH_SCALAR``, ``GH_FIELD``, ``GH_OPERATOR`` and# SHARKS add gh_array - +(``GH_SCALAR``, ``GH_ARRAY``, ``GH_FIELD``, ``GH_OPERATOR`` and ``GH_COLUMNWISE_OPERATOR``) may be read within a Kernel and this is specified in metadata using ``GH_READ``. At least one kernel argument must be listed as being modified. When data is *modified* @@ -1297,7 +1296,7 @@ modes depend upon the argument type and the function space it is on: +========================+==============================+====================+ | GH_SCALAR | n/a | GH_READ | +------------------------+------------------------------+--------------------+ -| GH_ARRAY | n/a #SHARKS | GH_READ | +| GH_ARRAY | n/a | GH_READ | +------------------------+------------------------------+--------------------+ | GH_FIELD | Discontinuous | GH_READ, GH_WRITE, | | | | GH_READWRITE | From b40e7dad6768bf928093247603ee157f35e0082a Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 7 Feb 2024 17:41:01 +0000 Subject: [PATCH 048/119] #1312 expanding on the Data Types and precision table, plus changing my mind on some styling changes --- doc/user_guide/dynamo0p3.rst | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index cbf1d23c60..43f290e7f3 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -411,7 +411,7 @@ have different precision. The table below gives the currently supported datatypes, their associated kernel metadata description and their precision: -.. tabularcolumns:: |l|l|l| #SHARKS update table to include GH_ARRAY +.. tabularcolumns:: |l|l|l| +--------------------------+---------------------------------+-----------+ | Data Type | Kernel Metadata | Precision | @@ -430,11 +430,21 @@ associated kernel metadata description and their precision: +--------------------------+---------------------------------+-----------+ | LOGICAL(L_DEF) | GH_SCALAR, GH_LOGICAL | L_DEF | +--------------------------+---------------------------------+-----------+ -| | GH_ARRAY, GH_REAL | | #SHARKS +# How many of the below are relevant/used/etc? obviously can't use the same +# Data Type names as above as need to differentiate between scalars and arrays +| #SHARKS(R_DEF) | GH_ARRAY, GH_REAL | R_DEF | ++--------------------------+---------------------------------+-----------+ +| #SHARKS(R_BL) | GH_ARRAY, GH_REAL | R_BL | ++--------------------------+---------------------------------+-----------+ +| #SHARKS(R_PHYS) | GH_ARRAY, GH_REAL | R_PHYS | ++--------------------------+---------------------------------+-----------+ +| #SHARKS(R_SOLVER) | GH_ARRAY, GH_REAL | R_SOLVER | ++--------------------------+---------------------------------+-----------+ +| #SHARKS(R_TRAN) | GH_ARRAY, GH_REAL | R_TRAN | +--------------------------+---------------------------------+-----------+ -| | GH_ARRAY, GH_INTEGER | | #SHARKS +| #SHARKS(I_DEF) | GH_ARRAY, GH_INTEGER | I_DEF | +--------------------------+---------------------------------+-----------+ -| | GH_ARRAY, GH_LOGICAL | | #SHARKS +| #SHARKS(L_DEF) | GH_ARRAY, GH_LOGICAL | L_DEF | +--------------------------+---------------------------------+-----------+ | FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | +--------------------------+---------------------------------+-----------+ @@ -1064,11 +1074,11 @@ of size 3. :: type(arg_type) :: meta_args(5) = (/ & - arg_type(GH_SCALAR, GH_REAL, ... ), & - arg_type(GH_ARRAY, GH_LOGICAL, ... ), & - arg_type(GH_FIELD, GH_INTEGER, ... ), & - arg_type(GH_FIELD*3, GH_REAL, ... ), & - arg_type(GH_OPERATOR, GH_REAL, ... ) & + arg_type(GH_SCALAR, GH_REAL, ...), & + arg_type(GH_ARRAY, GH_LOGICAL, ...), & + arg_type(GH_FIELD, GH_INTEGER, ...), & + arg_type(GH_FIELD*3, GH_REAL, ...), & + arg_type(GH_OPERATOR, GH_REAL, ...) & /) The second item in a metadata entry describes the Fortran primitive From 996a0a33c6a92bd1d53501d20b7e2b525ca7e122 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 8 Feb 2024 15:59:11 +0000 Subject: [PATCH 049/119] #1312 adding final bits of documentation --- doc/user_guide/dynamo0p3.rst | 94 ++++++++++--------- .../lfric/kernel/common_meta_arg_metadata.py | 2 +- 2 files changed, 50 insertions(+), 46 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index 43f290e7f3..cf3c50d20b 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -84,25 +84,29 @@ objects and their use are discussed in the following sections. :: - real(kind=r_def) :: rscalar - integer(kind=i_def) :: iscalar - logical(kind=l_def) :: lscalar - integer(kind=i_def) :: stencil_extent - type(field_type) :: field1, field2, field3 - type(field_type) :: field5(3), field6(3) - type(integer_field_type) :: field7 - type(quadrature_type) :: qr - type(operator_type) :: operator1 - type(columnwise_operator_type) :: cma_op1 + real(kind=r_def) :: rscalar + integer(kind=i_def) :: iscalar + logical(kind=l_def) :: lscalar + real(kind=r_def), dimension(50, 100) :: real_array + integer(kind=i_def), dimension(10) :: integer_array + logical(kind=l_def), dimension(2,5,10,8) :: logical_array + integer(kind=i_def) :: stencil_extent + type(field_type) :: field1, field2, field3 + type(field_type) :: field5(3), field6(3) + type(integer_field_type) :: field7 + type(quadrature_type) :: qr + type(operator_type) :: operator1 + type(columnwise_operator_type) :: cma_op1 ... - call invoke( kernel1(field1, field2, operator1, qr), & - builtin1(rscalar, field2, field3), & - int_builtin2(iscalar, field7), & - kernel2(field1, stencil_extent, field3, lscalar), & - assembly_kernel(cma_op1, operator1), & - name="some_calculation" & + call invoke( kernel1(field1, field2, operator1, real_array, qr), & + builtin1(rscalar, field2, field3), & + int_builtin2(iscalar, field7), & + kernel2(field1, stencil_extent, field3, lscalar), & + assembly_kernel(cma_op1, operator1), & + kernel3(field3, integer_array, logical_array), & + name="some_calculation" & ) - call invoke( prolong_kernel_type(field1, field4), & + call invoke( prolong_kernel_type(field1, field4), & restrict_kernel_type(field5, field6) ) @@ -112,13 +116,13 @@ Please see the :ref:`algorithm-layer` section for a description of the Objects in the LFRic API can be categorised by their functionality as data structures and information that specifies supported operations on a particular data structure. These data structures are represented by the -five LFRic (Dynamo 0.3) API argument types: :ref:`scalar `, -:ref:`field `, :ref:`field vector `, -:ref:`operator ` and :ref:`column-wise operator -`. All of them except the field vector are -represented in the above example. ``qr`` represents a quadrature object -which provides information required by a kernel to operate on fields -(see section :ref:`dynamo0.3-quadrature` for more details). +six LFRic (Dynamo 0.3) API argument types: :ref:`scalar `, +:ref:`array `,:ref:`field `, :ref:`field vector +`, :ref:`operator ` and :ref:`column-wise +operator `. All of them are represented in the above +example. ``qr`` represents a quadrature object which provides information +required by a kernel to operate on fields (see section +:ref:`dynamo0.3-quadrature` for more details). .. _lfric-scalar: @@ -131,14 +135,17 @@ with ``GH_SCALAR`` metadata. Scalar arguments can have ``real``, ` (``logical`` data type is not supported in the :ref:`LFRic Built-ins `). -.. _lfric-field: +.. _lfric-array: Array +++++ -LFRic API scalar arrays, identified with ``GH_ARRAY`` metadata, represent. -Array arguments can have ``real``, ``integer`` or ``logical`` data type in -:ref:`user-defined Kernels ` -#SHARKS + +In the LFRic API a scalar array represents a multi-valued Fortran array of +scalars, identified with ``GH_ARRAY`` metadata. As with scalars, array arguments +can have ``real``, ``integer`` or ``logical`` data type in :ref:`user-defined +Kernels `. + +.. _lfric-field: Field +++++ @@ -430,21 +437,19 @@ associated kernel metadata description and their precision: +--------------------------+---------------------------------+-----------+ | LOGICAL(L_DEF) | GH_SCALAR, GH_LOGICAL | L_DEF | +--------------------------+---------------------------------+-----------+ -# How many of the below are relevant/used/etc? obviously can't use the same -# Data Type names as above as need to differentiate between scalars and arrays -| #SHARKS(R_DEF) | GH_ARRAY, GH_REAL | R_DEF | +| REAL(R_DEF) | GH_ARRAY, GH_REAL | R_DEF | +--------------------------+---------------------------------+-----------+ -| #SHARKS(R_BL) | GH_ARRAY, GH_REAL | R_BL | +| REAL(R_BL) | GH_ARRAY, GH_REAL | R_BL | +--------------------------+---------------------------------+-----------+ -| #SHARKS(R_PHYS) | GH_ARRAY, GH_REAL | R_PHYS | +| REAL(R_PHYS) | GH_ARRAY, GH_REAL | R_PHYS | +--------------------------+---------------------------------+-----------+ -| #SHARKS(R_SOLVER) | GH_ARRAY, GH_REAL | R_SOLVER | +| REAL(R_SOLVER) | GH_ARRAY, GH_REAL | R_SOLVER | +--------------------------+---------------------------------+-----------+ -| #SHARKS(R_TRAN) | GH_ARRAY, GH_REAL | R_TRAN | +| REAL(R_TRAN) | GH_ARRAY, GH_REAL | R_TRAN | +--------------------------+---------------------------------+-----------+ -| #SHARKS(I_DEF) | GH_ARRAY, GH_INTEGER | I_DEF | +| INTEGER(I_DEF) | GH_ARRAY, GH_INTEGER | I_DEF | +--------------------------+---------------------------------+-----------+ -| #SHARKS(L_DEF) | GH_ARRAY, GH_LOGICAL | L_DEF | +| LOGICAL(L_DEF) | GH_ARRAY, GH_LOGICAL | L_DEF | +--------------------------+---------------------------------+-----------+ | FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | +--------------------------+---------------------------------+-----------+ @@ -472,7 +477,7 @@ capture all of the precision options. For example, from the metadata it is not possible to determine whether a ``REAL`` scalar, ``REAL`` field or ``REAL`` operator has precision ``R_DEF``, ``R_SOLVER`` or ``R_TRAN``. -If a scalar, field, or operator is specified with a particular +If a scalar, array, field, or operator is specified with a particular precision in the algorithm layer then any associated kernels that it is passed to must have been written so that they support this precision. If a kernel needs to support data that can be stored with @@ -561,11 +566,6 @@ layer. The rules for whether PSyclone requires information for particular LFRic datatypes and what it does with or without this information are given below: -Arrays -++++++ - -#SHARKS - array of scalars - .. _lfric-mixed-precision-fields: Fields @@ -1378,10 +1378,14 @@ checks (when generating the PSy layer) that any kernels which read operator values do not do so beyond the level-1 halo. If any such accesses are found then PSyclone aborts. +.. _lfric-array-sizes: + Array sizes ^^^^^^^^^^^ -# SHARKS +The size of a :ref:`scalar array ` is described by ``NRANKS*``, +where *n > 0* is the number of Fortran ranks representing the dimension of the +array. .. _lfric-function-space: diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 2eb0e2bb89..9ce0e70a2c 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -229,7 +229,7 @@ def get_array_ndims(cls, fparser2_tree): f"The array size metadata should be in the form " f"'NRANKS*array_ndims' but found '{array_datatype}'.") if components[0].lower().strip() != "NRANKS".lower(): - raise ParseError( # SHARKS (needs test coverage) + raise ParseError( f"In the LFRic API, the 4th argument of a 'meta_arg' " f"entry must use 'NRANKS' as the keyword in the format " f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " From b978fe17fc054d6416c078b844a13453730b2c11 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 9 Feb 2024 10:55:21 +0000 Subject: [PATCH 050/119] #1312 adding a modifier line that slipped through the cracks@ --- src/psyclone/domain/lfric/kernel/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/psyclone/domain/lfric/kernel/__init__.py b/src/psyclone/domain/lfric/kernel/__init__.py index e11847c738..f00945f422 100644 --- a/src/psyclone/domain/lfric/kernel/__init__.py +++ b/src/psyclone/domain/lfric/kernel/__init__.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab +# Modifier L. Turner, Met Office '''Module for Kernels in the LFRic domain.''' From e571bc1bc674be8895143066b54ba96c755cb40e Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 21 May 2024 14:34:25 +0100 Subject: [PATCH 051/119] #1312 space fixing --- doc/user_guide/dynamo0p3.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index cf3c50d20b..2a22d85d2e 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -117,7 +117,7 @@ Objects in the LFRic API can be categorised by their functionality as data structures and information that specifies supported operations on a particular data structure. These data structures are represented by the six LFRic (Dynamo 0.3) API argument types: :ref:`scalar `, -:ref:`array `,:ref:`field `, :ref:`field vector +:ref:`array `, :ref:`field `, :ref:`field vector `, :ref:`operator ` and :ref:`column-wise operator `. All of them are represented in the above example. ``qr`` represents a quadrature object which provides information @@ -876,7 +876,7 @@ types. an ``integer``-valued field as an argument. .. _lfric-no-cma-mdata-rules: - + Rules specific to General-Purpose Kernels without CMA Operators +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -1312,7 +1312,7 @@ modes depend upon the argument type and the function space it is on: | | | GH_READWRITE | +------------------------+------------------------------+--------------------+ | GH_FIELD | Continuous | GH_READ, GH_WRITE, | -| | | GH_INC, GH_READINC | +| | | GH_INC, GH_READINC | +------------------------+------------------------------+--------------------+ | GH_OPERATOR | Any for both 'to' and 'from' | GH_READ, GH_WRITE, | | | | GH_READWRITE | From 6857e55f7080b54f545ad8315acfb4aeac45bced Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 21 May 2024 16:57:00 +0100 Subject: [PATCH 052/119] #1312 removing backslashes in comments from lfric_arg_descriptor.py --- .../domain/lfric/lfric_arg_descriptor.py | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index e02267c85e..e23170eb58 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -63,26 +63,26 @@ class LFRicArgDescriptor(Descriptor): This class captures the information specified in one of LFRic API argument descriptors (scalars, fields and operators). - :param arg_type: LFRic API valid argument type (scalar, \ + :param arg_type: LFRic API valid argument type (scalar, field or operator). - :type arg_type: :py:class:`psyclone.expression.FunctionVar` or \ + :type arg_type: :py:class:`psyclone.expression.FunctionVar` or :py:class:`psyclone.expression.BinaryOperator` - :param str operates_on: value of operates_on from the parsed kernel \ + :param str operates_on: value of operates_on from the parsed kernel metadata (used for validation). - :param int metadata_index: position of this argument in the list of \ + :param int metadata_index: position of this argument in the list of arguments specified in the metadata. :raises ParseError: if a 'meta_arg' entry is not of 'arg_type' type. - :raises ParseError: if the first argument of a 'meta_arg' entry is not \ + :raises ParseError: if the first argument of a 'meta_arg' entry is not one of LFRic API valid argument types. - :raises ParseError: if the second argument of a 'meta_arg' entry is not \ + :raises ParseError: if the second argument of a 'meta_arg' entry is not one of LFRic API valid data types. :raises ParseError: if a 'meta_arg' entry has fewer than 3 args. - :raises ParseError: if the third 'meta_arg' entry is not a valid \ + :raises ParseError: if the third 'meta_arg' entry is not a valid access descriptor. - :raises InternalError: if the operates_on from the parsed kernel \ + :raises InternalError: if the operates_on from the parsed kernel metadata is not 'cell_column' or 'dof'. - :raises InternalError: if all the metadata checks fail to catch an \ + :raises InternalError: if all the metadata checks fail to catch an invalid argument type. ''' @@ -227,14 +227,14 @@ def _validate_vector_size(self, separator, arg_type): :param arg_type: LFRic API field (vector) argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises ParseError: if the field vector notation does not use \ + :raises ParseError: if the field vector notation does not use the '*' operator. - :raises ParseError: if the field vector notation is not in the \ - correct format '(field*n)' where 'n' is \ + :raises ParseError: if the field vector notation is not in the + correct format '(field*n)' where 'n' is an integer. - :raises ParseError: if the field vector notation is used for the \ + :raises ParseError: if the field vector notation is used for the vector size of less than 2. - :raises ParseError: if the field vector notation is used for an \ + :raises ParseError: if the field vector notation is used for an argument that is not a field. ''' @@ -284,14 +284,14 @@ def _validate_array_ndims(self, arg_type): :param arg_type: LFRic API array argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises ParseError: if the array notation does not use \ + :raises ParseError: if the array notation does not use the '*' operator. - :raises ParseError: if the array notation is not in the \ - correct format '(NRANKS*n)' where 'n' is \ + :raises ParseError: if the array notation is not in the + correct format '(NRANKS*n)' where 'n' is an integer. - :raises ParseError: if the array notation is used for the \ + :raises ParseError: if the array notation is used for the array size of less than 1. - :raises ParseError: if the array notation is used for an \ + :raises ParseError: if the array notation is used for an argument that is not an array. ''' @@ -340,36 +340,36 @@ def _init_field(self, arg_type, operates_on): :param arg_type: LFRic API field (vector) argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :param operates_on: value of operates_on from the parsed kernel \ + :param operates_on: value of operates_on from the parsed kernel metadata (used for validation). :type operates_on: str - :raises InternalError: if argument type other than a field is \ + :raises InternalError: if argument type other than a field is passed in. :raises ParseError: if there are fewer than 4 metadata arguments. :raises ParseError: if there are more than 5 metadata arguments. :raises ParseError: if a field argument has an invalid data type. :raises ParseError: if the 4th argument is not a valid function space. - :raises ParseError: if the optional 5th argument is not a stencil \ - specification or a mesh identifier (for \ + :raises ParseError: if the optional 5th argument is not a stencil + specification or a mesh identifier (for inter-grid kernels). - :raises ParseError: if a field passed to a kernel that operates on \ - DoFs does not have a valid access \ + :raises ParseError: if a field passed to a kernel that operates on + DoFs does not have a valid access (one of [READ, WRITE, READWRITE]). - :raises ParseError: if a field on a discontinuous function space \ - passed to a kernel that operates on cell-columns \ - does not have a valid access (one of \ + :raises ParseError: if a field on a discontinuous function space + passed to a kernel that operates on cell-columns + does not have a valid access (one of [READ, WRITE, READWRITE]). - :raises ParseError: if a field on a continuous function space \ - passed to a kernel that operates on cell-columns \ - does not have a valid access (one of [READ, WRITE,\ + :raises ParseError: if a field on a continuous function space + passed to a kernel that operates on cell-columns + does not have a valid access (one of [READ, WRITE, INC, READINC]). - :raises ParseError: if the kernel operates on the domain and is \ + :raises ParseError: if the kernel operates on the domain and is passed a field on a continuous space. - :raises InternalError: if an invalid value for operates_on is \ + :raises InternalError: if an invalid value for operates_on is passed in. :raises ParseError: if a field with a stencil access is not read-only. - :raises ParseError: if a field with a stencil access is passed to a \ + :raises ParseError: if a field with a stencil access is passed to a kernel that operates on the domain. ''' @@ -528,13 +528,13 @@ def _init_operator(self, arg_type): :param arg_type: LFRic API operator argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises InternalError: if argument type other than an operator is \ + :raises InternalError: if argument type other than an operator is passed in. :raises ParseError: if there are not exactly 5 metadata arguments. :raises ParseError: if an operator argument has an invalid data type. - :raises ParseError: if the function space to- is not one of the \ + :raises ParseError: if the function space to- is not one of the valid function spaces. - :raises ParseError: if the function space from- is not one of the \ + :raises ParseError: if the function space from- is not one of the valid function spaces. :raises ParseError: if the operator argument has an invalid access. @@ -608,13 +608,13 @@ def _init_scalar(self, arg_type): :param arg_type: LFRic API scalar argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises InternalError: if argument type other than a scalar is \ + :raises InternalError: if argument type other than a scalar is passed in. :raises ParseError: if there are not exactly 3 metadata arguments. :raises InternalError: if a scalar argument has an invalid data type. :raises ParseError: if scalar arguments do not have a read-only or a reduction access. - :raises ParseError: if a scalar argument that is not a real \ + :raises ParseError: if a scalar argument that is not a real scalar has a reduction access. ''' @@ -674,12 +674,12 @@ def _init_array(self, arg_type): :param arg_type: LFRic API scalar array argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises InternalError: if argument type other than an array is \ + :raises InternalError: if argument type other than an array is passed in. :raises ParseError: if there are not exactly 4 metadata arguments. :raises InternalError: if an array argument has an invalid data type. :raises ParseError: if array arguments do not have read-only access. - :raises ParseError: if a scalar argument that is not a real \ + :raises ParseError: if a scalar argument that is not a real scalar has a reduction access. ''' @@ -779,7 +779,7 @@ def function_space(self): depending on the argument type: a single function space for a field, function_space_from for an operator and nothing for a scalar. - :returns: function space relating to this kernel argument or \ + :returns: function space relating to this kernel argument or None (for a scalar). :rtype: str or NoneType From 901ea74ba9a4ab1adb163fe2134473463294d13f Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 21 May 2024 17:10:27 +0100 Subject: [PATCH 053/119] #1312 merging lines in table and adding missing array mention --- doc/user_guide/dynamo0p3.rst | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index fdb79f5c74..cc5f32d011 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -406,7 +406,7 @@ Mixed Precision The LFRic API supports the ability to specify the precision required by the model via precision variables. To make use of this, the code -developer must declare scalars, fields and operators in the algorithm +developer must declare scalars, arrays, fields and operators in the algorithm layer with the required LFRic-supported precision. In the current implementation there are two supported precisions for ``REAL`` data and one each for ``INTEGER`` and ``LOGICAL`` data. The actual precision used in @@ -423,33 +423,19 @@ associated kernel metadata description and their precision: +--------------------------+---------------------------------+-----------+ | Data Type | Kernel Metadata | Precision | +==========================+=================================+===========+ -| REAL(R_DEF) | GH_SCALAR, GH_REAL | R_DEF | +| REAL(R_DEF) | GH_SCALAR/GH_ARRAY, GH_REAL | R_DEF | +--------------------------+---------------------------------+-----------+ -| REAL(R_BL) | GH_SCALAR, GH_REAL | R_BL | +| REAL(R_BL) | GH_SCALAR/GH_ARRAY, GH_REAL | R_BL | +--------------------------+---------------------------------+-----------+ -| REAL(R_PHYS) | GH_SCALAR, GH_REAL | R_PHYS | +| REAL(R_PHYS) | GH_SCALAR/GH_ARRAY, GH_REAL | R_PHYS | +--------------------------+---------------------------------+-----------+ -| REAL(R_SOLVER) | GH_SCALAR, GH_REAL | R_SOLVER | +| REAL(R_SOLVER) | GH_SCALAR/GH_ARRAY, GH_REAL | R_SOLVER | +--------------------------+---------------------------------+-----------+ -| REAL(R_TRAN) | GH_SCALAR, GH_REAL | R_TRAN | +| REAL(R_TRAN) | GH_SCALAR/GH_ARRAY, GH_REAL | R_TRAN | +--------------------------+---------------------------------+-----------+ -| INTEGER(I_DEF) | GH_SCALAR, GH_INTEGER | I_DEF | +| INTEGER(I_DEF) | GH_SCALAR/GH_ARRAY, GH_INTEGER | I_DEF | +--------------------------+---------------------------------+-----------+ -| LOGICAL(L_DEF) | GH_SCALAR, GH_LOGICAL | L_DEF | -+--------------------------+---------------------------------+-----------+ -| REAL(R_DEF) | GH_ARRAY, GH_REAL | R_DEF | -+--------------------------+---------------------------------+-----------+ -| REAL(R_BL) | GH_ARRAY, GH_REAL | R_BL | -+--------------------------+---------------------------------+-----------+ -| REAL(R_PHYS) | GH_ARRAY, GH_REAL | R_PHYS | -+--------------------------+---------------------------------+-----------+ -| REAL(R_SOLVER) | GH_ARRAY, GH_REAL | R_SOLVER | -+--------------------------+---------------------------------+-----------+ -| REAL(R_TRAN) | GH_ARRAY, GH_REAL | R_TRAN | -+--------------------------+---------------------------------+-----------+ -| INTEGER(I_DEF) | GH_ARRAY, GH_INTEGER | I_DEF | -+--------------------------+---------------------------------+-----------+ -| LOGICAL(L_DEF) | GH_ARRAY, GH_LOGICAL | L_DEF | +| LOGICAL(L_DEF) | GH_SCALAR/GH_ARRAY, GH_LOGICAL | L_DEF | +--------------------------+---------------------------------+-----------+ | FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | +--------------------------+---------------------------------+-----------+ From 335205ce1084c8bdecff39403a0482283fa3789c Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 23 May 2024 12:59:01 +0100 Subject: [PATCH 054/119] #1312 including arrays in some missed spots in the docs --- doc/user_guide/dynamo0p3.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index cc5f32d011..b6bf833bef 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -1210,16 +1210,17 @@ For example:: does not yet support ``integer`` and ``logical`` reductions. For a scalar, the argument metadata contains only these three entries. -However, fields and operators require further entries specifying +However, arrays, fields and operators require further entries specifying function-space information. -The meaning of these further entries differs depending on whether a +The meaning of these further entries differs depending on whether an array, a field or an operator is being described. -In the case of an operator, the fourth and fifth arguments describe -the ``to`` and ``from`` function spaces respectively. In the case of a -field the fourth argument specifies the function space that the field -lives on. More details about the supported function spaces are in -subsection :ref:`lfric-function-space`. +In the case of an operator, the fourth and fifth arguments describe the ``to`` +and ``from`` function spaces respectively. In the case of a field the fourth +argument specifies the function space that the field lives on. In the case of +an array, the fourth argument specifies the number of dimensions the array has. +More details about the supported function spaces are in subsection +:ref:`lfric-function-space`. For example, the metadata for a kernel that applies a column-wise operator to a field might look like:: From 275b75563fb62e64dbd338d85a936b1ebd47d37f Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 30 May 2024 16:38:05 +0100 Subject: [PATCH 055/119] #1312 removing NRANKS, hopefully I got all of them --- .../domain/lfric/kernel/array_arg_metadata.py | 2 +- .../lfric/kernel/common_meta_arg_metadata.py | 15 +-- .../domain/lfric/lfric_arg_descriptor.py | 30 +---- .../lfric/kernel/array_arg_metadata_test.py | 4 +- .../kernel/common_meta_arg_metadata_test.py | 20 +--- .../domain/lfric/lfric_array_mdata_test.py | 106 ++++++------------ 6 files changed, 46 insertions(+), 131 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index dbb8ec56f7..85537a6e23 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -99,7 +99,7 @@ def fortran_string(self): :rtype: str ''' return (f"arg_type({self.form}, {self.datatype}, {self.access}, " - f"nranks*{self.array_ndims})") + f"{self.array_ndims})") @staticmethod def check_datatype(value): diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 9ce0e70a2c..bb376f5d34 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -222,20 +222,7 @@ def get_array_ndims(cls, fparser2_tree): ''' array_datatype = CommonArgMetadata.get_arg( fparser2_tree, cls.array_size_arg_index) - components = array_datatype.split("*") - print(components) - if len(components) != 2: - raise TypeError( - f"The array size metadata should be in the form " - f"'NRANKS*array_ndims' but found '{array_datatype}'.") - if components[0].lower().strip() != "NRANKS".lower(): - raise ParseError( - f"In the LFRic API, the 4th argument of a 'meta_arg' " - f"entry must use 'NRANKS' as the keyword in the format " - f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " - f"found '{components[0].strip()}' as the keyword in " - f"'{array_datatype}'.") - array_ndims = components[1].strip() + array_ndims = array_datatype.strip() return array_ndims @property diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index e23170eb58..04fd7c4bd1 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -284,10 +284,8 @@ def _validate_array_ndims(self, arg_type): :param arg_type: LFRic API array argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises ParseError: if the array notation does not use - the '*' operator. :raises ParseError: if the array notation is not in the - correct format '(NRANKS*n)' where 'n' is + correct format 'n' where 'n' is an integer. :raises ParseError: if the array notation is used for the array size of less than 1. @@ -295,40 +293,24 @@ def _validate_array_ndims(self, arg_type): argument that is not an array. ''' - print(arg_type.args[3].toks[0]) - if arg_type.args[3].toks[0].name != "NRANKS".lower(): - raise ParseError( - f"In the LFRic API, the 4th argument of a 'meta_arg' " - f"entry must use 'NRANKS' as the keyword in the format " - f"'NRANKS*n' if the 1st argument is 'GH_ARRAY', but " - f"found '{arg_type.args[3].toks[0]}' as the keyword " - f"in '{arg_type}'.") - - # Check that the operator is correct - if arg_type.args[3].toks[1] != "*": - raise ParseError( - f"In the LFRic API, the 4th argument of a 'meta_arg' " - f"entry may be an array but if so must use '*' as " - f"the separator in the format 'NRANKS*n', but found " - f"'{arg_type.args[3].toks[1]}' in '{arg_type}'.") print(arg_type.args[3]) - # Now try to find the array size for a scalar array and return + # Try to find the array size for a scalar array and return # an error if it is not an integer number... try: - array_ndims = int(arg_type.args[3].toks[2]) + array_ndims = int(arg_type.args[3]) except ValueError as err: raise ParseError( f"In the LFRic API, the array notation must be in " - f"the format 'NRANKS*n' where 'n' is an integer, " - f"but '{arg_type.args[3].toks[2]}' was found in " + f"the format 'n' where 'n' is an integer, " + f"but '{arg_type.args[3]}' was found in " f"'{arg_type}'.") from err # ... or it is less than 1 (1 is the default for all fields)... if array_ndims < 1: raise ParseError( f"In the LFRic API, the array notation must be in " - f"the format 'NRANKS*n' where 'n' is an integer >= 1. " + f"the format 'n' where 'n' is an integer >= 1. " f"However, found n = '{array_ndims}' in '{arg_type}'.") # ... and set the array size if all checks pass self._array_ndims = array_ndims diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 4d73a1cbe2..4c8b49a7ba 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -70,7 +70,7 @@ def test_init_invalid_an(): @pytest.mark.parametrize("metadata", - ["arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*2)"]) + ["arg_type(GH_ARRAY, GH_REAL, GH_READ, 2)"]) def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ArrayArgMetadata.create_fparser2( @@ -83,7 +83,7 @@ def test_get_metadata(metadata): @pytest.mark.parametrize("fortran_string", [ - "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*5)"]) + "arg_type(GH_ARRAY, GH_REAL, GH_READ, 5)"]) def test_fortran_string(fortran_string): '''Test that the fortran_string method works as expected.''' array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 7083138e8c..c18dd7705a 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -265,25 +265,7 @@ def test_get_array_ndims(): ''' fparser_tree = CheckArg.create_fparser2( - "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS2)", Fortran2003.Part_Ref) - with pytest.raises(TypeError) as info: - _ = CheckArg.get_array_ndims(fparser_tree) - assert ("The array size metadata should be in the form " - "'NRANKS*array_ndims' but found 'NRANKS2'." - in str(info.value)) - - fparser_tree = CheckArg.create_fparser2( - "arg_type(GH_ARRAY, GH_REAL, GH_READ, SKARN*2)", Fortran2003.Part_Ref) - with pytest.raises(ParseError) as info: - _ = CheckArg.get_array_ndims(fparser_tree) - assert ("In the LFRic API, the 4th argument of a 'meta_arg' entry must " - "use 'NRANKS' as the keyword in the format 'NRANKS*n' if the 1st " - "argument is 'GH_ARRAY', but found 'SKARN' as the keyword in " - "'SKARN * 2'." in - str(info.value)) - - fparser_tree = CheckArg.create_fparser2( - "arg_type(GH_ARRAY, GH_REAL, GH_READ, NRANKS*3)", Fortran2003.Part_Ref) + "arg_type(GH_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) vector_length = CheckArg.get_array_ndims(fparser_tree) assert vector_length == "3" diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 0b644bd9c3..c8ecb5b8e5 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -60,9 +60,9 @@ type, extends(kernel_type) :: testkern_array_type type(arg_type), meta_args(5) = & - (/ arg_type(gh_array, gh_real, gh_read, NRANKS*1), & - arg_type(gh_array, gh_integer, gh_read, NRANKS*2), & - arg_type(gh_array, gh_logical, gh_read, NRANKS*4), & + (/ arg_type(gh_array, gh_real, gh_read, 1), & + arg_type(gh_array, gh_integer, gh_read, 2), & + arg_type(gh_array, gh_logical, gh_read, 4), & arg_type(gh_operator, gh_real, gh_read, w2, w2), & arg_type(gh_field, gh_real, gh_write, w3) & /) @@ -97,8 +97,8 @@ def test_ad_array_type_wrong_num_of_args(): metadata for an array has fewer than 3 args. ''' fparser.logging.disable(fparser.logging.CRITICAL) code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_read)", 1) + "arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_real, gh_read)", 1) ast = fpapi.parse(code, ignore_comments=False) name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: @@ -113,9 +113,9 @@ def test_ad_array_invalid_data_type(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" # check real array - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_unreal, " - "gh_read, NRANKS*1)", 1) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_unreal, gh_read, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -123,11 +123,11 @@ def test_ad_array_invalid_data_type(): assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " f"but found 'gh_unreal' in 'arg_type(gh_array, gh_unreal, " - f"gh_read, nranks * 1)'." in str(excinfo.value)) + f"gh_read, 1)'." in str(excinfo.value)) # check integer array - code = ARRAY_CODE.replace("arg_type(gh_array, gh_integer, gh_read, " - "NRANKS*2)", "arg_type(gh_array, gh_frac, " - "gh_read, NRANKS*2)", 1) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_integer, gh_read, 2)", + "arg_type(gh_array, gh_frac, gh_read, 2)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -135,11 +135,11 @@ def test_ad_array_invalid_data_type(): assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " f"but found 'gh_frac' in 'arg_type(gh_array, gh_frac, " - f"gh_read, nranks * 2)'." in str(excinfo.value)) + f"gh_read, 2)'." in str(excinfo.value)) # check logical array - code = ARRAY_CODE.replace("arg_type(gh_array, gh_logical, gh_read, " - "NRANKS*4)", "arg_type(gh_array, gh_illogical, " - "gh_read, NRANKS*4)", 1) + code = ARRAY_CODE.replace( + "arg_type(gh_array, gh_logical, gh_read, 4)", + "arg_type(gh_array, gh_illogical, gh_read, 4)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: @@ -147,7 +147,7 @@ def test_ad_array_invalid_data_type(): assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " f"but found 'gh_illogical' in 'arg_type(gh_array, gh_illogical, " - f"gh_read, nranks * 4)'." in str(excinfo.value)) + f"gh_read, 4)'." in str(excinfo.value)) def test_ad_array_init_wrong_data_type(monkeypatch): @@ -178,8 +178,8 @@ def test_ad_array_type_no_write(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_write, NRANKS*1)", 1) + "arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_real, gh_write, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -193,8 +193,8 @@ def test_ad_array_type_no_inc(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_inc, NRANKS*1)", 1) + "arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_real, gh_inc, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -208,8 +208,8 @@ def test_ad_array_type_no_readwrite(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_readwrite, NRANKS*1)", 1) + "arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_real, gh_readwrite, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -222,8 +222,8 @@ def test_ad_array_type_no_sum(): metadata for an array specifies 'GH_SUM' access (reduction). ''' fparser.logging.disable(fparser.logging.CRITICAL) code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, NRANKS*1)", - "arg_type(gh_array, gh_real, gh_sum, NRANKS*1)", 1) + "arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_real, gh_sum, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: @@ -237,9 +237,8 @@ def test_no_vector_array(): specifies a vector scalar argument. ''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array*3, gh_real, " - "gh_read, NRANKS*1)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array*3, gh_real, gh_read, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -280,53 +279,18 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): assert array_descriptor.stencil is None -def test_keyword_not_nranks(): - ''' Tests that we raise an error when the keyword is not nranks''' - fparser.logging.disable(fparser.logging.CRITICAL) - name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, SKNARN*1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("the 4th argument of a 'meta_arg' entry must use 'NRANKS' as " - "the keyword in the format 'NRANKS*n' if the 1st argument " - "is 'GH_ARRAY', but found 'sknarn' as the keyword in " - "'arg_type(gh_array, gh_real, gh_read, sknarn * 1)'." - in str(excinfo.value)) - - -def test_incorrect_operator(): - ''' Tests that we raise an error when the operator is incorrect''' - fparser.logging.disable(fparser.logging.CRITICAL) - name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS+1)", 1) - ast = fpapi.parse(code, ignore_comments=False) - with pytest.raises(ParseError) as excinfo: - _ = LFRicKernMetadata(ast, name=name) - assert ("the 4th argument of a 'meta_arg' entry may be an " - "array but if so must use '*' as the separator " - "in the format 'NRANKS*n', but found '+' in " - "'arg_type(gh_array, gh_real, gh_read, nranks + 1)'." - in str(excinfo.value)) - - def test_n_not_integer(): ''' Tests that we raise an error when n is not an integer''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS*0.5)", 1) + code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, 1)", + "arg_type(gh_array, gh_real, gh_read, 0.5)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("the array notation must be in the format 'NRANKS*n' " + assert ("the array notation must be in the format 'n' " "where 'n' is an integer, but '0.5' was found in " - "'arg_type(gh_array, gh_real, gh_read, nranks * 0.5)'." + "'arg_type(gh_array, gh_real, gh_read, 0.5)'." in str(excinfo.value)) @@ -335,12 +299,12 @@ def test_n_less_than_one(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "NRANKS*1)", "arg_type(gh_array, gh_real, " - "gh_read, NRANKS*0)", 1) + "1)", "arg_type(gh_array, gh_real, " + "gh_read, 0)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("the array notation must be in the format 'NRANKS*n' " + assert ("the array notation must be in the format 'n' " "where 'n' is an integer >= 1. However, found n = '0' in " - "'arg_type(gh_array, gh_real, gh_read, nranks * 0)'." + "'arg_type(gh_array, gh_real, gh_read, 0)'." in str(excinfo.value)) From 8f98f7f1ca11a8a2d04dc9fdadbed4ff6075f224 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 30 May 2024 17:10:12 +0100 Subject: [PATCH 056/119] #1312 line length is 79 characters not 80 --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index c8ecb5b8e5..bff01f18b2 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -284,7 +284,7 @@ def test_n_not_integer(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_read, 0.5)", 1) + "arg_type(gh_array, gh_real, gh_read, 0.5)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) From bedf34032b5ca1800c960b292ebe1daf683aeaaf Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Thu, 30 May 2024 17:19:49 +0100 Subject: [PATCH 057/119] #1312 removing unused ParseError --- src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py | 1 - .../tests/domain/lfric/kernel/common_meta_arg_metadata_test.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index bb376f5d34..14d3641bf3 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -44,7 +44,6 @@ from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.errors import InternalError -from psyclone.parse.utils import ParseError class CommonMetaArgMetadata(CommonArgMetadata, ABC): diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index c18dd7705a..5cbc226bd0 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -44,7 +44,6 @@ from psyclone.domain.lfric.kernel import ( CommonMetaArgMetadata, ScalarArgMetadata) from psyclone.errors import InternalError -from psyclone.parse.utils import ParseError # pylint: disable=abstract-class-instantiated From 7134c9510972c2fb53e410329304735ac2754c96 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 18 Jun 2024 17:37:05 +0100 Subject: [PATCH 058/119] #1312 review changes on user guide --- doc/user_guide/dynamo0p3.rst | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index ac2a2c43a2..d9840e5796 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -119,10 +119,10 @@ a particular data structure. These data structures are represented by the six LFRic API argument types: :ref:`scalar `, :ref:`array `, :ref:`field `, :ref:`field vector `, :ref:`operator ` and :ref:`column-wise -operator `. All of them except the field vector are +operator `. All of them except the field vector are represented in the above example. ``qr`` represents a quadrature object which provides information required by a kernel to operate on fields (see section -:ref:`dynamo0.3-quadrature` for more details). +:ref:`lfric-quadrature` for more details). .. _lfric-scalar: @@ -1099,7 +1099,7 @@ details). As an example, the following ``meta_args`` metadata describes 5 entries, the first is a scalar, the second is an array, the next two -are fields and the fifth is an operator. The third entry is a field vector +are fields and the fifth is an operator. The fourth entry is a field vector of size 3. :: @@ -1210,15 +1210,14 @@ For example:: does not yet support ``integer`` and ``logical`` reductions. For a scalar, the argument metadata contains only these three entries. -However, arrays, fields and operators require further entries specifying -function-space information. -The meaning of these further entries differs depending on whether an array, a -field or an operator is being described. - -In the case of an operator, the fourth and fifth arguments describe the ``to`` -and ``from`` function spaces respectively. In the case of a field the fourth -argument specifies the function space that the field lives on. In the case of -an array, the fourth argument specifies the number of dimensions the array has. +However, arrays, fields and operators require further entries. The meaning of +these further entries differs depending on whether an array, a field or an +operator is being described. + +In the case of an array, the fourth argument specifies the number of dimensions +the array has. In the case of an operator, the fourth and fifth arguments +describe the ``to`` and ``from`` function spaces respectively. In the case of a +field the fourth argument specifies the function space that the field lives on. More details about the supported function spaces are in subsection :ref:`lfric-function-space`. @@ -1415,7 +1414,7 @@ accesses are found then PSyclone aborts. Array sizes ^^^^^^^^^^^ -The size of a :ref:`scalar array ` is described by ``NRANKS*``, +The size of a :ref:`scalar array ` is described by ````, where *n > 0* is the number of Fortran ranks representing the dimension of the array. From 288f7b25b8be3f35dab430d056eb52ab05cf4332 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Jun 2024 16:58:47 +0100 Subject: [PATCH 059/119] #1312 lfric_constants review comment --- src/psyclone/domain/lfric/lfric_constants.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_constants.py b/src/psyclone/domain/lfric/lfric_constants.py index 50f1c23af0..0977ca440f 100644 --- a/src/psyclone/domain/lfric/lfric_constants.py +++ b/src/psyclone/domain/lfric/lfric_constants.py @@ -158,8 +158,6 @@ def __init__(self): LFRicConstants.VALID_FIELD_INTRINSIC_TYPES = ["real", "integer", "logical"] - # Valid intrinsic types for array kernel argument data - # ('real', 'integer', and 'logical'). LFRicConstants.VALID_ARRAY_INTRINSIC_TYPES = ["real", "integer", "logical"] From 7d03e9a6b17c94a3a25fe76d43f938b0cf4e6640 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Jun 2024 17:15:19 +0100 Subject: [PATCH 060/119] #1312 changing gh_array to gh_scalar_array --- doc/user_guide/dynamo0p3.rst | 106 +++++++++--------- .../domain/lfric/kernel/array_arg_metadata.py | 2 +- src/psyclone/domain/lfric/lfric_constants.py | 2 +- src/psyclone/tests/domain/constants_test.py | 4 +- .../lfric/kernel/array_arg_metadata_test.py | 6 +- .../kernel/common_meta_arg_metadata_test.py | 2 +- .../domain/lfric/lfric_array_mdata_test.py | 74 ++++++------ 7 files changed, 99 insertions(+), 97 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index d9840e5796..8fdeb79c3e 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -141,9 +141,9 @@ Array +++++ In the LFRic API a scalar array represents a multi-valued Fortran array of -scalars, identified with ``GH_ARRAY`` metadata. As with scalars, array arguments -can have ``real``, ``integer`` or ``logical`` data type in :ref:`user-defined -Kernels `. +scalars, identified with ``GH_SCALAR_ARRAY`` metadata. As with scalars, array +arguments can have ``real``, ``integer`` or ``logical`` data type in +:ref:`user-defined Kernels `. .. _lfric-field: @@ -420,43 +420,43 @@ associated kernel metadata description and their precision: .. tabularcolumns:: |l|l|l| -+--------------------------+---------------------------------+-----------+ -| Data Type | Kernel Metadata | Precision | -+==========================+=================================+===========+ -| REAL(R_DEF) | GH_SCALAR/GH_ARRAY, GH_REAL | R_DEF | -+--------------------------+---------------------------------+-----------+ -| REAL(R_BL) | GH_SCALAR/GH_ARRAY, GH_REAL | R_BL | -+--------------------------+---------------------------------+-----------+ -| REAL(R_PHYS) | GH_SCALAR/GH_ARRAY, GH_REAL | R_PHYS | -+--------------------------+---------------------------------+-----------+ -| REAL(R_SOLVER) | GH_SCALAR/GH_ARRAY, GH_REAL | R_SOLVER | -+--------------------------+---------------------------------+-----------+ -| REAL(R_TRAN) | GH_SCALAR/GH_ARRAY, GH_REAL | R_TRAN | -+--------------------------+---------------------------------+-----------+ -| INTEGER(I_DEF) | GH_SCALAR/GH_ARRAY, GH_INTEGER | I_DEF | -+--------------------------+---------------------------------+-----------+ -| LOGICAL(L_DEF) | GH_SCALAR/GH_ARRAY, GH_LOGICAL | L_DEF | -+--------------------------+---------------------------------+-----------+ -| FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | -+--------------------------+---------------------------------+-----------+ -| R_BL_FIELD_TYPE | GH_FIELD, GH_REAL | R_BL | -+--------------------------+---------------------------------+-----------+ -| R_PHYS_FIELD_TYPE | GH_FIELD, GH_REAL | R_PHYS | -+--------------------------+---------------------------------+-----------+ -| R_SOLVER_FIELD_TYPE | GH_FIELD, GH_REAL | R_SOLVER | -+--------------------------+---------------------------------+-----------+ -| R_TRAN_FIELD_TYPE | GH_FIELD, GH_REAL | R_TRAN | -+--------------------------+---------------------------------+-----------+ -| INTEGER_FIELD_TYPE | GH_FIELD, GH_INTEGER | I_DEF | -+--------------------------+---------------------------------+-----------+ -| OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_DEF | -+--------------------------+---------------------------------+-----------+ -| R_SOLVER_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_SOLVER | -+--------------------------+---------------------------------+-----------+ -| R_TRAN_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_TRAN | -+--------------------------+---------------------------------+-----------+ -| COLUMNWISE_OPERATOR_TYPE | GH_COLUMNWISE_OPERATOR, GH_REAL | R_SOLVER | -+--------------------------+---------------------------------+-----------+ ++--------------------------+------------------------------------+-----------+ +| Data Type | Kernel Metadata | Precision | ++==========================+====================================+===========+ +| REAL(R_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_DEF | ++--------------------------+------------------------------------+-----------+ +| REAL(R_BL) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_BL | ++--------------------------+------------------------------------+-----------+ +| REAL(R_PHYS) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_PHYS | ++--------------------------+------------------------------------+-----------+ +| REAL(R_SOLVER) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_SOLVER | ++--------------------------+------------------------------------+-----------+ +| REAL(R_TRAN) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_TRAN | ++--------------------------+------------------------------------+-----------+ +| INTEGER(I_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_INTEGER | I_DEF | ++--------------------------+------------------------------------+-----------+ +| LOGICAL(L_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_LOGICAL | L_DEF | ++--------------------------+------------------------------------+-----------+ +| FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | ++--------------------------+------------------------------------+-----------+ +| R_BL_FIELD_TYPE | GH_FIELD, GH_REAL | R_BL | ++--------------------------+------------------------------------+-----------+ +| R_PHYS_FIELD_TYPE | GH_FIELD, GH_REAL | R_PHYS | ++--------------------------+------------------------------------+-----------+ +| R_SOLVER_FIELD_TYPE | GH_FIELD, GH_REAL | R_SOLVER | ++--------------------------+------------------------------------+-----------+ +| R_TRAN_FIELD_TYPE | GH_FIELD, GH_REAL | R_TRAN | ++--------------------------+------------------------------------+-----------+ +| INTEGER_FIELD_TYPE | GH_FIELD, GH_INTEGER | I_DEF | ++--------------------------+------------------------------------+-----------+ +| OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_DEF | ++--------------------------+------------------------------------+-----------+ +| R_SOLVER_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_SOLVER | ++--------------------------+------------------------------------+-----------+ +| R_TRAN_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_TRAN | ++--------------------------+------------------------------------+-----------+ +| COLUMNWISE_OPERATOR_TYPE | GH_COLUMNWISE_OPERATOR, GH_REAL | R_SOLVER | ++--------------------------+------------------------------------+-----------+ As can be seen from the above table, the kernel metadata does not capture all of the precision options. For example, from the metadata @@ -1089,7 +1089,7 @@ Argument metadata (information contained within the brackets of an or an **operator** (either LMA or CMA). The first argument-metadata entry describes whether the data that is -being passed is for a scalar (``GH_SCALAR``), an array (``GH_ARRAY``), a +being passed is for a scalar (``GH_SCALAR``), an array (``GH_SCALAR_ARRAY``), a field (``GH_FIELD``) or an operator (either ``GH_OPERATOR`` for LMA or ``GH_COLUMNWISE_OPERATOR`` for CMA). This information is mandatory. @@ -1106,7 +1106,7 @@ of size 3. type(arg_type) :: meta_args(5) = (/ & arg_type(GH_SCALAR, GH_REAL, ...), & - arg_type(GH_ARRAY, GH_LOGICAL, ...), & + arg_type(GH_SCALAR_ARRAY, GH_LOGICAL, ...), & arg_type(GH_FIELD, GH_INTEGER, ...), & arg_type(GH_FIELD*3, GH_REAL, ...), & arg_type(GH_OPERATOR, GH_REAL, ...) & @@ -1160,14 +1160,14 @@ combinations are specified later in this section (see For example:: - type(arg_type) :: meta_args(7) = (/ & - arg_type(GH_OPERATOR, GH_REAL, GH_READ, ... ), & - arg_type(GH_FIELD*3, GH_REAL, GH_WRITE, ... ), & - arg_type(GH_FIELD, GH_REAL, GH_READWRITE, ... ), & - arg_type(GH_FIELD, GH_INTEGER, GH_INC, ... ), & - arg_type(GH_FIELD, GH_REAL, GH_READINC, ... ), & - arg_type(GH_ARRAY, GH_LOGICAL, GH_READ, ... ), & - arg_type(GH_SCALAR, GH_REAL, GH_SUM) & + type(arg_type) :: meta_args(7) = (/ & + arg_type(GH_OPERATOR, GH_REAL, GH_READ, ... ), & + arg_type(GH_FIELD*3, GH_REAL, GH_WRITE, ... ), & + arg_type(GH_FIELD, GH_REAL, GH_READWRITE, ... ), & + arg_type(GH_FIELD, GH_INTEGER, GH_INC, ... ), & + arg_type(GH_FIELD, GH_REAL, GH_READINC, ... ), & + arg_type(GH_SCALAR_ARRAY, GH_LOGICAL, GH_READ, ... ), & + arg_type(GH_SCALAR, GH_REAL, GH_SUM) & /) .. warning:: It is important that ``GH_INC`` is not incorrectly used @@ -1304,7 +1304,7 @@ the :ref:`LFRic fields `): +========================+=================================+ | GH_SCALAR | GH_REAL, GH_INTEGER, GH_LOGICAL | +------------------------+---------------------------------+ -| GH_ARRAY | GH_REAL, GH_INTEGER, GH_LOGICAL | +| GH_SCALAR_ARRAY | GH_REAL, GH_INTEGER, GH_LOGICAL | +------------------------+---------------------------------+ | GH_FIELD | GH_REAL, GH_INTEGER | +------------------------+---------------------------------+ @@ -1321,7 +1321,7 @@ Valid Access Modes As mentioned earlier, not all combinations of metadata are valid. Valid combinations for each argument type in user-defined Kernels are summarised here. All argument types -(``GH_SCALAR``, ``GH_ARRAY``, ``GH_FIELD``, ``GH_OPERATOR`` and +(``GH_SCALAR``, ``GH_SCALAR_ARRAY``, ``GH_FIELD``, ``GH_OPERATOR`` and ``GH_COLUMNWISE_OPERATOR``) may be read within a Kernel and this is specified in metadata using ``GH_READ``. At least one kernel argument must be listed as being modified. When data is *modified* @@ -1337,7 +1337,7 @@ modes depend upon the argument type and the function space it is on: +========================+==============================+====================+ | GH_SCALAR | n/a | GH_READ | +------------------------+------------------------------+--------------------+ -| GH_ARRAY | n/a | GH_READ | +| GH_SCALAR_ARRAY | n/a | GH_READ | +------------------------+------------------------------+--------------------+ | GH_FIELD | Discontinuous | GH_READ, GH_WRITE, | | | | GH_READWRITE | diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 85537a6e23..0af65ec27e 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -53,7 +53,7 @@ class ArrayArgMetadata(ScalarArgMetadata): ''' # The name used to specify an array argument in LFRic metadata. - form = "gh_array" + form = "gh_scalar_array" # The relative positions of LFRic metadata. Metadata for an array # argument is provided in the following format 'arg_type(form, # datatype, access, function_space)'. Therefore, for example, the diff --git a/src/psyclone/domain/lfric/lfric_constants.py b/src/psyclone/domain/lfric/lfric_constants.py index 0977ca440f..c1a3f0a447 100644 --- a/src/psyclone/domain/lfric/lfric_constants.py +++ b/src/psyclone/domain/lfric/lfric_constants.py @@ -78,7 +78,7 @@ def __init__(self): # Supported LFRic API argument types (scalars, fields, operators) LFRicConstants.VALID_SCALAR_NAMES = ["gh_scalar"] - LFRicConstants.VALID_ARRAY_NAMES = ["gh_array"] + LFRicConstants.VALID_ARRAY_NAMES = ["gh_scalar_array"] LFRicConstants.VALID_FIELD_NAMES = ["gh_field"] LFRicConstants.VALID_OPERATOR_NAMES = ["gh_operator", "gh_columnwise_operator"] diff --git a/src/psyclone/tests/domain/constants_test.py b/src/psyclone/tests/domain/constants_test.py index d6ed8f5b12..251f2cd6b2 100644 --- a/src/psyclone/tests/domain/constants_test.py +++ b/src/psyclone/tests/domain/constants_test.py @@ -57,7 +57,7 @@ def test_lfric_const(): # Don't test intrinsic_types, which comes from the config file assert lfric_const.VALID_ARG_TYPE_NAMES == ["gh_field", "gh_operator", "gh_columnwise_operator", - "gh_array", "gh_scalar"] + "gh_scalar_array", "gh_scalar"] assert lfric_const.VALID_SCALAR_NAMES == ["gh_scalar"] @@ -69,7 +69,7 @@ def test_lfric_const(): assert lfric_const.VALID_INTRINSIC_TYPES == "INVALID" assert lfric_const.VALID_ARG_TYPE_NAMES == ["gh_field", "gh_operator", "gh_columnwise_operator", - "gh_array", "gh_scalar"] + "gh_scalar_array", "gh_scalar"] assert lfric_const.VALID_SCALAR_NAMES == ["gh_scalar"] assert lfric_const.VALID_ARG_DATA_TYPES == ["gh_real", "gh_integer", "gh_logical"] diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 4c8b49a7ba..df169b9e64 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -52,7 +52,7 @@ def test_create(datatype, access, array_ndims): ''' array_arg = ArrayArgMetadata(datatype, access, array_ndims) assert isinstance(array_arg, ArrayArgMetadata) - assert array_arg.form == "gh_array" + assert array_arg.form == "gh_scalar_array" assert array_arg.datatype == "gh_real" assert array_arg.access == "gh_read" assert array_arg.array_ndims == "1" @@ -70,7 +70,7 @@ def test_init_invalid_an(): @pytest.mark.parametrize("metadata", - ["arg_type(GH_ARRAY, GH_REAL, GH_READ, 2)"]) + ["arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 2)"]) def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ArrayArgMetadata.create_fparser2( @@ -83,7 +83,7 @@ def test_get_metadata(metadata): @pytest.mark.parametrize("fortran_string", [ - "arg_type(GH_ARRAY, GH_REAL, GH_READ, 5)"]) + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 5)"]) def test_fortran_string(fortran_string): '''Test that the fortran_string method works as expected.''' array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 5cbc226bd0..d978da80fa 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -264,7 +264,7 @@ def test_get_array_ndims(): ''' fparser_tree = CheckArg.create_fparser2( - "arg_type(GH_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) vector_length = CheckArg.get_array_ndims(fparser_tree) assert vector_length == "3" diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index bff01f18b2..8d14b3fbe7 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -60,9 +60,9 @@ type, extends(kernel_type) :: testkern_array_type type(arg_type), meta_args(5) = & - (/ arg_type(gh_array, gh_real, gh_read, 1), & - arg_type(gh_array, gh_integer, gh_read, 2), & - arg_type(gh_array, gh_logical, gh_read, 4), & + (/ arg_type(gh_scalar_array, gh_real, gh_read, 1), & + arg_type(gh_scalar_array, gh_integer, gh_read, 2), & + arg_type(gh_scalar_array, gh_logical, gh_read, 4), & arg_type(gh_operator, gh_real, gh_read, w2, w2), & arg_type(gh_field, gh_real, gh_write, w3) & /) @@ -97,14 +97,14 @@ def test_ad_array_type_wrong_num_of_args(): metadata for an array has fewer than 3 args. ''' fparser.logging.disable(fparser.logging.CRITICAL) code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_read)", 1) + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_read)", 1) ast = fpapi.parse(code, ignore_comments=False) name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert ("each 'meta_arg' entry must have 4 arguments if its first " - "argument is of ['gh_array'] type" in str(excinfo.value)) + "argument is of ['gh_scalar_array'] type" in str(excinfo.value)) def test_ad_array_invalid_data_type(): @@ -114,40 +114,40 @@ def test_ad_array_invalid_data_type(): name = "testkern_array_type" # check real array code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_unreal, gh_read, 1)", 1) + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_unreal, gh_read, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " - f"but found 'gh_unreal' in 'arg_type(gh_array, gh_unreal, " + f"but found 'gh_unreal' in 'arg_type(gh_scalar_array, gh_unreal, " f"gh_read, 1)'." in str(excinfo.value)) # check integer array code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_integer, gh_read, 2)", - "arg_type(gh_array, gh_frac, gh_read, 2)", 1) + "arg_type(gh_scalar_array, gh_integer, gh_read, 2)", + "arg_type(gh_scalar_array, gh_frac, gh_read, 2)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " - f"but found 'gh_frac' in 'arg_type(gh_array, gh_frac, " + f"but found 'gh_frac' in 'arg_type(gh_scalar_array, gh_frac, " f"gh_read, 2)'." in str(excinfo.value)) # check logical array code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_logical, gh_read, 4)", - "arg_type(gh_array, gh_illogical, gh_read, 4)", 1) + "arg_type(gh_scalar_array, gh_logical, gh_read, 4)", + "arg_type(gh_scalar_array, gh_illogical, gh_read, 4)", 1) ast = fpapi.parse(code, ignore_comments=False) const = LFRicConstants() with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert (f"In the LFRic API the 2nd argument of a 'meta_arg' entry should " f"be a valid data type (one of {const.VALID_ARRAY_DATA_TYPES}), " - f"but found 'gh_illogical' in 'arg_type(gh_array, gh_illogical, " - f"gh_read, 4)'." in str(excinfo.value)) + f"but found 'gh_illogical' in 'arg_type(gh_scalar_array, " + f"gh_illogical, gh_read, 4)'." in str(excinfo.value)) def test_ad_array_init_wrong_data_type(monkeypatch): @@ -178,8 +178,8 @@ def test_ad_array_type_no_write(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_write, 1)", 1) + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_write, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -193,8 +193,8 @@ def test_ad_array_type_no_inc(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_inc, 1)", 1) + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_inc, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -208,8 +208,8 @@ def test_ad_array_type_no_readwrite(): fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_readwrite, 1)", 1) + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_readwrite, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) @@ -222,8 +222,8 @@ def test_ad_array_type_no_sum(): metadata for an array specifies 'GH_SUM' access (reduction). ''' fparser.logging.disable(fparser.logging.CRITICAL) code = ARRAY_CODE.replace( - "arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_sum, 1)", 1) + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_sum, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: @@ -237,13 +237,14 @@ def test_no_vector_array(): specifies a vector scalar argument. ''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array*3, gh_real, gh_read, 1)", 1) + code = ARRAY_CODE.replace( + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array*3, gh_real, gh_read, 1)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert ("vector notation is only supported for ['gh_field'] argument " - "types but found 'gh_array * 3'" in str(excinfo.value)) + "types but found 'gh_scalar_array * 3'" in str(excinfo.value)) @pytest.mark.parametrize("array_ind, array_type, array_ndims", [ @@ -263,14 +264,14 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): result = str(array_descriptor) expected_output = ( f"LFRicArgDescriptor object\n" - f" argument_type[0]='gh_array'\n" + f" argument_type[0]='gh_scalar_array'\n" f" data_type[1]='{array_type}'\n" f" access_descriptor[2]='gh_read'\n" f" array_ndims[3]='{array_ndims}'") assert expected_output in result # Check LFRicArgDescriptor argument properties - assert array_descriptor.argument_type == "gh_array" + assert array_descriptor.argument_type == "gh_scalar_array" assert array_descriptor.data_type == array_type assert array_descriptor.array_ndims == array_ndims assert array_descriptor.function_spaces == [None] @@ -283,14 +284,15 @@ def test_n_not_integer(): ''' Tests that we raise an error when n is not an integer''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, 1)", - "arg_type(gh_array, gh_real, gh_read, 0.5)", 1) + code = ARRAY_CODE.replace( + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_read, 0.5)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert ("the array notation must be in the format 'n' " "where 'n' is an integer, but '0.5' was found in " - "'arg_type(gh_array, gh_real, gh_read, 0.5)'." + "'arg_type(gh_scalar_array, gh_real, gh_read, 0.5)'." in str(excinfo.value)) @@ -298,13 +300,13 @@ def test_n_less_than_one(): ''' Tests that we raise an error when n is less than 1''' fparser.logging.disable(fparser.logging.CRITICAL) name = "testkern_array_type" - code = ARRAY_CODE.replace("arg_type(gh_array, gh_real, gh_read, " - "1)", "arg_type(gh_array, gh_real, " - "gh_read, 0)", 1) + code = ARRAY_CODE.replace( + "arg_type(gh_scalar_array, gh_real, gh_read, 1)", + "arg_type(gh_scalar_array, gh_real, gh_read, 0)", 1) ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) assert ("the array notation must be in the format 'n' " "where 'n' is an integer >= 1. However, found n = '0' in " - "'arg_type(gh_array, gh_real, gh_read, 0)'." + "'arg_type(gh_scalar_array, gh_real, gh_read, 0)'." in str(excinfo.value)) From 62c648d7b38aa87c9f1f04f139b26d0593c3bcb2 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Jun 2024 17:34:14 +0100 Subject: [PATCH 061/119] #1312 ArrayArgMetadata -> ScalarArrayArgMetadata, some review changes, and a pylint fix --- src/psyclone/domain/lfric/kernel/__init__.py | 3 +- .../domain/lfric/kernel/array_arg_metadata.py | 25 +++++++++-------- .../lfric/kernel/array_arg_metadata_test.py | 28 +++++++++---------- .../domain/lfric/lfric_array_mdata_test.py | 6 ++-- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/__init__.py b/src/psyclone/domain/lfric/kernel/__init__.py index f00945f422..886c60b750 100644 --- a/src/psyclone/domain/lfric/kernel/__init__.py +++ b/src/psyclone/domain/lfric/kernel/__init__.py @@ -37,7 +37,8 @@ '''Module for Kernels in the LFRic domain.''' -from psyclone.domain.lfric.kernel.array_arg_metadata import ArrayArgMetadata +from psyclone.domain.lfric.kernel.array_arg_metadata import \ + ScalarArrayArgMetadata from psyclone.domain.lfric.kernel.columnwise_operator_arg_metadata import \ ColumnwiseOperatorArgMetadata from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 0af65ec27e..9ad04e2c9f 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -33,8 +33,8 @@ # ----------------------------------------------------------------------------- # Author L. Turner, Met Office -'''Module containing the ArrayArgMetadata class which captures the metadata -associated with an array argument. Supports the creation, modification +'''Module containing the ScalarArrayArgMetadata class which captures the +metadata associated with an array argument. Supports the creation, modification and Fortran output of an Array argument. ''' @@ -42,14 +42,13 @@ from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata -class ArrayArgMetadata(ScalarArgMetadata): +class ScalarArrayArgMetadata(ScalarArgMetadata): '''Class to capture LFRic kernel metadata information for an array argument. :param str datatype: the datatype of this array (GH_INTEGER, ...). :param str access: the way the kernel accesses this array (GH_READ). - :param str function_space: the function space that this array is \ - on (W0, ...). + :param str array_ndims: the rank (number of dimensions) of this array ''' # The name used to specify an array argument in LFRic metadata. @@ -111,7 +110,7 @@ def check_datatype(value): ''' const = LFRicConstants() - ArrayArgMetadata.validate_scalar_value( + ScalarArrayArgMetadata.validate_scalar_value( value, const.VALID_ARRAY_DATA_TYPES, "datatype descriptor") @staticmethod @@ -120,11 +119,11 @@ def check_access(value): :param str value: the access descriptor to validate. :raises ValueError: if the provided value is not a valid - access descriptor. + access descriptor. ''' const = LFRicConstants() - ArrayArgMetadata.validate_scalar_value( + ScalarArrayArgMetadata.validate_scalar_value( value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") @property @@ -138,8 +137,12 @@ def array_ndims(self): @array_ndims.setter def array_ndims(self, value): ''' - :param str value: set the function space to the - specified value. + :param str value: set the function space to the specified value. + + :raises TypeError: if the array_size is not a string + :raises ValueError: if the array size is not an integer + :raises ValeuError: if the array size is less than 1 + ''' if not isinstance(value, str): raise TypeError(f"The 'array_size' value should be of type str, " @@ -156,4 +159,4 @@ def array_ndims(self, value): self._array_ndims = value -__all__ = ["ArrayArgMetadata"] +__all__ = ["ScalarArrayArgMetadata"] diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index df169b9e64..96a5e8849c 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -33,25 +33,25 @@ # ----------------------------------------------------------------------------- # Author: L. Turner, Met Office -'''Module containing tests for the ArrayArgMetadata class. +'''Module containing tests for the ScalarArrayArgMetadata class. ''' import pytest from fparser.two import Fortran2003 -from psyclone.domain.lfric.kernel import ArrayArgMetadata +from psyclone.domain.lfric.kernel import ScalarArrayArgMetadata @pytest.mark.parametrize("datatype, access, array_ndims", [ ("GH_REAL", "GH_READ", "1"), ("gh_real", "gh_read", "1")]) def test_create(datatype, access, array_ndims): - '''Test that an instance of ArrayArgMetadata can be created + '''Test that an instance of ScalarArrayArgMetadata can be created successfully. Also test that the arguments are case insensitive. ''' - array_arg = ArrayArgMetadata(datatype, access, array_ndims) - assert isinstance(array_arg, ArrayArgMetadata) + array_arg = ScalarArrayArgMetadata(datatype, access, array_ndims) + assert isinstance(array_arg, ScalarArrayArgMetadata) assert array_arg.form == "gh_scalar_array" assert array_arg.datatype == "gh_real" assert array_arg.access == "gh_read" @@ -64,7 +64,7 @@ def test_init_invalid_an(): ''' with pytest.raises(TypeError) as info: - _ = ArrayArgMetadata("GH_REAL", "GH_READ", None) + _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) assert ("The 'array_size' value should be of type str, but found " "'NoneType'." in str(info.value)) @@ -73,9 +73,9 @@ def test_init_invalid_an(): ["arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 2)"]) def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' - fparser2_tree = ArrayArgMetadata.create_fparser2( + fparser2_tree = ScalarArrayArgMetadata.create_fparser2( metadata, Fortran2003.Part_Ref) - datatype, access, array_ndims = ArrayArgMetadata._get_metadata( + datatype, access, array_ndims = ScalarArrayArgMetadata._get_metadata( fparser2_tree) assert datatype == "GH_REAL" assert access == "GH_READ" @@ -86,7 +86,7 @@ def test_get_metadata(metadata): "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 5)"]) def test_fortran_string(fortran_string): '''Test that the fortran_string method works as expected.''' - array_arg = ArrayArgMetadata.create_from_fortran_string(fortran_string) + array_arg = ScalarArrayArgMetadata.create_from_fortran_string(fortran_string) result = array_arg.fortran_string() assert result == fortran_string.lower() @@ -94,9 +94,9 @@ def test_fortran_string(fortran_string): @pytest.mark.parametrize("datatype", ["GH_REAL", "GH_INTEGER", "GH_LOGICAL"]) def test_check_datatype(datatype): '''Test the check_datatype method works as expected.''' - ArrayArgMetadata.check_datatype(datatype) + ScalarArrayArgMetadata.check_datatype(datatype) with pytest.raises(ValueError) as info: - ArrayArgMetadata.check_datatype("invalid") + ScalarArrayArgMetadata.check_datatype("invalid") assert ("The 'datatype descriptor' metadata should be a recognised value " "(one of ['gh_real', 'gh_integer', 'gh_logical']) but found " "'invalid'." in str(info.value)) @@ -104,9 +104,9 @@ def test_check_datatype(datatype): def test_check_access(): '''Test the check_access method works as expected.''' - ArrayArgMetadata.check_access("GH_READ") + ScalarArrayArgMetadata.check_access("GH_READ") with pytest.raises(ValueError) as info: - ArrayArgMetadata.check_access("invalid") + ScalarArrayArgMetadata.check_access("invalid") assert ("The 'access descriptor' metadata should be a recognised value " "(one of ['gh_read']) but found 'invalid'." in str(info.value)) @@ -116,7 +116,7 @@ def test_array_ndims_setter_getter(): including raising an exception if the value is invalid. ''' - array_arg = ArrayArgMetadata("GH_REAL", "GH_READ", "2") + array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") with pytest.raises(ValueError) as info: array_arg.array_ndims = "invalid" diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 8d14b3fbe7..fcbde72345 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -60,9 +60,9 @@ type, extends(kernel_type) :: testkern_array_type type(arg_type), meta_args(5) = & - (/ arg_type(gh_scalar_array, gh_real, gh_read, 1), & - arg_type(gh_scalar_array, gh_integer, gh_read, 2), & - arg_type(gh_scalar_array, gh_logical, gh_read, 4), & + (/ arg_type(gh_scalar_array, gh_real, gh_read, 1), & + arg_type(gh_scalar_array, gh_integer, gh_read, 2), & + arg_type(gh_scalar_array, gh_logical, gh_read, 4), & arg_type(gh_operator, gh_real, gh_read, w2, w2), & arg_type(gh_field, gh_real, gh_write, w3) & /) From b22d45ed98c429fa1aff92be3d4b3b02c52da2a6 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Jun 2024 17:48:34 +0100 Subject: [PATCH 062/119] #1312 review changes in lfric_arg_descriptor --- .../domain/lfric/lfric_arg_descriptor.py | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index fda9886131..9848f075d0 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -278,7 +278,7 @@ def _validate_vector_size(self, separator, arg_type): def _validate_array_ndims(self, arg_type): ''' Validates descriptors for scalar array arguments and populates - vector properties accordingly. + properties accordingly. :param str separator: operator in a binary expression. :param arg_type: LFRic API array argument type. @@ -287,15 +287,13 @@ def _validate_array_ndims(self, arg_type): :raises ParseError: if the array notation is not in the correct format 'n' where 'n' is an integer. - :raises ParseError: if the array notation is used for the - array size of less than 1. + :raises ParseError: if the specified number of array dimensions + is less than 1. :raises ParseError: if the array notation is used for an argument that is not an array. ''' - print(arg_type.args[3]) - - # Try to find the array size for a scalar array and return + # Try to find the array size for a scalar array and raise # an error if it is not an integer number... try: array_ndims = int(arg_type.args[3]) @@ -659,10 +657,8 @@ def _init_array(self, arg_type): :raises InternalError: if argument type other than an array is passed in. :raises ParseError: if there are not exactly 4 metadata arguments. - :raises InternalError: if an array argument has an invalid data type. + :raises InternalError: if the array argument has an invalid data type. :raises ParseError: if array arguments do not have read-only access. - :raises ParseError: if a scalar argument that is not a real - scalar has a reduction access. ''' const = LFRicConstants() @@ -676,13 +672,13 @@ def _init_array(self, arg_type): nargs_array = 4 if self._nargs != nargs_array: raise ParseError( - "In the LFRic API each 'meta_arg' entry must have " + "In the LFRic API a 'meta_arg' entry must have " f"{nargs_array} arguments if its first argument is of " f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " f"'{arg_type}'.") # Check whether an invalid data type for an array argument is passed - # in. Valid data types for arrays are valid data types in LFRic API. + # in. if self._data_type not in const.VALID_ARRAY_DATA_TYPES: raise InternalError( f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " @@ -762,7 +758,7 @@ def function_space(self): function_space_from for an operator and nothing for a scalar. :returns: function space relating to this kernel argument or - None (for a scalar). + None (for a scalar or ScalarArray). :rtype: str or NoneType :raises InternalError: if an invalid argument type is passed in. @@ -774,7 +770,7 @@ def function_space(self): if self._argument_type in const.VALID_OPERATOR_NAMES: return self._function_space2 if self._argument_type in const.VALID_ARRAY_NAMES: - return self._function_space1 + return None if self._argument_type in const.VALID_SCALAR_NAMES: return None raise InternalError(f"Expected a valid argument type but got " From 8f883774f011f451c6c5604f217dc7ea71e2b490 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Jun 2024 17:51:23 +0100 Subject: [PATCH 063/119] #1312 pycodestyle change --- .../tests/domain/lfric/kernel/array_arg_metadata_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 96a5e8849c..39db564dab 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -86,7 +86,8 @@ def test_get_metadata(metadata): "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 5)"]) def test_fortran_string(fortran_string): '''Test that the fortran_string method works as expected.''' - array_arg = ScalarArrayArgMetadata.create_from_fortran_string(fortran_string) + array_arg = ScalarArrayArgMetadata.create_from_fortran_string( + fortran_string) result = array_arg.fortran_string() assert result == fortran_string.lower() From 21f2914e56d8915ccf79a58695f8bb639aaf1970 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Jun 2024 18:10:08 +0100 Subject: [PATCH 064/119] #1312 forgot to change a test to match --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index fcbde72345..bafd822201 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -103,7 +103,7 @@ def test_ad_array_type_wrong_num_of_args(): name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("each 'meta_arg' entry must have 4 arguments if its first " + assert ("a 'meta_arg' entry must have 4 arguments if its first " "argument is of ['gh_scalar_array'] type" in str(excinfo.value)) From 88c5135db41d71e6b5c2eb816eeb52f77ab3cbf7 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 23 Aug 2024 12:15:57 +0100 Subject: [PATCH 065/119] #1312 more changes from review comments --- doc/user_guide/dynamo0p3.rst | 26 +++--- .../domain/lfric/kernel/array_arg_metadata.py | 79 +++++++++---------- .../lfric/kernel/common_meta_arg_metadata.py | 25 +----- .../domain/lfric/lfric_arg_descriptor.py | 10 +-- .../lfric/kernel/array_arg_metadata_test.py | 12 +-- 5 files changed, 62 insertions(+), 90 deletions(-) diff --git a/doc/user_guide/dynamo0p3.rst b/doc/user_guide/dynamo0p3.rst index 8fdeb79c3e..21ab94d337 100644 --- a/doc/user_guide/dynamo0p3.rst +++ b/doc/user_guide/dynamo0p3.rst @@ -137,12 +137,13 @@ in the :ref:`LFRic Built-ins `). .. _lfric-array: -Array -+++++ +Scalar Array +++++++++++++ -In the LFRic API a scalar array represents a multi-valued Fortran array of -scalars, identified with ``GH_SCALAR_ARRAY`` metadata. As with scalars, array -arguments can have ``real``, ``integer`` or ``logical`` data type in +In the LFRic API a scalar array represents a Fortran array of scalars, of at +least rank (number of dimensions) one. Scalar arrays are identified with +``GH_SCALAR_ARRAY`` metadata. As with scalars, array arguments can have +``real``, ``integer`` or ``logical`` data type in :ref:`user-defined Kernels `. .. _lfric-field: @@ -1210,15 +1211,16 @@ For example:: does not yet support ``integer`` and ``logical`` reductions. For a scalar, the argument metadata contains only these three entries. -However, arrays, fields and operators require further entries. The meaning of -these further entries differs depending on whether an array, a field or an -operator is being described. +However, fields, operators and scalar arrays require further entries specifying +function-space information or dimensionality. The meaning of these further +entries differs depending on whether a field, an operator or a scalar array is +being described. -In the case of an array, the fourth argument specifies the number of dimensions -the array has. In the case of an operator, the fourth and fifth arguments +In the case of a field the fourth argument specifies the function space that the +field lives on. In the case of an operator, the fourth and fifth arguments describe the ``to`` and ``from`` function spaces respectively. In the case of a -field the fourth argument specifies the function space that the field lives on. -More details about the supported function spaces are in subsection +scalar array, the fourth argument specifies the number of dimensions the array +has. More details about the supported function spaces are in subsection :ref:`lfric-function-space`. For example, the metadata for a kernel that applies a column-wise diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 9ad04e2c9f..40b7157694 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -60,12 +60,12 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): form_arg_index = 0 datatype_arg_index = 1 access_arg_index = 2 - array_size_arg_index = 3 + array_ndims_arg_index = 3 # The name to use for any exceptions. check_name = "array" # The number of arguments in the language-level metadata (min and # max values). - nargs = (4) + nargs = (4,4) def __init__(self, datatype, access, array_ndims): super().__init__(datatype, access) @@ -100,36 +100,10 @@ def fortran_string(self): return (f"arg_type({self.form}, {self.datatype}, {self.access}, " f"{self.array_ndims})") - @staticmethod - def check_datatype(value): - ''' - :param str value: the datatype to check for validity. - - :raises ValueError: if the provided value is not a valid - datatype descriptor. - - ''' - const = LFRicConstants() - ScalarArrayArgMetadata.validate_scalar_value( - value, const.VALID_ARRAY_DATA_TYPES, "datatype descriptor") - - @staticmethod - def check_access(value): - ''' - :param str value: the access descriptor to validate. - - :raises ValueError: if the provided value is not a valid - access descriptor. - - ''' - const = LFRicConstants() - ScalarArrayArgMetadata.validate_scalar_value( - value, const.VALID_ARRAY_ACCESS_TYPES, "access descriptor") - @property def array_ndims(self): ''' - :returns: the array size for this array argument. + :returns: the number of dimensions for this scalar array argument. :rtype: str ''' return self._array_ndims @@ -137,26 +111,47 @@ def array_ndims(self): @array_ndims.setter def array_ndims(self, value): ''' - :param str value: set the function space to the specified value. + :param str value: set the number of dimensions to the specified value. - :raises TypeError: if the array_size is not a string - :raises ValueError: if the array size is not an integer - :raises ValeuError: if the array size is less than 1 + ''' + self._array_ndims = value + + @classmethod + def get_array_ndims(cls, fparser2_tree): + '''Retrieves the array ndims metadata value found within the + supplied fparser2 tree and checks that it is valid. + + :param fparser2_tree: fparser2 tree capturing the required metadata. + :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` + + :returns: the array ndims value extracted from the fparser2 tree. + :rtype: str + + :raises TypeError: if the array ndims is not a string. + :raises ValueError: if the array ndims is not an integer. + :raises ValueError: if the array ndims is less than 1. ''' - if not isinstance(value, str): - raise TypeError(f"The 'array_size' value should be of type str, " - f"but found '{type(value).__name__}'.") + array_datatype = CommonArgMetadata.get_arg( + fparser2_tree, cls.array_ndims_arg_index) + array_ndims = array_datatype.strip() + if not isinstance(array_ndims, str): + raise TypeError(f"The number of dimensions of a scalar array " + f"should be of type str, but found " + f"'{type(array_ndims).__name__}'.") try: - int_value = int(value) + int_value = int(array_ndims) except ValueError as info: - raise ValueError(f"The array size should be a string containing " - f"an integer, but found '{value}'.") from info + raise ValueError(f"The number of dimensions of a scalar array " + f"should be a string containing an integer, " + f"but found '{array_ndims}'.") from info if int_value < 1: - raise ValueError(f"The array size should be an integer greater " - f"than or equal to 1 but found {value}.") - self._array_ndims = value + raise ValueError(f"The number of dimensions of a scalar array " + f"should be an integer greater than or " + f"equal to 1 but found {array_ndims}.") + return array_ndims + __all__ = ["ScalarArrayArgMetadata"] diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 14d3641bf3..955f207cf8 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -62,7 +62,6 @@ class CommonMetaArgMetadata(CommonArgMetadata, ABC): datatype_arg_index = 1 access_arg_index = 2 function_space_arg_index = 3 - array_size_arg_index = 3 form = "" check_name = "" nargs = 1 @@ -188,7 +187,7 @@ def get_vector_length(cls, fparser2_tree): :returns: the vector length value extracted from the fparser2 tree. :rtype: str - :raises TypeError: if the vector length metadata is not in the \ + :raises TypeError: if the vector length metadata is not in the expected form. ''' @@ -202,28 +201,6 @@ def get_vector_length(cls, fparser2_tree): vector_length = components[1].strip() return vector_length - @classmethod - def get_array_ndims(cls, fparser2_tree): - '''Retrieves the array ndims metadata value found within the - supplied fparser2 tree and checks that it is valid. - - :param fparser2_tree: fparser2 tree capturing the required metadata. - :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` - - :returns: the array ndims value extracted from the fparser2 tree. - :rtype: str - - :raises TypeError: if the array ndims metadata is not in the - expected form. - :raises ParseError: if the array ndims metadata does not use the - expected keyword. - - ''' - array_datatype = CommonArgMetadata.get_arg( - fparser2_tree, cls.array_size_arg_index) - array_ndims = array_datatype.strip() - return array_ndims - @property def datatype(self): ''' diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 9848f075d0..cfac8fd4c4 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -769,9 +769,8 @@ def function_space(self): return self._function_space1 if self._argument_type in const.VALID_OPERATOR_NAMES: return self._function_space2 - if self._argument_type in const.VALID_ARRAY_NAMES: - return None - if self._argument_type in const.VALID_SCALAR_NAMES: + if self._argument_type in (const.VALID_ARRAY_NAMES + + const.VALID_SCALAR_NAMES): return None raise InternalError(f"Expected a valid argument type but got " f"'{self._argument_type}'.") @@ -796,9 +795,8 @@ def function_spaces(self): if self._argument_type in const.VALID_OPERATOR_NAMES: # Return to before from to maintain expected ordering return [self.function_space_to, self.function_space_from] - if self._argument_type in const.VALID_ARRAY_NAMES: - return [self.function_space] - if self._argument_type in const.VALID_SCALAR_NAMES: + if self._argument_type in (const.VALID_ARRAY_NAMES + + const.VALID_SCALAR_NAMES): return [] raise InternalError(f"Expected a valid argument type but got " f"'{self._argument_type}'.") diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 39db564dab..2d56609262 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -65,8 +65,8 @@ def test_init_invalid_an(): ''' with pytest.raises(TypeError) as info: _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) - assert ("The 'array_size' value should be of type str, but found " - "'NoneType'." in str(info.value)) + assert ("The number of dimensions of a scalar array should be of type " + "str, but found 'NoneType'." in str(info.value)) @pytest.mark.parametrize("metadata", @@ -121,13 +121,13 @@ def test_array_ndims_setter_getter(): with pytest.raises(ValueError) as info: array_arg.array_ndims = "invalid" - assert ("The array size should be a string containing an integer, " - "but found 'invalid'." in str(info.value)) + assert ("The number of dimensions of a scalar array should be a string " + "containing an integer, but found 'invalid'." in str(info.value)) with pytest.raises(ValueError) as info: array_arg.array_ndims = "0" - assert ("The array size should be an integer greater than or equal to " - "1 but found 0." in str(info.value)) + assert ("The number of dimensions of a scalar array should be an integer " + "greater than or equal to 1 but found 0." in str(info.value)) array_arg.array_ndims = "3" assert array_arg.array_ndims == "3" From 9434c8d736d965866d3db056696a3c7c0dbc7b37 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Fri, 23 Aug 2024 13:50:22 +0100 Subject: [PATCH 066/119] #1312 pylinting --- src/psyclone/domain/lfric/kernel/array_arg_metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 40b7157694..7c77b619cc 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -39,6 +39,7 @@ ''' from psyclone.domain.lfric import LFRicConstants +from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata @@ -65,7 +66,7 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): check_name = "array" # The number of arguments in the language-level metadata (min and # max values). - nargs = (4,4) + nargs = (4, 4) def __init__(self, datatype, access, array_ndims): super().__init__(datatype, access) @@ -153,5 +154,4 @@ def get_array_ndims(cls, fparser2_tree): return array_ndims - __all__ = ["ScalarArrayArgMetadata"] From dbfb0132556d8915fd7c2ab34028f0944d55a4f7 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 27 Aug 2024 11:01:05 +0100 Subject: [PATCH 067/119] #1312 more pylinting --- src/psyclone/domain/lfric/kernel/array_arg_metadata.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 7c77b619cc..a02825b120 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -38,7 +38,6 @@ and Fortran output of an Array argument. ''' -from psyclone.domain.lfric import LFRicConstants from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata From 81d076c05fe4a772b2650804b7d1c66637a9270d Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 16:55:01 +0000 Subject: [PATCH 068/119] #1312 fixing tests --- .../lfric/kernel/array_arg_metadata_test.py | 65 ++++++++++++------- .../kernel/common_meta_arg_metadata_test.py | 11 ---- .../domain/lfric/lfric_array_mdata_test.py | 2 +- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 2d56609262..0e5c6248bf 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -57,16 +57,16 @@ def test_create(datatype, access, array_ndims): assert array_arg.access == "gh_read" assert array_arg.array_ndims == "1" - -def test_init_invalid_an(): - '''Test that an invalid array_size supplied to the constructor - raises the expected exception. - - ''' - with pytest.raises(TypeError) as info: - _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) - assert ("The number of dimensions of a scalar array should be of type " - "str, but found 'NoneType'." in str(info.value)) +# +#def test_init_invalid_an(): +# '''Test that an invalid array_size supplied to the constructor +# raises the expected exception. +# +# ''' +# with pytest.raises(TypeError) as info: +# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) +# assert ("The number of dimensions of a scalar array should be of type " +# "str, but found 'NoneType'." in str(info.value)) @pytest.mark.parametrize("metadata", @@ -109,25 +109,46 @@ def test_check_access(): with pytest.raises(ValueError) as info: ScalarArrayArgMetadata.check_access("invalid") assert ("The 'access descriptor' metadata should be a recognised value " - "(one of ['gh_read']) but found 'invalid'." in str(info.value)) + "(one of ['gh_read', 'gh_sum']) but found 'invalid'." in str(info.value)) -def test_array_ndims_setter_getter(): - '''Test that the array_ndims setter and getter work as expected, +#def test_get_array_ndims(): +# '''Test that the get_array_ndims method in the +# ScalarArrayArgMetadata class works as expected. +# +# ''' +# fparser2_tree = ScalarArrayArgMetadata.create_fparser2( +# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) +# +# #array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") +# +# with pytest.raises(TypeError) as info: +# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) +# assert ("The number of dimensions of a scalar array should be of type str, " +# "but found 'ineteger'." in str(info.value)) +# +# with pytest.raises(ValueError) as info: +# fparser2_tree = ScalarArrayArgMetadata.create_fparser2( +# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, invalid)", Fortran2003.Part_Ref) +# #ScalarArrayArgMetadata.get_array_ndims("GH_REAL", "GH_READ", "invalid") +# assert ("The number of dimensions of a scalar array should be a string " +# "containing an integer, but found 'invalid'." in str(info.value)) +# +# with pytest.raises(ValueError) as info: +# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "0") +# assert ("The number of dimensions of a scalar array should be an integer " +# "greater than or equal to 1 but found 0." in str(info.value)) +# vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) +# assert vector_length == "3" + + +def test_array_ndims_setter(): + '''Test that the array_ndims setter works as expected, including raising an exception if the value is invalid. ''' array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") - with pytest.raises(ValueError) as info: - array_arg.array_ndims = "invalid" - assert ("The number of dimensions of a scalar array should be a string " - "containing an integer, but found 'invalid'." in str(info.value)) - - with pytest.raises(ValueError) as info: - array_arg.array_ndims = "0" - assert ("The number of dimensions of a scalar array should be an integer " - "greater than or equal to 1 but found 0." in str(info.value)) array_arg.array_ndims = "3" assert array_arg.array_ndims == "3" diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index d978da80fa..0098fa9452 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -258,17 +258,6 @@ def test_get_vector_length(): assert vector_length == "3" -def test_get_array_ndims(): - '''Test that the get_array_ndims method in the - CommonMetaArgMetadata class works as expected. - - ''' - fparser_tree = CheckArg.create_fparser2( - "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) - vector_length = CheckArg.get_array_ndims(fparser_tree) - assert vector_length == "3" - - def test_setter_getter(): '''Test that the setters and getters in the CommonMetaArgMetadata class work as expected. diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index bafd822201..cc296c5d5b 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -274,7 +274,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): assert array_descriptor.argument_type == "gh_scalar_array" assert array_descriptor.data_type == array_type assert array_descriptor.array_ndims == array_ndims - assert array_descriptor.function_spaces == [None] + assert array_descriptor.function_spaces == [] assert str(array_descriptor.access) == "READ" assert array_descriptor.mesh is None assert array_descriptor.stencil is None From fe877185470bdaccee1fc94bacdcdfaf184b4a98 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 16:58:01 +0000 Subject: [PATCH 069/119] Revert "#1312 fixing tests" This reverts commit 81d076c05fe4a772b2650804b7d1c66637a9270d. --- .../lfric/kernel/array_arg_metadata_test.py | 65 +++++++------------ .../kernel/common_meta_arg_metadata_test.py | 11 ++++ .../domain/lfric/lfric_array_mdata_test.py | 2 +- 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 0e5c6248bf..2d56609262 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -57,16 +57,16 @@ def test_create(datatype, access, array_ndims): assert array_arg.access == "gh_read" assert array_arg.array_ndims == "1" -# -#def test_init_invalid_an(): -# '''Test that an invalid array_size supplied to the constructor -# raises the expected exception. -# -# ''' -# with pytest.raises(TypeError) as info: -# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) -# assert ("The number of dimensions of a scalar array should be of type " -# "str, but found 'NoneType'." in str(info.value)) + +def test_init_invalid_an(): + '''Test that an invalid array_size supplied to the constructor + raises the expected exception. + + ''' + with pytest.raises(TypeError) as info: + _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) + assert ("The number of dimensions of a scalar array should be of type " + "str, but found 'NoneType'." in str(info.value)) @pytest.mark.parametrize("metadata", @@ -109,46 +109,25 @@ def test_check_access(): with pytest.raises(ValueError) as info: ScalarArrayArgMetadata.check_access("invalid") assert ("The 'access descriptor' metadata should be a recognised value " - "(one of ['gh_read', 'gh_sum']) but found 'invalid'." in str(info.value)) + "(one of ['gh_read']) but found 'invalid'." in str(info.value)) -#def test_get_array_ndims(): -# '''Test that the get_array_ndims method in the -# ScalarArrayArgMetadata class works as expected. -# -# ''' -# fparser2_tree = ScalarArrayArgMetadata.create_fparser2( -# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) -# -# #array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") -# -# with pytest.raises(TypeError) as info: -# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) -# assert ("The number of dimensions of a scalar array should be of type str, " -# "but found 'ineteger'." in str(info.value)) -# -# with pytest.raises(ValueError) as info: -# fparser2_tree = ScalarArrayArgMetadata.create_fparser2( -# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, invalid)", Fortran2003.Part_Ref) -# #ScalarArrayArgMetadata.get_array_ndims("GH_REAL", "GH_READ", "invalid") -# assert ("The number of dimensions of a scalar array should be a string " -# "containing an integer, but found 'invalid'." in str(info.value)) -# -# with pytest.raises(ValueError) as info: -# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "0") -# assert ("The number of dimensions of a scalar array should be an integer " -# "greater than or equal to 1 but found 0." in str(info.value)) -# vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) -# assert vector_length == "3" - - -def test_array_ndims_setter(): - '''Test that the array_ndims setter works as expected, +def test_array_ndims_setter_getter(): + '''Test that the array_ndims setter and getter work as expected, including raising an exception if the value is invalid. ''' array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") + with pytest.raises(ValueError) as info: + array_arg.array_ndims = "invalid" + assert ("The number of dimensions of a scalar array should be a string " + "containing an integer, but found 'invalid'." in str(info.value)) + + with pytest.raises(ValueError) as info: + array_arg.array_ndims = "0" + assert ("The number of dimensions of a scalar array should be an integer " + "greater than or equal to 1 but found 0." in str(info.value)) array_arg.array_ndims = "3" assert array_arg.array_ndims == "3" diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 0098fa9452..d978da80fa 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -258,6 +258,17 @@ def test_get_vector_length(): assert vector_length == "3" +def test_get_array_ndims(): + '''Test that the get_array_ndims method in the + CommonMetaArgMetadata class works as expected. + + ''' + fparser_tree = CheckArg.create_fparser2( + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) + vector_length = CheckArg.get_array_ndims(fparser_tree) + assert vector_length == "3" + + def test_setter_getter(): '''Test that the setters and getters in the CommonMetaArgMetadata class work as expected. diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index cc296c5d5b..bafd822201 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -274,7 +274,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): assert array_descriptor.argument_type == "gh_scalar_array" assert array_descriptor.data_type == array_type assert array_descriptor.array_ndims == array_ndims - assert array_descriptor.function_spaces == [] + assert array_descriptor.function_spaces == [None] assert str(array_descriptor.access) == "READ" assert array_descriptor.mesh is None assert array_descriptor.stencil is None From 359d4defdea568576ae6700758b7d55a70331e45 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 17:11:00 +0000 Subject: [PATCH 070/119] #1312 fixing tests (in 2/3 files) --- .../lfric/kernel/common_meta_arg_metadata_test.py | 11 ----------- .../tests/domain/lfric/lfric_array_mdata_test.py | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py index 08d052e4fb..edb07e069c 100644 --- a/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/common_meta_arg_metadata_test.py @@ -258,17 +258,6 @@ def test_get_vector_length(): assert vector_length == "3" -def test_get_array_ndims(): - '''Test that the get_array_ndims method in the - CommonMetaArgMetadata class works as expected. - - ''' - fparser_tree = CheckArg.create_fparser2( - "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) - vector_length = CheckArg.get_array_ndims(fparser_tree) - assert vector_length == "3" - - def test_setter_getter(): '''Test that the setters and getters in the CommonMetaArgMetadata class work as expected. diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index bafd822201..cc296c5d5b 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -274,7 +274,7 @@ def test_arg_descriptor_array(array_ind, array_type, array_ndims): assert array_descriptor.argument_type == "gh_scalar_array" assert array_descriptor.data_type == array_type assert array_descriptor.array_ndims == array_ndims - assert array_descriptor.function_spaces == [None] + assert array_descriptor.function_spaces == [] assert str(array_descriptor.access) == "READ" assert array_descriptor.mesh is None assert array_descriptor.stencil is None From 0652266e4d541383e6c868662fb060b50bbadacf Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 17:14:43 +0000 Subject: [PATCH 071/119] #1312 commenting out failing tests to see code coverage --- .../lfric/kernel/array_arg_metadata_test.py | 59 +++++++++++-------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 2d56609262..decd3bd5da 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -58,15 +58,15 @@ def test_create(datatype, access, array_ndims): assert array_arg.array_ndims == "1" -def test_init_invalid_an(): - '''Test that an invalid array_size supplied to the constructor - raises the expected exception. +# def test_init_invalid_an(): +# '''Test that an invalid array_size supplied to the constructor +# raises the expected exception. - ''' - with pytest.raises(TypeError) as info: - _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) - assert ("The number of dimensions of a scalar array should be of type " - "str, but found 'NoneType'." in str(info.value)) +# ''' +# with pytest.raises(TypeError) as info: +# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) +# assert ("The number of dimensions of a scalar array should be of type " +# "str, but found 'NoneType'." in str(info.value)) @pytest.mark.parametrize("metadata", @@ -109,25 +109,36 @@ def test_check_access(): with pytest.raises(ValueError) as info: ScalarArrayArgMetadata.check_access("invalid") assert ("The 'access descriptor' metadata should be a recognised value " - "(one of ['gh_read']) but found 'invalid'." in str(info.value)) + "(one of ['gh_read', 'gh_sum']) but found 'invalid'." in str(info.value)) -def test_array_ndims_setter_getter(): - '''Test that the array_ndims setter and getter work as expected, - including raising an exception if the value is invalid. +# def test_get_array_ndims(): +# '''Test that the get_array_ndims method in the +# ScalarArrayArgMetadata class works as expected. - ''' - array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") +# ''' +# fparser_tree = ScalarArrayArgMetadata.create_fparser2( +# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) +# vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) +# assert vector_length == "3" - with pytest.raises(ValueError) as info: - array_arg.array_ndims = "invalid" - assert ("The number of dimensions of a scalar array should be a string " - "containing an integer, but found 'invalid'." in str(info.value)) - with pytest.raises(ValueError) as info: - array_arg.array_ndims = "0" - assert ("The number of dimensions of a scalar array should be an integer " - "greater than or equal to 1 but found 0." in str(info.value)) +# def test_array_ndims_setter_getter(): +# '''Test that the array_ndims setter and getter work as expected, +# including raising an exception if the value is invalid. + +# ''' +# array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") + +# with pytest.raises(ValueError) as info: +# array_arg.array_ndims = "invalid" +# assert ("The number of dimensions of a scalar array should be a string " +# "containing an integer, but found 'invalid'." in str(info.value)) + +# with pytest.raises(ValueError) as info: +# array_arg.array_ndims = "0" +# assert ("The number of dimensions of a scalar array should be an integer " +# "greater than or equal to 1 but found 0." in str(info.value)) - array_arg.array_ndims = "3" - assert array_arg.array_ndims == "3" +# array_arg.array_ndims = "3" +# assert array_arg.array_ndims == "3" From 433b3854bdfc424afac48d8bbb8a2d22fd6960b1 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 17:22:01 +0000 Subject: [PATCH 072/119] #1312 pycodestyle fixes --- .../tests/domain/lfric/kernel/array_arg_metadata_test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index decd3bd5da..88c8e754d1 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -109,7 +109,8 @@ def test_check_access(): with pytest.raises(ValueError) as info: ScalarArrayArgMetadata.check_access("invalid") assert ("The 'access descriptor' metadata should be a recognised value " - "(one of ['gh_read', 'gh_sum']) but found 'invalid'." in str(info.value)) + "(one of ['gh_read', 'gh_sum']) but found 'invalid'." + in str(info.value)) # def test_get_array_ndims(): @@ -118,7 +119,7 @@ def test_check_access(): # ''' # fparser_tree = ScalarArrayArgMetadata.create_fparser2( -# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) +# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) # vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) # assert vector_length == "3" @@ -137,7 +138,7 @@ def test_check_access(): # with pytest.raises(ValueError) as info: # array_arg.array_ndims = "0" -# assert ("The number of dimensions of a scalar array should be an integer " +# assert ("The number of dimensions of a scalar array should be an integer" # "greater than or equal to 1 but found 0." in str(info.value)) # array_arg.array_ndims = "3" From ad0806441c0f6df5a7fddc2355e9ed8d77666988 Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 17:42:06 +0000 Subject: [PATCH 073/119] #1312 fixing final test file test_get_array_ndims --- .../lfric/kernel/array_arg_metadata_test.py | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 88c8e754d1..4fb140e191 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -113,15 +113,30 @@ def test_check_access(): in str(info.value)) -# def test_get_array_ndims(): -# '''Test that the get_array_ndims method in the -# ScalarArrayArgMetadata class works as expected. +def test_get_array_ndims(): + '''Test that the get_array_ndims method in the + ScalarArrayArgMetadata class works as expected. -# ''' -# fparser_tree = ScalarArrayArgMetadata.create_fparser2( -# "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) -# vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) -# assert vector_length == "3" + ''' + + fparser_tree = ScalarArrayArgMetadata.create_fparser2( + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, invalid)", Fortran2003.Part_Ref) + with pytest.raises(ValueError) as info: + _ = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) + assert ("The number of dimensions of a scalar array should be a string " + "containing an integer, but found 'invalid'." in str(info.value)) + + fparser_tree = ScalarArrayArgMetadata.create_fparser2( + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 0)", Fortran2003.Part_Ref) + with pytest.raises(ValueError) as info: + _ = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) + assert ("The number of dimensions of a scalar array should be an integer " + "greater than or equal to 1 but found 0." in str(info.value)) + + fparser_tree = ScalarArrayArgMetadata.create_fparser2( + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) + vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) + assert vector_length == "3" # def test_array_ndims_setter_getter(): @@ -131,15 +146,6 @@ def test_check_access(): # ''' # array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") -# with pytest.raises(ValueError) as info: -# array_arg.array_ndims = "invalid" -# assert ("The number of dimensions of a scalar array should be a string " -# "containing an integer, but found 'invalid'." in str(info.value)) - -# with pytest.raises(ValueError) as info: -# array_arg.array_ndims = "0" -# assert ("The number of dimensions of a scalar array should be an integer" -# "greater than or equal to 1 but found 0." in str(info.value)) # array_arg.array_ndims = "3" # assert array_arg.array_ndims == "3" From 6332d7edbac1be832672681fe35e14fab6e35b8c Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Wed, 26 Feb 2025 17:45:03 +0000 Subject: [PATCH 074/119] #1312 line length --- .../tests/domain/lfric/kernel/array_arg_metadata_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 4fb140e191..732a13b74b 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -120,7 +120,8 @@ def test_get_array_ndims(): ''' fparser_tree = ScalarArrayArgMetadata.create_fparser2( - "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, invalid)", Fortran2003.Part_Ref) + "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, invalid)", + Fortran2003.Part_Ref) with pytest.raises(ValueError) as info: _ = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) assert ("The number of dimensions of a scalar array should be a string " From e0899d515244eab6bd16717e30ce7608c1eeee1c Mon Sep 17 00:00:00 2001 From: Lottie Turner Date: Tue, 25 Mar 2025 16:55:29 +0000 Subject: [PATCH 075/119] #1312 removing an error and its test that can't be triggered --- .../domain/lfric/kernel/array_arg_metadata.py | 4 ---- .../domain/lfric/kernel/array_arg_metadata_test.py | 11 ----------- 2 files changed, 15 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index a02825b120..9cb4a7e5d7 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -135,10 +135,6 @@ def get_array_ndims(cls, fparser2_tree): array_datatype = CommonArgMetadata.get_arg( fparser2_tree, cls.array_ndims_arg_index) array_ndims = array_datatype.strip() - if not isinstance(array_ndims, str): - raise TypeError(f"The number of dimensions of a scalar array " - f"should be of type str, but found " - f"'{type(array_ndims).__name__}'.") try: int_value = int(array_ndims) except ValueError as info: diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py index 732a13b74b..4c83bb7d89 100644 --- a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py @@ -58,17 +58,6 @@ def test_create(datatype, access, array_ndims): assert array_arg.array_ndims == "1" -# def test_init_invalid_an(): -# '''Test that an invalid array_size supplied to the constructor -# raises the expected exception. - -# ''' -# with pytest.raises(TypeError) as info: -# _ = ScalarArrayArgMetadata("GH_REAL", "GH_READ", None) -# assert ("The number of dimensions of a scalar array should be of type " -# "str, but found 'NoneType'." in str(info.value)) - - @pytest.mark.parametrize("metadata", ["arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 2)"]) def test_get_metadata(metadata): From 732864873f051786a61c3614be95525b148a11e1 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Tue, 3 Jun 2025 15:31:08 +0100 Subject: [PATCH 076/119] #1312: fix table of datatypes --- doc/user_guide/lfric.rst | 74 ++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/doc/user_guide/lfric.rst b/doc/user_guide/lfric.rst index a13e543f68..0846e8ec45 100644 --- a/doc/user_guide/lfric.rst +++ b/doc/user_guide/lfric.rst @@ -438,43 +438,43 @@ associated kernel metadata description and their precision: .. tabularcolumns:: |l|l|l| -+--------------------------+------------------------------------+-----------+ -| Data Type | Kernel Metadata | Precision | -+==========================+====================================+===========+ -| REAL(R_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_DEF | -+--------------------------+------------------------------------+-----------+ -| REAL(R_BL) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_BL | -+--------------------------+------------------------------------+-----------+ -| REAL(R_PHYS) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_PHYS | -+--------------------------+------------------------------------+-----------+ -| REAL(R_SOLVER) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_SOLVER | -+--------------------------+------------------------------------+-----------+ -| REAL(R_TRAN) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_TRAN | -+--------------------------+------------------------------------+-----------+ -| INTEGER(I_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_INTEGER | I_DEF | -+--------------------------+------------------------------------+-----------+ -| LOGICAL(L_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_LOGICAL | L_DEF | -+--------------------------+------------------------------------+-----------+ -| FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | -+--------------------------+------------------------------------+-----------+ -| R_BL_FIELD_TYPE | GH_FIELD, GH_REAL | R_BL | -+--------------------------+------------------------------------+-----------+ -| R_PHYS_FIELD_TYPE | GH_FIELD, GH_REAL | R_PHYS | -+--------------------------+------------------------------------+-----------+ -| R_SOLVER_FIELD_TYPE | GH_FIELD, GH_REAL | R_SOLVER | -+--------------------------+------------------------------------+-----------+ -| R_TRAN_FIELD_TYPE | GH_FIELD, GH_REAL | R_TRAN | -+--------------------------+------------------------------------+-----------+ -| INTEGER_FIELD_TYPE | GH_FIELD, GH_INTEGER | I_DEF | -+--------------------------+------------------------------------+-----------+ -| OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_DEF | -+--------------------------+------------------------------------+-----------+ -| R_SOLVER_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_SOLVER | -+--------------------------+------------------------------------+-----------+ -| R_TRAN_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_TRAN | -+--------------------------+------------------------------------+-----------+ -| COLUMNWISE_OPERATOR_TYPE | GH_COLUMNWISE_OPERATOR, GH_REAL | R_SOLVER | -+--------------------------+------------------------------------+-----------+ ++--------------------------+---------------------------------------+-----------+ +| Data Type | Kernel Metadata | Precision | ++==========================+=======================================+===========+ +| REAL(R_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_DEF | ++--------------------------+---------------------------------------+-----------+ +| REAL(R_BL) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_BL | ++--------------------------+---------------------------------------+-----------+ +| REAL(R_PHYS) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_PHYS | ++--------------------------+---------------------------------------+-----------+ +| REAL(R_SOLVER) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_SOLVER | ++--------------------------+---------------------------------------+-----------+ +| REAL(R_TRAN) | GH_SCALAR/GH_SCALAR_ARRAY, GH_REAL | R_TRAN | ++--------------------------+---------------------------------------+-----------+ +| INTEGER(I_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_INTEGER | I_DEF | ++--------------------------+---------------------------------------+-----------+ +| LOGICAL(L_DEF) | GH_SCALAR/GH_SCALAR_ARRAY, GH_LOGICAL | L_DEF | ++--------------------------+---------------------------------------+-----------+ +| FIELD_TYPE | GH_FIELD, GH_REAL | R_DEF | ++--------------------------+---------------------------------------+-----------+ +| R_BL_FIELD_TYPE | GH_FIELD, GH_REAL | R_BL | ++--------------------------+---------------------------------------+-----------+ +| R_PHYS_FIELD_TYPE | GH_FIELD, GH_REAL | R_PHYS | ++--------------------------+---------------------------------------+-----------+ +| R_SOLVER_FIELD_TYPE | GH_FIELD, GH_REAL | R_SOLVER | ++--------------------------+---------------------------------------+-----------+ +| R_TRAN_FIELD_TYPE | GH_FIELD, GH_REAL | R_TRAN | ++--------------------------+---------------------------------------+-----------+ +| INTEGER_FIELD_TYPE | GH_FIELD, GH_INTEGER | I_DEF | ++--------------------------+---------------------------------------+-----------+ +| OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_DEF | ++--------------------------+---------------------------------------+-----------+ +| R_SOLVER_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_SOLVER | ++--------------------------+---------------------------------------+-----------+ +| R_TRAN_OPERATOR_TYPE | GH_OPERATOR, GH_REAL | R_TRAN | ++--------------------------+---------------------------------------+-----------+ +| COLUMNWISE_OPERATOR_TYPE | GH_COLUMNWISE_OPERATOR, GH_REAL | R_SOLVER | ++--------------------------+---------------------------------------+-----------+ As can be seen from the above table, the kernel metadata does not capture all of the precision options. For example, from the metadata From 0b740e1a533bee158d44b380bc28b38d4f32e0cf Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:30:27 +0100 Subject: [PATCH 077/119] #1312: Update LFRic array names to ScalarArray --- .../domain/lfric/kernel/array_arg_metadata.py | 12 ++--- .../domain/lfric/lfric_arg_descriptor.py | 54 +++++++++---------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index 9cb4a7e5d7..dd044f6693 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -34,8 +34,8 @@ # Author L. Turner, Met Office '''Module containing the ScalarArrayArgMetadata class which captures the -metadata associated with an array argument. Supports the creation, modification -and Fortran output of an Array argument. +metadata associated with a ScalarArray argument. Supports the creation, +modification and Fortran output of a ScalarArray argument. ''' from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata @@ -43,12 +43,12 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): - '''Class to capture LFRic kernel metadata information for an array + '''Class to capture LFRic kernel metadata information for a scalar array argument. - :param str datatype: the datatype of this array (GH_INTEGER, ...). - :param str access: the way the kernel accesses this array (GH_READ). - :param str array_ndims: the rank (number of dimensions) of this array + :param str datatype: the datatype of this scalar array (GH_INTEGER, ...). + :param str access: the way the kernel accesses this scalar array (GH_READ). + :param str array_ndims: the rank (number of dimensions) of this scalar array ''' # The name used to specify an array argument in LFRic metadata. diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 89f0fd6904..07faffd92d 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -203,7 +203,7 @@ def __init__(self, arg_type, operates_on, metadata_index): self._init_scalar(arg_type) elif self._argument_type in const.VALID_ARRAY_NAMES: - # Validate array arguments + # Validate ScalarArray arguments self._init_array(arg_type) else: @@ -277,40 +277,40 @@ def _validate_vector_size(self, separator, arg_type): def _validate_array_ndims(self, arg_type): ''' - Validates descriptors for scalar array arguments and populates + Validates descriptors for ScalarArray arguments and populates properties accordingly. :param str separator: operator in a binary expression. - :param arg_type: LFRic API array argument type. + :param arg_type: LFRic API ScalarArray argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises ParseError: if the array notation is not in the + :raises ParseError: if the ScalarArray notation is not in the correct format 'n' where 'n' is an integer. - :raises ParseError: if the specified number of array dimensions - is less than 1. - :raises ParseError: if the array notation is used for an - argument that is not an array. + :raises ParseError: if the specified number of ScalarArray + dimensions is less than 1. + :raises ParseError: if the ScalarArray notation is used for an + argument that is not a ScalarArray. ''' - # Try to find the array size for a scalar array and raise + # Try to find the array size for a ScalarArray and raise # an error if it is not an integer number... try: array_ndims = int(arg_type.args[3]) except ValueError as err: raise ParseError( - f"In the LFRic API, the array notation must be in " - f"the format 'n' where 'n' is an integer, " + f"In the LFRic API, the ScalarArray notation must be " + f"in the format 'n' where 'n' is an integer, " f"but '{arg_type.args[3]}' was found in " f"'{arg_type}'.") from err - # ... or it is less than 1 (1 is the default for all fields)... + # ... or it is less than 1... if array_ndims < 1: raise ParseError( - f"In the LFRic API, the array notation must be in " - f"the format 'n' where 'n' is an integer >= 1. " + f"In the LFRic API, the ScalarArray notation must be " + f"in the format 'n' where 'n' is an integer >= 1. " f"However, found n = '{array_ndims}' in '{arg_type}'.") - # ... and set the array size if all checks pass + # ... and set the ScalarArray size if all checks pass self._array_ndims = array_ndims def _init_field(self, arg_type, operates_on): @@ -649,24 +649,24 @@ def _init_scalar(self, arg_type): def _init_array(self, arg_type): ''' - Validates metadata descriptors for scalar array arguments and - initialises scalar array argument properties accordingly. + Validates metadata descriptors for ScalarArray arguments and + initialises ScalarArray argument properties accordingly. - :param arg_type: LFRic API scalar array argument type. + :param arg_type: LFRic API ScalarArray argument type. :type arg_type: :py:class:`psyclone.expression.FunctionVar` - :raises InternalError: if argument type other than an array is + :raises InternalError: if argument type other than a ScalarArray is passed in. :raises ParseError: if there are not exactly 4 metadata arguments. - :raises InternalError: if the array argument has an invalid data type. - :raises ParseError: if array arguments do not have read-only access. + :raises InternalError: if the ScalarArray argument has an invalid data type. + :raises ParseError: if ScalarArray argument has an invalid access type. ''' const = LFRicConstants() # Check whether something other than a scalar is passed in if self._argument_type not in const.VALID_ARRAY_NAMES: raise InternalError( - f"Expected an array argument but got an argument of type " + f"Expected a ScalarArray argument but got an argument of type " f"'{arg_type.args[0]}'.") # There must be 4 arguments @@ -678,14 +678,14 @@ def _init_array(self, arg_type): f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " f"'{arg_type}'.") - # Check whether an invalid data type for an array argument is passed + # Check whether an invalid data type for a ScalarArray argument is passed # in. if self._data_type not in const.VALID_ARRAY_DATA_TYPES: raise InternalError( f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " - f"array data type but got '{self._data_type}'.") + f"ScalarArray data type but got '{self._data_type}'.") - # Test allowed accesses for arrays (read_only) + # Test allowed accesses for ScalarArrays (read_only) array_accesses = [AccessType.READ] # Convert generic access types to GH_* names for error messages api_config = Config.get().api_conf(API) @@ -693,13 +693,13 @@ def _init_array(self, arg_type): if self._access_type not in array_accesses: api_specific_name = rev_access_mapping[self._access_type] raise ParseError( - f"In the LFRic API array arguments must have read-only " + f"In the LFRic API, ScalarArray arguments must have read-only " f"('gh_read') access but found '{api_specific_name}' " f"in '{arg_type}'.") self._validate_array_ndims(arg_type) - # Arrays don't have vector size + # ScalarArrays don't have vector size self._vector_size = 0 @property From de5ba1d9ce1c5956872d73cfcbaa9c00b1b466af Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:33:34 +0100 Subject: [PATCH 078/119] #1312: lint fix --- src/psyclone/domain/lfric/kernel/array_arg_metadata.py | 3 ++- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py index dd044f6693..588f32e9e7 100644 --- a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/array_arg_metadata.py @@ -48,7 +48,8 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): :param str datatype: the datatype of this scalar array (GH_INTEGER, ...). :param str access: the way the kernel accesses this scalar array (GH_READ). - :param str array_ndims: the rank (number of dimensions) of this scalar array + :param str array_ndims: the rank (number of dimensions) of this scalar + array. ''' # The name used to specify an array argument in LFRic metadata. diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 07faffd92d..6ee92a8d4f 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -658,7 +658,8 @@ def _init_array(self, arg_type): :raises InternalError: if argument type other than a ScalarArray is passed in. :raises ParseError: if there are not exactly 4 metadata arguments. - :raises InternalError: if the ScalarArray argument has an invalid data type. + :raises InternalError: if the ScalarArray argument has an invalid data + type. :raises ParseError: if ScalarArray argument has an invalid access type. ''' @@ -678,8 +679,8 @@ def _init_array(self, arg_type): f"{const.VALID_ARRAY_NAMES} type, but found {self._nargs} in " f"'{arg_type}'.") - # Check whether an invalid data type for a ScalarArray argument is passed - # in. + # Check whether an invalid data type for a ScalarArray argument is + # passed in. if self._data_type not in const.VALID_ARRAY_DATA_TYPES: raise InternalError( f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " From df5816b8761b5072ecd874abb72f7f404e5d1b5a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:58:48 +0100 Subject: [PATCH 079/119] #1312: Update LFRic array tests to be ScalarArray --- .../domain/lfric/lfric_array_mdata_test.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index cc296c5d5b..895e53f8e8 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -78,23 +78,23 @@ def test_ad_array_init_wrong_argument_type(): - ''' Test that an error is raised if something other than an array + ''' Test that an error is raised if something other than a ScalarArray is passed to the LFRicArgDescriptor._init_array() method. ''' ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) name = "testkern_array_type" metadata = LFRicKernMetadata(ast, name=name) - # Get an argument which is not an array + # Get an argument which is not a ScalarArray wrong_arg = metadata._inits[3] with pytest.raises(InternalError) as excinfo: LFRicArgDescriptor( wrong_arg, metadata.iterates_over, 0)._init_array(wrong_arg) - assert ("Expected an array argument but got an argument of type " + assert ("Expected a ScalarArray argument but got an argument of type " "'gh_operator'." in str(excinfo.value)) def test_ad_array_type_wrong_num_of_args(): - ''' Tests that an error is raised when the array argument descriptor - metadata for an array has fewer than 3 args. ''' + ''' Tests that an error is raised when the ScalarArray argument + descriptor metadata for a ScalarArray has fewer than 3 args. ''' fparser.logging.disable(fparser.logging.CRITICAL) code = ARRAY_CODE.replace( "arg_type(gh_scalar_array, gh_real, gh_read, 1)", @@ -156,7 +156,7 @@ def test_ad_array_init_wrong_data_type(monkeypatch): ast = fpapi.parse(ARRAY_CODE, ignore_comments=False) name = "testkern_array_type" metadata = LFRicKernMetadata(ast, name=name) - # Get an array argument descriptor and set a wrong data type + # Get a ScalarArray argument descriptor and set a wrong data type scalar_arg = metadata._inits[0] scalar_arg.args[1].name = "gh_double" const = LFRicConstants() @@ -168,7 +168,7 @@ def test_ad_array_init_wrong_data_type(monkeypatch): with pytest.raises(InternalError) as excinfo: LFRicArgDescriptor( scalar_arg, metadata.iterates_over, 0)._init_scalar(scalar_arg) - assert (f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the array " + assert (f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the ScalarArray " f"data type but got 'gh_double'." in str(excinfo.value)) @@ -183,7 +183,7 @@ def test_ad_array_type_no_write(): ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " + assert ("ScalarArray arguments must have read-only ('gh_read') " "access but found 'gh_write'" in str(excinfo.value)) @@ -198,7 +198,7 @@ def test_ad_array_type_no_inc(): ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " + assert ("ScalarArray arguments must have read-only ('gh_read') " "access but found 'gh_inc'" in str(excinfo.value)) @@ -213,7 +213,7 @@ def test_ad_array_type_no_readwrite(): ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " + assert ("ScalarArray arguments must have read-only ('gh_read') " "access but found 'gh_readwrite'" in str(excinfo.value)) @@ -228,7 +228,7 @@ def test_ad_array_type_no_sum(): name = "testkern_array_type" with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("array arguments must have read-only ('gh_read') " + assert ("ScalarArray arguments must have read-only ('gh_read') " "access but found 'gh_sum'" in str(excinfo.value)) @@ -251,7 +251,7 @@ def test_no_vector_array(): (0, "gh_real", 1), (1, "gh_integer", 2), (2, "gh_logical", 4)]) def test_arg_descriptor_array(array_ind, array_type, array_ndims): ''' Test that the LFRicArgDescriptor argument representation works - as expected for all three types of valid array argument: + as expected for all three types of valid ScalarArray argument: 'real', 'integer' and 'logical'. ''' From b8ac6c1adf37fe6ffd143edca069510f205c2a14 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 6 Jun 2025 11:32:01 +0100 Subject: [PATCH 080/119] #1312: Change array size to array rank --- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index 6ee92a8d4f..b4f130a663 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -819,11 +819,11 @@ def vector_size(self): @property def array_ndims(self): ''' - Returns the array size of the argument. This will be 1 if ``*n`` + Returns the array rank of the argument. This will be 1 if ``*n`` has not been specified for all argument types except scalars - (their array size is set to 0). + (their array rank is set to 0). - :returns: array size of the argument. + :returns: array rank of the argument. :rtype: int ''' From e00f0d112b9148468345ccb77e2ec6a8808f6601 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 6 Jun 2025 13:20:03 +0100 Subject: [PATCH 081/119] #1312: lint fix --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 895e53f8e8..7350e871e2 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -168,8 +168,9 @@ def test_ad_array_init_wrong_data_type(monkeypatch): with pytest.raises(InternalError) as excinfo: LFRicArgDescriptor( scalar_arg, metadata.iterates_over, 0)._init_scalar(scalar_arg) - assert (f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the ScalarArray " - f"data type but got 'gh_double'." in str(excinfo.value)) + assert (f"Expected one of {const.VALID_ARRAY_DATA_TYPES} as the " + f"ScalarArray data type but got " + f"'gh_double'." in str(excinfo.value)) def test_ad_array_type_no_write(): From 51a618d3ca3a8c7c741d61bf142b0588d63b6288 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 6 Jun 2025 16:11:23 +0100 Subject: [PATCH 082/119] #1312: Fix test --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 7350e871e2..4ef240504e 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -291,7 +291,7 @@ def test_n_not_integer(): ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("the array notation must be in the format 'n' " + assert ("the ScalarArray notation must be in the format 'n' " "where 'n' is an integer, but '0.5' was found in " "'arg_type(gh_scalar_array, gh_real, gh_read, 0.5)'." in str(excinfo.value)) @@ -307,7 +307,7 @@ def test_n_less_than_one(): ast = fpapi.parse(code, ignore_comments=False) with pytest.raises(ParseError) as excinfo: _ = LFRicKernMetadata(ast, name=name) - assert ("the array notation must be in the format 'n' " + assert ("the ScalarArray notation must be in the format 'n' " "where 'n' is an integer >= 1. However, found n = '0' in " "'arg_type(gh_scalar_array, gh_real, gh_read, 0)'." in str(excinfo.value)) From 398a867469fa806de05c0fc869f7a56d0dc9237a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 9 Jun 2025 09:45:05 +0100 Subject: [PATCH 083/119] #1312: Rename to scalar_array_arg_metadata --- src/psyclone/domain/lfric/kernel/__init__.py | 2 +- .../{array_arg_metadata.py => scalar_array_arg_metadata.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/psyclone/domain/lfric/kernel/{array_arg_metadata.py => scalar_array_arg_metadata.py} (100%) diff --git a/src/psyclone/domain/lfric/kernel/__init__.py b/src/psyclone/domain/lfric/kernel/__init__.py index 6209a080ea..96ee528665 100644 --- a/src/psyclone/domain/lfric/kernel/__init__.py +++ b/src/psyclone/domain/lfric/kernel/__init__.py @@ -37,7 +37,7 @@ '''Module for Kernels in the LFRic domain.''' -from psyclone.domain.lfric.kernel.array_arg_metadata import \ +from psyclone.domain.lfric.kernel.scalar_array_arg_metadata import \ ScalarArrayArgMetadata from psyclone.domain.lfric.kernel.columnwise_operator_arg_metadata import \ ColumnwiseOperatorArgMetadata diff --git a/src/psyclone/domain/lfric/kernel/array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py similarity index 100% rename from src/psyclone/domain/lfric/kernel/array_arg_metadata.py rename to src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py From 2cbd2d015f2c194b607dd7a8d311561187bf0787 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:20:16 +0100 Subject: [PATCH 084/119] #1312: Rename scalar array test --- ...ray_arg_metadata_test.py => scalar_array_arg_metadata_test.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/psyclone/tests/domain/lfric/kernel/{array_arg_metadata_test.py => scalar_array_arg_metadata_test.py} (100%) diff --git a/src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py similarity index 100% rename from src/psyclone/tests/domain/lfric/kernel/array_arg_metadata_test.py rename to src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py From 37ff3bfbdd539bafe847ef02e2f1383c06ebbbf4 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:59:14 +0100 Subject: [PATCH 085/119] #1312: test the scalar array setter --- .../lfric/kernel/scalar_array_arg_metadata.py | 20 ++++++++++++ .../kernel/scalar_array_arg_metadata_test.py | 31 ++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 588f32e9e7..e1fe175cfe 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -114,7 +114,27 @@ def array_ndims(self, value): ''' :param str value: set the number of dimensions to the specified value. + :raises TypeError: if value is not a string. + :raises ValueError: if value is not an integer. + :raises ValueError: if value is less than 1. + ''' + if not value.isinstance(str): + raise TypeError(f"The type of value must be a string, but " + f"found input of type {type(value)}.") + + try: + int_value = int(value) + except ValueError as info: + raise ValueError(f"The number of dimensions of a scalar array " + f"should be a string containing an integer, " + f"but found '{value}'.") from info + + if int_value < 1: + raise ValueError(f"The number of dimensions of a scalar array " + f"should be an integer greater than or " + f"equal to 1 but found '{value}'.") + self._array_ndims = value @classmethod diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index 4c83bb7d89..a0a912ff04 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -129,13 +129,30 @@ def test_get_array_ndims(): assert vector_length == "3" -# def test_array_ndims_setter_getter(): -# '''Test that the array_ndims setter and getter work as expected, -# including raising an exception if the value is invalid. +def test_array_ndims_setter_getter(): + '''Test that the array_ndims setter and getter work as expected, + including raising an exception if the value is invalid. -# ''' -# array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") + ''' + array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") + with pytest.raises(TypeError) as info: + test_value = int(2) + array_arg.array_ndims(test_value) + assert ("The type of value must be a string, but found input of type " + "int." in str(info.value)) + + with pytest.raises(ValueError) as info: + test_value = "1.5" + array_arg.array_ndims(test_value) + assert ("The number of dimensions of a scalar array should be a string " + "containing an integer, but found '"1.5"'." in str(info.value)) + with pytest.raises(ValueError) as info: + test_value = "-1" + array_arg.array_ndims(test_value) + assert ("The number of dimensions of a scalar array should be an " + "integer greater than or equal to 1 but found '"-1"'." + in str(info.value)) -# array_arg.array_ndims = "3" -# assert array_arg.array_ndims == "3" + # array_arg.array_ndims = "3" + # assert array_arg.array_ndims == "3" From fdeb70fcfae9b5958565d346b4034070c2e9b6f5 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:02:52 +0100 Subject: [PATCH 086/119] #1312: fix syntax --- .../domain/lfric/kernel/scalar_array_arg_metadata_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index a0a912ff04..af3f1002a3 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -145,13 +145,13 @@ def test_array_ndims_setter_getter(): test_value = "1.5" array_arg.array_ndims(test_value) assert ("The number of dimensions of a scalar array should be a string " - "containing an integer, but found '"1.5"'." in str(info.value)) + "containing an integer, but found '1.5'." in str(info.value)) with pytest.raises(ValueError) as info: test_value = "-1" array_arg.array_ndims(test_value) assert ("The number of dimensions of a scalar array should be an " - "integer greater than or equal to 1 but found '"-1"'." + "integer greater than or equal to 1 but found '-1'." in str(info.value)) # array_arg.array_ndims = "3" From 79892834c90eeae30198034869d18bf8e50139a4 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:38:00 +0100 Subject: [PATCH 087/119] #1312: fix type comparison --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index e1fe175cfe..1998a557b2 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -119,7 +119,7 @@ def array_ndims(self, value): :raises ValueError: if value is less than 1. ''' - if not value.isinstance(str): + if not isinstance(value,str): raise TypeError(f"The type of value must be a string, but " f"found input of type {type(value)}.") From 2d4e0d3d5e5ceaf6807bf6fa710711c4e1d4125e Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:42:20 +0100 Subject: [PATCH 088/119] #1312: lint fix --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 1998a557b2..ef263cee5f 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -119,7 +119,7 @@ def array_ndims(self, value): :raises ValueError: if value is less than 1. ''' - if not isinstance(value,str): + if not isinstance(value, str): raise TypeError(f"The type of value must be a string, but " f"found input of type {type(value)}.") From 17ef14e33742b4b05250d5d499da034a076bc5f2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 13:02:33 +0100 Subject: [PATCH 089/119] #1312: Fix test --- .../tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index af3f1002a3..fce56a8e8e 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -139,7 +139,7 @@ def test_array_ndims_setter_getter(): test_value = int(2) array_arg.array_ndims(test_value) assert ("The type of value must be a string, but found input of type " - "int." in str(info.value)) + "int." in info.value) with pytest.raises(ValueError) as info: test_value = "1.5" From 2e7b7ca8eafdffd0c95127a2afd207fe179b3d98 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:22:23 +0100 Subject: [PATCH 090/119] #1312: fix test --- .../tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index fce56a8e8e..f13f73f3a3 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -139,7 +139,7 @@ def test_array_ndims_setter_getter(): test_value = int(2) array_arg.array_ndims(test_value) assert ("The type of value must be a string, but found input of type " - "int." in info.value) + "'int'." in str(info.value)) with pytest.raises(ValueError) as info: test_value = "1.5" From d0fa6159321b56668903c8348efc37cca3aabf79 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:54:54 +0100 Subject: [PATCH 091/119] #1312: Add print statements to diagnose --- .../domain/lfric/kernel/scalar_array_arg_metadata_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index f13f73f3a3..30e2567367 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -138,8 +138,11 @@ def test_array_ndims_setter_getter(): with pytest.raises(TypeError) as info: test_value = int(2) array_arg.array_ndims(test_value) + print(info) + print(info.value) + print(str(info.value)) assert ("The type of value must be a string, but found input of type " - "'int'." in str(info.value)) + "'int'." in info.value) with pytest.raises(ValueError) as info: test_value = "1.5" From b652b7471f3a722e7ef2e4a13440dbfb6f650ef6 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:32:20 +0100 Subject: [PATCH 092/119] #1312: temporarily remove test --- .../kernel/scalar_array_arg_metadata_test.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index 30e2567367..d7720062c5 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -135,14 +135,14 @@ def test_array_ndims_setter_getter(): ''' array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") - with pytest.raises(TypeError) as info: - test_value = int(2) - array_arg.array_ndims(test_value) - print(info) - print(info.value) - print(str(info.value)) - assert ("The type of value must be a string, but found input of type " - "'int'." in info.value) + # with pytest.raises(TypeError) as info: + # test_value = int(2) + # array_arg.array_ndims(test_value) + # print(info) + # print(info.value) + # print(str(info.value)) + # assert ("The type of value must be a string, but found input of type " + # "'int'." in info.value) with pytest.raises(ValueError) as info: test_value = "1.5" From a976ad8faf152380c260dc45bb51b34d8702cd08 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:23:45 +0100 Subject: [PATCH 093/119] #1312: test fix for scalar array tests --- .../domain/lfric/kernel/scalar_array_arg_metadata_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index d7720062c5..d2b61ed855 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -64,11 +64,11 @@ def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ScalarArrayArgMetadata.create_fparser2( metadata, Fortran2003.Part_Ref) - datatype, access, array_ndims = ScalarArrayArgMetadata._get_metadata( + datatype, access, array_ndims_val = ScalarArrayArgMetadata._get_metadata( fparser2_tree) assert datatype == "GH_REAL" assert access == "GH_READ" - assert array_ndims == "2" + assert array_ndims_val == "2" @pytest.mark.parametrize("fortran_string", [ From 249229b70d1963c8ae6323e8da0398a5635363e5 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:54:16 +0100 Subject: [PATCH 094/119] #1312: revert changes --- .../kernel/scalar_array_arg_metadata_test.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index d2b61ed855..58910bf85c 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -64,11 +64,11 @@ def test_get_metadata(metadata): '''Test that the _get_metadata class method works as expected ''' fparser2_tree = ScalarArrayArgMetadata.create_fparser2( metadata, Fortran2003.Part_Ref) - datatype, access, array_ndims_val = ScalarArrayArgMetadata._get_metadata( + datatype, access, array_ndims = ScalarArrayArgMetadata._get_metadata( fparser2_tree) assert datatype == "GH_REAL" assert access == "GH_READ" - assert array_ndims_val == "2" + assert array_ndims == "2" @pytest.mark.parametrize("fortran_string", [ @@ -134,15 +134,16 @@ def test_array_ndims_setter_getter(): including raising an exception if the value is invalid. ''' - array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "2") - # with pytest.raises(TypeError) as info: - # test_value = int(2) - # array_arg.array_ndims(test_value) - # print(info) - # print(info.value) - # print(str(info.value)) - # assert ("The type of value must be a string, but found input of type " - # "'int'." in info.value) + array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "1") + array_arg.array_ndims(test_value) + with pytest.raises(TypeError) as info: + test_value = int(2) + array_arg.array_ndims(test_value) + print(info) + print(info.value) + print(str(info.value)) + assert ("The type of value must be a string, but found input of type " + "'int'." in info.value) with pytest.raises(ValueError) as info: test_value = "1.5" From 2cbdd8617146390498aa2711bee8be51d88577ef Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:59:53 +0100 Subject: [PATCH 095/119] #1312: fix test --- .../tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index 58910bf85c..6820be39a4 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -135,9 +135,9 @@ def test_array_ndims_setter_getter(): ''' array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "1") + test_value = int(2) array_arg.array_ndims(test_value) with pytest.raises(TypeError) as info: - test_value = int(2) array_arg.array_ndims(test_value) print(info) print(info.value) From c8991cd9a97deb47a8f3709a433764819e6e90b4 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 13 Jun 2025 15:17:43 +0100 Subject: [PATCH 096/119] #1312: fix setter in scalar array tests --- .../lfric/kernel/scalar_array_arg_metadata_test.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index 6820be39a4..fbc908dccd 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -135,25 +135,21 @@ def test_array_ndims_setter_getter(): ''' array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "1") - test_value = int(2) - array_arg.array_ndims(test_value) with pytest.raises(TypeError) as info: - array_arg.array_ndims(test_value) - print(info) - print(info.value) - print(str(info.value)) + test_value = int(2) + array_arg.array_ndims = test_value assert ("The type of value must be a string, but found input of type " "'int'." in info.value) with pytest.raises(ValueError) as info: test_value = "1.5" - array_arg.array_ndims(test_value) + array_arg.array_ndims = test_value assert ("The number of dimensions of a scalar array should be a string " "containing an integer, but found '1.5'." in str(info.value)) with pytest.raises(ValueError) as info: test_value = "-1" - array_arg.array_ndims(test_value) + array_arg.array_ndims = test_value assert ("The number of dimensions of a scalar array should be an " "integer greater than or equal to 1 but found '-1'." in str(info.value)) From af2b0fa614a0f4bd9bfb61cee9e3cbe8d6d69d35 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 13 Jun 2025 15:36:54 +0100 Subject: [PATCH 097/119] #1312: convert error into string --- .../tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index fbc908dccd..d118cdef01 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -139,7 +139,7 @@ def test_array_ndims_setter_getter(): test_value = int(2) array_arg.array_ndims = test_value assert ("The type of value must be a string, but found input of type " - "'int'." in info.value) + "'int'." in str(info.value)) with pytest.raises(ValueError) as info: test_value = "1.5" From 03cbd749a7d388c7788c3104741fc7e869a2db91 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 13 Jun 2025 15:57:46 +0100 Subject: [PATCH 098/119] #1312: change class name in test --- .../tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index d118cdef01..24ebfafb2f 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -139,7 +139,7 @@ def test_array_ndims_setter_getter(): test_value = int(2) array_arg.array_ndims = test_value assert ("The type of value must be a string, but found input of type " - "'int'." in str(info.value)) + "." in str(info.value)) with pytest.raises(ValueError) as info: test_value = "1.5" From e0335227f04317ffdba04f77acd830f868998421 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:55:32 +0100 Subject: [PATCH 099/119] #1312: update text to ScalarArray --- .../lfric/kernel/scalar_array_arg_metadata.py | 26 +++++++++---------- .../kernel/scalar_array_arg_metadata_test.py | 11 +++----- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index ef263cee5f..cf15cdcdde 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -43,18 +43,17 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): - '''Class to capture LFRic kernel metadata information for a scalar array + '''Class to capture LFRic kernel metadata information for a ScalarArray argument. - :param str datatype: the datatype of this scalar array (GH_INTEGER, ...). - :param str access: the way the kernel accesses this scalar array (GH_READ). - :param str array_ndims: the rank (number of dimensions) of this scalar - array. + :param str datatype: the datatype of this ScalarArray (GH_INTEGER, ...). + :param str access: the way the kernel accesses this Scalar Array (GH_READ). + :param str array_ndims: the rank (number of dimensions) of this ScalaArrray. ''' - # The name used to specify an array argument in LFRic metadata. + # The name used to specify a ScalarArray argument in LFRic metadata. form = "gh_scalar_array" - # The relative positions of LFRic metadata. Metadata for an array + # The relative positions of LFRic metadata. Metadata for a ScalarAarray # argument is provided in the following format 'arg_type(form, # datatype, access, function_space)'. Therefore, for example, the # index of the form argument (form_arg_index) is 0. @@ -104,7 +103,7 @@ def fortran_string(self): @property def array_ndims(self): ''' - :returns: the number of dimensions for this scalar array argument. + :returns: the number of dimensions for this ScalarArray argument. :rtype: str ''' return self._array_ndims @@ -114,7 +113,7 @@ def array_ndims(self, value): ''' :param str value: set the number of dimensions to the specified value. - :raises TypeError: if value is not a string. + :raises TypeError: if value is not a string type. :raises ValueError: if value is not an integer. :raises ValueError: if value is less than 1. @@ -126,12 +125,12 @@ def array_ndims(self, value): try: int_value = int(value) except ValueError as info: - raise ValueError(f"The number of dimensions of a scalar array " + raise ValueError(f"The number of dimensions of a ScalarArray " f"should be a string containing an integer, " f"but found '{value}'.") from info if int_value < 1: - raise ValueError(f"The number of dimensions of a scalar array " + raise ValueError(f"The number of dimensions of a ScalarArray " f"should be an integer greater than or " f"equal to 1 but found '{value}'.") @@ -148,7 +147,6 @@ def get_array_ndims(cls, fparser2_tree): :returns: the array ndims value extracted from the fparser2 tree. :rtype: str - :raises TypeError: if the array ndims is not a string. :raises ValueError: if the array ndims is not an integer. :raises ValueError: if the array ndims is less than 1. @@ -159,12 +157,12 @@ def get_array_ndims(cls, fparser2_tree): try: int_value = int(array_ndims) except ValueError as info: - raise ValueError(f"The number of dimensions of a scalar array " + raise ValueError(f"The number of dimensions of a ScalarArray " f"should be a string containing an integer, " f"but found '{array_ndims}'.") from info if int_value < 1: - raise ValueError(f"The number of dimensions of a scalar array " + raise ValueError(f"The number of dimensions of a ScalarArray " f"should be an integer greater than or " f"equal to 1 but found {array_ndims}.") return array_ndims diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index 24ebfafb2f..66cf30835c 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -113,14 +113,14 @@ def test_get_array_ndims(): Fortran2003.Part_Ref) with pytest.raises(ValueError) as info: _ = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) - assert ("The number of dimensions of a scalar array should be a string " + assert ("The number of dimensions of a ScalarArray should be a string " "containing an integer, but found 'invalid'." in str(info.value)) fparser_tree = ScalarArrayArgMetadata.create_fparser2( "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 0)", Fortran2003.Part_Ref) with pytest.raises(ValueError) as info: _ = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) - assert ("The number of dimensions of a scalar array should be an integer " + assert ("The number of dimensions of a ScalarArray should be an integer " "greater than or equal to 1 but found 0." in str(info.value)) fparser_tree = ScalarArrayArgMetadata.create_fparser2( @@ -144,15 +144,12 @@ def test_array_ndims_setter_getter(): with pytest.raises(ValueError) as info: test_value = "1.5" array_arg.array_ndims = test_value - assert ("The number of dimensions of a scalar array should be a string " + assert ("The number of dimensions of a ScalarArray should be a string " "containing an integer, but found '1.5'." in str(info.value)) with pytest.raises(ValueError) as info: test_value = "-1" array_arg.array_ndims = test_value - assert ("The number of dimensions of a scalar array should be an " + assert ("The number of dimensions of a ScalarArray should be an " "integer greater than or equal to 1 but found '-1'." in str(info.value)) - - # array_arg.array_ndims = "3" - # assert array_arg.array_ndims == "3" From 1f64126639e0f85114c8865a145c58ec55dff850 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:58:33 +0100 Subject: [PATCH 100/119] #1312: fix ScalarArray test bug --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index cf15cdcdde..99fcd7d249 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -132,7 +132,7 @@ def array_ndims(self, value): if int_value < 1: raise ValueError(f"The number of dimensions of a ScalarArray " f"should be an integer greater than or " - f"equal to 1 but found '{value}'.") + f"equal to 1 but found '{int_value}'.") self._array_ndims = value From 3ecb824279f5a2fa3146ee2cd239b7e9b58937f2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 16 Jun 2025 15:09:42 +0100 Subject: [PATCH 101/119] #1312: fix ScalarArray error handling --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 99fcd7d249..cf15cdcdde 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -132,7 +132,7 @@ def array_ndims(self, value): if int_value < 1: raise ValueError(f"The number of dimensions of a ScalarArray " f"should be an integer greater than or " - f"equal to 1 but found '{int_value}'.") + f"equal to 1 but found '{value}'.") self._array_ndims = value From 8b2127bbaeebe4e9d433abd805bd7a66c1930299 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 16 Jun 2025 15:14:10 +0100 Subject: [PATCH 102/119] #1312: lint fix --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index cf15cdcdde..37531f6004 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -48,7 +48,8 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): :param str datatype: the datatype of this ScalarArray (GH_INTEGER, ...). :param str access: the way the kernel accesses this Scalar Array (GH_READ). - :param str array_ndims: the rank (number of dimensions) of this ScalaArrray. + :param str array_ndims: the rank (number of dimensions) of this + ScalaArrray. ''' # The name used to specify a ScalarArray argument in LFRic metadata. From 8dbc1831699317f93074d701860128a680957101 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 09:10:39 +0100 Subject: [PATCH 103/119] #1312: fix typo --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 37531f6004..9799ab5eeb 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -49,7 +49,7 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): :param str datatype: the datatype of this ScalarArray (GH_INTEGER, ...). :param str access: the way the kernel accesses this Scalar Array (GH_READ). :param str array_ndims: the rank (number of dimensions) of this - ScalaArrray. + ScalaArray. ''' # The name used to specify a ScalarArray argument in LFRic metadata. From ceca33ca514189a3064e0dc80335725709c969b3 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:48:19 +0100 Subject: [PATCH 104/119] #1312: add typehinting --- .../domain/lfric/kernel/scalar_array_arg_metadata.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 9799ab5eeb..275f7dc9fe 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -40,6 +40,7 @@ ''' from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata +from typing import Tuple, Union class ScalarArrayArgMetadata(ScalarArgMetadata): @@ -73,7 +74,8 @@ def __init__(self, datatype, access, array_ndims): self.array_ndims = array_ndims @classmethod - def _get_metadata(cls, fparser2_tree): + def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, Fortran2003.Structure_Constructor]) -> Tuple[str, str, str]: + '''Extract the required metadata from the fparser2 tree and return it as strings. Also check that the metadata is in the expected form (but do not check the metadata values as that is done @@ -81,12 +83,9 @@ def _get_metadata(cls, fparser2_tree): :param fparser2_tree: fparser2 tree containing the metadata for this argument. - :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | - :py:class:`fparser.two.Fortran2003.Structure_Constructor` :returns: a tuple containing the datatype, access and array ndims metadata. - :rtype: Tuple[str, str, str] ''' datatype, access = super()._get_metadata(fparser2_tree) @@ -102,10 +101,9 @@ def fortran_string(self): f"{self.array_ndims})") @property - def array_ndims(self): + def array_ndims(self) -> str: ''' :returns: the number of dimensions for this ScalarArray argument. - :rtype: str ''' return self._array_ndims From 2f55dc497aedb02d91351bef9d45b750a90e39d7 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:43:15 +0100 Subject: [PATCH 105/119] #1312: Import Fparser and fix lint --- .../domain/lfric/kernel/scalar_array_arg_metadata.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 275f7dc9fe..e766ae7071 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -38,9 +38,10 @@ modification and Fortran output of a ScalarArray argument. ''' +from typing import Tuple, Union +from fparser.two import Fortran2003 from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata -from typing import Tuple, Union class ScalarArrayArgMetadata(ScalarArgMetadata): @@ -74,7 +75,9 @@ def __init__(self, datatype, access, array_ndims): self.array_ndims = array_ndims @classmethod - def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, Fortran2003.Structure_Constructor]) -> Tuple[str, str, str]: + def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, + Fortran2003.Structure_Constructor] + ) -> Tuple[str, str, str]: '''Extract the required metadata from the fparser2 tree and return it as strings. Also check that the metadata is in the expected From f6bc943f051bf81004bffb37dac6d6bb59b690eb Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:12:12 +0100 Subject: [PATCH 106/119] #1312: Remove typing module dependence --- .../domain/lfric/kernel/scalar_array_arg_metadata.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index e766ae7071..a39c0fb823 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -38,7 +38,6 @@ modification and Fortran output of a ScalarArray argument. ''' -from typing import Tuple, Union from fparser.two import Fortran2003 from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata @@ -75,9 +74,9 @@ def __init__(self, datatype, access, array_ndims): self.array_ndims = array_ndims @classmethod - def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, - Fortran2003.Structure_Constructor] - ) -> Tuple[str, str, str]: + def _get_metadata(cls, fparser2_tree: Fortran2003.Part_Ref | + Fortran2003.Structure_Constructor + ) -> tuple[str, str, str]: '''Extract the required metadata from the fparser2 tree and return it as strings. Also check that the metadata is in the expected From 59e7d02340c122d2cc66e6276e5ef63302abe710 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:25:47 +0100 Subject: [PATCH 107/119] #1312: Reintroduce typing for union --- .../domain/lfric/kernel/scalar_array_arg_metadata.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index a39c0fb823..9246ce9a87 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -38,6 +38,7 @@ modification and Fortran output of a ScalarArray argument. ''' +from typing import Union from fparser.two import Fortran2003 from psyclone.domain.lfric.kernel.common_arg_metadata import CommonArgMetadata from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata @@ -74,8 +75,8 @@ def __init__(self, datatype, access, array_ndims): self.array_ndims = array_ndims @classmethod - def _get_metadata(cls, fparser2_tree: Fortran2003.Part_Ref | - Fortran2003.Structure_Constructor + def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, + Fortran2003.Structure_Constructor] ) -> tuple[str, str, str]: '''Extract the required metadata from the fparser2 tree and return it From 98dfa5949a9eae14a40a4ef95aa3070bb46f107c Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:45:04 +0100 Subject: [PATCH 108/119] #1312: change raises text --- src/psyclone/domain/lfric/lfric_arg_descriptor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/lfric_arg_descriptor.py b/src/psyclone/domain/lfric/lfric_arg_descriptor.py index b4f130a663..98ce90d48e 100644 --- a/src/psyclone/domain/lfric/lfric_arg_descriptor.py +++ b/src/psyclone/domain/lfric/lfric_arg_descriptor.py @@ -660,7 +660,8 @@ def _init_array(self, arg_type): :raises ParseError: if there are not exactly 4 metadata arguments. :raises InternalError: if the ScalarArray argument has an invalid data type. - :raises ParseError: if ScalarArray argument has an invalid access type. + :raises ParseError: if ScalarArray argument does not have read-only + access. ''' const = LFRicConstants() From df2ca5a425d5e5f25616812d21ce2645eabf26e4 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:48:03 +0100 Subject: [PATCH 109/119] #1312: revert common_meta_arg_metadata --- src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py index 4b87757e23..2e87ec2d57 100644 --- a/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/common_meta_arg_metadata.py @@ -32,7 +32,6 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab -# Modifier L. Turner, Met Office '''Module containing the abstract CommonMetaArgMetadata class which captures the metadata associated with an LFRic meta_arg @@ -187,7 +186,7 @@ def get_vector_length(cls, fparser2_tree): :returns: the vector length value extracted from the fparser2 tree. :rtype: str - :raises TypeError: if the vector length metadata is not in the + :raises TypeError: if the vector length metadata is not in the \ expected form. ''' From 1a140a946e50f4530cc3b99c9500ede9deb13831 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 18 Jul 2025 09:31:08 +0100 Subject: [PATCH 110/119] #1312: update api to LFRic --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 4ef240504e..3b52d1109e 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -51,8 +51,8 @@ BASE_PATH = os.path.join( os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))), - "test_files", "dynamo0p3") -TEST_API = "dynamo0.3" + "test_files", "lfric") +TEST_API = "lfric" ARRAY_CODE = ''' From a7c76ce9a36a87d81d91d3384e71b89f6d1bce88 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:22:09 +0100 Subject: [PATCH 111/119] #1312: correct the number of ScalarArray arguments needed to 4 --- src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py index 3b52d1109e..32fbd60182 100644 --- a/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py +++ b/src/psyclone/tests/domain/lfric/lfric_array_mdata_test.py @@ -94,7 +94,7 @@ def test_ad_array_init_wrong_argument_type(): def test_ad_array_type_wrong_num_of_args(): ''' Tests that an error is raised when the ScalarArray argument - descriptor metadata for a ScalarArray has fewer than 3 args. ''' + descriptor metadata for a ScalarArray has fewer than 4 args. ''' fparser.logging.disable(fparser.logging.CRITICAL) code = ARRAY_CODE.replace( "arg_type(gh_scalar_array, gh_real, gh_read, 1)", From d4f4ff2a42fa5ea1e29451fcd1dd2ae6b054d732 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:50:17 +0100 Subject: [PATCH 112/119] #1312: fix ScalarArray metadata comment --- src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 9246ce9a87..22856f77e3 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -56,9 +56,9 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): ''' # The name used to specify a ScalarArray argument in LFRic metadata. form = "gh_scalar_array" - # The relative positions of LFRic metadata. Metadata for a ScalarAarray + # The relative positions of LFRic metadata. Metadata for a ScalarArray # argument is provided in the following format 'arg_type(form, - # datatype, access, function_space)'. Therefore, for example, the + # datatype, access, array_ndims)'. Therefore, for example, the # index of the form argument (form_arg_index) is 0. form_arg_index = 0 datatype_arg_index = 1 From c614ade2bfb9906255f93eb776542923be492989 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:54:47 +0100 Subject: [PATCH 113/119] #1312: update user guide for scalar arrays --- doc/user_guide/lfric.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/user_guide/lfric.rst b/doc/user_guide/lfric.rst index 0846e8ec45..47dde6f6c4 100644 --- a/doc/user_guide/lfric.rst +++ b/doc/user_guide/lfric.rst @@ -2007,7 +2007,7 @@ conventions, are: is an ``integer`` of kind ``i_def`` and has intent ``in``. PSyclone will obtain the value of ``nlayers`` to use for a particular kernel from the first field or operator in the argument list. -3) For each scalar/field/vector_field/operator in the order specified by +3) For each scalar/field/vector_field/operator/ScalarArray in the order specified by the meta_args metadata: 1) If the current entry is a scalar quantity then include the Fortran @@ -2047,7 +2047,7 @@ conventions, are: 3) If the current entry is a field vector then for each dimension of the vector, include a field array. The field array name is - specified as being using + specified as ``"field_""_""_v"``. A field array in a field vector is declared in the same way as a field array (described in the previous step). @@ -2062,6 +2062,10 @@ conventions, are: freedom for the ``to`` and ``from`` function spaces, respectively. Again the intent is determined from the metadata (see :ref:`lfric-api-meta-args`). + 5) If the current entry is a :ref:`scalar array ` + then include the Fortran variable in the argument list. The + ScalarArray must be denoted with intent ``in`` to match its + read-only nature. 4) For each function space in the order they appear in the metadata arguments (the ``to`` function space of an operator is considered to be before the From 9992239607941d6fed5f7393a5413d890a053564 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:22:51 +0100 Subject: [PATCH 114/119] #1312: fix lfric doc to allow it to build --- doc/user_guide/lfric.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/user_guide/lfric.rst b/doc/user_guide/lfric.rst index 47dde6f6c4..4099092ec4 100644 --- a/doc/user_guide/lfric.rst +++ b/doc/user_guide/lfric.rst @@ -2062,10 +2062,9 @@ conventions, are: freedom for the ``to`` and ``from`` function spaces, respectively. Again the intent is determined from the metadata (see :ref:`lfric-api-meta-args`). - 5) If the current entry is a :ref:`scalar array ` - then include the Fortran variable in the argument list. The - ScalarArray must be denoted with intent ``in`` to match its - read-only nature. + 5) If the current entry is a ScalarArray then include the Fortran + variable in the argument list. The ScalarArray must be denoted + with intent ``in`` to match its read-only nature. 4) For each function space in the order they appear in the metadata arguments (the ``to`` function space of an operator is considered to be before the From 2ac7ccbd5698940b0fa390f7794c3975ea927148 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:10:24 +0100 Subject: [PATCH 115/119] #1312: fix indentation on numbered list --- doc/user_guide/lfric.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_guide/lfric.rst b/doc/user_guide/lfric.rst index 4099092ec4..227c268791 100644 --- a/doc/user_guide/lfric.rst +++ b/doc/user_guide/lfric.rst @@ -2062,7 +2062,7 @@ conventions, are: freedom for the ``to`` and ``from`` function spaces, respectively. Again the intent is determined from the metadata (see :ref:`lfric-api-meta-args`). - 5) If the current entry is a ScalarArray then include the Fortran + 5) If the current entry is a ScalarArray then include the Fortran variable in the argument list. The ScalarArray must be denoted with intent ``in`` to match its read-only nature. From dc31eb9751246f51330f8201b699dc099826a769 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:03:31 +0100 Subject: [PATCH 116/119] #1312: change array_ndims to be saved as an int --- .../lfric/kernel/scalar_array_arg_metadata.py | 40 ++++++++----------- .../kernel/scalar_array_arg_metadata_test.py | 34 +++++++--------- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py index 22856f77e3..af9da5595b 100644 --- a/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py +++ b/src/psyclone/domain/lfric/kernel/scalar_array_arg_metadata.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author L. Turner, Met Office +# Modified A. Pirrie, Met Office '''Module containing the ScalarArrayArgMetadata class which captures the metadata associated with a ScalarArray argument. Supports the creation, @@ -51,7 +52,7 @@ class ScalarArrayArgMetadata(ScalarArgMetadata): :param str datatype: the datatype of this ScalarArray (GH_INTEGER, ...). :param str access: the way the kernel accesses this Scalar Array (GH_READ). :param str array_ndims: the rank (number of dimensions) of this - ScalaArray. + ScalarArray. ''' # The name used to specify a ScalarArray argument in LFRic metadata. @@ -77,7 +78,7 @@ def __init__(self, datatype, access, array_ndims): @classmethod def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, Fortran2003.Structure_Constructor] - ) -> tuple[str, str, str]: + ) -> tuple[str, str, int]: '''Extract the required metadata from the fparser2 tree and return it as strings. Also check that the metadata is in the expected @@ -95,16 +96,15 @@ def _get_metadata(cls, fparser2_tree: Union[Fortran2003.Part_Ref, array_ndims = cls.get_array_ndims(fparser2_tree) return (datatype, access, array_ndims) - def fortran_string(self): + def fortran_string(self) -> str: ''' :returns: the metadata represented by this class as Fortran. - :rtype: str ''' return (f"arg_type({self.form}, {self.datatype}, {self.access}, " f"{self.array_ndims})") @property - def array_ndims(self) -> str: + def array_ndims(self) -> int: ''' :returns: the number of dimensions for this ScalarArray argument. ''' @@ -115,41 +115,33 @@ def array_ndims(self, value): ''' :param str value: set the number of dimensions to the specified value. - :raises TypeError: if value is not a string type. - :raises ValueError: if value is not an integer. + :raises TypeError: if value is not an integer type. :raises ValueError: if value is less than 1. ''' - if not isinstance(value, str): - raise TypeError(f"The type of value must be a string, but " + if not isinstance(value, int): + raise TypeError(f"The type of value must be an integer, but " f"found input of type {type(value)}.") - try: - int_value = int(value) - except ValueError as info: - raise ValueError(f"The number of dimensions of a ScalarArray " - f"should be a string containing an integer, " - f"but found '{value}'.") from info - - if int_value < 1: + if value < 1: raise ValueError(f"The number of dimensions of a ScalarArray " f"should be an integer greater than or " - f"equal to 1 but found '{value}'.") + f"equal to 1 but found {value}.") self._array_ndims = value @classmethod - def get_array_ndims(cls, fparser2_tree): + def get_array_ndims(cls, fparser2_tree) -> int: '''Retrieves the array ndims metadata value found within the supplied fparser2 tree and checks that it is valid. :param fparser2_tree: fparser2 tree capturing the required metadata. :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` - :returns: the array ndims value extracted from the fparser2 tree. - :rtype: str + :returns: the array ndims value extracted from the fparser2 tree, + converted to an int. - :raises ValueError: if the array ndims is not an integer. + :raises ValueError: if the array ndims is not a string. :raises ValueError: if the array ndims is less than 1. ''' @@ -166,8 +158,8 @@ def get_array_ndims(cls, fparser2_tree): if int_value < 1: raise ValueError(f"The number of dimensions of a ScalarArray " f"should be an integer greater than or " - f"equal to 1 but found {array_ndims}.") - return array_ndims + f"equal to 1 but found {int_value}.") + return int_value __all__ = ["ScalarArrayArgMetadata"] diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index 66cf30835c..c5dd7795cd 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -31,7 +31,8 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- -# Author: L. Turner, Met Office +# Author L. Turner, Met Office +# Modified A. Pirrie, Met Office '''Module containing tests for the ScalarArrayArgMetadata class. @@ -44,7 +45,7 @@ @pytest.mark.parametrize("datatype, access, array_ndims", [ - ("GH_REAL", "GH_READ", "1"), ("gh_real", "gh_read", "1")]) + ("GH_REAL", "GH_READ", 1), ("gh_real", "gh_read", 1)]) def test_create(datatype, access, array_ndims): '''Test that an instance of ScalarArrayArgMetadata can be created successfully. Also test that the arguments are case insensitive. @@ -55,7 +56,7 @@ def test_create(datatype, access, array_ndims): assert array_arg.form == "gh_scalar_array" assert array_arg.datatype == "gh_real" assert array_arg.access == "gh_read" - assert array_arg.array_ndims == "1" + assert array_arg.array_ndims == 1 @pytest.mark.parametrize("metadata", @@ -68,7 +69,7 @@ def test_get_metadata(metadata): fparser2_tree) assert datatype == "GH_REAL" assert access == "GH_READ" - assert array_ndims == "2" + assert array_ndims == 2 @pytest.mark.parametrize("fortran_string", [ @@ -125,8 +126,8 @@ def test_get_array_ndims(): fparser_tree = ScalarArrayArgMetadata.create_fparser2( "arg_type(GH_SCALAR_ARRAY, GH_REAL, GH_READ, 3)", Fortran2003.Part_Ref) - vector_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) - assert vector_length == "3" + array_length = ScalarArrayArgMetadata.get_array_ndims(fparser_tree) + assert array_length == 3 def test_array_ndims_setter_getter(): @@ -134,22 +135,17 @@ def test_array_ndims_setter_getter(): including raising an exception if the value is invalid. ''' - array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", "1") - with pytest.raises(TypeError) as info: - test_value = int(2) - array_arg.array_ndims = test_value - assert ("The type of value must be a string, but found input of type " - "." in str(info.value)) + array_arg = ScalarArrayArgMetadata("GH_REAL", "GH_READ", 1) - with pytest.raises(ValueError) as info: - test_value = "1.5" + with pytest.raises(TypeError) as info: + test_value = float(1.5) array_arg.array_ndims = test_value - assert ("The number of dimensions of a ScalarArray should be a string " - "containing an integer, but found '1.5'." in str(info.value)) + assert ("The type of value must be an int, but found input of type " + "." in str(info.value)) with pytest.raises(ValueError) as info: - test_value = "-1" + test_value = -1 array_arg.array_ndims = test_value - assert ("The number of dimensions of a ScalarArray should be an " - "integer greater than or equal to 1 but found '-1'." + assert ("The number of dimensions of a ScalarArray should be an" + " integer greater than or equal to 1 but found -1." in str(info.value)) From cbeee616959e4df99f91dd2a2cbef547df3e2f69 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:34:50 +0100 Subject: [PATCH 117/119] #1312: update the documentation --- doc/user_guide/lfric.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/user_guide/lfric.rst b/doc/user_guide/lfric.rst index 227c268791..b5cfa7c513 100644 --- a/doc/user_guide/lfric.rst +++ b/doc/user_guide/lfric.rst @@ -1432,7 +1432,11 @@ Array sizes The size of a :ref:`scalar array ` is described by ````, where *n > 0* is the number of Fortran ranks representing the dimension of the -array. +array, e.g. a logical, scalar array of rank three would be specified as: + +:: + + arg_type(GH_SCALAR_ARRAY, GH_LOGICAL, GH_READ, 3) .. _lfric-function-space: @@ -2062,9 +2066,13 @@ conventions, are: freedom for the ``to`` and ``from`` function spaces, respectively. Again the intent is determined from the metadata (see :ref:`lfric-api-meta-args`). - 5) If the current entry is a ScalarArray then include the Fortran - variable in the argument list. The ScalarArray must be denoted - with intent ``in`` to match its read-only nature. + 5) If the current entry is a ScalarArray then first include a rank-1 + ``integer`` array of kind ``i_def`` and size ``nranks_`` + containing the upper bounds for each rank, ``dims_`` + (the lower bound is assumed to be 1 as this is how Fortran passes + array slices to subroutines by default). Then pass the array of + the data type and kind specifed in the metadata. The ScalarArray + must be denoted with intent ``in`` to match its read-only nature. 4) For each function space in the order they appear in the metadata arguments (the ``to`` function space of an operator is considered to be before the From a66cc502f85be1a6078158d14ebd498d220ce71a Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:38:35 +0100 Subject: [PATCH 118/119] #1312: correct the author section --- src/psyclone/domain/lfric/kernel/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/domain/lfric/kernel/__init__.py b/src/psyclone/domain/lfric/kernel/__init__.py index 96ee528665..e72bba56a4 100644 --- a/src/psyclone/domain/lfric/kernel/__init__.py +++ b/src/psyclone/domain/lfric/kernel/__init__.py @@ -32,7 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- # Author R. W. Ford, STFC Daresbury Lab -# Modifier L. Turner, Met Office +# Modified L. Turner, Met Office '''Module for Kernels in the LFRic domain.''' From 7ca77cd972c1b4de31fcf46afe4ccb5a0a7df9e2 Mon Sep 17 00:00:00 2001 From: Alistair Pirrie <187289694+mo-alistairp@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:22:58 +0100 Subject: [PATCH 119/119] #1312: fix test text from int to integer --- .../domain/lfric/kernel/scalar_array_arg_metadata_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py index c5dd7795cd..6bd3a841d8 100644 --- a/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py +++ b/src/psyclone/tests/domain/lfric/kernel/scalar_array_arg_metadata_test.py @@ -140,8 +140,8 @@ def test_array_ndims_setter_getter(): with pytest.raises(TypeError) as info: test_value = float(1.5) array_arg.array_ndims = test_value - assert ("The type of value must be an int, but found input of type " - "." in str(info.value)) + assert ("The type of value must be an integer, but found " + "input of type ." in str(info.value)) with pytest.raises(ValueError) as info: test_value = -1