Reference Guide  2.5.0
psyclone.dynamo0p3.LFRicHaloExchange Class Reference
Inheritance diagram for psyclone.dynamo0p3.LFRicHaloExchange:
Collaboration diagram for psyclone.dynamo0p3.LFRicHaloExchange:

Public Member Functions

def __init__ (self, field, check_dirty=True, vector_index=None, parent=None)
 
def required (self, ignore_hex_dep=False)
 
def node_str (self, colour=True)
 
def gen_code (self, parent)
 
def lower_to_language_level (self)
 
- Public Member Functions inherited from psyclone.psyGen.HaloExchange
def vector_index (self)
 
def halo_depth (self)
 
def halo_depth (self, value)
 
def field (self)
 
def dag_name (self)
 
def args (self)
 
def check_vector_halos_differ (self, node)
 

Additional Inherited Members

- Public Attributes inherited from psyclone.psyGen.HaloExchange
 vector_index
 

Detailed Description

Dynamo specific halo exchange class which can be added to and
manipulated in a schedule.

:param field: the field that this halo exchange will act on
:type field: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
:param check_dirty: optional argument default True indicating \
whether this halo exchange should be subject to a run-time check \
for clean/dirty halos.
:type check_dirty: bool
:param vector_index: optional vector index (default None) to \
identify which index of a vector field this halo exchange is \
responsible for
:type vector_index: int
:param parent: optional PSyIRe parent node (default None) of this \
object
:type parent: :py:class:`psyclone.psyir.nodes.Node`

Definition at line 3796 of file dynamo0p3.py.

Member Function Documentation

◆ gen_code()

def psyclone.dynamo0p3.LFRicHaloExchange.gen_code (   self,
  parent 
)
Dynamo specific code generation for this class.

:param parent: an f2pygen object that will be the parent of \
f2pygen objects created in this method
:type parent: :py:class:`psyclone.f2pygen.BaseGen`

Definition at line 4197 of file dynamo0p3.py.

4197  def gen_code(self, parent):
4198  '''Dynamo specific code generation for this class.
4199 
4200  :param parent: an f2pygen object that will be the parent of \
4201  f2pygen objects created in this method
4202  :type parent: :py:class:`psyclone.f2pygen.BaseGen`
4203 
4204  '''
4205  parent.add(PSyIRGen(parent, self))
4206 
Here is the caller graph for this function:

◆ lower_to_language_level()

def psyclone.dynamo0p3.LFRicHaloExchange.lower_to_language_level (   self)
:returns: this node lowered to language-level PSyIR.
:rtype: :py:class:`psyclone.psyir.nodes.Node`

Definition at line 4207 of file dynamo0p3.py.

4207  def lower_to_language_level(self):
4208  '''
4209  :returns: this node lowered to language-level PSyIR.
4210  :rtype: :py:class:`psyclone.psyir.nodes.Node`
4211  '''
4212  symbol = DataSymbol(self._field.proxy_name, UnresolvedType())
4213  method = self._halo_exchange_name
4214  depth_expr = self._psyir_depth_expression()
4215 
4216  # Create infrastructure Calls
4217  if self.vector_index:
4218  idx = Literal(str(self.vector_index), INTEGER_TYPE)
4219  if_condition = Call.create(
4220  ArrayOfStructuresReference.create(symbol, [idx], ['is_dirty']),
4221  [('depth', depth_expr)])
4222  if_body = Call.create(
4223  ArrayOfStructuresReference.create(
4224  symbol, [idx.copy()], [method]),
4225  [('depth', depth_expr.copy())])
4226  else:
4227  if_condition = Call.create(
4228  StructureReference.create(symbol, ['is_dirty']),
4229  [('depth', depth_expr)])
4230  if_body = Call.create(
4231  StructureReference.create(symbol, [method]),
4232  [('depth', depth_expr.copy())])
4233 
4234  # Add the "if_dirty" check when necessary
4235  _, known = self.required()
4236  if not known:
4237  haloex = IfBlock.create(if_condition, [if_body])
4238  else:
4239  haloex = if_body
4240 
4241  self.replace_with(haloex)
4242  return haloex
4243 
4244 

