Reference Guide  2.5.0
psyclone.transformations.Dynamo0p3RedundantComputationTrans Class Reference
Inheritance diagram for psyclone.transformations.Dynamo0p3RedundantComputationTrans:
Collaboration diagram for psyclone.transformations.Dynamo0p3RedundantComputationTrans:

Public Member Functions

def __str__ (self)
 
def validate (self, node, options=None)
 
def apply (self, loop, options=None)
 
- Public Member Functions inherited from psyclone.psyir.transformations.loop_trans.LoopTrans
def name (self)
 

Additional Inherited Members

- Static Public Attributes inherited from psyclone.psyir.transformations.loop_trans.LoopTrans
tuple excluded_node_types = ()
 

Detailed Description

This transformation allows the user to modify a loop's bounds so
that redundant computation will be performed. Redundant
computation can result in halo exchanges being modified, new halo
exchanges being added or existing halo exchanges being removed.

* This transformation should be performed before any
  parallelisation transformations (e.g. for OpenMP) to the loop in
  question and will raise an exception if this is not the case.

* This transformation can not be applied to a loop containing a
  reduction and will again raise an exception if this is the case.

* This transformation can only be used to add redundant
  computation to a loop, not to remove it.

* This transformation allows a loop that is already performing
  redundant computation to be modified, but only if the depth is
  increased.

Definition at line 1768 of file transformations.py.

Member Function Documentation

◆ apply()

def psyclone.transformations.Dynamo0p3RedundantComputationTrans.apply (   self,
  loop,
  options = None 
)
Apply the redundant computation transformation to the loop
:py:obj:`loop`. This transformation can be applied to loops iterating
over 'cells or 'dofs'. if :py:obj:`depth` is set to a value then the
value will be the depth of the field's halo over which redundant
computation will be performed. If :py:obj:`depth` is not set to a
value then redundant computation will be performed to the full depth
of the field's halo.

:param loop: the loop that we are transforming.
:type loop: :py:class:`psyclone.psyGen.LFRicLoop`
:param options: a dictionary with options for transformations.
:type options: Optional[Dict[str, Any]]
:param int options["depth"]: the depth of the stencil. Defaults \
        to None.

Reimplemented from psyclone.psyGen.Transformation.

Definition at line 1951 of file transformations.py.

1951  def apply(self, loop, options=None):
1952  # pylint:disable=arguments-renamed
1953  '''Apply the redundant computation transformation to the loop
1954  :py:obj:`loop`. This transformation can be applied to loops iterating
1955  over 'cells or 'dofs'. if :py:obj:`depth` is set to a value then the
1956  value will be the depth of the field's halo over which redundant
1957  computation will be performed. If :py:obj:`depth` is not set to a
1958  value then redundant computation will be performed to the full depth
1959  of the field's halo.
1960 
1961  :param loop: the loop that we are transforming.
1962  :type loop: :py:class:`psyclone.psyGen.LFRicLoop`
1963  :param options: a dictionary with options for transformations.
1964  :type options: Optional[Dict[str, Any]]
1965  :param int options["depth"]: the depth of the stencil. Defaults \
1966  to None.
1967 
1968  '''
1969  self.validate(loop, options=options)
1970  if not options:
1971  options = {}
1972  depth = options.get("depth")
1973 
1974  if loop.loop_type == "":
1975  # Loop is over cells
1976  loop.set_upper_bound("cell_halo", depth)
1977  elif loop.loop_type == "colour":
1978  # Loop is over cells of a single colour
1979  loop.set_upper_bound("colour_halo", depth)
1980  elif loop.loop_type == "dof":
1981  loop.set_upper_bound("dof_halo", depth)
1982  else:
1983  raise TransformationError(
1984  f"Unsupported loop_type '{loop.loop_type}' found in "
1985  f"Dynamo0p3Redundant ComputationTrans.apply()")
1986  # Add/remove halo exchanges as required due to the redundant
1987  # computation
1988  loop.update_halo_exchanges()
1989 
1990 

