Reference Guide  2.5.0
field_arg_metadata.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2022-2024, Science and Technology Facilities Council
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are met:
9 #
10 # * Redistributions of source code must retain the above copyright notice, this
11 # list of conditions and the following disclaimer.
12 #
13 # * Redistributions in binary form must reproduce the above copyright notice,
14 # this list of conditions and the following disclaimer in the documentation
15 # and/or other materials provided with the distribution.
16 #
17 # * Neither the name of the copyright holder nor the names of its
18 # contributors may be used to endorse or promote products derived from
19 # this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 # -----------------------------------------------------------------------------
34 # Author R. W. Ford, STFC Daresbury Lab
35 
36 '''Module containing the FieldArgMetadata class which captures the metadata
37 associated with a field argument. Supports the creation, modification
38 and Fortran output of a Field argument.
39 
40 '''
41 from psyclone.domain.lfric import LFRicConstants
43  ScalarArgMetadata
44 
45 
47  '''Class to capture LFRic kernel metadata information for a field
48  argument.
49 
50  :param str datatype: the datatype of this field (GH_INTEGER, ...).
51  :param str access: the way the kernel accesses this field (GH_WRITE, ...).
52  :param str function_space: the function space that this field is \
53  on (W0, ...).
54  :param Optional[str] stencil: the type of stencil used by the \
55  kernel when accessing this field.
56 
57  '''
58  # The name used to specify a field argument in LFRic metadata.
59  form = "gh_field"
60  # The relative positions of LFRic metadata. Metadata for a field
61  # argument is provided in the following format 'arg_type(form,
62  # datatype, access, function_space)'. Therefore, for example, the
63  # index of the form argument (form_arg_index) is 0.
64  form_arg_index = 0
65  datatype_arg_index = 1
66  access_arg_index = 2
67  function_space_arg_index = 3
68  stencil_arg_index = 4
69  # The name to use for any exceptions.
70  check_name = "field"
71  # The number of arguments in the language-level metadata (min and
72  # max values).
73  nargs = (4, 5)
74 
75  def __init__(self, datatype, access, function_space, stencil=None):
76  super().__init__(datatype, access)
77  self.function_spacefunction_spacefunction_spacefunction_space = function_space
78  self.stencilstencilstencilstencil = stencil
79 
80  @classmethod
81  def _get_metadata(cls, fparser2_tree):
82  '''Extract the required metadata from the fparser2 tree and return it
83  as strings. Also check that the metadata is in the expected
84  form (but do not check the metadata values as that is done
85  separately).
86 
87  :param fparser2_tree: fparser2 tree containing the metadata \
88  for this argument.
89  :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` | \
90  :py:class:`fparser.two.Fortran2003.Structure_Constructor`
91 
92  :returns: a tuple containing the datatype, access, function \
93  space and stencil metadata.
94  :rtype: Tuple[str, str, str, Optional[str]]
95 
96  '''
97  datatype, access = super()._get_metadata(fparser2_tree)
98  function_space = cls.get_argget_arg(
99  fparser2_tree, cls.function_space_arg_indexfunction_space_arg_indexfunction_space_arg_index)
100  stencil = cls.get_stencilget_stencil(fparser2_tree)
101  return (datatype, access, function_space, stencil)
102 
103  @classmethod
104  def get_stencil(cls, fparser2_tree):
105  '''Retrieves the stencil metadata value found within the supplied
106  fparser2 tree (if there is one) and checks that it is valid.
107 
108  :param fparser2_tree: fparser2 tree capturing the required metadata.
109  :type fparser2_tree: :py:class:`fparser.two.Fortran2003.Part_Ref`
110 
111  :returns: the stencil value extracted from the fparser2 tree \
112  if there is one, or None if not.
113  :rtype: Optional[str]
114 
115  :raises TypeError: if the stencil metadata is not in the \
116  expected form.
117 
118  '''
119  raw_stencil_text = FieldArgMetadata.get_arg(
120  fparser2_tree, cls.stencil_arg_indexstencil_arg_index)
121  if not raw_stencil_text:
122  return None
123  raw_stencil_text = raw_stencil_text.strip().lower()
124  if not (raw_stencil_text.startswith("stencil(") and
125  raw_stencil_text.endswith(")") and len(raw_stencil_text) > 9):
126  raise TypeError(f"The stencil metadata should be in the form "
127  f"'stencil(type)' but found '{raw_stencil_text}'.")
128  stencil = raw_stencil_text[8:-1]
129  return stencil
130 
131  def fortran_string(self):
132  '''
133  :returns: the metadata represented by this class as Fortran.
134  :rtype: str
135  '''
136  if self.stencilstencilstencilstencil:
137  return (f"arg_type({self.form}, {self.datatype}, {self.access}, "
138  f"{self.function_space}, stencil({self.stencil}))")
139  return (f"arg_type({self.form}, {self.datatype}, {self.access}, "
140  f"{self.function_space})")
141 
142  @staticmethod
143  def check_datatype(value):
144  '''
145  :param str value: the datatype to check for validity.
146 
147  :raises ValueError: if the provided value is not a valid \
148  datatype descriptor.
149 
150  '''
151  const = LFRicConstants()
152  FieldArgMetadata.validate_scalar_value(
153  value, const.VALID_FIELD_DATA_TYPES, "datatype descriptor")
154 
155  @staticmethod
156  def check_access(value):
157  '''
158  :param str value: the access descriptor to validate.
159  '''
160  const = LFRicConstants()
161  FieldArgMetadata.validate_scalar_value(
162  value, const.VALID_FIELD_ACCESS_TYPES, "access descriptor")
163 
164  @property
165  def function_space(self):
166  '''
167  :returns: the function space for this field argument.
168  :rtype: str
169  '''
170  return self._function_space_function_space
171 
172  @function_space.setter
173  def function_space(self, value):
174  '''
175  :param str value: set the function space to the \
176  specified value.
177  '''
178  const = LFRicConstants()
179  FieldArgMetadata.validate_scalar_value(
180  value, const.VALID_FUNCTION_SPACE_NAMES, "function space")
181  self._function_space_function_space = value.lower()
182 
183  @property
184  def stencil(self):
185  '''
186  :returns: the stencil for this field argument, or None if there
187  isn't one.
188  :rtype: Optional[str]
189 
190  '''
191  return self._stencil_stencil
192 
193  @stencil.setter
194  def stencil(self, value):
195  '''
196  :param str value: set the stencil to the specified value.
197  '''
198  if value is None:
199  self._stencil_stencil = None
200  else:
201  const = LFRicConstants()
202  FieldArgMetadata.validate_scalar_value(
203  value, const.VALID_STENCIL_TYPES, "stencil")
204  self._stencil_stencil = value.lower()
205 
206 
207 __all__ = ["FieldArgMetadata"]