Reference Guide  2.5.0
lfric_constants.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2021-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 # Author: J. Henrichs, Bureau of Meteorology
35 # Modified: I. Kavcic, Met Office
36 # A. R. Porter, STFC Daresbury Laboratory
37 # R. W. Ford, STFC Daresbury Laboratory
38 
39 '''
40 This module provides a class with all LFRic related constants.
41 '''
42 
43 from collections import OrderedDict
44 
45 from psyclone.configuration import Config
46 from psyclone.errors import InternalError
47 
48 
49 # pylint: disable=too-few-public-methods
51  '''This class stores all LFRic constants. Note that some constants
52  depend on values in the config file, so this class can only be
53  used after the config file has been read.
54  It stores all values in class variables (to avoid re-evaluating them).
55 
56  '''
57  HAS_BEEN_INITIALISED = False
58 
59  def __init__(self):
60  # pylint: disable=too-many-statements
61  if LFRicConstants.HAS_BEEN_INITIALISED:
62  return
63 
64  if not Config.has_config_been_initialised():
65  raise InternalError("LFRicConstants is being created before the "
66  "config file is loaded")
67 
68  LFRicConstants.HAS_BEEN_INITIALISED = True
69  api_config = Config.get().api_conf("dynamo0.3")
70 
71  # ---------- Evaluators: quadrature -----------------------------------
72  LFRicConstants.VALID_QUADRATURE_SHAPES = \
73  ["gh_quadrature_xyoz", "gh_quadrature_face", "gh_quadrature_edge"]
74  LFRicConstants.VALID_EVALUATOR_SHAPES = \
75  LFRicConstants.VALID_QUADRATURE_SHAPES + ["gh_evaluator"]
76 
77  # ---------- LFRicArgDescriptor class constants ----------------------
78 
79  # Supported LFRic API argument types (scalars, fields, operators)
80  LFRicConstants.VALID_SCALAR_NAMES = ["gh_scalar"]
81  LFRicConstants.VALID_FIELD_NAMES = ["gh_field"]
82  LFRicConstants.VALID_OPERATOR_NAMES = ["gh_operator",
83  "gh_columnwise_operator"]
84  LFRicConstants.VALID_ARG_TYPE_NAMES = \
85  LFRicConstants.VALID_FIELD_NAMES + \
86  LFRicConstants.VALID_OPERATOR_NAMES + \
87  LFRicConstants.VALID_SCALAR_NAMES
88 
89  # Mapping from argument type to the suffix used when creating
90  # pointers to actual data arrays (and the associated symbol tags).
91  LFRicConstants.ARG_TYPE_SUFFIX_MAPPING = {
92  "gh_field": "data",
93  "gh_operator": "local_stencil",
94  "gh_columnwise_operator": "cma_matrix"
95  }
96 
97  # Supported API argument data types ('gh_real', 'gh_integer'
98  # and 'gh_logical')
99  LFRicConstants.VALID_ARG_DATA_TYPES = \
100  ["gh_real", "gh_integer", "gh_logical"]
101  LFRicConstants.VALID_SCALAR_DATA_TYPES = \
102  LFRicConstants.VALID_ARG_DATA_TYPES
103  LFRicConstants.VALID_FIELD_DATA_TYPES = ["gh_real", "gh_integer"]
104  LFRicConstants.VALID_OPERATOR_DATA_TYPES = ["gh_real"]
105 
106  # pylint: disable=too-many-instance-attributes
107 
108  # Supported access types
109  # gh_sum for scalars is restricted to iterates_over == 'dof'
110  LFRicConstants.VALID_SCALAR_ACCESS_TYPES = ["gh_read", "gh_sum"]
111  LFRicConstants.VALID_FIELD_ACCESS_TYPES = [
112  "gh_read", "gh_write", "gh_readwrite", "gh_inc", "gh_readinc"]
113  LFRicConstants.VALID_OPERATOR_ACCESS_TYPES = [
114  "gh_read", "gh_write", "gh_readwrite"]
115  LFRicConstants.VALID_ACCESS_TYPES = [
116  "gh_read", "gh_write", "gh_readwrite", "gh_inc", "gh_readinc"]
117 
118  LFRicConstants.WRITE_ACCESSES = [
119  "gh_write", "gh_readwrite", "gh_inc", "gh_readinc", "gh_sum"]
120 
121  # Supported LFRic API stencil types and directions
122  LFRicConstants.VALID_STENCIL_TYPES = ["x1d", "y1d", "xory1d", "cross",
123  "region", "cross2d"]
124  # Note, can't use VALID_STENCIL_DIRECTIONS at all locations in this
125  # file as it causes failures with py.test 2.8.7. Therefore some parts
126  # of the code do not use the VALID_STENCIL_DIRECTIONS variable.
127  LFRicConstants.VALID_STENCIL_DIRECTIONS = ["x_direction",
128  "y_direction"]
129 
130  # Note, xory1d does not have a direct mapping in STENCIL_MAPPING as it
131  # indicates either x1d or y1d.
132  LFRicConstants.STENCIL_MAPPING = \
133  {"x1d": "STENCIL_1DX", "y1d": "STENCIL_1DY",
134  "cross": "STENCIL_CROSS", "cross2d": "STENCIL_2D_CROSS",
135  "region": "STENCIL_REGION"}
136 
137  # Supported LFRic API mesh types that may be specified for a field
138  # using the mesh_arg=... meta-data element (for inter-grid kernels that
139  # perform prolongation/restriction).
140  LFRicConstants.VALID_MESH_TYPES = ["gh_coarse", "gh_fine"]
141 
142  # ---------- Fortran datatypes ----------------------------------------
143  # This is only used here, so no class variable:
144  supported_fortran_datatypes = api_config.supported_fortran_datatypes
145 
146  # psyGen intrinsic types for kernel argument data as defined in LFRic
147  # configuration by the supported Fortran datatypes ('real', 'integer'
148  # and 'logical').
149  LFRicConstants.VALID_INTRINSIC_TYPES = supported_fortran_datatypes
150 
151  # Valid intrinsic types for field kernel argument data
152  # ('real', 'integer', and 'logical').
153  LFRicConstants.VALID_FIELD_INTRINSIC_TYPES = ["real", "integer",
154  "logical"]
155 
156  # ---------- Mapping from metadata data_type to Fortran intrinsic type
157  LFRicConstants.MAPPING_DATA_TYPES = \
158  OrderedDict(zip(LFRicConstants.VALID_ARG_DATA_TYPES,
159  LFRicConstants.VALID_INTRINSIC_TYPES))
160 
161  # ---------- Mapping from Fortran intrinsic type to metadata data_type
162  LFRicConstants.MAPPING_INTRINSIC_TYPES = \
163  OrderedDict(zip(LFRicConstants.VALID_INTRINSIC_TYPES,
164  LFRicConstants.VALID_ARG_DATA_TYPES))
165 
166  # ---------- Loops (bounds, types, names) -----------------------------
167  # These are loop bound names which identify positions in a field's
168  # halo. It is useful to group these together as we often need to
169  # determine whether an access to a field or other object includes
170  # access to the halo, or not.
171  LFRicConstants.HALO_ACCESS_LOOP_BOUNDS = ["cell_halo", "dof_halo",
172  "colour_halo"]
173 
174  LFRicConstants.VALID_LOOP_BOUNDS_NAMES = \
175  (["start", # the starting
176  # index. Currently this is
177  # always 1
178  "inner", # a placeholder for when we
179  # support loop splitting into
180  # work that does not access
181  # the halo and work that does.
182  # This will be used to help
183  # overlap computation and
184  # communication
185  "ncolour", # the number of cells with
186  # the current colour
187  "ncolours", # the number of colours in a
188  # coloured loop
189  "ncells", # the number of owned cells
190  "ndofs", # the number of owned dofs
191  "nannexed"] # the number of owned dofs
192  # plus the number of annexed
193  # dofs. As the indices of
194  # dofs are arranged that
195  # owned dofs have lower
196  # indices than annexed dofs,
197  # having this value as an
198  # upper bound will compute
199  # both owned and annexed
200  # dofs.
201  + LFRicConstants.HALO_ACCESS_LOOP_BOUNDS)
202 
203  # Valid LFRic loop types. The default is "" which is over cell columns
204  # (in the horizontal plane). A "null" loop doesn't iterate over
205  # anything but is required for the halo-exchange logic.
206  LFRicConstants.VALID_LOOP_TYPES = ["dof", "colours", "colour", "",
207  "null"]
208 
209  # Valid LFRic iteration spaces for built-in kernels
210  LFRicConstants.BUILTIN_ITERATION_SPACES = ["dof"]
211 
212  # The types of argument that are valid for built-in kernels in the
213  # LFRic API
214  LFRicConstants.VALID_BUILTIN_ARG_TYPES = \
215  LFRicConstants.VALID_FIELD_NAMES + \
216  LFRicConstants.VALID_SCALAR_NAMES
217 
218  # The data types of argument that are valid for built-in kernels
219  # in the LFRic API ('real' and 'integer')
220  LFRicConstants.VALID_BUILTIN_DATA_TYPES = ["gh_real", "gh_integer"]
221 
222  # Valid LFRic iteration spaces for user-supplied kernels and
223  # built-in kernels
224  LFRicConstants.USER_KERNEL_ITERATION_SPACES = ["cell_column", "domain"]
225  LFRicConstants.VALID_ITERATION_SPACES = \
226  LFRicConstants.USER_KERNEL_ITERATION_SPACES + \
227  LFRicConstants.BUILTIN_ITERATION_SPACES
228 
229  # ---------- Function spaces (FS) -------------------------------------
230  # Discontinuous FS
231  LFRicConstants.DISCONTINUOUS_FUNCTION_SPACES = \
232  ["w3", "wtheta", "w2v", "w2vtrace", "w2broken"]
233 
234  # Continuous FS
235  # Note, any_w2 is not a space on its own. any_w2 is used as a common
236  # term for any vector "w2*" function space (w2, w2h, w2v, w2broken) but
237  # not w2*trace (spaces of scalar functions). As any_w2 stands for all
238  # vector "w2*" spaces it needs to a) be treated as continuous and b)
239  # have vector basis and scalar differential basis dimensions.
240  # TODO #540: resolve what W2* spaces should be included in ANY_W2 list
241  # and whether ANY_W2 should be in the continuous function space list.
242  LFRicConstants.ANY_W2_FUNCTION_SPACES = \
243  ["w2", "w2h", "w2v", "w2broken"]
244 
245  LFRicConstants.CONTINUOUS_FUNCTION_SPACES = \
246  ["w0", "w1", "w2", "w2trace", "w2h", "w2htrace", "any_w2"]
247 
248  # Read-only FS
249  LFRicConstants.READ_ONLY_FUNCTION_SPACES = ["wchi"]
250 
251  # Valid FS names
252  LFRicConstants.VALID_FUNCTION_SPACES = \
253  LFRicConstants.DISCONTINUOUS_FUNCTION_SPACES + \
254  LFRicConstants.CONTINUOUS_FUNCTION_SPACES + \
255  LFRicConstants.READ_ONLY_FUNCTION_SPACES
256 
257  # Valid any_space metadata (general FS, could be continuous or
258  # discontinuous). The number of 'ANY_SPACE' spaces is set in the
259  # PSyclone configuration file.
260  LFRicConstants.VALID_ANY_SPACE_NAMES = [
261  f"any_space_{x+1}" for x in
262  range(api_config.num_any_space)]
263 
264  # Valid any_discontinuous_space metadata (general FS known to be
265  # discontinuous). The number of 'ANY_DISCONTINUOU_SPACE' spaces is
266  # set in the PSyclone configuration file.
267  LFRicConstants.VALID_ANY_DISCONTINUOUS_SPACE_NAMES = [
268  f"any_discontinuous_space_{x+1}" for x in
269  range(api_config.num_any_discontinuous_space)]
270 
271  # Valid discontinuous FS names (for optimisation purposes)
272  LFRicConstants.VALID_DISCONTINUOUS_NAMES = \
273  LFRicConstants.DISCONTINUOUS_FUNCTION_SPACES +\
274  LFRicConstants.VALID_ANY_DISCONTINUOUS_SPACE_NAMES
275 
276  # FS names consist of all valid names
277  LFRicConstants.VALID_FUNCTION_SPACE_NAMES = \
278  LFRicConstants.VALID_FUNCTION_SPACES + \
279  LFRicConstants.VALID_ANY_SPACE_NAMES + \
280  LFRicConstants.VALID_ANY_DISCONTINUOUS_SPACE_NAMES
281 
282  # Lists of function spaces that have
283  # a) scalar basis functions;
284  LFRicConstants.SCALAR_BASIS_SPACE_NAMES = \
285  ["w0", "w2trace", "w2htrace", "w2vtrace", "w3", "wtheta", "wchi"]
286  # b) vector basis functions;
287  LFRicConstants.VECTOR_BASIS_SPACE_NAMES = ["w1", "w2", "w2h", "w2v",
288  "w2broken", "any_w2"]
289  # c) scalar differential basis functions;
290  LFRicConstants.SCALAR_DIFF_BASIS_SPACE_NAMES = ["w2", "w2h", "w2v",
291  "w2broken", "any_w2"]
292  # d) vector differential basis functions.
293  LFRicConstants.VECTOR_DIFF_BASIS_SPACE_NAMES = \
294  ["w0", "w1", "w2trace", "w2htrace", "w2vtrace", "w3", "wtheta",
295  "wchi"]
296 
297  # Evaluators: basis and differential basis
298  LFRicConstants.VALID_EVALUATOR_NAMES = ["gh_basis", "gh_diff_basis"]
299 
300  # Meta functions
301  LFRicConstants.VALID_METAFUNC_NAMES = \
302  LFRicConstants.VALID_EVALUATOR_NAMES
303 
304  # Valid Reference Element names
305  LFRicConstants.VALID_REF_ELEMENT_NAMES = [
306  "normals_to_horizontal_faces", "normals_to_vertical_faces",
307  "normals_to_faces", "outward_normals_to_horizontal_faces",
308  "outward_normals_to_vertical_faces", "outward_normals_to_faces"]
309 
310  # Valid mesh names
311  LFRicConstants.VALID_MESH_NAMES = ["adjacent_face"]
312 
313  # ---------- Map from scalar intrinsic type to its precision ----------
314  LFRicConstants.SCALAR_PRECISION_MAP = \
315  OrderedDict(zip(LFRicConstants.VALID_INTRINSIC_TYPES,
316  ["r_def", "i_def", "l_def"]))
317 
318  # ---------- Infrastructure module maps -------------------------------
319 
320  # Dictionary allowing us to look-up the name of the Fortran module,
321  # type and proxy-type associated with each LFRic data structure type.
322  # Data structure type mandates its proxy name, Fortran intrinsic type
323  # of its data and the kind (precision) for the intrinsic type.
324  LFRicConstants.DATA_TYPE_MAP = {
325  # 'real'-valued scalar reduction of kind 'r_def' (used for global
326  # reductions of "field_type" data)
327  "reduction": {"module": "scalar_mod",
328  "type": "scalar_type",
329  "proxy_type": None,
330  "intrinsic": "real",
331  "kind": "r_def"},
332  # 'real'-valued field with data of kind 'r_def'
333  "field": {"module": "field_mod",
334  "type": "field_type",
335  "proxy_type": "field_proxy_type",
336  "intrinsic": "real",
337  "kind": "r_def"},
338  # 'real'-valued field with data of kind 'r_solver'
339  "r_solver_field": {"module": "r_solver_field_mod",
340  "type": "r_solver_field_type",
341  "proxy_type": "r_solver_field_proxy_type",
342  "intrinsic": "real",
343  "kind": "r_solver"},
344  # 'real'-valued field with data of kind 'r_tran'
345  "r_tran_field": {"module": "r_tran_field_mod",
346  "type": "r_tran_field_type",
347  "proxy_type": "r_tran_field_proxy_type",
348  "intrinsic": "real",
349  "kind": "r_tran"},
350  # 'real'-valued field with data of kind 'r_bl'
351  "r_bl_field": {"module": "r_bl_field_mod",
352  "type": "r_bl_field_type",
353  "proxy_type": "r_bl_field_proxy_type",
354  "intrinsic": "real",
355  "kind": "r_bl"},
356  # 'real'-valued field with data of kind 'r_phys'
357  "r_phys_field": {"module": "r_phys_field_mod",
358  "type": "r_phys_field_type",
359  "proxy_type": "r_phys_field_proxy_type",
360  "intrinsic": "real",
361  "kind": "r_phys"},
362  # 'integer'-valued field with data of kind 'i_def'
363  "integer_field": {"module": "integer_field_mod",
364  "type": "integer_field_type",
365  "proxy_type": "integer_field_proxy_type",
366  "intrinsic": "integer",
367  "kind": "i_def"},
368  # 'real'-valued operator with data of kind 'r_def'
369  "operator": {"module": "operator_mod",
370  "type": "operator_type",
371  "proxy_type": "operator_proxy_type",
372  "intrinsic": "real",
373  "kind": "r_def"},
374  # 'real'-valued operator with data of kind 'r_solver'
375  "r_solver_operator": {
376  "module": "r_solver_operator_mod",
377  "type": "r_solver_operator_type",
378  "proxy_type": "r_solver_operator_proxy_type",
379  "intrinsic": "real",
380  "kind": "r_solver"},
381  # 'real'-valued operator with data of kind 'r_tran'
382  "r_tran_operator": {
383  "module": "r_tran_operator_mod",
384  "type": "r_tran_operator_type",
385  "proxy_type": "r_tran_operator_proxy_type",
386  "intrinsic": "real",
387  "kind": "r_tran"},
388  # 'real'-valued columnwise operator with data of kind 'r_solver'
389  "columnwise_operator": {
390  "module": "columnwise_operator_mod",
391  "type": "columnwise_operator_type",
392  "proxy_type": "columnwise_operator_proxy_type",
393  "intrinsic": "real",
394  "kind": "r_solver"}}
395 
396  # Mapping from a vector type used in the algorithm-layer to
397  # the actual type used in the PSy-layer.
398  LFRicConstants.FIELD_VECTOR_TO_FIELD_MAP = {
399  "field_vector_type": "field_type",
400  "r_solver_field_vector_type": "r_solver_field_type",
401  "r_tran_field_vector_type": "r_tran_field_type",
402  "r_bl_field_vector_type": "r_bl_field_type",
403  "r_phys_field_vector_type": "r_phys_field_type"}
404 
405  # Dictionary allowing us to look-up the name of the Fortran module
406  # and type (if existing) associated with stencil shapes and directions.
407  LFRicConstants.STENCIL_TYPE_MAP = {
408  "stencil_dofmap": {"module": "stencil_dofmap_mod",
409  "type": "stencil_dofmap_type"},
410  "stencil_2D_dofmap": {"module": "stencil_2D_dofmap_mod",
411  "type": "stencil_2D_dofmap_type"},
412  "direction": {"module": "flux_direction_mod"}}
413 
414  # Dictionary allowing us to look-up the name of the Fortran module,
415  # type and proxy-type associated with each quadrature shape.
416  LFRicConstants.QUADRATURE_TYPE_MAP = {
417  "gh_quadrature_xyoz": {"module": "quadrature_xyoz_mod",
418  "type": "quadrature_xyoz_type",
419  "proxy_type": "quadrature_xyoz_proxy_type",
420  "intrinsic": "real",
421  "kind": "r_def"},
422  "gh_quadrature_face": {"module": "quadrature_face_mod",
423  "type": "quadrature_face_type",
424  "proxy_type": "quadrature_face_proxy_type",
425  "intrinsic": "real",
426  "kind": "r_def"},
427  "gh_quadrature_edge": {"module": "quadrature_edge_mod",
428  "type": "quadrature_edge_type",
429  "proxy_type": "quadrature_edge_proxy_type",
430  "intrinsic": "real",
431  "kind": "r_def"}}
432 
433  # Dictionary allowing us to look-up the name of the Fortran module
434  # and type associated with mesh.
435  LFRicConstants.MESH_TYPE_MAP = {
436  "mesh": {"module": "mesh_mod",
437  "type": "mesh_type"},
438  "mesh_map": {"module": "mesh_map_mod",
439  "type": "mesh_map_type"}}
440 
441  # Dictionary allowing us to look-up the name of the Fortran module
442  # and type associated with reference element.
443  LFRicConstants.REFELEMENT_TYPE_MAP = {
444  "refelement": {"module": "reference_element_mod",
445  "type": "reference_element_type"}}
446 
447  # Dictionary allowing us to look-up the name of the Fortran module
448  # and type (if existing) associated with function space.
449  LFRicConstants.FUNCTION_SPACE_TYPE_MAP = {
450  # Function space type (for basis and differential basis functions)
451  "function_space": {"module": "function_space_mod",
452  "type": "function_space_type"},
453  # Function space identifiers
454  "fs_continuity": {"module": "fs_continuity_mod"}}
455 
456  # Dictionary allowing us to look-up the name of the Fortran modules
457  # that store various utilities in LFRic.
458  LFRicConstants.UTILITIES_MOD_MAP = {
459  # Constants module (stores precisions)
460  "constants": {"module": "constants_mod"},
461  # Logging module (used for runtime checks)
462  "logging": {"module": "log_mod"}}
463 
464  @staticmethod
466  '''
467  Maps from a valid kernel metadata function-space name to one
468  that exists within the LFRic infrastructure. This is necessary
469  because meta-data can contain 'generic' names such as 'any_w2' but,
470  when generating code, we need the name of a specific function space
471  that is recognised by the LFRic infrastructure.
472 
473  :param str name: the name of the function space in metadata.
474 
475  :returns: the name of a specific function space.
476  :rtype: str
477 
478  :raises ValueError: if the supplied name is not a valid LFRic \
479  function-space name.
480  :raises InternalError: if an unrecognised wildcard function-space \
481  name is supplied.
482  '''
483  space = name.lower()
484  if space not in LFRicConstants.VALID_FUNCTION_SPACE_NAMES:
485  raise ValueError(
486  f"'{space}' is not a recognised LFRic function space (one of "
487  f"{LFRicConstants.VALID_FUNCTION_SPACE_NAMES}).")
488 
489  # TODO #1709 - make this mapping configurable rather than
490  # hardwiring it here.
491  if not space.startswith("any_"):
492  return space
493  if space == "any_w2":
494  return "w2"
495  if space.startswith("any_space_"):
496  return LFRicConstants.CONTINUOUS_FUNCTION_SPACES[0]
497  if space.startswith("any_discontinuous_space_"):
498  return LFRicConstants.DISCONTINUOUS_FUNCTION_SPACES[0]
499 
500  raise InternalError(f"Error mapping from meta-data function space "
501  f"to actual space: cannot handle '{space}'")
502 
503  def precision_for_type(self, data_type):
504  '''This function returns the precision required for the various
505  LFRic types.
506 
507  :param str data_type: the name of the data type.
508 
509  :returns: the precision as defined in domain.lfric.lfric_types
510  (one of R_SOLVER, R_TRAN, R_DEF).
511  :rtype: :py:class:`psyclone.psyir.symbols.DataSymbol`
512 
513  :raises InternalError: if an unknown data_type is specified.
514 
515  '''
516  for module_info in self.DATA_TYPE_MAP.values():
517  if module_info["type"] == data_type:
518  # pylint: disable=import-outside-toplevel
519  from psyclone.domain.lfric.lfric_types import LFRicTypes
520  return LFRicTypes(module_info["kind"].upper())
521 
522  valid = [module_info["type"]
523  for module_info in self.DATA_TYPE_MAP.values()]
524  raise InternalError(f"Unknown data type '{data_type}', expected one "
525  f"of {valid}.")
526 
527 
528 # =============================================================================
529 # Documentation utils: The list of module members that we wish AutoAPI to
530 # generate documentation for (see https://psyclone-ref.readthedocs.io).
531 __all__ = ['LFRicConstants']