References psyclone.domain.common.psylayer.psyloop.PSyLoop._field, psyclone.domain.lfric.arg_index_to_metadata_index.ArgIndexToMetadataIndex._field(), psyclone.domain.lfric.lfric_loop.LFRicLoop._field, psyclone.domain.lfric.metadata_to_arguments_rules.MetadataToArgumentsRules._field(), psyclone.psyGen.HaloExchange._field, psyclone.dynamo0p3.LFRicHaloExchange._halo_exchange_name, psyclone.dynamo0p3.LFRicHaloExchangeStart._halo_exchange_name, psyclone.dynamo0p3.LFRicHaloExchangeEnd._halo_exchange_name, psyclone.gocean1p0.GOHaloExchange._halo_exchange_name, psyclone.dynamo0p3.LFRicHaloExchange._psyir_depth_expression(), psyclone.dynamo0p3.LFRicHaloExchangeStart._psyir_depth_expression(), psyclone.psyir.nodes.node.Node.replace_with(), psyclone.dynamo0p3.LFRicHaloExchangeStart.required(), psyclone.dynamo0p3.LFRicHaloExchange.required(), and psyclone.psyGen.HaloExchange.vector_index.

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

◆ node_str()

def psyclone.dynamo0p3.LFRicHaloExchange.node_str (   self,
  colour = True 
)
 Creates a text summary of this HaloExchange node.

:param bool colour: whether or not to include control codes for colour.

:returns: text summary of this node, optionally with control codes \
          for colour highlighting.
:rtype: str

Reimplemented from psyclone.psyGen.HaloExchange.

Definition at line 4177 of file dynamo0p3.py.

4177  def node_str(self, colour=True):
4178  ''' Creates a text summary of this HaloExchange node.
4179 
4180  :param bool colour: whether or not to include control codes for colour.
4181 
4182  :returns: text summary of this node, optionally with control codes \
4183  for colour highlighting.
4184  :rtype: str
4185 
4186  '''
4187  _, known = self.required()
4188  runtime_check = not known
4189  field_id = self._field.name
4190  if self.vector_index:
4191  field_id += f"({self.vector_index})"
4192  return (f"{self.coloured_name(colour)}[field='{field_id}', "
4193  f"type='{self._compute_stencil_type()}', "
4194  f"depth={self._compute_halo_depth()}, "
4195  f"check_dirty={runtime_check}]")
4196 

References psyclone.domain.common.psylayer.psyloop.PSyLoop._field, psyclone.domain.lfric.arg_index_to_metadata_index.ArgIndexToMetadataIndex._field(), psyclone.domain.lfric.lfric_loop.LFRicLoop._field, psyclone.domain.lfric.metadata_to_arguments_rules.MetadataToArgumentsRules._field(), psyclone.psyGen.HaloExchange._field, psyclone.dynamo0p3.LFRicHaloExchangeStart.required(), psyclone.dynamo0p3.LFRicHaloExchange.required(), and psyclone.psyGen.HaloExchange.vector_index.

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

◆ required()

def psyclone.dynamo0p3.LFRicHaloExchange.required (   self,
  ignore_hex_dep = False 
)
Determines whether this halo exchange is definitely required
``(True, True)``, might be required ``(True, False)`` or is definitely
not required ``(False, *)``.

If the optional ignore_hex_dep argument is set to True then
any read accesses contained in halo exchange nodes are
ignored. This option can therefore be used to filter out any
halo exchange dependencies and only consider non-halo exchange
dependencies if and when required.

Whilst a halo exchange is generally only ever added if it is
required, or if it may be required, this situation can change
if redundant computation transformations are applied. The
first argument can be used to remove such halo exchanges if
required.