References psyclone.domain.lfric.kernel.lfric_kernel_metadata.LFRicKernelMetadata.validate(), psyclone.transformations.MoveTrans.validate(), psyclone.transformations.Dynamo0p3AsyncHaloExchangeTrans.validate(), psyclone.domain.common.transformations.alg_invoke_2_psy_call_trans.AlgInvoke2PSyCallTrans.validate(), psyclone.domain.common.transformations.alg_trans.AlgTrans.validate(), psyclone.domain.common.transformations.kernel_module_inline_trans.KernelModuleInlineTrans.validate(), psyclone.domain.common.transformations.raise_psyir_2_alg_trans.RaisePSyIR2AlgTrans.validate(), psyclone.domain.gocean.transformations.gocean_const_loop_bounds_trans.GOConstLoopBoundsTrans.validate(), psyclone.domain.gocean.transformations.gocean_move_iteration_boundaries_inside_kernel_trans.GOMoveIterationBoundariesInsideKernelTrans.validate(), psyclone.domain.gocean.transformations.gocean_opencl_trans.GOOpenCLTrans.validate(), psyclone.domain.gocean.transformations.raise_psyir_2_gocean_kern_trans.RaisePSyIR2GOceanKernTrans.validate(), psyclone.domain.lfric.transformations.lfric_alg_invoke_2_psy_call_trans.LFRicAlgInvoke2PSyCallTrans.validate(), psyclone.domain.lfric.transformations.raise_psyir_2_lfric_kern_trans.RaisePSyIR2LFRicKernTrans.validate(), psyclone.domain.nemo.transformations.create_nemo_invoke_schedule_trans.CreateNemoInvokeScheduleTrans.validate(), psyclone.domain.nemo.transformations.create_nemo_psy_trans.CreateNemoPSyTrans.validate(), psyclone.domain.nemo.transformations.nemo_allarrayrange2loop_trans.NemoAllArrayRange2LoopTrans.validate(), psyclone.domain.nemo.transformations.nemo_arrayrange2loop_trans.NemoArrayRange2LoopTrans.validate(), psyclone.domain.nemo.transformations.nemo_outerarrayrange2loop_trans.NemoOuterArrayRange2LoopTrans.validate(), psyclone.psyad.transformations.assignment_trans.AssignmentTrans.validate(), psyclone.psyGen.Transformation.validate(), psyclone.psyir.transformations.acc_update_trans.ACCUpdateTrans.validate(), psyclone.psyir.transformations.allarrayaccess2loop_trans.AllArrayAccess2LoopTrans.validate(), psyclone.psyir.transformations.arrayaccess2loop_trans.ArrayAccess2LoopTrans.validate(), psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.validate(), psyclone.psyir.transformations.chunk_loop_trans.ChunkLoopTrans.validate(), psyclone.psyir.transformations.fold_conditional_return_expressions_trans.FoldConditionalReturnExpressionsTrans.validate(), psyclone.psyir.transformations.hoist_local_arrays_trans.HoistLocalArraysTrans.validate(), psyclone.psyir.transformations.hoist_loop_bound_expr_trans.HoistLoopBoundExprTrans.validate(), psyclone.psyir.transformations.hoist_trans.HoistTrans.validate(), psyclone.psyir.transformations.inline_trans.InlineTrans.validate(), psyclone.psyir.transformations.intrinsics.array_reduction_base_trans.ArrayReductionBaseTrans.validate(), psyclone.psyir.transformations.intrinsics.dotproduct2code_trans.DotProduct2CodeTrans.validate(), psyclone.psyir.transformations.intrinsics.intrinsic2code_trans.Intrinsic2CodeTrans.validate(), psyclone.psyir.transformations.intrinsics.matmul2code_trans.Matmul2CodeTrans.validate(), psyclone.psyir.transformations.loop_swap_trans.LoopSwapTrans.validate(), psyclone.psyir.transformations.loop_tiling_2d_trans.LoopTiling2DTrans.validate(), psyclone.psyir.transformations.loop_trans.LoopTrans.validate(), psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans.validate(), psyclone.psyir.transformations.omp_taskwait_trans.OMPTaskwaitTrans.validate(), psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans.validate(), psyclone.psyir.transformations.reference2arrayrange_trans.Reference2ArrayRangeTrans.validate(), psyclone.psyir.transformations.replace_induction_variables_trans.ReplaceInductionVariablesTrans.validate(), psyclone.transformations.OMPDeclareTargetTrans.validate(), psyclone.transformations.DynamoOMPParallelLoopTrans.validate(), psyclone.transformations.Dynamo0p3OMPLoopTrans.validate(), psyclone.transformations.GOceanOMPLoopTrans.validate(), psyclone.transformations.Dynamo0p3RedundantComputationTrans.validate(), psyclone.transformations.Dynamo0p3KernelConstTrans.validate(), psyclone.transformations.ACCRoutineTrans.validate(), psyclone.transformations.KernelImportsToArguments.validate(), psyclone.domain.gocean.transformations.gocean_loop_fuse_trans.GOceanLoopFuseTrans.validate(), psyclone.domain.lfric.transformations.lfric_loop_fuse_trans.LFRicLoopFuseTrans.validate(), psyclone.psyir.transformations.loop_fuse_trans.LoopFuseTrans.validate(), psyclone.domain.gocean.transformations.gocean_extract_trans.GOceanExtractTrans.validate(), psyclone.domain.lfric.transformations.lfric_extract_trans.LFRicExtractTrans.validate(), psyclone.psyir.transformations.extract_trans.ExtractTrans.validate(), psyclone.psyir.transformations.nan_test_trans.NanTestTrans.validate(), psyclone.psyir.transformations.read_only_verify_trans.ReadOnlyVerifyTrans.validate(), psyclone.transformations.ParallelRegionTrans.validate(), psyclone.transformations.OMPParallelTrans.validate(), psyclone.transformations.ACCParallelTrans.validate(), psyclone.transformations.ACCKernelsTrans.validate(), psyclone.transformations.ACCDataTrans.validate(), psyclone.psyir.transformations.psy_data_trans.PSyDataTrans.validate(), psyclone.psyir.transformations.region_trans.RegionTrans.validate(), and psyclone.transformations.ACCEnterDataTrans.validate().

