Reference Guide  2.5.0
psyclone.gocean1p0.GOLoop Class Reference
Inheritance diagram for psyclone.gocean1p0.GOLoop:
Collaboration diagram for psyclone.gocean1p0.GOLoop:

Public Member Functions

def __init__ (self, parent, loop_type="", field_name="", field_space="", iteration_space="", index_offset="")
 
def field_space (self)
 
def field_space (self, my_field_space)
 
def iteration_space (self)
 
def iteration_space (self, it_space)
 
def bounds_lookup (self)
 
def independent_iterations (self, test_all_variables=False, signatures_to_ignore=None, dep_tools=None)
 
def create_halo_exchanges (self)
 
def get_custom_bound_string (self, side)
 
def upper_bound (self)
 
def lower_bound (self)
 
def gen_code (self, parent)
 
- Public Member Functions inherited from psyclone.domain.common.psylayer.psyloop.PSyLoop
def __init__ (self, valid_loop_types=None, **kwargs)
 
def __eq__ (self, other)
 
def dag_name (self)
 
def valid_loop_types (self)
 
def loop_type (self)
 
def loop_type (self, value)
 
def node_str (self, colour=True)
 
def field_name (self)
 
def field (self)
 
def field_name (self, my_field_name)
 
def kernel (self)
 
def kernel (self, kern)
 
def __str__ (self)
 
def has_inc_arg (self)
 
def unique_modified_args (self, arg_type)
 
def unique_fields_with_halo_reads (self)
 
def args_filter (self, arg_types=None, arg_accesses=None, unique=False)
 
def gen_mark_halos_clean_dirty (self, parent)
 

Static Public Member Functions

def create (parent, loop_type, field_name="", field_space="", iteration_space="", index_offset="")
 
def setup_bounds ()
 
def add_bounds (bound_info)
 

Public Attributes

 loop_type
 
 field_name
 
 field_space
 
 iteration_space
 
 index_offset
 
 variable
 
- Public Attributes inherited from psyclone.domain.common.psylayer.psyloop.PSyLoop
 loop_type
 
 field
 
 field_name
 
 field_space
 
 iteration_space
 
 kernel
 

Detailed Description

 The GOcean specific PSyLoop class. This passes the GOcean specific
    single loop information to the base class so it creates the one we
    require. Adds a GOcean specific setBounds method which tells the loop
    what to iterate over. Need to harmonise with the topology_name method
    in the Dynamo api.

    :param parent: optional parent node (default None).
    :type parent: :py:class:`psyclone.psyir.nodes.Node`
    :param str loop_type: loop type - must be 'inner' or 'outer'.
    :param str field_name: name of the field this loop iterates on.
    :param str field_space: space of the field this loop iterates on.
    :param str iteration_space: iteration space of the loop.

    :raises GenerationError: if the loop is not inserted inside a \
        GOInvokeSchedule region.

Definition at line 331 of file gocean1p0.py.

Member Function Documentation

◆ add_bounds()

def psyclone.gocean1p0.GOLoop.add_bounds (   bound_info)
static
Adds a new iteration space to PSyclone. An iteration space in the
gocean1.0 API is for a certain offset type and field type. It defines
the loop boundaries for the outer and inner loop. The format is a
":" separated tuple:

>>> bound_info = offset-type:field-type:iteration-space:outer-start:
                 outer-stop:inner-start:inner-stop

Example:

>>> bound_info = go_offset_ne:go_ct:go_all_pts:
                 {start}-1:{stop}+1:{start}:{stop}

The expressions {start} and {stop} will be replaced with the loop
indices that correspond to the inner points (i.e. non-halo or
boundary points) of the field. So the index {start}-1 is actually
on the halo / boundary.

:param str bound_info: A string that contains a ":" separated \
                       tuple with the iteration space definition.

:raises ValueError: if bound_info is not a string.
:raises ConfigurationError: if bound_info is not formatted correctly.

Definition at line 696 of file gocean1p0.py.

696  def add_bounds(bound_info):
697  # pylint: disable=too-many-locals
698  '''
699  Adds a new iteration space to PSyclone. An iteration space in the
700  gocean1.0 API is for a certain offset type and field type. It defines
701  the loop boundaries for the outer and inner loop. The format is a
702  ":" separated tuple:
703 
704  >>> bound_info = offset-type:field-type:iteration-space:outer-start:
705  outer-stop:inner-start:inner-stop
706 
707  Example:
708 
709  >>> bound_info = go_offset_ne:go_ct:go_all_pts:
710  {start}-1:{stop}+1:{start}:{stop}
711 
712  The expressions {start} and {stop} will be replaced with the loop
713  indices that correspond to the inner points (i.e. non-halo or
714  boundary points) of the field. So the index {start}-1 is actually
715  on the halo / boundary.
716 
717  :param str bound_info: A string that contains a ":" separated \
718  tuple with the iteration space definition.
719 
720  :raises ValueError: if bound_info is not a string.
721  :raises ConfigurationError: if bound_info is not formatted correctly.
722 
723  '''
724  if not isinstance(bound_info, str):
725  raise InternalError(f"The parameter 'bound_info' must be a "
726  f"string, got '{bound_info}' "
727  f"(type {type(bound_info)})")
728 
729  data = bound_info.split(":")
730  if len(data) != 7:
731  raise ConfigurationError(f"An iteration space must be in the form "
732  f"\"offset-type:field-type:"
733  f"iteration-space:outer-start:"
734  f"outer-stop:inner-start:inner-stop\"\n"
735  f"But got \"{bound_info}\"")
736 
737  if not GOLoop._bounds_lookup:
738  GOLoop.setup_bounds()
739 
740  # Check that all bound specifications (min and max index) are valid.
741  # ------------------------------------------------------------------
742  # Regular expression that finds stings surrounded by {}
743  bracket_regex = re.compile("{[^}]+}")
744  for bound in data[3:7]:
745  all_expr = bracket_regex.findall(bound)
746  for bracket_expr in all_expr:
747  if bracket_expr not in ["{start}", "{stop}"]:
748  raise ConfigurationError(f"Only '{{start}}' and "
749  f"'{{stop}}' are allowed as "
750  f"bracketed expression in an "
751  f"iteration space. But got "
752  f"{bracket_expr}")
753 
754  # We need to make sure the fparser is properly initialised, which
755  # typically has not yet happened when the config file is read.
756  # Otherwise the Nonlabel_Do_Stmt cannot parse valid expressions.
757  ParserFactory().create(std="f2008")
758 
759  # Test both the outer loop indices (index 3 and 4) and inner
760  # indices (index 5 and 6):
761  for bound in data[3:7]:
762  do_string = f"do i=1, {bound}"
763  # Now replace any {start}/{stop} expression in the loop
764  # with a valid integer value:
765  do_string = do_string.format(start='15', stop='25')
766  # Check if the do loop can be parsed as a nonlabel do loop
767  try:
768  _ = Nonlabel_Do_Stmt(do_string)
769  except NoMatchError as err:
770  raise ConfigurationError(f"Expression '{bound}' is not a "
771  f"valid do loop boundary. Error "
772  f"message: '{err}'.") from err
773 
774  # All tests successful, so add the new bounds:
775  # --------------------------------------------
776  current_bounds = GOLoop._bounds_lookup # Shortcut
777  # Check offset-type exists
778  if not data[0] in current_bounds:
779  current_bounds[data[0]] = {}
780 
781  # Check field-type exists
782  if not data[1] in current_bounds[data[0]]:
783  current_bounds[data[0]][data[1]] = {}
784 
785  const = GOceanConstants()
786  # Check iteration space exists:
787  if not data[2] in current_bounds[data[0]][data[1]]:
788  current_bounds[data[0]][data[1]][data[2]] = {}
789  const.VALID_ITERATES_OVER.append(data[2])
790 
791  current_bounds[data[0]][data[1]][data[2]] = \
792  {'outer': {'start': data[3], 'stop': data[4]},
793  'inner': {'start': data[5], 'stop': data[6]}}
794 

References psyclone.gocean1p0.GOLoop.create().

Here is the call graph for this function:

◆ bounds_lookup()

def psyclone.gocean1p0.GOLoop.bounds_lookup (   self)
:returns: the GOcean loop bounds lookup table. This is a \
          5-dimensional dictionary with index-offset, field-space, \
          iteration-space, loop-type, and boundary-side lookup keys \
          which provides information about how to construct the \
          loop boundaries for a kernel with such parameters.
:rtype: dict

Definition at line 506 of file gocean1p0.py.

506  def bounds_lookup(self):
507  '''
508  :returns: the GOcean loop bounds lookup table. This is a \
509  5-dimensional dictionary with index-offset, field-space, \
510  iteration-space, loop-type, and boundary-side lookup keys \
511  which provides information about how to construct the \
512  loop boundaries for a kernel with such parameters.
513  :rtype: dict
514  '''
515  return self._bounds_lookup
516 

References psyclone.gocean1p0.GOLoop._bounds_lookup.

Here is the caller graph for this function:

◆ create()

def psyclone.gocean1p0.GOLoop.create (   parent,
  loop_type,
  field_name = "",
  field_space = "",
  iteration_space = "",
  index_offset = "" 
)
static
Create a new instance of a GOLoop with the expected children to
represent the bounds given by the loop properties.