When the first return value is True, the second return value
can be used to see if we need to rely on the runtime
(set_dirty and set_clean calls) and therefore add a
check_dirty() call around the halo exchange or whether we
definitely know that this halo exchange is required.

This routine assumes that a stencil size provided via a
variable may take the value 0. If a variables value is
constrained to be 1, or more, then the logic for deciding
whether a halo exchange is definitely required should be
updated. Note, the routine would still be correct as is, it
would just return more unknown results than it should).

:param bool ignore_hex_dep: if True then ignore any read \
    accesses contained in halo exchanges. This is an optional \
    argument that defaults to False.

:returns: (x, y) where x specifies whether this halo \
    exchange is (or might be) required - True, or is not \
    required - False. If the first tuple item is True then the \
    second argument specifies whether we definitely know that \
    we need the HaloExchange - True, or are not sure - False.
:rtype: (bool, bool)

Definition at line 4002 of file dynamo0p3.py.

4002  def required(self, ignore_hex_dep=False):
4003  '''Determines whether this halo exchange is definitely required
4004  ``(True, True)``, might be required ``(True, False)`` or is definitely
4005  not required ``(False, *)``.
4006 
4007  If the optional ignore_hex_dep argument is set to True then
4008  any read accesses contained in halo exchange nodes are
4009  ignored. This option can therefore be used to filter out any
4010  halo exchange dependencies and only consider non-halo exchange
4011  dependencies if and when required.
4012 
4013  Whilst a halo exchange is generally only ever added if it is
4014  required, or if it may be required, this situation can change
4015  if redundant computation transformations are applied. The
4016  first argument can be used to remove such halo exchanges if
4017  required.
4018 
4019  When the first return value is True, the second return value
4020  can be used to see if we need to rely on the runtime
4021  (set_dirty and set_clean calls) and therefore add a
4022  check_dirty() call around the halo exchange or whether we
4023  definitely know that this halo exchange is required.
4024 
4025  This routine assumes that a stencil size provided via a
4026  variable may take the value 0. If a variables value is
4027  constrained to be 1, or more, then the logic for deciding
4028  whether a halo exchange is definitely required should be
4029  updated. Note, the routine would still be correct as is, it
4030  would just return more unknown results than it should).
4031 
4032  :param bool ignore_hex_dep: if True then ignore any read \
4033  accesses contained in halo exchanges. This is an optional \
4034  argument that defaults to False.
4035 
4036  :returns: (x, y) where x specifies whether this halo \
4037  exchange is (or might be) required - True, or is not \
4038  required - False. If the first tuple item is True then the \
4039  second argument specifies whether we definitely know that \
4040  we need the HaloExchange - True, or are not sure - False.
4041  :rtype: (bool, bool)
4042 
4043  '''
4044  # pylint: disable=too-many-branches, too-many-return-statements
4045  # get *aggregated* information about halo reads
4046  required_clean_info = self._compute_halo_read_depth_info(
4047  ignore_hex_dep)
4048  # get information about the halo write
4049  clean_info = self._compute_halo_write_info()
4050 
4051  # no need to test whether we return at least one read
4052  # dependency as _compute_halo_read_depth_info() raises an
4053  # exception if none are found
4054 
4055  if Config.get().api_conf("dynamo0.3").compute_annexed_dofs and \
4056  len(required_clean_info) == 1 and \
4057  required_clean_info[0].annexed_only:
4058  # We definitely don't need the halo exchange as we
4059  # only read annexed dofs and these are always clean as
4060  # they are computed by default when iterating over
4061  # dofs and kept up-to-date by redundant computation
4062  # when iterating over cells.
4063  required = False
4064  known = True # redundant information as it is always known
4065  return required, known
4066 
4067  if not clean_info:
4068  # this halo exchange has no previous write dependencies so
4069  # we do not know the initial state of the halo. This means
4070  # that we do not know if we need a halo exchange or not
4071  required = True
4072  known = False
4073  return required, known
4074 
4075  if clean_info.max_depth:
4076  if not clean_info.dirty_outer:
4077  # all of the halo is cleaned by redundant computation
4078  # so halo exchange is not required
4079  required = False
4080  known = True # redundant information as it is always known
4081  else:
4082  # the last level halo is dirty
4083  if required_clean_info[0].max_depth:
4084  # we know that we need to clean the outermost halo level
4085  required = True
4086  known = True
4087  else:
4088  # we don't know whether the halo exchange is
4089  # required or not as the reader reads the halo to
4090  # a specified depth but we don't know the depth
4091  # of the halo
4092  required = True
4093  known = False
4094  return required, known
4095 
4096  # at this point we know that clean_info.max_depth is False
4097 
4098  if not clean_info.literal_depth:
4099  # if literal_depth is 0 then the writer does not
4100  # redundantly compute so we definitely need the halo
4101  # exchange
4102  required = True
4103  known = True
4104  return required, known
4105 
4106  if clean_info.literal_depth == 1 and clean_info.dirty_outer:
4107  # the writer redundantly computes in the level 1 halo but
4108  # leaves it dirty (although annexed dofs are now clean).
4109  if len(required_clean_info) == 1 and \
4110  required_clean_info[0].annexed_only:
4111  # we definitely don't need the halo exchange as we
4112  # only read annexed dofs and these have been made
4113  # clean by the redundant computation
4114  required = False
4115  known = True # redundant information as it is always known
4116  else:
4117  # we definitely need the halo exchange as the reader(s)
4118  # require the halo to be clean
4119  required = True
4120  known = True
4121  return required, known
4122 
4123  # At this point we know that the writer cleans the halo to a
4124  # known (literal) depth through redundant computation. We now
4125  # compute this value for use by the logic in the rest of the
4126  # routine.
4127  clean_depth = clean_info.literal_depth
4128  if clean_info.dirty_outer:
4129  # outer layer stays dirty
4130  clean_depth -= 1
4131 
4132  # If a literal value in any of the required clean halo depths
4133  # is greater than the cleaned depth then we definitely need
4134  # the halo exchange (as any additional variable depth would
4135  # increase the required depth value). We only look at the case
4136  # where we have multiple entries as the single entry case is
4137  # dealt with separately
4138  if len(required_clean_info) > 1:
4139  for required_clean in required_clean_info:
4140  if required_clean.literal_depth > clean_depth:
4141  required = True
4142  known = True
4143  return required, known
4144 
4145  # The only other case where we know that a halo exchange is
4146  # required (or not) is where we read the halo to a known
4147  # literal depth. As the read information is aggregated, a known
4148  # literal depth will mean that there is only one
4149  # required_clean_info entry
4150  if len(required_clean_info) == 1:
4151  # the halo might be read to a fixed literal depth
4152  if required_clean_info[0].var_depth or \
4153  required_clean_info[0].max_depth:
4154  # no it isn't so we might need the halo exchange
4155  required = True
4156  known = False
4157  else:
4158  # the halo is read to a fixed literal depth.
4159  required_clean_depth = required_clean_info[0].literal_depth
4160  if clean_depth < required_clean_depth:
4161  # we definitely need this halo exchange
4162  required = True
4163  known = True
4164  else:
4165  # we definitely don't need this halo exchange
4166  required = False
4167  known = True # redundant information as it is always known
4168  return required, known
4169 
4170  # We now know that at least one required_clean entry has a
4171  # variable depth and any required_clean fixed depths are less
4172  # than the cleaned depth so we may need a halo exchange.
4173  required = True
4174  known = False
4175  return required, known
4176 

References psyclone.dynamo0p3.LFRicHaloExchange._compute_halo_read_depth_info(), and psyclone.dynamo0p3.LFRicHaloExchange._compute_halo_write_info().

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: