Reference Guide  2.5.0
psyclone.domain.lfric.lfric_kern.LFRicKern Class Reference
Inheritance diagram for psyclone.domain.lfric.lfric_kern.LFRicKern:
Collaboration diagram for psyclone.domain.lfric.lfric_kern.LFRicKern:

Public Member Functions

def __init__ (self)
 
def reference_accesses (self, var_accesses)
 
def load (self, call, parent=None)
 
def load_meta (self, ktype)
 
def qr_rules (self)
 
def cma_operation (self)
 
def is_intergrid (self)
 
def colourmap (self)
 
def last_cell_all_colours_symbol (self)
 
def ncolours_var (self)
 
def fs_descriptors (self)
 
def qr_required (self)
 
def eval_shapes (self)
 
def eval_targets (self)
 
def reference_element (self)
 
def mesh (self)
 
def all_updates_are_writes (self)
 
def base_name (self)
 
def argument_kinds (self)
 
def gen_stub (self)
 
def get_kernel_schedule (self)
 
def validate_kernel_code_args (self, table)
 
def validate_global_constraints (self)
 
- Public Member Functions inherited from psyclone.psyGen.CodedKern
def __init__ (self, KernelArguments, call, parent=None, check=True)
 
def opencl_options (self)
 
def set_opencl_options (self, options)
 
def __str__ (self)
 
def module_name (self)
 
def dag_name (self)
 
def module_inline (self)
 
def module_inline (self, value)
 
def node_str (self, colour=True)
 
def lower_to_language_level (self)
 
def incremented_arg (self)
 
def ast (self)
 
def rename_and_write (self)
 
def modified (self)
 
def modified (self, value)
 
- Public Member Functions inherited from psyclone.psyGen.Kern
def __init__ (self, parent, call, name, ArgumentsClass, check=True)
 
def args (self)
 
def is_reduction (self)
 
def reduction_arg (self)
 
def reprod_reduction (self)
 
def local_reduction_name (self)
 
def zero_reduction_variable (self, parent, position=None)
 
def reduction_sum_loop (self, parent)
 
def arg_descriptors (self)
 
def arg_descriptors (self, obj)
 
def arguments (self)
 
def name (self)
 
def name (self, value)
 
def is_coloured (self)
 
def iterates_over (self)
 
def local_vars (self)
 
def gen_code (self, parent)
 

Static Public Attributes

 QRRule
 

Additional Inherited Members

- Public Attributes inherited from psyclone.psyGen.CodedKern
 arg_descriptors
 
 modified
 
 name
 

Detailed Description

 Stores information about LFRic Kernels as specified by the
Kernel metadata and associated algorithm call. Uses this
information to generate appropriate PSy layer code for the Kernel
instance or to generate a Kernel stub.

Definition at line 59 of file lfric_kern.py.

Member Function Documentation

◆ all_updates_are_writes()

def psyclone.domain.lfric.lfric_kern.LFRicKern.all_updates_are_writes (   self)
:returns: True if all of the arguments updated by this kernel have \
          'GH_WRITE' access, False otherwise.
:rtype: bool

Definition at line 538 of file lfric_kern.py.

538  def all_updates_are_writes(self):
539  '''
540  :returns: True if all of the arguments updated by this kernel have \
541  'GH_WRITE' access, False otherwise.
542  :rtype: bool
543 
544  '''
545  accesses = set(arg.access for arg in self.args)
546  all_writes = AccessType.all_write_accesses()
547  all_writes.remove(AccessType.WRITE)
548  return (not accesses.intersection(set(all_writes)))
549 

References psyclone.expression.FunctionVar.args, psyclone.f2pygen.SubroutineGen.args(), psyclone.parse.algorithm.ParsedCall.args(), psyclone.psyGen.GlobalSum.args(), psyclone.psyGen.HaloExchange.args(), psyclone.psyGen.Kern.args(), psyclone.psyGen.Arguments.args(), and psyclone.psyir.nodes.node.Node.args().

Here is the call graph for this function:

◆ argument_kinds()

def psyclone.domain.lfric.lfric_kern.LFRicKern.argument_kinds (   self)
:returns: kinds (precisions) for all arguments in a kernel.
:rtype: set of str

Definition at line 559 of file lfric_kern.py.

559  def argument_kinds(self):
560  '''
561  :returns: kinds (precisions) for all arguments in a kernel.
562  :rtype: set of str
563 
564  '''
565  return self._argument_kinds
566 

References psyclone.domain.lfric.lfric_kern.LFRicKern._argument_kinds.

◆ base_name()

def psyclone.domain.lfric.lfric_kern.LFRicKern.base_name (   self)
:returns: a base name for this kernel.
:rtype: str

Definition at line 551 of file lfric_kern.py.

551  def base_name(self):
552  '''
553  :returns: a base name for this kernel.
554  :rtype: str
555  '''
556  return self._base_name
557 

References psyclone.domain.lfric.lfric_kern.LFRicKern._base_name.

◆ cma_operation()

def psyclone.domain.lfric.lfric_kern.LFRicKern.cma_operation (   self)
:return: the type of CMA operation performed by this kernel
         (one of 'assembly', 'apply' or 'matrix-matrix') or None
         if the kernel does not involve CMA operators.
:rtype: str

Definition at line 380 of file lfric_kern.py.

380  def cma_operation(self):
381  '''
382  :return: the type of CMA operation performed by this kernel
383  (one of 'assembly', 'apply' or 'matrix-matrix') or None
384  if the kernel does not involve CMA operators.
385  :rtype: str
386  '''
387  return self._cma_operation
388 

References psyclone.domain.lfric.lfric_kern.LFRicKern._cma_operation, and psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._cma_operation.

◆ colourmap()

def psyclone.domain.lfric.lfric_kern.LFRicKern.colourmap (   self)
Getter for the name of the colourmap associated with this kernel call.

