Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1786 Adding real-to-real conversion builtin #2420

Merged
merged 28 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8666926
#1786 renamed LFRicIntXKern to LFRicRealToIntXKern
oakleybrunt Nov 27, 2023
447b9dd
#1786 Caught unchanged instances
oakleybrunt Nov 27, 2023
f757b18
#1786 Renamed LFRicRealXKern to LFRicIntToRealXKern
oakleybrunt Nov 27, 2023
c95f268
Added source code for LFRicRealToReal builtin (#1786)
oakleybrunt Nov 28, 2023
7f35c45
#1786 Updated testing of real_to_real_X builtin
oakleybrunt Nov 30, 2023
51c617d
#1786 Updated docs
oakleybrunt Dec 1, 2023
579a0c4
Merge branch 'master' into 1786_renaming_conversion_builtins
oakleybrunt Dec 1, 2023
5867cfe
#1786 Fixed test assertion
oakleybrunt Dec 1, 2023
016ac87
Merge branch '1786_renaming_conversion_builtins' of github.com:stfc/P…
oakleybrunt Dec 1, 2023
9c9aeb1
#1786 Cleaning up
oakleybrunt Dec 1, 2023
c82d8d6
Merge branch 'master' into 1786_renaming_conversion_builtins
oakleybrunt Dec 19, 2023
ec6a91a
#1786 Fixed missing hastag for comment
oakleybrunt Dec 19, 2023
bb881e8
#1786 Removed partial datatype accessor
oakleybrunt Dec 19, 2023
bc24dc1
Merge branch 'master' into 1786_renaming_conversion_builtins
oakleybrunt Dec 20, 2023
9488f60
Merge branch 'master' into 1786_renaming_conversion_builtins
oakleybrunt Jan 8, 2024
b42a518
#1786 Actioned @TeranIvy comments
oakleybrunt Jan 12, 2024
f3a7312
Merge branch '1786_renaming_conversion_builtins' of github.com:stfc/P…
oakleybrunt Jan 12, 2024
e173244
#1786 output matches code
oakleybrunt Jan 12, 2024
4ab0223
#1786 git renamed instead of del/make conversion test files
oakleybrunt Jan 15, 2024
eb08cf9
Merge branch 'master' into 1786_renaming_conversion_builtins
oakleybrunt Jan 15, 2024
d9c2d93
#1786 Renamed BACK to match branch changesÂ
oakleybrunt Jan 15, 2024
f9164a8
Merge branch 'master' into 1786_renaming_conversion_builtins
TeranIvy Jan 15, 2024
59dc9f9
Merge branch 'master' into 1786_renaming_conversion_builtins
oakleybrunt Jan 18, 2024
7307eb3
#1786 Actioned @TeranIvy changes
oakleybrunt Jan 18, 2024
f765bbe
Merge branch '1786_renaming_conversion_builtins' of github.com:stfc/P…
oakleybrunt Jan 18, 2024
4beeee7
PR #2420: Small documentation update
TeranIvy Jan 19, 2024
2f4a5a7
PR #2420: Merged branch 'master' into 1786_renaming_conversion_builtins
TeranIvy Jan 19, 2024
c511ffb
PR #2420: Update changelog and user guide for merge to master
TeranIvy Jan 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@
dl_esm_inf library and updates associated links (remove references to
puma).

49) PR #2420 towards #1786. Add and update Built-ins to support
mixed precision in the LFRic API: real to real, real to integer
and integer to real field types.

release 2.4.0 29th of September 2023

1) PR #1758 for #1741. Splits the PSyData read functionality into a
Expand Down
9 changes: 0 additions & 9 deletions doc/developer_guide/APIs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1073,15 +1073,6 @@ layer routine. A lot of this work is currently performed in the
https://github.com/stfc/PSyclone/issues/1258) much of this will be
removed.

To date, all the LFRic BuiltIns have had ``lower_to_language_level()``
methods implemented except for the following:

* ``LFRicXInnerproductYKern``,
* ``LFRicXInnerproductXKern``,
* ``LFRicSumXKern``,
* ``LFRicIntXKern``,
* ``LFRicRealXKern``.

The sum and inner product BuiltIns require extending PSyIR to handle
reductions in the ``GlobalSum`` class in ``psyGen.py``. Conversions from
``real`` to ``int`` and vice-versa require the target precisions be
Expand Down
86 changes: 53 additions & 33 deletions doc/user_guide/dynamo0p3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
.. POSSIBILITY OF SUCH DAMAGE.
.. -----------------------------------------------------------------------------
.. Written by R. W. Ford and A. R. Porter, STFC Daresbury Lab
.. Modified by I. Kavcic and A. Coughtrie, Met Office
.. Modified by I. Kavcic, A. Coughtrie and O. Brunt Met Office
TeranIvy marked this conversation as resolved.
Show resolved Hide resolved

.. highlight:: fortran

Expand Down Expand Up @@ -2509,8 +2509,8 @@ following rules:

8) The only two exceptions from the rules 6) and 7) above regarding the
same data type of "write" and "read" field arguments are Built-ins
that convert field data from ``real`` to ``integer``, ``int_X``,
and from ``integer`` to ``real``, ``real_X``.
that convert field data from ``real`` to ``integer``, ``real_to_int_X``,
and from ``integer`` to ``real``, ``int_to_real_X``.

The Built-ins supported for the LFRic API are listed in the related
subsections, grouped first by the data type of fields they operate on
Expand Down Expand Up @@ -2661,9 +2661,7 @@ scheme presented below. Any new Built-in needs to comply with these rules.
arguments (i.e. ``"inc_"<RHSargs>_<operationname>_<RHSargs>``);

4) Prefix ``"int_"`` for the Built-in operations on the ``integer``-valued
field arguments (i.e. ``"int_inc_"<RHSargs>_<operationname>_<RHSargs>``),
except for the Built-in that converts the data type of field arguments
from ``integer`` to ``real`` (see rule 7 below).
field arguments (i.e. ``"int_inc_"<RHSargs>_<operationname>_<RHSargs>``).

6) Built-ins names in Python definitions are similar to their Fortran
counterparts, with a few differences:
Expand All @@ -2677,14 +2675,7 @@ scheme presented below. Any new Built-in needs to comply with these rules.

3) Common prefix is ``"LFRic"`` for the Built-in operations on the
``real``-valued arguments and ``"LFRicInt"`` for the Built-in
operations on the ``integer``-valued fields (except for the
data-type conversion Built-ins, see rule 7 below).

7) As in the case of Built-in field argument rules, the names of the
field data-type conversion Built-ins, ``int_X`` (converts field data
from ``real`` to ``integer``) and ``real_X`` (converts field data
from ``integer`` to ``real``), are the only exceptions for the
naming of Built-ins in Fortran above.
operations on the ``integer``-valued fields.

.. _lfric-built-ins-real:

Expand Down Expand Up @@ -3265,28 +3256,54 @@ the same field (``X = min(a, X)``)::

field(:) = MIN(rscalar, field(:))

Conversion of ``real`` to ``integer`` field elements
####################################################
Conversion of ``real`` field elements
#####################################

A Built-in which takes a ``real`` field and converts it to an
``integer`` field is denoted with the keyword **int**.
Built-ins which take a ``real`` field for conversion to a field of
a different datatype or precision are denoted by the datatype that the
input ``real`` field will be converted to. A Built-in that converts a
``real`` to an ``integer`` field is denoted by the phrase **to_int**.
Likewise, a Built-in that converts a ``real`` to a ``real`` field is
denoted by the phrase **to_real**.

int_X
^^^^^
.. _real-to-int-built-in:

real_to_int_X
^^^^^^^^^^^^^

**int_X** (**ifield2**, *field1*)
**real_to_int_X** (**ifield2**, *field1*)

Converts ``real``-valued field elements to ``integer``-valued field
elements, e.g. in Fortran this would be: ``Y = INT(X, kind=i_def)``.
elements, e.g. in Fortran this would be: ``Y = INT(X, kind=i_<prec>)``.
Here ``Y`` is an ``integer``-valued field and ``X`` is the
``real``-valued field being converted::

ifield2(:) = INT(field1(:), kind=i_def)
ifield2(:) = INT(field1(:), kind=i_<prec>)

where **ifield2** is currently the only supported ``integer``-valued field
type in LFRic (``integer_field_type`` of ``i_def`` precision) and a ``real``
-valued field *field1* can be of any :ref:`supported precisions
<lfric-mixed-precision>` for ``GH_REAL`` fields (e.g. ``r_tran`` for
``r_tran_field_type``).

where **ifield2** is an ``integer_field_type`` of ``i_def`` precision
and a ``real``-valued field *field1* can be of any :ref:`supported
precisions <lfric-mixed-precision>` for ``GH_REAL`` fields (e.g.
``r_tran`` for ``r_tran_field_type``).
.. _real-to-real-built-in:

real_to_real_X
^^^^^^^^^^^^^^

**real_to_real_X** (**field2**, *field1*)

Converts ``real``-valued field elements from a precision ``r_<prec>``
to ``real``-valued field elements of a differing precision ``r_<prec>``,
e.g. in Fortran this would be: ``Y = REAL(X, kind=r_<prec>)``. Here ``Y``
and ``X`` are both ``real``-valued fields, with ``X`` being converted
to the precision of ``Y``::

field2(:) = REAL(field1(:), kind=r_<prec>)

**field2** and *field1* are ``real``-valued fields of any :ref:`supported
precisions <lfric-mixed-precision>` for ``GH_REAL`` fields (e.g. ``r_tran``
for ``r_tran_field_type``).

.. _lfric-built-ins-int:

Expand Down Expand Up @@ -3572,21 +3589,24 @@ Conversion of ``integer`` to ``real`` field elements
####################################################

A Built-in which takes an ``integer`` field and converts it to
a ``real`` field is denoted with the keyword **real**.
a ``real`` field is denoted by the phrase **to_real**.

real_X
^^^^^^
.. _int-to-real-built-in:

int_to_real_X
^^^^^^^^^^^^^

**real_X** (**field2**, *ifield1*)
**int_to_real_X** (**field2**, *ifield1*)

Converts ``integer``-valued field elements to ``real``-valued field
elements, e.g. in Fortran this would be ``Y = REAL(X, kind=r_def)``.
elements, e.g. in Fortran this would be ``Y = REAL(X, kind=r_<prec>)``.
Here ``Y`` is a ``real``-valued field and ``X`` is the
``integer``-valued field being converted::
TeranIvy marked this conversation as resolved.
Show resolved Hide resolved

field2(:) = REAL(ifield1(:), kind=r_<prec>)

where *ifield1* is an ``integer_field_type`` of ``i_def`` precision.
where **ifield1** is currently the only supported ``integer``-valued
field type in LFRic (``integer_field_type`` of ``i_def`` precision).
The ``real``-valued **field1** can be of any :ref:`supported
precisions <lfric-mixed-precision>` for ``GH_REAL`` fields, hence
``r_<prec>`` is determined from the algorithm layer (e.g.
Expand Down
Binary file modified psyclone.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion src/psyclone/domain/lfric/kernel/lfric_kernel_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def _validate_general_purpose_kernel(self):
# 7: The only two exceptions from the rules 5) and 6) above
# regarding the same data type of “write” and “read” field
# arguments are Built-ins that convert field data from real to
# integer, int_X, and from integer to real, real_X.
# integer, real_to_int_X, and from integer to real, int_to_real_X.

def _validate_domain_kernel(self):
'''Validation checks for a domain kernel.
Expand Down
84 changes: 72 additions & 12 deletions src/psyclone/domain/lfric/lfric_builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
# POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------
# Author A. R. Porter, STFC Daresbury Lab
# Modified by I. Kavcic and L. Turner, Met Office
# Modified by I. Kavcic, L. Turner and O. Brunt, Met Office
TeranIvy marked this conversation as resolved.
Show resolved Hide resolved
# Modified by J. Henrichs, Bureau of Meteorology
# Modified by R. W. Ford, N. Nobre and S. Siso, STFC Daresbury Lab

Expand Down Expand Up @@ -351,7 +351,9 @@ def _validate(self):
f"must be on the same space. However, found spaces "
f"{spaces_str} for arguments to '{self.name}'")

conversion_builtins = ["int_X", "real_X"]
conversion_builtins = ["real_to_int_X",
"real_to_real_X",
"int_to_real_X"]
conversion_builtins_lower = [x.lower() for x in conversion_builtins]
if len(data_types) != 1 and self.name not in conversion_builtins_lower:
data_types_str = [str(x) for x in sorted(data_types)]
Expand Down Expand Up @@ -2697,7 +2699,7 @@ def lower_to_language_level(self):
# ------------------------------------------------------------------- #


class LFRicIntXKern(LFRicBuiltIn):
class LFRicRealToIntXKern(LFRicBuiltIn):
''' Converts real-valued field elements to integer-valued
field elements using the Fortran intrinsic `INT` function,
`Y = INT(X, kind=i_<prec>)`. Here `Y` is an integer-valued
Expand All @@ -2706,7 +2708,7 @@ class LFRicIntXKern(LFRicBuiltIn):

'''
_datatype = "integer"
_case_name = "int_X"
_case_name = "real_to_int_X"
TeranIvy marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def metadata(cls):
Expand Down Expand Up @@ -2737,7 +2739,7 @@ def lower_to_language_level(self):
arg_refs = self.get_indexed_field_argument_references()

# Create the PSyIR for the kernel:
# proxy0%data(df) = INT(proxy0%data, kind=i_<prec>)
# proxy0%data(df) = INT(proxy1%data, kind=i_<prec>)
i_precision = arg_refs[0].datatype.precision
rhs = IntrinsicCall.create(
IntrinsicCall.Intrinsic.INT,
Expand All @@ -2748,6 +2750,61 @@ def lower_to_language_level(self):
return assign


# ------------------------------------------------------------------- #
# ============== Converting real to real field elements ============= #
# ------------------------------------------------------------------- #

class LFRicRealToRealXKern(LFRicBuiltIn):
''' Converts real-valued field elements to real-valued field elements
of a different precision using the Fortran intrinsic `REAL` function,
`Y = REAL(X, kind=r_<prec>)`. Here `Y` is a real-valued field of
precision `kind=r_<prec>` and `X` is the real-valued field whose
values are to be converted from their defined precision.

'''
_datatype = "real"
_case_name = "real_to_real_X"

@classmethod
def metadata(cls):
'''Returns the kernel metadata describing this built-in.

:returns: kernel metadata describing this built-in.
:rtype: :py:class:`psyclone.domain.lfric.kernel.LFRicKernelMetadata`

'''
return cls._builtin_metadata([
FieldArgMetadata("gh_real", "gh_write", "any_space_1"),
FieldArgMetadata("gh_real", "gh_read", "any_space_1")])

def __str__(self):
return (f"Built-in: {self._case_name} (convert a real-valued "
f"to a real-valued field)")

def lower_to_language_level(self):
'''
Lowers this LFRic-specific built-in kernel to language-level PSyIR.
This BuiltIn node is replaced by an Assignment node.

:returns: the lowered version of this node.
:rtype: :py:class:`psyclone.psyir.node.Node`

'''
# Get indexed references for each of the field (proxy) arguments.
arg_refs = self.get_indexed_field_argument_references()

# Create the PSyIR for the kernel:
# proxy0%data(df) = REAL(proxy1%data, kind=r_<prec>)
r_precision = arg_refs[0].datatype.precision
rhs = IntrinsicCall.create(
IntrinsicCall.Intrinsic.REAL,
[arg_refs[1], ("kind", Reference(r_precision))])
assign = Assignment.create(arg_refs[0], rhs)
# Finally, replace this kernel node with the Assignment
self.replace_with(assign)
return assign


# ******************************************************************* #
# ************** Built-ins for integer-valued fields **************** #
# ******************************************************************* #
Expand Down Expand Up @@ -3040,7 +3097,7 @@ class LFRicIntIncMinAXKern(LFRicIncMinAXKern):
# ============== Converting integer to real field elements ========== #
# ------------------------------------------------------------------- #

class LFRicRealXKern(LFRicBuiltIn):
class LFRicIntToRealXKern(LFRicBuiltIn):
''' Converts integer-valued field elements to real-valued
field elements using the Fortran intrinsic `REAL` function,
`Y = REAL(X, kind=r_<prec>)`. Here `Y` is a real-valued
Expand All @@ -3049,7 +3106,7 @@ class LFRicRealXKern(LFRicBuiltIn):

'''
_datatype = "real"
_case_name = "real_X"
_case_name = "int_to_real_X"

@classmethod
def metadata(cls):
Expand Down Expand Up @@ -3080,7 +3137,7 @@ def lower_to_language_level(self):
arg_refs = self.get_indexed_field_argument_references()

# Create the PSyIR for the kernel:
# proxy0%data(df) = REAL(proxy0%data, kind=r_<prec>)
# proxy0%data(df) = REAL(proxy1%data, kind=r_<prec>)
r_precision = arg_refs[0].datatype.precision
rhs = IntrinsicCall.create(
IntrinsicCall.Intrinsic.REAL,
Expand Down Expand Up @@ -3157,7 +3214,9 @@ def lower_to_language_level(self):
"min_aX": LFRicMinAXKern,
"inc_min_aX": LFRicIncMinAXKern,
# Converting real to integer field elements
"int_X": LFRicIntXKern}
"real_to_int_X": LFRicRealToIntXKern,
# Converting real to real field elements
"real_to_real_X": LFRicRealToRealXKern}

# Built-ins for integer-valued fields
INT_BUILTIN_MAP_CAPITALISED = {
Expand Down Expand Up @@ -3192,7 +3251,7 @@ def lower_to_language_level(self):
"int_min_aX": LFRicIntMinAXKern,
"int_inc_min_aX": LFRicIntIncMinAXKern,
# Converting integer to real field elements
"real_X": LFRicRealXKern}
"int_to_real_X": LFRicIntToRealXKern}

# Built-in map dictionary for all built-ins
BUILTIN_MAP_CAPITALISED = REAL_BUILTIN_MAP_CAPITALISED
Expand Down Expand Up @@ -3251,7 +3310,8 @@ def lower_to_language_level(self):
'LFRicIncMaxAXKern',
'LFRicMinAXKern',
'LFRicIncMinAXKern',
'LFRicIntXKern',
'LFRicRealToIntXKern',
'LFRicRealToRealXKern',
'LFRicIntXPlusYKern',
'LFRicIntIncXPlusYKern',
'LFRicIntAPlusXKern',
Expand All @@ -3273,4 +3333,4 @@ def lower_to_language_level(self):
'LFRicIntIncMaxAXKern',
'LFRicIntMinAXKern',
'LFRicIntIncMinAXKern',
'LFRicRealXKern']
'LFRicIntToRealXKern']
Loading
Loading