:param parent: parent node of this GOLoop.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:param str loop_type: loop type - must be 'inner' or 'outer'.
:param str field_name: name of the field this loop iterates on.
:param str field_space: space of the field this loop iterates on.
:param str iteration_space: iteration space of the loop.
:param str index_offset: the grid index offset used by the kernel(s) \
    within this loop.

:returns: a new GOLoop node (with appropriate child nodes).
:rtype: :py:class:`psyclone.gocean1p0.GOLoop`

Definition at line 402 of file gocean1p0.py.

403  iteration_space="", index_offset=""):
404  # pylint: disable=too-many-arguments,arguments-renamed
405  '''
406  Create a new instance of a GOLoop with the expected children to
407  represent the bounds given by the loop properties.
408 
409  :param parent: parent node of this GOLoop.
410  :type parent: :py:class:`psyclone.psyir.nodes.Node`
411  :param str loop_type: loop type - must be 'inner' or 'outer'.
412  :param str field_name: name of the field this loop iterates on.
413  :param str field_space: space of the field this loop iterates on.
414  :param str iteration_space: iteration space of the loop.
415  :param str index_offset: the grid index offset used by the kernel(s) \
416  within this loop.
417 
418  :returns: a new GOLoop node (with appropriate child nodes).
419  :rtype: :py:class:`psyclone.gocean1p0.GOLoop`
420  '''
421 
422  # Create loop node
423  node = GOLoop(parent, loop_type, field_name, field_space,
424  iteration_space, index_offset)
425 
426  # Add start, stop, step and body and Loop children
427  node.addchild(node.lower_bound())
428  node.addchild(node.upper_bound())
429  node.addchild(Literal("1", INTEGER_TYPE))
430  node.addchild(Schedule())
431 
432  return node
433 
Here is the caller graph for this function:

◆ create_halo_exchanges()

def psyclone.gocean1p0.GOLoop.create_halo_exchanges (   self)
Add halo exchanges before this loop as required by fields within
this loop. The PSyIR insertion logic is coded in the _add_halo_exchange
helper method. 

Definition at line 576 of file gocean1p0.py.

576  def create_halo_exchanges(self):
577  '''Add halo exchanges before this loop as required by fields within
578  this loop. The PSyIR insertion logic is coded in the _add_halo_exchange
579  helper method. '''
580 
581  for halo_field in self.unique_fields_with_halo_reads():
582  # for each unique field in this loop that has its halo
583  # read, find the previous update of this field.
584  prev_arg_list = halo_field.backward_write_dependencies()
585  if not prev_arg_list:
586  # field has no previous dependence so create new halo
587  # exchange(s) as we don't know the state of the fields
588  # halo on entry to the invoke
589  # TODO 856: If dl_es_inf supported an is_dirty flag, we could
590  # be more selective on which HaloEx are needed. This
591  # function then will be the same as in LFRic and therefore
592  # the code can maybe be generalised.
593  self._add_halo_exchange(halo_field)
594  else:
595  prev_node = prev_arg_list[0].call
596  if not isinstance(prev_node, HaloExchange):
597  # Previous dependence is not a halo exchange so one needs
598  # to be added to satisfy the dependency in distributed
599  # memory.
600  self._add_halo_exchange(halo_field)
601 

References psyclone.domain.lfric.lfric_loop.LFRicLoop._add_halo_exchange(), psyclone.gocean1p0.GOLoop._add_halo_exchange(), psyclone.f2pygen.BaseGen.parent(), psyclone.psyir.nodes.node.Node.parent(), psyclone.f2pygen.Directive.position(), psyclone.psyir.nodes.node.Node.position, and psyclone.domain.common.psylayer.psyloop.PSyLoop.unique_fields_with_halo_reads().

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

◆ field_space() [1/2]

def psyclone.gocean1p0.GOLoop.field_space (   self)
:returns: the loop's field space (e.g. CU, CV...).
:rtype: str

Reimplemented from psyclone.domain.common.psylayer.psyloop.PSyLoop.

Definition at line 435 of file gocean1p0.py.

435  def field_space(self):
436  '''
437  :returns: the loop's field space (e.g. CU, CV...).
438  :rtype: str
439  '''
440  return self._field_space
441 

References psyclone.domain.common.psylayer.psyloop.PSyLoop._field_space, psyclone.domain.lfric.lfric_loop.LFRicLoop._field_space, and psyclone.gocean1p0.GOLoop._field_space.

Here is the caller graph for this function:

◆ field_space() [2/2]

def psyclone.gocean1p0.GOLoop.field_space (   self,
  my_field_space 
)
 Sets new value for the field_space and updates the Loop bounds,
if these exist, to match the given field_space.

:param str my_field_space: new field_space value.

