Reference Guide  2.5.0
kern_stub_arg_list.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2017-2024, Science and Technology Facilities Council.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are met:
9 #
10 # * Redistributions of source code must retain the above copyright notice, this
11 # list of conditions and the following disclaimer.
12 #
13 # * Redistributions in binary form must reproduce the above copyright notice,
14 # this list of conditions and the following disclaimer in the documentation
15 # and/or other materials provided with the distribution.
16 #
17 # * Neither the name of the copyright holder nor the names of its
18 # contributors may be used to endorse or promote products derived from
19 # this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 # -----------------------------------------------------------------------------
34 # Authors R. W. Ford, A. R. Porter and S. Siso, STFC Daresbury Lab
35 # Modified I. Kavcic, A. Coughtrie and L. Turner, Met Office
36 # Modified J. Henrichs, Bureau of Meteorology
37 
38 '''This module implements a class that creates the argument list
39 for a kernel subroutine.
40 '''
41 
42 from psyclone.domain.lfric import ArgOrdering, LFRicConstants, LFRicSymbolTable
43 from psyclone.errors import InternalError
44 
45 
47  # pylint: disable=too-many-public-methods, abstract-method
48  # TODO: #845 Check that all implicit variables have the right type.
49  '''Creates the argument list required to create and declare the
50  required arguments for a kernel subroutine. The ordering and type
51  of the arguments is captured by the base class.
52 
53  :param kern: Kernel for which to create argument list.
54  :type kern: :py:class:`psyclone.domain.lfric.LFRicKern`
55 
56  :raises NotImplementedError: if the kernel is inter-grid.
57  :raises NotImplementedError: if the kernel requires properties of the \
58  reference element.
59  '''
60  def __init__(self, kern):
61  ArgOrdering.__init__(self, kern)
62  # TODO 719 The stub_symtab is not connected to other parts of the
63  # Stub generation. Also the symboltable already has an
64  # argument_list that may be able to replace the argument list below.
65  self._stub_symtab_stub_symtab = LFRicSymbolTable()
66 
67  def cell_position(self, var_accesses=None):
68  '''Adds a cell argument to the argument list and if supplied stores
69  this access in var_accesses.
70 
71  :param var_accesses: optional VariablesAccessInfo instance to store \
72  the information about variable accesses.
73  :type var_accesses: \
74  :py:class:`psyclone.core.VariablesAccessInfo`
75 
76  '''
77  self.appendappend("cell", var_accesses)
78 
79  def mesh_height(self, var_accesses=None):
80  '''Add mesh height (nlayers) to the argument list and if supplied
81  stores this access in var_accesses.
82 
83  :param var_accesses: optional VariablesAccessInfo instance to store \
84  the information about variable accesses.
85  :type var_accesses: \
86  :py:class:`psyclone.core.VariablesAccessInfo`
87 
88  '''
89  self.appendappend("nlayers", var_accesses)
90 
91  def _mesh_ncell2d(self, var_accesses=None):
92  '''Add the number of columns in the mesh to the argument list and if
93  supplied stores this access in var_accesses.
94 
95  :param var_accesses: optional VariablesAccessInfo instance to store \
96  the information about variable accesses.
97  :type var_accesses: \
98  :py:class:`psyclone.core.VariablesAccessInfo`
99 
100  '''
101  self.appendappend("ncell_2d", var_accesses)
102 
103  def cma_operator(self, arg, var_accesses=None):
104  '''Add the CMA operator and associated scalars to the argument
105  list and optionally add them to the variable access
106  information.
107 
108  :param arg: the CMA operator argument.
109  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
110  :param var_accesses: optional VariablesAccessInfo instance to store \
111  the information about variable accesses.
112  :type var_accesses: \
113  :py:class:`psyclone.core.VariablesAccessInfo`
114 
115  '''
116  # The CMA operator itself
117  self.appendappend(arg.name, var_accesses)
118  # Associated scalar parameters
119  nrow = arg.name + "_nrow"
120  _local_args = [nrow]
121  if arg.function_space_to.orig_name != \
122  arg.function_space_from.orig_name:
123  # If the to- and from-spaces are different then so are ncol and
124  # nrow so we pass both of them. If they are the same then we
125  # could pass either but choose to pass nrow and not ncol.
126  ncol = arg.name + "_ncol"
127  _local_args.append(ncol)
128  bandwidth = arg.name + "_bandwidth"
129  alpha = arg.name + "_alpha"
130  beta = arg.name + "_beta"
131  gamma_m = arg.name + "_gamma_m"
132  gamma_p = arg.name + "_gamma_p"
133  _local_args += [bandwidth, alpha, beta, gamma_m, gamma_p]
134  self.extendextend(_local_args, var_accesses)
135 
136  def field_vector(self, argvect, var_accesses=None):
137  '''Add the field vector associated with the argument 'argvect' to the
138  argument list. If supplied it also stores these accesses to the
139  var_access object.
140 
141  :param argvect: the field vector to add.
142  :type argvect: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
143  :param var_accesses: optional VariablesAccessInfo instance to store \
144  the information about variable accesses.
145  :type var_accesses: \
146  :py:class:`psyclone.core.VariablesAccessInfo`
147 
148  '''
149  # the range function below returns values from
150  # 1 to the vector size which is what we
151  # require in our Fortran code
152  for idx in range(1, argvect.vector_size+1):
153  text = (argvect.name + "_" +
154  argvect.function_space.mangled_name +
155  "_v" + str(idx))
156  self.appendappend(text, var_accesses)
157 
158  def field(self, arg, var_accesses=None):
159  '''Add the field array associated with the argument 'arg' to the
160  argument list. If supplied it also stores this access in var_accesses.
161 
162  :param arg: the field to be added.
163  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
164  :param var_accesses: optional VariablesAccessInfo instance to store \
165  the information about variable accesses.
166  :type var_accesses: \
167  :py:class:`psyclone.core.VariablesAccessInfo`
168 
169  '''
170  text = arg.name + "_" + arg.function_space.mangled_name
171  self.appendappend(text, var_accesses, mode=arg.access)
172 
173  def stencil_unknown_extent(self, arg, var_accesses=None):
174  '''Add stencil information to the argument list associated with the
175  argument 'arg' if the extent is unknown. If supplied it also stores
176  this access in var_accesses.
177 
178  :param arg: the kernel argument with which the stencil is associated.
179  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
180  :param var_accesses: optional VariablesAccessInfo instance to store \
181  the information about variable accesses.
182  :type var_accesses: \
183  :py:class:`psyclone.core.VariablesAccessInfo`
184 
185  '''
186  # Import here to avoid circular dependency
187  # pylint: disable=import-outside-toplevel
188  from psyclone.domain.lfric.lfric_stencils import LFRicStencils
189  name = LFRicStencils.dofmap_size_symbol(self._stub_symtab_stub_symtab, arg).name
190  self.appendappend(name, var_accesses)
191 
192  def stencil_unknown_direction(self, arg, var_accesses=None):
193  '''Add stencil information to the argument list associated with the
194  argument 'arg' if the direction is unknown. If supplied it also stores
195  this access in var_accesses.
196 
197  :param arg: the kernel argument with which the stencil is associated.
198  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
199  :param var_accesses: optional VariablesAccessInfo instance to store \
200  the information about variable accesses.
201  :type var_accesses: \
202  :py:class:`psyclone.core.VariablesAccessInfo`
203 
204  '''
205  # Import here to avoid circular dependency
206  # pylint: disable=import-outside-toplevel
207  from psyclone.domain.lfric.lfric_stencils import LFRicStencils
208  name = LFRicStencils.direction_name(self._stub_symtab_stub_symtab, arg)
209  self.appendappend(name, var_accesses)
210 
211  def stencil(self, arg, var_accesses=None):
212  '''Add general stencil information associated with the argument 'arg'
213  to the argument list. If supplied it also stores this access in
214  var_accesses.
215 
216  :param arg: the meta-data description of the kernel \
217  argument with which the stencil is associated.
218  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
219  :param var_accesses: optional VariablesAccessInfo instance to store \
220  the information about variable accesses.
221  :type var_accesses: \
222  :py:class:`psyclone.core.VariablesAccessInfo`
223 
224  '''
225  # Import here to avoid circular dependency
226  # pylint: disable=import-outside-toplevel
227  from psyclone.domain.lfric.lfric_stencils import LFRicStencils
228  var_name = LFRicStencils.dofmap_symbol(self._stub_symtab_stub_symtab, arg).name
229  self.appendappend(var_name, var_accesses)
230 
231  def stencil_2d_max_extent(self, arg, var_accesses=None):
232  '''Add the maximum branch extent for a 2D stencil associated with the
233  argument 'arg' to the argument list. If supplied it also stores this
234  in var_accesses.
235 
236  :param arg: the kernel argument with which the stencil is associated.
237  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
238  :param var_accesses: optional `SingleVariableAccessInfo` \
239  instance to store the information about variable accesses.
240  :type var_accesses: \
241  :py:class:`psyclone.core.SingleVariableAccessInfo`
242 
243  '''
244  # The maximum branch extent is not specified in the metadata so pass
245  # the value in.
246  # Import here to avoid circular dependency
247  # pylint: disable=import-outside-toplevel
248  from psyclone.domain.lfric.lfric_stencils import LFRicStencils
249  name = LFRicStencils.max_branch_length_name(self._stub_symtab_stub_symtab, arg)
250  self.appendappend(name, var_accesses)
251 
252  def stencil_2d_unknown_extent(self, arg, var_accesses=None):
253  '''Add 2D stencil information to the argument list associated with the
254  argument 'arg' if the extent is unknown. If supplied it also stores
255  this access in var_accesses.
256 
257  :param arg: the kernel argument with which the stencil is associated.
258  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
259  :param var_accesses: optional `VariablesAccessInfo` instance to store \
260  the information about variable accesses.
261  :type var_accesses: \
262  :py:class:`psyclone.core.VariablesAccessInfo`
263 
264  '''
265  # Import here to avoid circular dependency
266  # pylint: disable=import-outside-toplevel
267  from psyclone.domain.lfric.lfric_stencils import LFRicStencils
268  name = LFRicStencils.dofmap_size_symbol(self._stub_symtab_stub_symtab, arg).name
269  self.appendappend(name, var_accesses)
270 
271  def stencil_2d(self, arg, var_accesses=None):
272  '''Add general 2D stencil information associated with the argument
273  'arg' to the argument list. If supplied it also stores this access in
274  var_accesses.
275 
276  :param arg: the meta-data description of the kernel \
277  argument with which the stencil is associated.
278  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
279  :param var_accesses: optional `VariablesAccessInfo` instance to store \
280  the information about variable accesses.
281  :type var_accesses: \
282  :py:class:`psyclone.core.VariablesAccessInfo`
283 
284  '''
285  # The stencil_2D differs from the stencil in that the direction
286  # of the branch is baked into the stencil_dofmap array.
287  # The array dimensions are thus (dof_in_cell, cell_in_branch,
288  # branch_in_stencil) where the branch_in_stencil is always ordered
289  # West, South, East, North which is standard in LFRic. This allows
290  # for knowledge of what direction a stencil cell is in relation
291  # to the centre even when the stencil is truncated at boundaries.
292  # Import here to avoid circular dependency
293  # pylint: disable=import-outside-toplevel
294  from psyclone.domain.lfric.lfric_stencils import LFRicStencils
295  var_name = LFRicStencils.dofmap_symbol(self._stub_symtab_stub_symtab, arg).name
296  self.appendappend(var_name, var_accesses)
297 
298  def operator(self, arg, var_accesses=None):
299  '''Add the operator arguments to the argument list. If supplied it
300  also stores this access in var_accesses.
301 
302  :param arg: the meta-data description of the operator.
303  :type arg: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
304  :param var_accesses: optional VariablesAccessInfo instance to store \
305  the information about variable accesses.
306  :type var_accesses: \
307  :py:class:`psyclone.core.VariablesAccessInfo`
308 
309  '''
310  size = arg.name + "_ncell_3d"
311  self.appendappend(size, var_accesses)
312  self.appendappend(arg.name, var_accesses)
313 
314  def fs_compulsory_field(self, function_space, var_accesses=None):
315  ''' Provide compulsory arguments if there is a field on this
316  function space. If supplied it also stores this access in
317  var_accesses.
318 
319  :param function_space: the function space for which the compulsory \
320  arguments are added.
321  :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace`
322  :param var_accesses: optional VariablesAccessInfo instance to store \
323  the information about variable accesses.
324  :type var_accesses: \
325  :py:class:`psyclone.core.VariablesAccessInfo`
326 
327  '''
328  self.appendappend(function_space.undf_name, var_accesses)
329  self.appendappend(function_space.map_name, var_accesses)
330 
331  def basis(self, function_space, var_accesses=None):
332  '''Add basis function information for this function space to the
333  argument list and optionally to the variable access information.
334  There can be more than one if this is an evaluator and/or multiple
335  'gh_shape's have been requested in the kernel metadata. If supplied
336  it also stores these accesses in var_accesses.
337 
338  :param function_space: the function space for which to provide \
339  the basis functions
340  :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace`
341  :param var_accesses: optional VariablesAccessInfo instance to store \
342  the information about variable accesses.
343  :type var_accesses: \
344  :py:class:`psyclone.core.VariablesAccessInfo`
345 
346  :raises InternalError: if the evaluator shape is not recognised.
347 
348  '''
349  const = LFRicConstants()
350  for shape in self._kern_kern.eval_shapes:
351  if shape in const.VALID_QUADRATURE_SHAPES:
352  # A kernel stub won't have a name for the corresponding
353  # quadrature argument so we create one by appending the last
354  # part of the shape name to "qr_".
355  basis_name = function_space.get_basis_name(
356  qr_var="qr_"+shape.split("_")[-1])
357  self.appendappend(basis_name, var_accesses)
358 
359  elif shape in const.VALID_EVALUATOR_SHAPES:
360  # Need a basis array for each target space upon which the basis
361  # functions have been evaluated. _kern.eval_targets is a dict
362  # where the values are 2-tuples of (FunctionSpace, argument).
363  for _, target in self._kern_kern.eval_targets.items():
364  basis_name = \
365  function_space.get_basis_name(on_space=target[0])
366  self.appendappend(basis_name, var_accesses)
367  else:
368  raise InternalError(
369  f"Unrecognised evaluator shape ('{shape}'). Expected one "
370  f"of: {const.VALID_EVALUATOR_SHAPES}")
371 
372  def diff_basis(self, function_space, var_accesses=None):
373  '''Add differential basis information for the function space to the
374  argument list. If supplied it also stores this access in
375  var_accesses.
376 
377  :param function_space: the function space for which the differential \
378  basis functions are required.
379  :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace`
380  :param var_accesses: optional VariablesAccessInfo instance to store \
381  the information about variable accesses.
382  :type var_accesses: \
383  :py:class:`psyclone.core.VariablesAccessInfo`
384 
385  :raises InternalError: if the evaluator shape is not recognised.
386 
387  '''
388  const = LFRicConstants()
389  for shape in self._kern_kern.eval_shapes:
390  if shape in const.VALID_QUADRATURE_SHAPES:
391  # We need differential basis functions for quadrature. A
392  # kernel stub won't have a name for the corresponding
393  # quadrature argument so we create one by appending the
394  # last part of the shape name to "qr_".
395  diff_basis_name = function_space.get_diff_basis_name(
396  qr_var="qr_"+shape.split("_")[-1])
397  self.appendappend(diff_basis_name, var_accesses)
398 
399  elif shape in const.VALID_EVALUATOR_SHAPES:
400  # We need differential basis functions for an evaluator,
401  # potentially for multiple target spaces. _kern.eval_targets is
402  # a dict where the values are 2-tuples of
403  # (FunctionSpace, argument).
404  for _, target in self._kern_kern.eval_targets.items():
405  diff_basis_name = function_space.get_diff_basis_name(
406  on_space=target[0])
407  self.appendappend(diff_basis_name, var_accesses)
408  else:
409  raise InternalError(f"Unrecognised evaluator shape "
410  f"('{shape}'). Expected one of: "
411  f"{const.VALID_EVALUATOR_SHAPES}")
412 
413  def field_bcs_kernel(self, function_space, var_accesses=None):
414  '''Implement the boundary_dofs array fix for a field. If supplied it
415  also stores this access in var_accesses.
416 
417  :param function_space: the function space for which boundary dofs \
418  are required.
419  :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace`
420  :param var_accesses: optional VariablesAccessInfo instance to store \
421  the information about variable accesses.
422  :type var_accesses: \
423  :py:class:`psyclone.core.VariablesAccessInfo`
424 
425  '''
426  arg = self._kern_kern.arguments.get_arg_on_space(function_space)
427  name = "boundary_dofs_"+arg.name
428  self.appendappend(name, var_accesses)
429 
430  def operator_bcs_kernel(self, function_space, var_accesses=None):
431  '''Supply necessary additional arguments for the kernel that
432  applies boundary conditions to a LMA operator. If supplied it
433  also stores this access in var_accesses.
434 
435  :param function_space: the 'to' function space of the operator.
436  :type function_space: :py:class:`psyclone.dynamo3.FunctionSpace`
437  :param var_accesses: optional VariablesAccessInfo instance to store \
438  the information about variable accesses.
439  :type var_accesses: \
440  :py:class:`psyclone.core.VariablesAccessInfo`
441 
442  '''
443  self.field_bcs_kernelfield_bcs_kernelfield_bcs_kernel(function_space, var_accesses=var_accesses)
444 
445  def mesh_properties(self, var_accesses=None):
446  '''Provide the kernel arguments required for the mesh properties
447  specified in the kernel metadata. If supplied it also stores this
448  access in var_accesses.
449 
450  :param var_accesses: optional VariablesAccessInfo instance to store \
451  the information about variable accesses.
452  :type var_accesses: \
453  :py:class:`psyclone.core.VariablesAccessInfo`
454 
455  '''
456  if self._kern_kern.mesh.properties:
457  # Avoid circular import
458  # pylint: disable=import-outside-toplevel
459  from psyclone.dynamo0p3 import LFRicMeshProperties
460  self.extendextend(LFRicMeshProperties(self._kern_kern).
461  kern_args(stub=True, var_accesses=var_accesses))
462 
463  def quad_rule(self, var_accesses=None):
464  '''Add quadrature-related information to the kernel argument list.
465  Adds the necessary arguments to the argument list, and optionally
466  adds variable access information to the var_accesses object.
467 
468  :param var_accesses: optional VariablesAccessInfo instance to store \
469  the information about variable accesses.
470  :type var_accesses: \
471  :py:class:`psyclone.core.VariablesAccessInfo`
472 
473  '''
474  for rule in self._kern_kern.qr_rules.values():
475  self.extendextend(rule.kernel_args, var_accesses)
476 
477  def indirection_dofmap(self, function_space, operator=None,
478  var_accesses=None):
479  '''Add indirection dofmap required when applying a CMA operator. If
480  supplied it also stores this access in var_accesses.
481 
482  :param function_space: the function space for which the indirect \
483  dofmap is required.
484  :type function_space: :py:class:`psyclone.domain.lfric.FunctionSpace`
485  :param operator: the CMA operator.
486  :type operator: :py:class:`psyclone.dynamo0p3.DynKernelArgument`
487  :param var_accesses: optional VariablesAccessInfo instance to store \
488  the information about variable accesses.
489  :type var_accesses: \
490  :py:class:`psyclone.core.VariablesAccessInfo`
491 
492  :raises InternalError: if no kernel argument is supplied.
493  :raises InternalError: if the supplied kernel argument is not a \
494  CMA operator.
495 
496  '''
497  if not operator:
498  raise InternalError("No CMA operator supplied.")
499  if operator.argument_type != "gh_columnwise_operator":
500  raise InternalError(
501  f"A CMA operator (gh_columnwise_operator) must "
502  f"be supplied but got '{operator.argument_type}'.")
503  super().indirection_dofmap(function_space, operator, var_accesses)
504 
505 
506 # ============================================================================
507 # For automatic documentation creation:
508 __all__ = ["KernStubArgList"]
def field_bcs_kernel(self, function_space, var_accesses=None)
def append(self, var_name, var_accesses=None, var_access_name=None, mode=AccessType.READ, metadata_posn=None)
def extend(self, list_var_name, var_accesses=None, mode=AccessType.READ, list_metadata_posn=None)
def diff_basis(self, function_space, var_accesses=None)
def fs_compulsory_field(self, function_space, var_accesses=None)
def indirection_dofmap(self, function_space, operator=None, var_accesses=None)
def basis(self, function_space, var_accesses=None)
def field_bcs_kernel(self, function_space, var_accesses=None)
def operator_bcs_kernel(self, function_space, var_accesses=None)