:returns: name of the colourmap (Fortran array).
:rtype: str

:raises InternalError: if this kernel is not coloured.

Definition at line 398 of file lfric_kern.py.

398  def colourmap(self):
399  '''
400  Getter for the name of the colourmap associated with this kernel call.
401 
402  :returns: name of the colourmap (Fortran array).
403  :rtype: str
404 
405  :raises InternalError: if this kernel is not coloured.
406 
407  '''
408  if not self.is_coloured():
409  raise InternalError(f"Kernel '{self.name}' is not inside a "
410  f"coloured loop.")
411  sched = self.ancestor(InvokeSchedule)
412  if self.is_intergrid:
413  cmap = self._intergrid_ref.colourmap_symbol.name
414  else:
415  try:
416  cmap = sched.symbol_table.lookup_with_tag("cmap").name
417  except KeyError:
418  # We have to do this here as _init_colourmap (which calls this
419  # method) is only called at code-generation time.
420  cmap = sched.symbol_table.find_or_create_array(
421  "cmap", 2, ScalarType.Intrinsic.INTEGER,
422  tag="cmap").name
423 
424  return cmap
425 

References psyclone.domain.lfric.lfric_kern.LFRicKern._intergrid_ref, psyclone.psyir.nodes.node.Node.ancestor(), psyclone.psyGen.Kern.is_coloured(), psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn.is_intergrid(), psyclone.domain.lfric.lfric_kern.LFRicKern.is_intergrid(), and psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata.is_intergrid().

Here is the call graph for this function:

◆ eval_shapes()

def psyclone.domain.lfric.lfric_kern.LFRicKern.eval_shapes (   self)
:return: the value(s) of GH_SHAPE for this kernel or an empty list \
         if none are specified.
:rtype: list

Definition at line 501 of file lfric_kern.py.

501  def eval_shapes(self):
502  '''
503  :return: the value(s) of GH_SHAPE for this kernel or an empty list \
504  if none are specified.
505  :rtype: list
506 
507  '''
508  return self._eval_shapes
509 

References psyclone.domain.lfric.lfric_kern.LFRicKern._eval_shapes, and psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._eval_shapes.

◆ eval_targets()

def psyclone.domain.lfric.lfric_kern.LFRicKern.eval_targets (   self)
:return: the function spaces upon which basis/diff-basis functions \
         are to be evaluated for this kernel.
:rtype: dict of (:py:class:`psyclone.domain.lfric.FunctionSpace`, \
        :py:class`psyclone.dynamo0p3.DynKernelArgument`), indexed by \
        the names of the target function spaces.

Definition at line 511 of file lfric_kern.py.

511  def eval_targets(self):
512  '''
513  :return: the function spaces upon which basis/diff-basis functions \
514  are to be evaluated for this kernel.
515  :rtype: dict of (:py:class:`psyclone.domain.lfric.FunctionSpace`, \
516  :py:class`psyclone.dynamo0p3.DynKernelArgument`), indexed by \
517  the names of the target function spaces.
518  '''
519  return self._eval_targets
520 

References psyclone.domain.lfric.lfric_kern.LFRicKern._eval_targets, psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._eval_targets, and psyclone.dynamo0p3.DynBasisFunctions._eval_targets.

◆ fs_descriptors()

def psyclone.domain.lfric.lfric_kern.LFRicKern.fs_descriptors (   self)
:return: a list of function space descriptor objects of
         type FSDescriptors which contain information about
         the function spaces.
:rtype: List[:py:class:`psyclone.FSDescriptors`].

Definition at line 481 of file lfric_kern.py.

481  def fs_descriptors(self):
482  '''
483  :return: a list of function space descriptor objects of
484  type FSDescriptors which contain information about
485  the function spaces.
486  :rtype: List[:py:class:`psyclone.FSDescriptors`].
487 
488  '''
489  return self._fs_descriptors
490 

References psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn._fs_descriptors, psyclone.domain.lfric.lfric_kern.LFRicKern._fs_descriptors, and psyclone.psyGen.BuiltIn._fs_descriptors.

◆ gen_stub()

def psyclone.domain.lfric.lfric_kern.LFRicKern.gen_stub (   self)
Create the fparser1 AST for a kernel stub.

:returns: root of fparser1 AST for the stub routine.
:rtype: :py:class:`fparser.one.block_statements.Module`

:raises GenerationError: if the supplied kernel stub does not operate \
    on a supported subset of the domain (currently only "cell_column").

Definition at line 568 of file lfric_kern.py.

