39 This module contains the LFRicArgDescriptor class and related constants
63 This class captures the information specified in one of LFRic API argument
64 descriptors (scalars, fields and operators).
66 :param arg_type: LFRic API valid argument type (scalar, \
68 :type arg_type: :py:class:`psyclone.expression.FunctionVar` or \
69 :py:class:`psyclone.expression.BinaryOperator`
70 :param str operates_on: value of operates_on from the parsed kernel \
71 metadata (used for validation).
72 :param int metadata_index: position of this argument in the list of \
73 arguments specified in the metadata.
75 :raises ParseError: if a 'meta_arg' entry is not of 'arg_type' type.
76 :raises ParseError: if the first argument of a 'meta_arg' entry is not \
77 one of LFRic API valid argument types.
78 :raises ParseError: if the second argument of a 'meta_arg' entry is not \
79 one of LFRic API valid data types.
80 :raises ParseError: if a 'meta_arg' entry has fewer than 3 args.
81 :raises ParseError: if the third 'meta_arg' entry is not a valid \
83 :raises InternalError: if the operates_on from the parsed kernel \
84 metadata is not 'cell_column' or 'dof'.
85 :raises InternalError: if all the metadata checks fail to catch an \
86 invalid argument type.
93 def __init__(self, arg_type, operates_on, metadata_index):
114 if arg_type.name !=
'arg_type':
116 f
"In the LFRic API each 'meta_arg' entry must be of type "
117 f
"'arg_type', but found '{arg_type.name}'.")
125 if isinstance(arg_type.args[0], expr.BinaryOperator):
126 argtype = arg_type.args[0].toks[0]
127 separator = arg_type.args[0].toks[1]
129 argtype = arg_type.args[0]
134 if isinstance(argtype, expr.FunctionVar)
and argtype.name
in \
135 const.VALID_ARG_TYPE_NAMES:
139 f
"In the LFRic API the 1st argument of a 'meta_arg' entry "
140 f
"should be a valid argument type (one of "
141 f
"{const.VALID_ARG_TYPE_NAMES}), but found '{argtype}' in "
150 self.
_nargs_nargs = len(arg_type.args)
152 if self.
_nargs_nargs < min_nargs:
154 f
"In the LFRic API each 'meta_arg' entry must have at least "
155 f
"{min_nargs} args, but found {self._nargs} in '{arg_type}'.")
158 dtype = arg_type.args[1].name
159 if dtype
in const.VALID_ARG_DATA_TYPES:
163 f
"In the LFRic API the 2nd argument of a 'meta_arg' entry "
164 f
"should be a valid data type (one of "
165 f
"{const.VALID_ARG_DATA_TYPES}), but found '{dtype}' in "
171 api_config = Config.get().api_conf(API)
172 access_mapping = api_config.get_access_mapping()
175 self.
_access_type_access_type = access_mapping[arg_type.args[prop_ind].name]
176 except KeyError
as err:
177 valid_names = api_config.get_valid_accesses_api()
179 f
"In the LFRic API argument {prop_ind+1} of a 'meta_arg' entry"
180 f
" must be a valid access descriptor (one of {valid_names}), "
181 f
"but found '{arg_type.args[prop_ind].name}' in "
182 f
"'{arg_type}'.")
from err
186 if operates_on
not in const.VALID_ITERATION_SPACES:
188 f
"Expected operates_on in the kernel metadata to be one of "
189 f
"{const.VALID_ITERATION_SPACES} but got '{operates_on}'.")
207 f
"Failed argument validation for the 'meta_arg' entry "
208 f
"'{arg_type}', should not get to here.")
216 def _validate_vector_size(self, separator, arg_type):
218 Validates descriptors for field vector arguments and populates
219 vector properties accordingly.
221 :param str separator: operator in a binary expression.
222 :param arg_type: LFRic API field (vector) argument type.
223 :type arg_type: :py:class:`psyclone.expression.FunctionVar`
225 :raises ParseError: if the field vector notation does not use \
227 :raises ParseError: if the field vector notation is not in the \
228 correct format '(field*n)' where 'n' is \
230 :raises ParseError: if the field vector notation is used for the \
231 vector size of less than 2.
232 :raises ParseError: if the field vector notation is used for an \
233 argument that is not a field.
239 f
"In the LFRic API the 1st argument of a 'meta_arg' "
240 f
"entry may be a field vector but if so must use '*' as "
241 f
"the separator in the format 'field*n', but found "
242 f
"'{separator}' in '{arg_type}'.")
247 vectsize = int(arg_type.args[0].toks[2])
248 except TypeError
as err:
250 f
"In the LFRic API, the field vector notation must be in the "
251 f
"format 'field*n' where 'n' is an integer, but the following "
252 f
"'{arg_type.args[0].toks[2]}' was found in "
253 f
"'{arg_type}'.")
from err
259 f
"In the LFRic API the 1st argument of a 'meta_arg' entry may "
260 f
"be a field vector with format 'field*n' where n is an "
261 f
"integer > 1. However, found n = {vectsize} in '{arg_type}'.")
267 const.VALID_FIELD_NAMES
and self.
_vector_size_vector_size:
269 f
"In the LFRic API, vector notation is only supported for "
270 f
"{const.VALID_FIELD_NAMES} argument types but found "
271 f
"'{arg_type.args[0]}'.")
273 def _init_field(self, arg_type, operates_on):
275 Validates metadata descriptors for field arguments and
276 initialises field argument properties accordingly.
278 :param arg_type: LFRic API field (vector) argument type.
279 :type arg_type: :py:class:`psyclone.expression.FunctionVar`
280 :param operates_on: value of operates_on from the parsed kernel \
281 metadata (used for validation).
282 :type operates_on: str
284 :raises InternalError: if argument type other than a field is \
286 :raises ParseError: if there are fewer than 4 metadata arguments.
287 :raises ParseError: if there are more than 5 metadata arguments.
288 :raises ParseError: if a field argument has an invalid data type.
289 :raises ParseError: if the 4th argument is not a valid function space.
290 :raises ParseError: if the optional 5th argument is not a stencil \
291 specification or a mesh identifier (for \
293 :raises ParseError: if a field passed to a kernel that operates on \
294 DoFs does not have a valid access \
295 (one of [READ, WRITE, READWRITE]).
296 :raises ParseError: if a field on a discontinuous function space \
297 passed to a kernel that operates on cell-columns \
298 does not have a valid access (one of \
299 [READ, WRITE, READWRITE]).
300 :raises ParseError: if a field on a continuous function space \
301 passed to a kernel that operates on cell-columns \
302 does not have a valid access (one of [READ, WRITE,\
304 :raises ParseError: if the kernel operates on the domain and is \
305 passed a field on a continuous space.
306 :raises InternalError: if an invalid value for operates_on is \
308 :raises ParseError: if a field with a stencil access is not read-only.
309 :raises ParseError: if a field with a stencil access is passed to a \
310 kernel that operates on the domain.
320 f
"Expected a field argument but got an argument of type "
321 f
"'{arg_type.args[0]}'.")
325 if self.
_nargs_nargs < nargs_field_min:
327 "In the LFRic API each 'meta_arg' entry must have at least "
328 f
"{nargs_field_min} arguments if its first argument is of "
329 f
"{const.VALID_FIELD_NAMES} type, but found {self._nargs} in "
333 if self.
_nargs_nargs > nargs_field_max:
335 f
"In the LFRic API each 'meta_arg' entry must have at most "
336 f
"{nargs_field_max} arguments if its first argument is of "
337 f
"{const.VALID_FIELD_NAMES} type, but found {self._nargs} in "
341 if self.
_data_type_data_type
not in const.VALID_FIELD_DATA_TYPES:
343 f
"In the LFRic API the allowed data types for field arguments "
344 f
"are one of {const.VALID_FIELD_DATA_TYPES}, but found "
345 f
"'{self._data_type}' in '{arg_type}'.")
349 if arg_type.args[prop_ind].name
not in \
350 const.VALID_FUNCTION_SPACE_NAMES:
352 f
"In the LFRic API argument {prop_ind+1} of a 'meta_arg' "
353 f
"field entry must be a valid function-space name (one of "
354 f
"{const.VALID_FUNCTION_SPACE_NAMES}) if its first argument "
355 f
"is of {const.VALID_FIELD_NAMES} type, but found "
356 f
"'{arg_type.args[prop_ind].name}' in '{arg_type}'.")
362 if self.
_nargs_nargs == nargs_field_max:
364 if "stencil" in str(arg_type.args[prop_ind]):
366 arg_type.args[prop_ind],
367 const.VALID_STENCIL_TYPES)
368 elif "mesh" in str(arg_type.args[prop_ind]):
369 self.
_mesh_mesh_mesh = get_mesh(arg_type.args[prop_ind],
370 const.VALID_MESH_TYPES)
372 raise ParseError(
"Unrecognised metadata entry")
373 except ParseError
as err:
375 f
"In the LFRic API argument {prop_ind+1} of a 'meta_arg' "
376 f
"field entry must be either a valid stencil specification"
377 f
" or a mesh identifier (for inter-grid kernels). However,"
378 f
" entry '{arg_type}' raised the following error: "
382 field_disc_accesses = [AccessType.READ, AccessType.WRITE,
383 AccessType.READWRITE]
387 field_cont_accesses = [AccessType.READ, AccessType.WRITE,
388 AccessType.INC, AccessType.READINC]
390 api_config = Config.get().api_conf(API)
391 rev_access_mapping = api_config.get_reverse_access_mapping()
393 fld_disc_acc_msg = [rev_access_mapping[acc]
for acc
in
395 fld_cont_acc_msg = [rev_access_mapping[acc]
for acc
in
398 fld_cont_spaces = (const.CONTINUOUS_FUNCTION_SPACES +
399 const.VALID_ANY_SPACE_NAMES)
402 if operates_on ==
"dof":
403 if self.
_access_type_access_type
not in field_disc_accesses:
405 f
"In the LFRic API, allowed field accesses for a kernel "
406 f
"that operates on DoFs are {fld_disc_acc_msg}, but found "
407 f
"'{rev_access_mapping[self._access_type]}' for "
408 f
"'{self._function_space1.lower()}' in '{arg_type}'.")
411 elif operates_on
in [
"cell_column",
"domain"]:
414 const.VALID_DISCONTINUOUS_NAMES
and
415 self.
_access_type_access_type
not in field_disc_accesses):
417 f
"In the LFRic API, allowed accesses for fields on "
418 f
"discontinuous function spaces that are arguments to "
419 f
"kernels that operate on either cell-columns or the "
420 f
"domain are {fld_disc_acc_msg}, but found "
421 f
"'{rev_access_mapping[self._access_type]}' for "
422 f
"'{self._function_space1.lower()}' in '{arg_type}'.")
425 if operates_on ==
"domain":
427 f
"In the LFRic API, kernels that operate on the domain"
428 f
" only accept field arguments on discontinuous "
429 f
"function spaces but found "
430 f
"'{self._function_space1.lower()}' in '{arg_type}'")
432 if self.
_access_type_access_type
not in field_cont_accesses:
434 f
"In the LFRic API, allowed accesses for fields on "
435 f
"continuous function spaces that are arguments to "
436 f
"kernels that operate on cell-columns are "
437 f
"{fld_cont_acc_msg}, but found "
438 f
"'{rev_access_mapping[self._access_type]}' for "
439 f
"'{self._function_space1.lower()}' in '{arg_type}'.")
443 f
"Invalid operates_on '{operates_on}' in the kernel metadata "
444 f
"(expected one of {const.VALID_ITERATION_SPACES}).")
450 f
"In the LFRic API a field with a stencil access must be "
451 f
"read-only ('{rev_access_mapping[AccessType.READ]}'), "
452 f
"but found '{rev_access_mapping[self._access_type]}' in "
454 if operates_on ==
"domain":
456 f
"In the LFRic API, kernels that operate on the domain "
457 f
"are not permitted to have arguments with a stencil "
458 f
"access but found: '{arg_type}'")
460 def _init_operator(self, arg_type):
462 Validates metadata descriptors for operator arguments and
463 initialises operator argument properties accordingly.
465 :param arg_type: LFRic API operator argument type.
466 :type arg_type: :py:class:`psyclone.expression.FunctionVar`
468 :raises InternalError: if argument type other than an operator is \
470 :raises ParseError: if there are not exactly 5 metadata arguments.
471 :raises ParseError: if an operator argument has an invalid data type.
472 :raises ParseError: if the function space to- is not one of the \
473 valid function spaces.
474 :raises ParseError: if the function space from- is not one of the \
475 valid function spaces.
476 :raises ParseError: if the operator argument has an invalid access.
483 f
"Expected an operator argument but got an argument of type "
484 f
"'{self._argument_type}'.")
489 if self.
_nargs_nargs != nargs_operator:
491 f
"In the LFRic API each 'meta_arg' entry must have "
492 f
"{nargs_operator} arguments if its first argument is an "
493 f
"operator (one of {const.VALID_OPERATOR_NAMES}), but found "
494 f
"{self._nargs} in '{arg_type}'.")
498 if self.
_data_type_data_type
not in const.VALID_OPERATOR_DATA_TYPES:
500 f
"In the LFRic API the allowed data types for operator "
501 f
"arguments are one of {const.VALID_OPERATOR_DATA_TYPES}, but "
502 f
"found '{self._data_type}' in '{arg_type}'.")
507 if arg_type.args[prop_ind].name
not in \
508 const.VALID_FUNCTION_SPACE_NAMES:
510 f
"In the LFRic API argument {prop_ind+1} of a 'meta_arg' "
511 f
"operator entry must be a valid function-space name (one of "
512 f
"{const.VALID_FUNCTION_SPACE_NAMES}), but found "
513 f
"'{arg_type.args[prop_ind].name}' in '{arg_type}'.")
517 if arg_type.args[prop_ind].name
not in \
518 const.VALID_FUNCTION_SPACE_NAMES:
520 f
"In the LFRic API argument {prop_ind+1} of a 'meta_arg' "
521 f
"operator entry must be a valid function-space name (one of "
522 f
"{const.VALID_FUNCTION_SPACE_NAMES}), but found "
523 f
"'{arg_type.args[prop_ind].name}' in '{arg_type}'.")
527 operator_accesses = [AccessType.READ, AccessType.WRITE,
528 AccessType.READWRITE]
530 api_config = Config.get().api_conf(API)
531 rev_access_mapping = api_config.get_reverse_access_mapping()
532 op_acc_msg = [rev_access_mapping[acc]
for acc
in operator_accesses]
533 if self.
_access_type_access_type
not in operator_accesses:
535 f
"In the LFRic API, allowed accesses for operators are "
536 f
"{op_acc_msg} because they behave as discontinuous "
537 f
"quantities, but found "
538 f
"'{rev_access_mapping[self._access_type]}' in '{arg_type}'.")
540 def _init_scalar(self, arg_type):
542 Validates metadata descriptors for scalar arguments and
543 initialises scalar argument properties accordingly.
545 :param arg_type: LFRic API scalar argument type.
546 :type arg_type: :py:class:`psyclone.expression.FunctionVar`
548 :raises InternalError: if argument type other than a scalar is \
550 :raises ParseError: if there are not exactly 3 metadata arguments.
551 :raises InternalError: if a scalar argument has an invalid data type.
552 :raises ParseError: if scalar arguments do not have a read-only or
554 :raises ParseError: if a scalar argument that is not a real \
555 scalar has a reduction access.
562 f
"Expected a scalar argument but got an argument of type "
563 f
"'{arg_type.args[0]}'.")
567 if self.
_nargs_nargs != nargs_scalar:
569 f
"In the LFRic API each 'meta_arg' entry must have "
570 f
"{nargs_scalar} arguments if its first argument is "
571 f
"'gh_scalar', but found {self._nargs} in '{arg_type}'.")
575 if self.
_data_type_data_type
not in const.VALID_SCALAR_DATA_TYPES:
577 f
"Expected one of {const.VALID_SCALAR_DATA_TYPES} as the "
578 f
"scalar data type but got '{self._data_type}'.")
581 scalar_accesses = [AccessType.READ] + \
582 AccessType.get_valid_reduction_modes()
584 api_config = Config.get().api_conf(API)
585 rev_access_mapping = api_config.get_reverse_access_mapping()
586 if self.
_access_type_access_type
not in scalar_accesses:
587 api_specific_name = rev_access_mapping[self.
_access_type_access_type]
588 valid_reductions = AccessType.get_valid_reduction_names()
590 f
"In the LFRic API scalar arguments must have read-only "
591 f
"('gh_read') or a reduction {valid_reductions} access but "
592 f
"found '{api_specific_name}' in '{arg_type}'.")
595 AccessType.get_valid_reduction_modes():
597 f
"In the LFRic API a reduction access "
598 f
"'{self._access_type.api_specific_name()}' is only valid "
599 f
"with a real scalar argument, but a scalar argument with "
600 f
"'{self._data_type}' data type was found in '{arg_type}'.")
608 :returns: intrinsic Fortran (primitive) type of the argument data.
617 Returns the "to" function space for an operator. This is
618 the first function space specified in the metadata.
620 :returns: "to" function space for an operator.
623 :raises InternalError: if this is not an operator.
630 f
"In the LFRic API 'function_space_to' only makes sense for one "
631 f
"of {const.VALID_OPERATOR_NAMES}, but this is a "
632 f
"'{self._argument_type}'.")
637 Returns the "from" function space for an operator. This is
638 the second function space specified in the metadata.
640 :returns: "from" function space for an operator.
643 :raises InternalError: if this is not an operator.
650 f
"In the LFRic API 'function_space_from' only makes sense for one "
651 f
"of {const.VALID_OPERATOR_NAMES}, but this is a "
652 f
"'{self._argument_type}'.")
657 Returns the function space name related to this kernel argument
658 depending on the argument type: a single function space for a field,
659 function_space_from for an operator and nothing for a scalar.
661 :returns: function space relating to this kernel argument or \
663 :rtype: str or NoneType
665 :raises InternalError: if an invalid argument type is passed in.
675 raise InternalError(f
"Expected a valid argument type but got "
676 f
"'{self._argument_type}'.")
681 Returns the function space names related to this kernel argument
682 as a list depending on the argument type: one function space for
683 a field, both function spaces ("to"- and then "from"-) for an
684 operator and an empty list for a scalar.
686 :returns: function space names related to this kernel argument.
689 :raises InternalError: if an invalid argument type is passed in.
700 raise InternalError(f
"Expected a valid argument type but got "
701 f
"'{self._argument_type}'.")
706 Returns the vector size of the argument. This will be 1 if ``*n``
707 has not been specified for all argument types except scalars
708 (their vector size is set to 0).
710 :returns: vector size of the argument.
718 Creates a string representation of the argument descriptor. This
719 is type and access for scalars with the addition of function
720 space(s) for fields and operators.
722 :returns: string representation of the argument descriptor.
725 :raises InternalError: if an invalid argument type is passed in.
729 res =
"LFRicArgDescriptor object" + os.linesep
730 res += f
" argument_type[0]='{self._argument_type}'"
734 res += f
" data_type[1]='{self._data_type}'" + os.linesep
735 res += (f
" access_descriptor[2]="
736 f
"'{self._access_type.api_specific_name()}'"
739 res += (f
" function_space[3]='{self._function_space1}'"
742 res += (f
" function_space_to[3]='{self._function_space1}'"
744 res += (f
" function_space_from[4]='{self._function_space2}'"
749 raise InternalError(f
"Expected a valid argument type but got "
750 f
"'{self._argument_type}'.")
757 'LFRicArgDescriptor']
def function_spaces(self)
def _init_field(self, arg_type, operates_on)
def _init_scalar(self, arg_type)
def _validate_vector_size(self, separator, arg_type)
def function_space_to(self)
def function_space_from(self)
def _init_operator(self, arg_type)