:raises TypeError: if the provided field_space is not a string.
:raises ValueError: if the provided field_space is not a valid GOcean \
                    field_space.

Reimplemented from psyclone.domain.common.psylayer.psyloop.PSyLoop.

Definition at line 443 of file gocean1p0.py.

443  def field_space(self, my_field_space):
444  ''' Sets new value for the field_space and updates the Loop bounds,
445  if these exist, to match the given field_space.
446 
447  :param str my_field_space: new field_space value.
448 
449  :raises TypeError: if the provided field_space is not a string.
450  :raises ValueError: if the provided field_space is not a valid GOcean \
451  field_space.
452 
453  '''
454  # TODO 1393: This could call the super setter if the validations are
455  # generic
456  if not isinstance(my_field_space, str):
457  raise TypeError(
458  f"Field space must be a 'str' but found "
459  f"'{type(my_field_space).__name__}' instead.")
460  valid_fs = GOceanConstants().VALID_FIELD_GRID_TYPES + ['']
461  if my_field_space not in valid_fs:
462  raise ValueError(
463  f"Invalid string '{my_field_space}' provided for a GOcean "
464  f"field_space. The valid values are {valid_fs}")
465 
466  self._field_space = my_field_space
467  if len(self.children) > 1:
468  self.start_expr.replace_with(self.lower_bound())
469  if len(self.children) > 2:
470  self.stop_expr.replace_with(self.upper_bound())
471 

References psyclone.domain.common.psylayer.psyloop.PSyLoop._field_space, psyclone.domain.lfric.lfric_loop.LFRicLoop._field_space, psyclone.gocean1p0.GOLoop._field_space, psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, psyclone.psyir.nodes.node.Node.children(), psyclone.gocean1p0.GOLoop.lower_bound(), psyclone.psyir.backend.sympy_writer.SymPyWriter.lower_bound(), psyclone.domain.lfric.lfric_loop.LFRicLoop.start_expr(), psyclone.psyir.nodes.loop.Loop.start_expr(), psyclone.domain.lfric.lfric_loop.LFRicLoop.stop_expr(), psyclone.psyir.nodes.loop.Loop.stop_expr(), psyclone.gocean1p0.GOLoop.upper_bound(), and psyclone.psyir.backend.sympy_writer.SymPyWriter.upper_bound().

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

◆ gen_code()

def psyclone.gocean1p0.GOLoop.gen_code (   self,
  parent 
)
 Create the f2pygen AST for this loop (and update the PSyIR
representing the loop bounds if necessary).

:param parent: the node in the f2pygen AST to which to add content.
:type parent: :py:class:`psyclone.f2pygen.SubroutineGen`

Definition at line 992 of file gocean1p0.py.

992  def gen_code(self, parent):
993  ''' Create the f2pygen AST for this loop (and update the PSyIR
994  representing the loop bounds if necessary).
995 
996  :param parent: the node in the f2pygen AST to which to add content.
997  :type parent: :py:class:`psyclone.f2pygen.SubroutineGen`
998 
999  '''
1000  # Check that it is a properly formed GOLoop
1001  self._validate_loop()
1002 
1003  super().gen_code(parent)
1004 
1005 
1006 # pylint: disable=too-few-public-methods

References psyclone.gocean1p0.GOLoop._validate_loop().

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

◆ get_custom_bound_string()

def psyclone.gocean1p0.GOLoop.get_custom_bound_string (   self,
  side 
)
Get the string that represents a customized custom bound for this
GOLoop (provided by the add_bounds() method). It can provide the
'start' or 'stop' side of the bounds.

:param str side: 'start' or 'stop' side of the bound.

:returns: the string that represents the loop bound.
:rtype: str

:raises GenerationError: if this node can not find a field in \
    the Invoke to be the base of the infrastructure call.
:raises GenerationError: if no expression is known to obtain the \
    boundaries for a loop of this characteristics, because they \
    are not in the GOcean lookup table or the loop type is not \
    `inner` or `outer`.

Definition at line 795 of file gocean1p0.py.