568  def gen_stub(self):
569  '''
570  Create the fparser1 AST for a kernel stub.
571 
572  :returns: root of fparser1 AST for the stub routine.
573  :rtype: :py:class:`fparser.one.block_statements.Module`
574 
575  :raises GenerationError: if the supplied kernel stub does not operate \
576  on a supported subset of the domain (currently only "cell_column").
577 
578  '''
579  # The operates-on/iterates-over values supported by the stub generator.
580  const = LFRicConstants()
581  supported_operates_on = const.USER_KERNEL_ITERATION_SPACES[:]
582  # TODO #925 Add support for 'domain' kernels
583  supported_operates_on.remove("domain")
584 
585  # Check operates-on (iteration space) before generating code
586  if self.iterates_over not in supported_operates_on:
587  raise GenerationError(
588  f"The LFRic API kernel-stub generator supports kernels that "
589  f"operate on one of {supported_operates_on} but found "
590  f"'{self.iterates_over}' in kernel '{self.name}'.")
591 
592  # Create an empty PSy layer module
593  psy_module = ModuleGen(self._base_name+"_mod")
594 
595  # Create the subroutine
596  sub_stub = SubroutineGen(psy_module, name=self._base_name+"_code",
597  implicitnone=True)
598 
599  # Add all the declarations
600  # Import here to avoid circular dependency
601  # pylint: disable=import-outside-toplevel
602  from psyclone.domain.lfric import (LFRicScalarArgs, LFRicFields,
603  LFRicDofmaps, LFRicStencils)
604  from psyclone.dynamo0p3 import (DynCellIterators, DynFunctionSpaces,
605  DynCMAOperators, DynBoundaryConditions,
606  DynLMAOperators, LFRicMeshProperties,
607  DynBasisFunctions, DynReferenceElement)
608  for entities in [DynCellIterators, LFRicDofmaps, DynFunctionSpaces,
609  DynCMAOperators, LFRicScalarArgs, LFRicFields,
610  DynLMAOperators, LFRicStencils, DynBasisFunctions,
611  DynBoundaryConditions, DynReferenceElement,
612  LFRicMeshProperties]:
613  entities(self).declarations(sub_stub)
614 
615  # Add wildcard "use" statement for all supported argument
616  # kinds (precisions)
617  sub_stub.add(
618  UseGen(sub_stub,
619  name=const.UTILITIES_MOD_MAP["constants"]["module"]))
620 
621  # Create the arglist
622  create_arg_list = KernStubArgList(self)
623  create_arg_list.generate()
624 
625  # Add the arglist
626  sub_stub.args = create_arg_list.arglist
627 
628  # Add the subroutine to the parent module
629  psy_module.add(sub_stub)
630  return psy_module.root
631 

References psyclone.domain.lfric.lfric_kern.LFRicKern._base_name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.iterates_over, psyclone.parse.kernel.KernelType.iterates_over(), and psyclone.psyGen.Kern.iterates_over().

Here is the call graph for this function:

◆ get_kernel_schedule()

def psyclone.domain.lfric.lfric_kern.LFRicKern.get_kernel_schedule (   self)
Returns a PSyIR Schedule representing the kernel code. The base
class creates the PSyIR schedule on first invocation which is
then checked for consistency with the kernel metadata
here. The Schedule is just generated on first invocation, this
allows us to retain transformations that may subsequently be
applied to the Schedule.

Once issue #935 is implemented, this routine will return the
PSyIR Schedule using LFRic-specific PSyIR where possible.

:returns: Schedule representing the kernel code.
:rtype: :py:class:`psyclone.psyGen.KernelSchedule`

:raises GenerationError: if no subroutine matching this kernel can \
    be found in the parse tree of the associated source code.

Reimplemented from psyclone.psyGen.CodedKern.

Definition at line 632 of file lfric_kern.py.

632  def get_kernel_schedule(self):
633  '''Returns a PSyIR Schedule representing the kernel code. The base
634  class creates the PSyIR schedule on first invocation which is
635  then checked for consistency with the kernel metadata
636  here. The Schedule is just generated on first invocation, this
637  allows us to retain transformations that may subsequently be
638  applied to the Schedule.
639 
640  Once issue #935 is implemented, this routine will return the
641  PSyIR Schedule using LFRic-specific PSyIR where possible.
642 
643  :returns: Schedule representing the kernel code.
644  :rtype: :py:class:`psyclone.psyGen.KernelSchedule`
645 
646  :raises GenerationError: if no subroutine matching this kernel can \
647  be found in the parse tree of the associated source code.
648  '''
649  if self._kern_schedule:
650  return self._kern_schedule
651 
652  # Get the PSyIR Kernel Schedule(s)
653  routines = Fparser2Reader().get_routine_schedules(self.name, self.ast)
654  for routine in routines:
655  # If one of the symbols is not declared in a routine then
656  # this is only picked up when writing out the routine
657  # (raising a VisitorError), so we check here so that
658  # invalid code is not inlined. We use debug_string() to
659  # minimise the overhead.
660 
661  # TODO #2271 could potentially avoid the need for
662  # debug_string() within. Sergi suggests that we may be
663  # missing the traversal of the declaration init
664  # expressions and that might solve the problem. I'm not so
665  # sure as we are talking about unknown symbols that will
666  # only be resolved in the back-end (or not). If I am right
667  # then one option would be to use the FortranWriter, but
668  # that would be bigger overhead, or perhaps just the
669  # declarations part of FortranWriter if that is possible.
670  # Also see TODO issue #2336 which captures the specific
671  # problem in LFRic that this fixes.
672  routine.debug_string()
673 
674  if len(routines) == 1:
675  sched = routines[0]
676  # TODO #928: We don't validate the arguments yet because the
677  # validation has many false negatives.
678  # self.validate_kernel_code_args(sched.symbol_table)
679  else:
680  # The kernel name corresponds to an interface block. Find which
681  # of the routines matches the precision of the arguments.
682  for routine in routines:
683  try:
684  # The validity check for the kernel arguments will raise
685  # an exception if the precisions don't match.
686  self.validate_kernel_code_args(routine.symbol_table)
687  sched = routine
688  break
689  except GenerationError:
690  pass
691  else:
692  raise GenerationError(
693  f"Failed to find a kernel implementation with an interface"
694  f" that matches the invoke of '{self.name}'. (Tried "
695  f"routines {[item.name for item in routines]}.)")
696 
697  # TODO #935 - replace the PSyIR argument data symbols with LFRic data
698  # symbols. For the moment we just return the unmodified PSyIR schedule
699  # but this should use RaisePSyIR2LFRicKernTrans once KernelInterface
700  # is fully functional (#928).
701  ksched = KernelSchedule(sched.name,
702  symbol_table=sched.symbol_table.detach())
703  for child in sched.pop_all_children():
704  ksched.addchild(child)
705  sched.replace_with(ksched)
706 
707  self._kern_schedule = ksched
708 
709  return self._kern_schedule
710 