Here is the call graph for this function:

◆ validate()

def psyclone.transformations.Dynamo0p3RedundantComputationTrans.validate (   self,
  node,
  options = None 
)
Perform various checks to ensure that it is valid to apply the
RedundantComputation transformation to the supplied node

:param node: the supplied node on which we are performing\
             validity checks
:type node: :py:class:`psyclone.psyir.nodes.Node`
:param options: a dictionary with options for transformations.
:type options: Optional[Dict[str, Any]]
:param int options["depth"]: the depth of the stencil if the value \
             is provided and None if not.

:raises TransformationError: if the parent of the loop is a\
    :py:class:`psyclone.psyir.nodes.Directive`.
:raises TransformationError: if the parent of the loop is not a\
    :py:class:`psyclone.psyir.nodes.Loop` or a\
    :py:class:`psyclone.psyGen.LFRicInvokeSchedule`.
:raises TransformationError: if the parent of the loop is a\
    :py:class:`psyclone.psyir.nodes.Loop` but the original loop does\
    not iterate over 'colour'.
:raises TransformationError: if the parent of the loop is a\
    :py:class:`psyclone.psyir.nodes.Loop` but the parent does not
    iterate over 'colours'.
:raises TransformationError: if the parent of the loop is a\
    :py:class:`psyclone.psyir.nodes.Loop` but the parent's parent is\
    not a :py:class:`psyclone.psyGen.LFRicInvokeSchedule`.
:raises TransformationError: if this transformation is applied\
    when distributed memory is not switched on.
:raises TransformationError: if the loop does not iterate over\
    cells, dofs or colour.
:raises TransformationError: if the transformation is setting the\
    loop to the maximum halo depth but the loop already computes\
    to the maximum halo depth.
:raises TransformationError: if the transformation is setting the\
    loop to the maximum halo depth but the loop contains a stencil\
    access (as this would result in the field being accessed\
    beyond the halo depth).
:raises TransformationError: if the supplied depth value is not an\
    integer.
:raises TransformationError: if the supplied depth value is less\
    than 1.
:raises TransformationError: if the supplied depth value is not\
    greater than 1 when a continuous loop is modified as this is\
    the minimum valid value.
:raises TransformationError: if the supplied depth value is not\
    greater than the existing depth value, as we should not need\
    to undo existing transformations.
:raises TransformationError: if a depth value has been supplied\
    but the loop has already been set to the maximum halo depth.

Reimplemented from psyclone.psyir.transformations.loop_trans.LoopTrans.

Definition at line 1792 of file transformations.py.

1792  def validate(self, node, options=None):
1793  '''Perform various checks to ensure that it is valid to apply the
1794  RedundantComputation transformation to the supplied node
1795 
1796  :param node: the supplied node on which we are performing\
1797  validity checks
1798  :type node: :py:class:`psyclone.psyir.nodes.Node`
1799  :param options: a dictionary with options for transformations.
1800  :type options: Optional[Dict[str, Any]]
1801  :param int options["depth"]: the depth of the stencil if the value \
1802  is provided and None if not.
1803 
1804  :raises TransformationError: if the parent of the loop is a\
1805  :py:class:`psyclone.psyir.nodes.Directive`.
1806  :raises TransformationError: if the parent of the loop is not a\
1807  :py:class:`psyclone.psyir.nodes.Loop` or a\
1808  :py:class:`psyclone.psyGen.LFRicInvokeSchedule`.
1809  :raises TransformationError: if the parent of the loop is a\
1810  :py:class:`psyclone.psyir.nodes.Loop` but the original loop does\
1811  not iterate over 'colour'.
1812  :raises TransformationError: if the parent of the loop is a\
1813  :py:class:`psyclone.psyir.nodes.Loop` but the parent does not
1814  iterate over 'colours'.
1815  :raises TransformationError: if the parent of the loop is a\
1816  :py:class:`psyclone.psyir.nodes.Loop` but the parent's parent is\
1817  not a :py:class:`psyclone.psyGen.LFRicInvokeSchedule`.
1818  :raises TransformationError: if this transformation is applied\
1819  when distributed memory is not switched on.
1820  :raises TransformationError: if the loop does not iterate over\
1821  cells, dofs or colour.
1822  :raises TransformationError: if the transformation is setting the\
1823  loop to the maximum halo depth but the loop already computes\
1824  to the maximum halo depth.
1825  :raises TransformationError: if the transformation is setting the\
1826  loop to the maximum halo depth but the loop contains a stencil\
1827  access (as this would result in the field being accessed\
1828  beyond the halo depth).
1829  :raises TransformationError: if the supplied depth value is not an\
1830  integer.
1831  :raises TransformationError: if the supplied depth value is less\
1832  than 1.
1833  :raises TransformationError: if the supplied depth value is not\
1834  greater than 1 when a continuous loop is modified as this is\
1835  the minimum valid value.
1836  :raises TransformationError: if the supplied depth value is not\
1837  greater than the existing depth value, as we should not need\
1838  to undo existing transformations.
1839  :raises TransformationError: if a depth value has been supplied\
1840  but the loop has already been set to the maximum halo depth.
1841 
1842  '''
1843  # pylint: disable=too-many-branches
1844  # check node is a loop
1845  super().validate(node, options=options)
1846 
1847  # Check loop's parent is the InvokeSchedule, or that it is nested
1848  # in a colours loop and perform other colour(s) loop checks,
1849  # otherwise halo exchange placement might fail. The only
1850  # current example where the placement would fail is when
1851  # directives have already been added. This could be fixed but
1852  # it actually makes sense to require redundant computation
1853  # transformations to be applied before adding directives so it
1854  # is not particularly important.
1855  dir_node = node.ancestor(Directive)
1856  if dir_node:
1857  raise TransformationError(
1858  f"In the Dynamo0p3RedundantComputation transformation apply "
1859  f"method the supplied loop is sits beneath a directive of "
1860  f"type {type(dir_node)}. Redundant computation must be applied"
1861  f" before directives are added.")
1862  if not (isinstance(node.parent, LFRicInvokeSchedule) or
1863  isinstance(node.parent.parent, Loop)):
1864  raise TransformationError(
1865  f"In the Dynamo0p3RedundantComputation transformation "
1866  f"apply method the parent of the supplied loop must be the "
1867  f"LFRicInvokeSchedule, or a Loop, but found "
1868  f"{type(node.parent)}")
1869  if isinstance(node.parent.parent, Loop):
1870  if node.loop_type != "colour":
1871  raise TransformationError(
1872  f"In the Dynamo0p3RedundantComputation transformation "
1873  f"apply method, if the parent of the supplied Loop is "
1874  f"also a Loop then the supplied Loop must iterate over "
1875  f"'colour', but found '{node.loop_type}'")
1876  if node.parent.parent.loop_type != "colours":
1877  raise TransformationError(
1878  f"In the Dynamo0p3RedundantComputation transformation "
1879  f"apply method, if the parent of the supplied Loop is "
1880  f"also a Loop then the parent must iterate over "
1881  f"'colours', but found '{node.parent.parent.loop_type}'")
1882  if not isinstance(node.parent.parent.parent, LFRicInvokeSchedule):
1883  raise TransformationError(
1884  f"In the Dynamo0p3RedundantComputation transformation "
1885  f"apply method, if the parent of the supplied Loop is "
1886  f"also a Loop then the parent's parent must be the "
1887  f"LFRicInvokeSchedule, but found {type(node.parent)}")
1888  if not Config.get().distributed_memory:
1889  raise TransformationError(
1890  "In the Dynamo0p3RedundantComputation transformation apply "
1891  "method distributed memory must be switched on")
1892 
1893  # loop must iterate over cell-column, dof or colour. Note, an
1894  # empty loop_type iterates over cell-columns.
1895  if node.loop_type not in ["", "dof", "colour"]:
1896  raise TransformationError(
1897  f"In the Dynamo0p3RedundantComputation transformation apply "
1898  f"method the loop type must be one of '' (cell-columns), 'dof'"
1899  f" or 'colour', but found '{node.loop_type}'")
1900 
1901  # We don't currently support the application of transformations to
1902  # loops containing inter-grid kernels
1903  check_intergrid(node)
1904  const = LFRicConstants()
1905 
1906  if not options:
1907  options = {}
1908  depth = options.get("depth")
1909  if depth is None:
1910  if node.upper_bound_name in const.HALO_ACCESS_LOOP_BOUNDS:
1911  if not node.upper_bound_halo_depth:
1912  raise TransformationError(
1913  "In the Dynamo0p3RedundantComputation transformation "
1914  "apply method the loop is already set to the maximum "
1915  "halo depth so this transformation does nothing")
1916  for call in node.kernels():
1917  for arg in call.arguments.args:
1918  if arg.stencil:
1919  raise TransformationError(
1920  f"In the Dynamo0p3RedundantComputation "
1921  f"transformation apply method the loop "
1922  f"contains field '{arg.name}' with a stencil "
1923  f"access in kernel '{call.name}', so it is "
1924  f"invalid to set redundant computation to "
1925  f"maximum depth")
1926  else:
1927  if not isinstance(depth, int):
1928  raise TransformationError(
1929  f"In the Dynamo0p3RedundantComputation transformation "
1930  f"apply method the supplied depth should be an integer but"
1931  f" found type '{type(depth)}'")
1932  if depth < 1:
1933  raise TransformationError(
1934  "In the Dynamo0p3RedundantComputation transformation "
1935  "apply method the supplied depth is less than 1")
1936 
1937  if node.upper_bound_name in const.HALO_ACCESS_LOOP_BOUNDS:
1938  if node.upper_bound_halo_depth:
1939  if node.upper_bound_halo_depth >= depth:
1940  raise TransformationError(
1941  f"In the Dynamo0p3RedundantComputation "
1942  f"transformation apply method the supplied depth "
1943  f"({depth}) must be greater than the existing halo"
1944  f" depth ({node.upper_bound_halo_depth})")
1945  else:
1946  raise TransformationError(
1947  "In the Dynamo0p3RedundantComputation transformation "
1948  "apply method the loop is already set to the maximum "
1949  "halo depth so can't be set to a fixed value")
1950 
Here is the caller graph for this function:

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