795  def get_custom_bound_string(self, side):
796  '''
797  Get the string that represents a customized custom bound for this
798  GOLoop (provided by the add_bounds() method). It can provide the
799  'start' or 'stop' side of the bounds.
800 
801  :param str side: 'start' or 'stop' side of the bound.
802 
803  :returns: the string that represents the loop bound.
804  :rtype: str
805 
806  :raises GenerationError: if this node can not find a field in \
807  the Invoke to be the base of the infrastructure call.
808  :raises GenerationError: if no expression is known to obtain the \
809  boundaries for a loop of this characteristics, because they \
810  are not in the GOcean lookup table or the loop type is not \
811  `inner` or `outer`.
812  '''
813  api_config = Config.get().api_conf("gocean1.0")
814  # Get a field argument from the argument list
815  field = None
816  invoke = self.ancestor(InvokeSchedule)
817  if invoke:
818  for arg in invoke.symbol_table.argument_list:
819  if isinstance(arg.datatype, DataTypeSymbol):
820  if arg.datatype.name == "r2d_field":
821  field = arg
822  break
823 
824  if field is None:
825  raise GenerationError(
826  f"Cannot generate custom loop bound for loop {self}. "
827  f"Couldn't find any suitable field.")
828 
829  if self.loop_type == "inner":
830  prop_access = api_config.grid_properties["go_grid_xstop"]
831  elif self.loop_type == "outer":
832  prop_access = api_config.grid_properties["go_grid_ystop"]
833  else:
834  raise GenerationError(
835  f"Invalid loop type of '{self.loop_type}'. Expected one of "
836  f"{GOceanConstants().VALID_LOOP_TYPES}")
837 
838  stop_expr = prop_access.fortran.format(field.name)
839  try:
840  bound = self.bounds_lookup[self.index_offset][self.field_space][
841  self.iteration_space][self.loop_type][side].format(
842  start='2', stop=stop_expr)
843  except KeyError as err:
844  raise GenerationError(
845  f"Cannot generate custom loop bound for a loop with an index-"
846  f"offset of '{self.index_offset}', a field-space of "
847  f"'{self.field_space}', an iteration-space of "
848  f"'{self.iteration_space}' and a loop-type of "
849  f"'{self.loop_type}', for the side '{side}' because "
850  f"this keys combination does not exist in the "
851  f"GOLoop.bounds_lookup table.") from err
852 
853  return bound
854 

References psyclone.psyir.nodes.node.Node.ancestor(), psyclone.gocean1p0.GOLoop.bounds_lookup(), psyclone.domain.common.psylayer.psyloop.PSyLoop.field_name, psyclone.gocean1p0.GOLoop.field_name, psyclone.domain.common.psylayer.psyloop.PSyLoop.field_space, psyclone.gocean1p0.GOLoop.field_space, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.index_offset, psyclone.gocean1p0.GOLoop.index_offset, psyclone.gocean1p0.GOKern.index_offset(), psyclone.gocean1p0.GOKernelType1p0.index_offset(), psyclone.domain.common.psylayer.psyloop.PSyLoop.iteration_space, psyclone.gocean1p0.GOLoop.iteration_space, psyclone.domain.common.psylayer.psyloop.PSyLoop.loop_type, psyclone.domain.lfric.lfric_loop.LFRicLoop.loop_type, psyclone.gocean1p0.GOLoop.loop_type, psyclone.psyir.nodes.loop.Loop.loop_type(), psyclone.psyir.nodes.node.Node.scope(), and psyclone.psyir.symbols.symbol_table.SymbolTable.scope().

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

◆ independent_iterations()

def psyclone.gocean1p0.GOLoop.independent_iterations (   self,
  test_all_variables = False,
  signatures_to_ignore = None,
  dep_tools = None 
)
This function is a GOcean-specific override of the default method
in the Loop class. It allows domain-specific rules to be applied when
determining whether or not loop iterations are independent.

:param bool test_all_variables: if True, it will test if all variable
    accesses are independent, otherwise it will stop after the first
    variable access is found that isn't.
:param signatures_to_ignore: list of signatures for which to skip
    the access checks.
:type signatures_to_ignore: Optional[
    List[:py:class:`psyclone.core.Signature`]]
:param dep_tools: an optional instance of DependencyTools so that the
    caller can access any diagnostic messages detailing why the loop
    iterations are not independent.
:type dep_tools: Optional[
    :py:class:`psyclone.psyir.tools.DependencyTools`]

:returns: True if the loop iterations are independent, False otherwise.
:rtype: bool

Definition at line 517 of file gocean1p0.py.

520  dep_tools=None):
521  '''
522  This function is a GOcean-specific override of the default method
523  in the Loop class. It allows domain-specific rules to be applied when
524  determining whether or not loop iterations are independent.
525 
526  :param bool test_all_variables: if True, it will test if all variable
527  accesses are independent, otherwise it will stop after the first
528  variable access is found that isn't.
529  :param signatures_to_ignore: list of signatures for which to skip
530  the access checks.
531  :type signatures_to_ignore: Optional[
532  List[:py:class:`psyclone.core.Signature`]]
533  :param dep_tools: an optional instance of DependencyTools so that the
534  caller can access any diagnostic messages detailing why the loop
535  iterations are not independent.
536  :type dep_tools: Optional[
537  :py:class:`psyclone.psyir.tools.DependencyTools`]
538 
539  :returns: True if the loop iterations are independent, False otherwise.
540  :rtype: bool
541 
542  '''
543  if not dep_tools:
544  dtools = DependencyTools()
545  else:
546  dtools = dep_tools
547 
548  try:
549  stat = dtools.can_loop_be_parallelised(
550  self, test_all_variables=test_all_variables,
551  signatures_to_ignore=signatures_to_ignore)
552  return stat
553  except InternalError:
554  # The dependence analysis in GOcean doesn't yet use PSyIR
555  # consistently and that causes failures - TODO #845.
556  return True
557 

◆ iteration_space() [1/2]

def psyclone.gocean1p0.GOLoop.iteration_space (   self)
:returns: the loop's iteration space (e.g. 'go_internal_pts', \
          'go_all_pts', ...).
:rtype: str

Reimplemented from psyclone.domain.common.psylayer.psyloop.PSyLoop.

Definition at line 473 of file gocean1p0.py.

473  def iteration_space(self):
474  '''
475  :returns: the loop's iteration space (e.g. 'go_internal_pts', \
476  'go_all_pts', ...).
477  :rtype: str
478  '''
479  return self._iteration_space
480 

References psyclone.domain.common.psylayer.psyloop.PSyLoop._iteration_space, psyclone.domain.lfric.lfric_loop.LFRicLoop._iteration_space, and psyclone.gocean1p0.GOLoop._iteration_space.

Here is the caller graph for this function:

◆ iteration_space() [2/2]

def psyclone.gocean1p0.GOLoop.iteration_space (   self,
  it_space 
)
 Sets new value for the iteration_space and updates the Loop bounds,
if these exist, to match the given iteration_space.

:param str it_space: new iteration_space value.

:raises TypeError: if the provided it_space is not a string.

Reimplemented from psyclone.domain.common.psylayer.psyloop.PSyLoop.

Definition at line 482 of file gocean1p0.py.

482  def iteration_space(self, it_space):
483  ''' Sets new value for the iteration_space and updates the Loop bounds,
484  if these exist, to match the given iteration_space.
485 
486  :param str it_space: new iteration_space value.
487 
488  :raises TypeError: if the provided it_space is not a string.
489 
490  '''
491  if not isinstance(it_space, str):
492  raise TypeError(
493  f"Iteration space must be a 'str' but found "
494  f"'{type(it_space).__name__}' instead.")
495 
496  # TODO 1393: We could validate also the value, but at the moment there
497  # are some ambiguities to resolve.
498 
499  self._iteration_space = it_space
500  if len(self.children) > 1:
501  self.start_expr.replace_with(self.lower_bound())
502  if len(self.children) > 2:
503  self.stop_expr.replace_with(self.upper_bound())
504 

References psyclone.domain.common.psylayer.psyloop.PSyLoop._iteration_space, psyclone.domain.lfric.lfric_loop.LFRicLoop._iteration_space, psyclone.gocean1p0.GOLoop._iteration_space, psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, psyclone.psyir.nodes.node.Node.children(), psyclone.gocean1p0.GOLoop.lower_bound(), psyclone.psyir.backend.sympy_writer.SymPyWriter.lower_bound(), psyclone.domain.lfric.lfric_loop.LFRicLoop.start_expr(), psyclone.psyir.nodes.loop.Loop.start_expr(), psyclone.domain.lfric.lfric_loop.LFRicLoop.stop_expr(), psyclone.psyir.nodes.loop.Loop.stop_expr(), psyclone.gocean1p0.GOLoop.upper_bound(), and psyclone.psyir.backend.sympy_writer.SymPyWriter.upper_bound().

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

◆ lower_bound()

def psyclone.gocean1p0.GOLoop.lower_bound (   self)
 Returns the lower bound of this loop as a string.

:returns: root of PSyIR sub-tree describing this lower bound.
:rtype: :py:class:`psyclone.psyir.nodes.Node`

Definition at line 928 of file gocean1p0.py.

928  def lower_bound(self):
929  ''' Returns the lower bound of this loop as a string.
930 
931  :returns: root of PSyIR sub-tree describing this lower bound.
932  :rtype: :py:class:`psyclone.psyir.nodes.Node`
933 
934  '''
935  if self.field_space == "go_every":
936  # Bounds are independent of the grid-offset convention in use
937  return Literal("1", INTEGER_TYPE)
938 
939  # Loop bounds are pulled from a infrastructure call from a field
940  # object. For 'go_internal_pts' and 'go_all_points' we use the
941  # 'internal' and 'whole' structures respectively. For other
942  # iteration_spaces we look if a custom expression is defined in the
943  # lookup table.
944  props = Config.get().api_conf("gocean1.0").grid_properties
945  if self.iteration_space.lower() == "go_internal_pts":
946  return self._grid_property_psyir_expression(
947  props[f"go_grid_internal_{self._loop_type}_start"].fortran)
948  if self.iteration_space.lower() == "go_all_pts":
949  return self._grid_property_psyir_expression(
950  props[f"go_grid_whole_{self._loop_type}_start"].fortran)
951  bound_str = self.get_custom_bound_string("start")
952  return FortranReader().psyir_from_expression(
953  bound_str, self.ancestor(GOInvokeSchedule).symbol_table)
954 

References psyclone.gocean1p0.GOLoop._grid_property_psyir_expression(), psyclone.psyir.nodes.node.Node.ancestor(), psyclone.domain.common.psylayer.psyloop.PSyLoop.field_space, psyclone.gocean1p0.GOLoop.field_space, psyclone.gocean1p0.GOLoop.get_custom_bound_string(), psyclone.domain.common.psylayer.psyloop.PSyLoop.iteration_space, psyclone.gocean1p0.GOLoop.iteration_space, and psyclone.psyir.nodes.node.Node.walk().

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

◆ setup_bounds()

def psyclone.gocean1p0.GOLoop.setup_bounds ( )
static
Populates the GOLoop._bounds_lookup dictionary. This is
used by PSyclone to look up the loop boundaries for each loop
it creates.

Definition at line 616 of file gocean1p0.py.

616  def setup_bounds():
617  '''Populates the GOLoop._bounds_lookup dictionary. This is
618  used by PSyclone to look up the loop boundaries for each loop
619  it creates.
620 
621  '''
622  const = GOceanConstants()
623  for grid_offset in const.SUPPORTED_OFFSETS:
624  GOLoop._bounds_lookup[grid_offset] = {}
625  for gridpt_type in const.VALID_FIELD_GRID_TYPES:
626  GOLoop._bounds_lookup[grid_offset][gridpt_type] = {}
627  for itspace in const.VALID_ITERATES_OVER:
628  GOLoop._bounds_lookup[grid_offset][gridpt_type][
629  itspace] = {}
630 
631  # Loop bounds for a mesh with NE offset
632  GOLoop._bounds_lookup['go_offset_ne']['go_ct']['go_all_pts'] = \
633  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
634  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
635  GOLoop._bounds_lookup['go_offset_ne']['go_ct']['go_internal_pts'] = \
636  {'inner': {'start': "{start}", 'stop': "{stop}"},
637  'outer': {'start': "{start}", 'stop': "{stop}"}}
638  GOLoop._bounds_lookup['go_offset_ne']['go_cu']['go_all_pts'] = \
639  {'inner': {'start': "{start}-1", 'stop': "{stop}"},
640  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
641  GOLoop._bounds_lookup['go_offset_ne']['go_cu']['go_internal_pts'] = \
642  {'inner': {'start': "{start}", 'stop': "{stop}-1"},
643  'outer': {'start': "{start}", 'stop': "{stop}"}}
644  GOLoop._bounds_lookup['go_offset_ne']['go_cv']['go_all_pts'] = \
645  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
646  'outer': {'start': "{start}-1", 'stop': "{stop}"}}
647  GOLoop._bounds_lookup['go_offset_ne']['go_cv']['go_internal_pts'] = \
648  {'inner': {'start': "{start}", 'stop': "{stop}"},
649  'outer': {'start': "{start}", 'stop': "{stop}-1"}}
650  GOLoop._bounds_lookup['go_offset_ne']['go_cf']['go_all_pts'] = \
651  {'inner': {'start': "{start}-1", 'stop': "{stop}"},
652  'outer': {'start': "{start}-1", 'stop': "{stop}"}}
653  GOLoop._bounds_lookup['go_offset_ne']['go_cf']['go_internal_pts'] = \
654  {'inner': {'start': "{start}-1", 'stop': "{stop}-1"},
655  'outer': {'start': "{start}-1", 'stop': "{stop}-1"}}
656  # Loop bounds for a mesh with SE offset
657  GOLoop._bounds_lookup['go_offset_sw']['go_ct']['go_all_pts'] = \
658  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
659  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
660  GOLoop._bounds_lookup['go_offset_sw']['go_ct']['go_internal_pts'] = \
661  {'inner': {'start': "{start}", 'stop': "{stop}"},
662  'outer': {'start': "{start}", 'stop': "{stop}"}}
663  GOLoop._bounds_lookup['go_offset_sw']['go_cu']['go_all_pts'] = \
664  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
665  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
666  GOLoop._bounds_lookup['go_offset_sw']['go_cu']['go_internal_pts'] = \
667  {'inner': {'start': "{start}", 'stop': "{stop}+1"},
668  'outer': {'start': "{start}", 'stop': "{stop}"}}
669  GOLoop._bounds_lookup['go_offset_sw']['go_cv']['go_all_pts'] = \
670  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
671  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
672  GOLoop._bounds_lookup['go_offset_sw']['go_cv']['go_internal_pts'] = \
673  {'inner': {'start': "{start}", 'stop': "{stop}"},
674  'outer': {'start': "{start}", 'stop': "{stop}+1"}}
675  GOLoop._bounds_lookup['go_offset_sw']['go_cf']['go_all_pts'] = \
676  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
677  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
678  GOLoop._bounds_lookup['go_offset_sw']['go_cf']['go_internal_pts'] = \
679  {'inner': {'start': "{start}", 'stop': "{stop}+1"},
680  'outer': {'start': "{start}", 'stop': "{stop}+1"}}
681  # For offset 'any'
682  for gridpt_type in const.VALID_FIELD_GRID_TYPES:
683  for itspace in const.VALID_ITERATES_OVER:
684  GOLoop._bounds_lookup['go_offset_any'][gridpt_type][itspace] =\
685  {'inner': {'start': "{start}-1", 'stop': "{stop}"},
686  'outer': {'start': "{start}-1", 'stop': "{stop}"}}
687  # For 'every' grid-point type
688  for offset in const.SUPPORTED_OFFSETS:
689  for itspace in const.VALID_ITERATES_OVER:
690  GOLoop._bounds_lookup[offset]['go_every'][itspace] = \
691  {'inner': {'start': "{start}-1", 'stop': "{stop}+1"},
692  'outer': {'start': "{start}-1", 'stop': "{stop}+1"}}
693 

◆ upper_bound()

def psyclone.gocean1p0.GOLoop.upper_bound (   self)
 Creates the PSyIR of the upper bound of this loop.

:returns: the PSyIR for the upper bound of this loop.
:rtype: :py:class:`psyclone.psyir.nodes.Node`

Definition at line 888 of file gocean1p0.py.

888  def upper_bound(self):
889  ''' Creates the PSyIR of the upper bound of this loop.
890 
891  :returns: the PSyIR for the upper bound of this loop.
892  :rtype: :py:class:`psyclone.psyir.nodes.Node`
893 
894  '''
895  if self.field_space == "go_every":
896  # Bounds are independent of the grid-offset convention in use
897  # We look-up the upper bounds by enquiring about the SIZE of
898  # the array itself
899  stop = IntrinsicCall(IntrinsicCall.Intrinsic.SIZE)
900  # Use the data property to access the member of the field that
901  # contains the actual grid points.
902  api_config = Config.get().api_conf("gocean1.0")
903  sref = self._grid_property_psyir_expression(
904  api_config.grid_properties["go_grid_data"].fortran)
905  stop.addchild(sref)
906  if self._loop_type == "inner":
907  stop.addchild(Literal("1", INTEGER_TYPE, parent=stop))
908  elif self._loop_type == "outer":
909  stop.addchild(Literal("2", INTEGER_TYPE, parent=stop))
910  return stop
911 
912  # Loop bounds are pulled from a infrastructure call from a field
913  # object. For 'go_internal_pts' and 'go_all_points' we use the
914  # 'internal' and 'whole' structures respectively. For other
915  # iteration_spaces we look if a custom expression is defined in the
916  # lookup table.
917  props = Config.get().api_conf("gocean1.0").grid_properties
918  if self.iteration_space.lower() == "go_internal_pts":
919  return self._grid_property_psyir_expression(
920  props[f"go_grid_internal_{self._loop_type}_stop"].fortran)
921  if self.iteration_space.lower() == "go_all_pts":
922  return self._grid_property_psyir_expression(
923  props[f"go_grid_whole_{self._loop_type}_stop"].fortran)
924  bound_str = self.get_custom_bound_string("stop")
925  return FortranReader().psyir_from_expression(
926  bound_str, self.ancestor(GOInvokeSchedule).symbol_table)
927 

References psyclone.gocean1p0.GOLoop._grid_property_psyir_expression(), psyclone.domain.common.psylayer.psyloop.PSyLoop._loop_type, psyclone.domain.lfric.lfric_loop.LFRicLoop._loop_type, psyclone.gocean1p0.GOLoop._loop_type, psyclone.psyir.nodes.node.Node.ancestor(), psyclone.domain.common.psylayer.psyloop.PSyLoop.field_space, psyclone.gocean1p0.GOLoop.field_space, psyclone.gocean1p0.GOLoop.get_custom_bound_string(), psyclone.domain.common.psylayer.psyloop.PSyLoop.iteration_space, and psyclone.gocean1p0.GOLoop.iteration_space.

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

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