References psyclone.domain.lfric.lfric_kern.LFRicKern._kern_schedule, psyclone.gocean1p0.GOKern._kern_schedule, psyclone.psyGen.CodedKern._kern_schedule, psyclone.parse.kernel.KernelProcedure.ast(), psyclone.psyGen.CodedKern.ast(), psyclone.psyir.nodes.codeblock.CodeBlock.ast, psyclone.psyir.nodes.node.Node.ast(), psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg.name, psyclone.domain.gocean.transformations.gocean_const_loop_bounds_trans.GOConstLoopBoundsTrans.name(), psyclone.domain.gocean.transformations.gocean_move_iteration_boundaries_inside_kernel_trans.GOMoveIterationBoundariesInsideKernelTrans.name(), psyclone.domain.gocean.transformations.gocean_opencl_trans.GOOpenCLTrans.name(), psyclone.domain.lfric.kernel.lfric_kernel_metadata.LFRicKernelMetadata.name, psyclone.domain.nemo.transformations.create_nemo_invoke_schedule_trans.CreateNemoInvokeScheduleTrans.name(), psyclone.domain.nemo.transformations.create_nemo_psy_trans.CreateNemoPSyTrans.name(), psyclone.domain.nemo.transformations.nemo_allarrayrange2loop_trans.NemoAllArrayRange2LoopTrans.name(), psyclone.domain.nemo.transformations.nemo_arrayrange2loop_trans.NemoArrayRange2LoopTrans.name(), psyclone.domain.nemo.transformations.nemo_outerarrayrange2loop_trans.NemoOuterArrayRange2LoopTrans.name(), psyclone.dynamo0p3.DynamoPSy.name(), psyclone.expression.FunctionVar.name, psyclone.expression.NamedArg.name(), psyclone.gocean1p0.GOKernelGridArgument.name(), psyclone.gocean1p0.GOStencil.name(), psyclone.parse.algorithm.FileInfo.name(), psyclone.parse.algorithm.InvokeCall.name(), psyclone.parse.kernel.KernelProcedure.name(), psyclone.parse.kernel.KernelType.name(), psyclone.parse.module_info.ModuleInfo.name(), psyclone.psyad.transformations.assignment_trans.AssignmentTrans.name(), psyclone.psyGen.PSy.name(), psyclone.psyGen.Invoke.name(), psyclone.psyGen.Kern.name(), psyclone.psyGen.CodedKern.name, psyclone.psyGen.Argument.name(), psyclone.psyGen.Transformation.name(), psyclone.psyGen.DummyTransformation.name(), psyclone.psyir.nodes.container.Container.name, psyclone.psyir.nodes.member.Member.name, psyclone.psyir.nodes.reference.Reference.name(), psyclone.psyir.nodes.routine.Routine.name, psyclone.psyir.symbols.symbol.Symbol.name(), psyclone.psyir.transformations.allarrayaccess2loop_trans.AllArrayAccess2LoopTrans.name(), psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.name(), psyclone.psyir.transformations.fold_conditional_return_expressions_trans.FoldConditionalReturnExpressionsTrans.name(), psyclone.psyir.transformations.loop_trans.LoopTrans.name(), psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans.name(), psyclone.psyir.transformations.psy_data_trans.PSyDataTrans.name(), psyclone.transformations.OMPSingleTrans.name(), psyclone.transformations.OMPMasterTrans.name(), psyclone.transformations.OMPParallelTrans.name(), psyclone.transformations.MoveTrans.name(), psyclone.transformations.Dynamo0p3AsyncHaloExchangeTrans.name(), psyclone.transformations.Dynamo0p3KernelConstTrans.name(), psyclone.transformations.ACCEnterDataTrans.name(), psyclone.transformations.ACCRoutineTrans.name(), psyclone.transformations.ACCKernelsTrans.name(), psyclone.transformations.ACCDataTrans.name(), psyclone.transformations.KernelImportsToArguments.name(), and psyclone.domain.lfric.lfric_kern.LFRicKern.validate_kernel_code_args().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_intergrid()

def psyclone.domain.lfric.lfric_kern.LFRicKern.is_intergrid (   self)
:return: True if it is an inter-grid kernel, False otherwise
:rtype: bool

Definition at line 390 of file lfric_kern.py.

390  def is_intergrid(self):
391  '''
392  :return: True if it is an inter-grid kernel, False otherwise
393  :rtype: bool
394  '''
395  return self._intergrid_ref is not None
396 

References psyclone.domain.lfric.lfric_kern.LFRicKern._intergrid_ref.

Here is the caller graph for this function:

◆ last_cell_all_colours_symbol()

def psyclone.domain.lfric.lfric_kern.LFRicKern.last_cell_all_colours_symbol (   self)
Getter for the symbol of the array holding the index of the last
cell of each colour.

:returns: name of the array.
:rtype: str

:raises InternalError: if this kernel is not coloured.

Definition at line 427 of file lfric_kern.py.

427  def last_cell_all_colours_symbol(self):
428  '''
429  Getter for the symbol of the array holding the index of the last
430  cell of each colour.
431 
432  :returns: name of the array.
433  :rtype: str
434 
435  :raises InternalError: if this kernel is not coloured.
436  '''
437  if not self.is_coloured():
438  raise InternalError(f"Kernel '{self.name}' is not inside a "
439  f"coloured loop.")
440 
441  if self.is_intergrid:
442  return self._intergrid_ref.last_cell_var_symbol
443 
444  ubnd_name = self.ancestor(Loop).upper_bound_name
445  const = LFRicConstants()
446 
447  if ubnd_name in const.HALO_ACCESS_LOOP_BOUNDS:
448  return self.scope.symbol_table.find_or_create_array(
449  "last_halo_cell_all_colours", 2,
450  ScalarType.Intrinsic.INTEGER,
451  tag="last_halo_cell_all_colours")
452 
453  return self.scope.symbol_table.find_or_create_array(
454  "last_edge_cell_all_colours", 1,
455  ScalarType.Intrinsic.INTEGER,
456  tag="last_edge_cell_all_colours")
457 

References psyclone.domain.lfric.lfric_kern.LFRicKern._intergrid_ref, psyclone.psyir.nodes.node.Node.ancestor(), psyclone.psyGen.Kern.is_coloured(), psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn.is_intergrid(), psyclone.domain.lfric.lfric_kern.LFRicKern.is_intergrid(), psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata.is_intergrid(), psyclone.psyir.nodes.node.Node.scope(), and psyclone.psyir.symbols.symbol_table.SymbolTable.scope().

Here is the call graph for this function:

◆ load()

def psyclone.domain.lfric.lfric_kern.LFRicKern.load (   self,
  call,
  parent = None 
)
Sets up kernel information with the call object which is
created by the parser. This object includes information about
the invoke call and the associated kernel.

:param call: The KernelCall object from which to extract information
             about this kernel
:type call: :py:class:`psyclone.parse.algorithm.KernelCall`
:param parent: The parent node of the kernel call in the AST
               we are constructing. This will be a loop.
:type parent: :py:class:`psyclone.domain.lfric.LFRicLoop`

Definition at line 139 of file lfric_kern.py.

139  def load(self, call, parent=None):
140  '''
141  Sets up kernel information with the call object which is
142  created by the parser. This object includes information about
143  the invoke call and the associated kernel.
144 
145  :param call: The KernelCall object from which to extract information
146  about this kernel
147  :type call: :py:class:`psyclone.parse.algorithm.KernelCall`
148  :param parent: The parent node of the kernel call in the AST
149  we are constructing. This will be a loop.
150  :type parent: :py:class:`psyclone.domain.lfric.LFRicLoop`
151  '''
152  self._setup_basis(call.ktype)
153  self._setup(call.ktype, call.module_name, call.args, parent)
154 

References psyclone.domain.lfric.lfric_kern.LFRicKern._setup(), and psyclone.domain.lfric.lfric_kern.LFRicKern._setup_basis().

Here is the call graph for this function:

◆ load_meta()

def psyclone.domain.lfric.lfric_kern.LFRicKern.load_meta (   self,
  ktype 
)
Sets up kernel information with the kernel type object
which is created by the parser. The object includes the
metadata describing the kernel code.

:param ktype: the kernel metadata object produced by the parser
:type ktype: :py:class:`psyclone.domain.lfric.LFRicKernMetadata`

:raises InternalError: for an invalid data type of a scalar argument.
:raises GenerationError: if an invalid argument type is found \
                         in the kernel.

Definition at line 155 of file lfric_kern.py.

155  def load_meta(self, ktype):
156  '''
157  Sets up kernel information with the kernel type object
158  which is created by the parser. The object includes the
159  metadata describing the kernel code.
160 
161  :param ktype: the kernel metadata object produced by the parser
162  :type ktype: :py:class:`psyclone.domain.lfric.LFRicKernMetadata`
163 
164  :raises InternalError: for an invalid data type of a scalar argument.
165  :raises GenerationError: if an invalid argument type is found \
166  in the kernel.
167 
168  '''
169  # pylint: disable=too-many-branches
170  # Create a name for each argument
171  args = []
172  const = LFRicConstants()
173  for idx, descriptor in enumerate(ktype.arg_descriptors):
174  pre = None
175  if descriptor.argument_type.lower() == "gh_operator":
176  pre = "op_"
177  elif descriptor.argument_type.lower() == "gh_columnwise_operator":
178  pre = "cma_op_"
179  elif descriptor.argument_type.lower() == "gh_field":
180  pre = "field_"
181  elif (descriptor.argument_type.lower() in
182  const.VALID_SCALAR_NAMES):
183  if descriptor.data_type.lower() == "gh_real":
184  pre = "rscalar_"
185  elif descriptor.data_type.lower() == "gh_integer":
186  pre = "iscalar_"
187  elif descriptor.data_type.lower() == "gh_logical":
188  pre = "lscalar_"
189  else:
190  raise InternalError(
191  f"Expected one of {const.VALID_SCALAR_DATA_TYPES} "
192  f"data types for a scalar argument but found "
193  f"'{descriptor.data_type}'.")
194  else:
195  raise GenerationError(
196  f"LFRicKern.load_meta() expected one of "
197  f"{const.VALID_ARG_TYPE_NAMES} but found "
198  f"'{descriptor.argument_type}'")
199  args.append(Arg("variable", pre+str(idx+1)))
200 
201  if descriptor.stencil:
202  if not descriptor.stencil["extent"]:
203  # Stencil size (in cells) is passed in
204  args.append(Arg("variable",
205  pre+str(idx+1)+"_stencil_size"))
206  if descriptor.stencil["type"] == "xory1d":
207  # Direction is passed in
208  args.append(Arg("variable", pre+str(idx+1)+"_direction"))
209 
210  # Initialise basis/diff basis so we can test whether quadrature
211  # or an evaluator is required
212  self._setup_basis(ktype)
213  if self._basis_required:
214  for shape in self._eval_shapes:
215  if shape in const.VALID_QUADRATURE_SHAPES:
216  # Add a quadrature argument for each required quadrature
217  # rule.
218  args.append(Arg("variable", "qr_"+shape))
219  self._setup(ktype, "dummy_name", args, None, check=False)
220 

References psyclone.domain.lfric.lfric_kern.LFRicKern._base_name, psyclone.domain.lfric.lfric_kern.LFRicKern._basis_required, psyclone.domain.lfric.lfric_kern.LFRicKern._cma_operation, psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._cma_operation, psyclone.domain.lfric.lfric_kern.LFRicKern._eval_shapes, psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._eval_shapes, psyclone.domain.lfric.lfric_kern.LFRicKern._eval_targets, psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._eval_targets, psyclone.dynamo0p3.DynBasisFunctions._eval_targets, psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn._fs_descriptors, psyclone.domain.lfric.lfric_kern.LFRicKern._fs_descriptors, psyclone.psyGen.BuiltIn._fs_descriptors, psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn._func_descriptors, psyclone.domain.lfric.lfric_kern.LFRicKern._func_descriptors, psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata._func_descriptors, psyclone.psyGen.BuiltIn._func_descriptors, psyclone.domain.lfric.lfric_kern.LFRicKern._intergrid_ref, psyclone.domain.lfric.lfric_kern.LFRicKern._mesh_properties, psyclone.domain.lfric.metadata_to_arguments_rules.MetadataToArgumentsRules._mesh_properties(), psyclone.domain.lfric.lfric_kern.LFRicKern._qr_rules, psyclone.domain.lfric.kernel.meta_ref_element_arg_metadata.MetaRefElementArgMetadata._reference_element, psyclone.domain.lfric.lfric_kern.LFRicKern._reference_element, psyclone.domain.lfric.lfric_kern.LFRicKern._setup(), psyclone.domain.lfric.lfric_kern.LFRicKern._setup_basis(), psyclone.psyir.nodes.node.Node.ancestor(), psyclone.psyGen.Kern.arguments(), psyclone.psyir.nodes.call.Call.arguments(), psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg.name, psyclone.domain.gocean.transformations.gocean_const_loop_bounds_trans.GOConstLoopBoundsTrans.name(), psyclone.domain.gocean.transformations.gocean_move_iteration_boundaries_inside_kernel_trans.GOMoveIterationBoundariesInsideKernelTrans.name(), psyclone.domain.gocean.transformations.gocean_opencl_trans.GOOpenCLTrans.name(), psyclone.domain.lfric.kernel.lfric_kernel_metadata.LFRicKernelMetadata.name, psyclone.domain.nemo.transformations.create_nemo_invoke_schedule_trans.CreateNemoInvokeScheduleTrans.name(), psyclone.domain.nemo.transformations.create_nemo_psy_trans.CreateNemoPSyTrans.name(), psyclone.domain.nemo.transformations.nemo_allarrayrange2loop_trans.NemoAllArrayRange2LoopTrans.name(), psyclone.domain.nemo.transformations.nemo_arrayrange2loop_trans.NemoArrayRange2LoopTrans.name(), psyclone.domain.nemo.transformations.nemo_outerarrayrange2loop_trans.NemoOuterArrayRange2LoopTrans.name(), psyclone.dynamo0p3.DynamoPSy.name(), psyclone.expression.FunctionVar.name, psyclone.expression.NamedArg.name(), psyclone.gocean1p0.GOKernelGridArgument.name(), psyclone.gocean1p0.GOStencil.name(), psyclone.parse.algorithm.FileInfo.name(), psyclone.parse.algorithm.InvokeCall.name(), psyclone.parse.kernel.KernelProcedure.name(), psyclone.parse.kernel.KernelType.name(), psyclone.parse.module_info.ModuleInfo.name(), psyclone.psyad.transformations.assignment_trans.AssignmentTrans.name(), psyclone.psyGen.PSy.name(), psyclone.psyGen.Invoke.name(), psyclone.psyGen.Kern.name(), psyclone.psyGen.CodedKern.name, psyclone.psyGen.Argument.name(), psyclone.psyGen.Transformation.name(), psyclone.psyGen.DummyTransformation.name(), psyclone.psyir.nodes.container.Container.name, psyclone.psyir.nodes.member.Member.name, psyclone.psyir.nodes.reference.Reference.name(), psyclone.psyir.nodes.routine.Routine.name, psyclone.psyir.symbols.symbol.Symbol.name(), psyclone.psyir.transformations.allarrayaccess2loop_trans.AllArrayAccess2LoopTrans.name(), psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.name(), psyclone.psyir.transformations.fold_conditional_return_expressions_trans.FoldConditionalReturnExpressionsTrans.name(), psyclone.psyir.transformations.loop_trans.LoopTrans.name(), psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans.name(), psyclone.psyir.transformations.psy_data_trans.PSyDataTrans.name(), psyclone.transformations.OMPSingleTrans.name(), psyclone.transformations.OMPMasterTrans.name(), psyclone.transformations.OMPParallelTrans.name(), psyclone.transformations.MoveTrans.name(), psyclone.transformations.Dynamo0p3AsyncHaloExchangeTrans.name(), psyclone.transformations.Dynamo0p3KernelConstTrans.name(), psyclone.transformations.ACCEnterDataTrans.name(), psyclone.transformations.ACCRoutineTrans.name(), psyclone.transformations.ACCKernelsTrans.name(), psyclone.transformations.ACCDataTrans.name(), psyclone.transformations.KernelImportsToArguments.name(), and psyclone.domain.lfric.lfric_kern.LFRicKern.QRRule.

Here is the call graph for this function:

◆ mesh()

def psyclone.domain.lfric.lfric_kern.LFRicKern.mesh (   self)
:returns: the mesh properties required by this kernel.
:rtype: :py:class`psyclone.dynamo0p3.MeshPropertiesMetaData`

Definition at line 530 of file lfric_kern.py.

530  def mesh(self):
531  '''
532  :returns: the mesh properties required by this kernel.
533  :rtype: :py:class`psyclone.dynamo0p3.MeshPropertiesMetaData`
534  '''
535  return self._mesh_properties
536 

References psyclone.domain.lfric.lfric_kern.LFRicKern._mesh_properties, and psyclone.domain.lfric.metadata_to_arguments_rules.MetadataToArgumentsRules._mesh_properties().

Here is the call graph for this function:

◆ ncolours_var()

def psyclone.domain.lfric.lfric_kern.LFRicKern.ncolours_var (   self)
Getter for the name of the variable holding the number of colours
associated with this kernel call.

:return: name of the variable holding the number of colours
:rtype: Optional[str]

:raises InternalError: if this kernel is not coloured.

Definition at line 459 of file lfric_kern.py.

459  def ncolours_var(self):
460  '''
461  Getter for the name of the variable holding the number of colours
462  associated with this kernel call.
463 
464  :return: name of the variable holding the number of colours
465  :rtype: Optional[str]
466 
467  :raises InternalError: if this kernel is not coloured.
468  '''
469  if not self.is_coloured():
470  raise InternalError(f"Kernel '{self.name}' is not inside a "
471  f"coloured loop.")
472  if self.is_intergrid:
473  ncols_sym = self._intergrid_ref.ncolours_var_symbol
474  if not ncols_sym:
475  return None
476  return ncols_sym.name
477 
478  return self.scope.symbol_table.lookup_with_tag("ncolour").name
479 

References psyclone.domain.lfric.lfric_kern.LFRicKern._intergrid_ref, psyclone.psyGen.Kern.is_coloured(), psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn.is_intergrid(), psyclone.domain.lfric.lfric_kern.LFRicKern.is_intergrid(), psyclone.domain.lfric.lfric_kern_metadata.LFRicKernMetadata.is_intergrid(), psyclone.psyir.nodes.node.Node.scope(), and psyclone.psyir.symbols.symbol_table.SymbolTable.scope().

Here is the call graph for this function:

◆ qr_required()

def psyclone.domain.lfric.lfric_kern.LFRicKern.qr_required (   self)
:return: True if this kernel requires quadrature, else returns False.
:rtype: bool

Definition at line 492 of file lfric_kern.py.

492  def qr_required(self):
493  '''
494  :return: True if this kernel requires quadrature, else returns False.
495  :rtype: bool
496 
497  '''
498  return self._basis_required and self.qr_rules
499 

References psyclone.domain.lfric.lfric_kern.LFRicKern._basis_required, psyclone.domain.lfric.lfric_builtins.LFRicBuiltIn.qr_rules, and psyclone.domain.lfric.lfric_kern.LFRicKern.qr_rules().

Here is the call graph for this function:

◆ qr_rules()

def psyclone.domain.lfric.lfric_kern.LFRicKern.qr_rules (   self)
:return: details of each of the quadrature rules required by this \
         kernel.
:rtype: OrderedDict containing \
        :py:class:`psyclone.domain.lfric.LFRicKern.QRRule` indexed by \
        quadrature shape.

Definition at line 369 of file lfric_kern.py.

369  def qr_rules(self):
370  '''
371  :return: details of each of the quadrature rules required by this \
372  kernel.
373  :rtype: OrderedDict containing \
374  :py:class:`psyclone.domain.lfric.LFRicKern.QRRule` indexed by \
375  quadrature shape.
376  '''
377  return self._qr_rules
378 

References psyclone.domain.lfric.lfric_kern.LFRicKern._qr_rules.

Here is the caller graph for this function:

◆ reference_accesses()

def psyclone.domain.lfric.lfric_kern.LFRicKern.reference_accesses (   self,
  var_accesses 
)
Get all variable access information. All accesses are marked
according to the kernel metadata

:param var_accesses: VariablesAccessInfo instance that stores the \
    information about variable accesses.
:type var_accesses: \
    :py:class:`psyclone.core.VariablesAccessInfo`

Reimplemented from psyclone.psyGen.Kern.

Definition at line 119 of file lfric_kern.py.

119  def reference_accesses(self, var_accesses):
120  '''Get all variable access information. All accesses are marked
121  according to the kernel metadata
122 
123  :param var_accesses: VariablesAccessInfo instance that stores the \
124  information about variable accesses.
125  :type var_accesses: \
126  :py:class:`psyclone.core.VariablesAccessInfo`
127 
128  '''
129  # Use the KernelCallArgList class, which can also provide variable
130  # access information:
131  create_arg_list = KernCallArgList(self)
132  create_arg_list.generate(var_accesses)
133 
134  super().reference_accesses(var_accesses)
135  # Set the current location index to the next location, since after
136  # this kernel a new statement starts.
137  var_accesses.next_location()
138 
Here is the caller graph for this function:

◆ reference_element()

def psyclone.domain.lfric.lfric_kern.LFRicKern.reference_element (   self)
:returns: the reference-element properties required by this kernel.
:rtype: :py:class:`psyclone.dynamo0p3.RefElementMetaData`

Definition at line 522 of file lfric_kern.py.

522  def reference_element(self):
523  '''
524  :returns: the reference-element properties required by this kernel.
525  :rtype: :py:class:`psyclone.dynamo0p3.RefElementMetaData`
526  '''
527  return self._reference_element
528 

References psyclone.domain.lfric.kernel.meta_ref_element_arg_metadata.MetaRefElementArgMetadata._reference_element, and psyclone.domain.lfric.lfric_kern.LFRicKern._reference_element.

◆ validate_global_constraints()

def psyclone.domain.lfric.lfric_kern.LFRicKern.validate_global_constraints (   self)
Perform validation checks for any global constraints (that require the
tree to be complete).

:raises GenerationError: if this kernel does not have a supported
                operates-on (currently only "cell_column").
:raises GenerationError: if the loop goes beyond the level 1
                halo and an operator is accessed.
:raises GenerationError: if a kernel in the loop has an inc access
                and the loop is not coloured but is within an OpenMP
                parallel region.

Definition at line 883 of file lfric_kern.py.

883  def validate_global_constraints(self):
884  '''
885  Perform validation checks for any global constraints (that require the
886  tree to be complete).
887 
888  :raises GenerationError: if this kernel does not have a supported
889  operates-on (currently only "cell_column").
890  :raises GenerationError: if the loop goes beyond the level 1
891  halo and an operator is accessed.
892  :raises GenerationError: if a kernel in the loop has an inc access
893  and the loop is not coloured but is within an OpenMP
894  parallel region.
895  '''
896  # Check operates-on (iteration space) before generating code
897  const = LFRicConstants()
898  if self.iterates_over not in const.USER_KERNEL_ITERATION_SPACES:
899  raise GenerationError(
900  f"The LFRic API supports calls to user-supplied kernels that "
901  f"operate on one of {const.USER_KERNEL_ITERATION_SPACES}, but "
902  f"kernel '{self.name}' operates on '{self.iterates_over}'.")
903 
904  # pylint: disable=import-outside-toplevel
905  from psyclone.domain.lfric import LFRicLoop
906  parent_loop = self.ancestor(LFRicLoop)
907 
908  # Check whether this kernel reads from an operator
909  op_args = parent_loop.args_filter(
910  arg_types=const.VALID_OPERATOR_NAMES,
911  arg_accesses=[AccessType.READ, AccessType.READWRITE])
912  if op_args:
913  # It does. We must check that our parent loop does not
914  # go beyond the L1 halo.
915  if (parent_loop.upper_bound_name == "cell_halo" and
916  parent_loop.upper_bound_halo_depth > 1):
917  raise GenerationError(
918  f"Kernel '{self._name}' reads from an operator and "
919  f"therefore cannot be used for cells beyond the level 1 "
920  f"halo. However the containing loop goes out to level "
921  f"{parent_loop.upper_bound_halo_depth}")
922 
923  if not self.is_coloured():
924  # This kernel call has not been coloured
925  # - is it OpenMP parallel, i.e. are we a child of
926  # an OpenMP directive?
927  if self.is_openmp_parallel():
928  try:
929  # It is OpenMP parallel - does it have an argument
930  # with INC access?
931  _ = self.incremented_arg()
932  raise GenerationError(f"Kernel '{self._name}' has an "
933  f"argument with INC access and "
934  f"therefore must be coloured in "
935  f"order to be parallelised with "
936  f"OpenMP.")
937  except FieldNotFoundError:
938  pass
939 
940  super().validate_global_constraints()
941 
942 
943 # ---------- Documentation utils -------------------------------------------- #
944 # The list of module members that we wish AutoAPI to generate
945 # documentation for. (See https://psyclone-ref.readthedocs.io)

References psyclone.psyir.nodes.node.Node.ancestor(), psyclone.psyGen.CodedKern.incremented_arg(), psyclone.psyGen.Kern.is_coloured(), psyclone.psyir.nodes.node.Node.is_openmp_parallel(), psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.iterates_over, psyclone.parse.kernel.KernelType.iterates_over(), and psyclone.psyGen.Kern.iterates_over().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_kernel_code_args()

def psyclone.domain.lfric.lfric_kern.LFRicKern.validate_kernel_code_args (   self,
  table 
)
Check that the arguments in the kernel code match the expected
arguments as defined by the kernel metadata and the LFRic
API.

:param table: the symbol table to validate against the metadata.
:type table: :py:class:`psyclone.psyir.symbols.SymbolTable`

:raises GenerationError: if the number of arguments indicated by the \
    kernel metadata doesn't match the actual number of arguments in \
    the symbol table.

Definition at line 711 of file lfric_kern.py.

711  def validate_kernel_code_args(self, table):
712  '''Check that the arguments in the kernel code match the expected
713  arguments as defined by the kernel metadata and the LFRic
714  API.
715 
716  :param table: the symbol table to validate against the metadata.
717  :type table: :py:class:`psyclone.psyir.symbols.SymbolTable`
718 
719  :raises GenerationError: if the number of arguments indicated by the \
720  kernel metadata doesn't match the actual number of arguments in \
721  the symbol table.
722 
723  '''
724  # Get the kernel subroutine arguments
725  kern_code_args = table.argument_list
726 
727  # Get the kernel code interface according to the kernel
728  # metadata and LFRic API
729  interface_info = KernelInterface(self)
730  interface_info.generate()
731  interface_args = interface_info.arglist
732 
733  # 1: Check the the number of arguments match
734  actual_n_args = len(kern_code_args)
735  expected_n_args = len(interface_args)
736  if actual_n_args != expected_n_args:
737  raise GenerationError(
738  f"In kernel '{self.name}' the number of arguments indicated by"
739  f" the kernel metadata is {expected_n_args} but the actual "
740  f"number of kernel arguments found is {actual_n_args}.")
741 
742  # 2: Check that the properties of each argument match.
743  for idx, kern_code_arg in enumerate(kern_code_args):
744  interface_arg = interface_args[idx]
745  try:
746  alg_idx = interface_info.metadata_index_from_actual_index(idx)
747  alg_arg = self.arguments.args[alg_idx]
748  except KeyError:
749  # There's no algorithm argument directly associated with this
750  # kernel argument. (We only care about the data associated
751  # with scalar, field and operator arguments.)
752  alg_arg = None
753  self._validate_kernel_code_arg(kern_code_arg, interface_arg,
754  alg_arg)
755 

References psyclone.domain.lfric.lfric_kern.LFRicKern._validate_kernel_code_arg(), psyclone.psyGen.Kern.arguments(), and psyclone.psyir.nodes.call.Call.arguments().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ QRRule

psyclone.domain.lfric.lfric_kern.LFRicKern.QRRule
static
Initial value:
= namedtuple("QRRule",
["alg_name", "psy_name", "kernel_args"])

Definition at line 75 of file lfric_kern.py.


The documentation for this class was generated from the following file: