.. _algorithm-layer:

Algorithm layer
===============

In the PSyKAl separation of concerns, the Algorithm layer specifies
the algorithm that the scientist would like to run (in terms of calls
to kernel routines and Built-in operations) and logically operates on full
fields. Algorithm code in the algorithm layer is not allowed to
include any parallelisation calls or directives and passes datatypes
specified by the particular API.

API
---

The Algorithm layer is forbidden from calling the Kernel layer
directly. In PSyclone, if the programmer would like to call a Kernel
routine or a Built-in operation from the algorithm layer they must use
the ``invoke`` call (which is common to all APIs). The ``invoke``
call is not necessary (and indeed will not work) if the PSy layer is
written manually.

To make an ``invoke`` call, the algorithm layer developer adds one or more
``call invoke()`` statements
to their code and within the content of the ``invoke`` call they add a
reference to the required Kernel/Built-in and the data to pass to it. For
example,
::

    ...
    call invoke(integrate_one_kernel(arg1,arg2))
    ...

For more information on the concept of Built-in operations see the
:ref:`built-ins` Section. Details of which operations are supported
for a specific API are given in the documentation of that API.

The algorithm layer can consist of an arbitrary number of files
containing fortran code, any of which may contain as many ``invoke()``
calls as is required. PSyclone is applied to an individual algorithm
layer file and must therefore be run multiple times if multiple files
containing ``invoke()`` calls exist in the algorithm layer.

The algorithm developer is also able to reference more than one
Kernel/Built-in within an invoke. In fact this feature is encouraged for
performance reasons. **As a general guideline the developer should aim to
use as few invokes as possible with as many Kernel references within them
as is possible**. The reason for this is that it allows for greater
freedom for optimisation in the PSy layer as PSy layer optimisations
are limited to the contents of individual invoke calls - PSyclone
currently does not attempt to optimise the PSy layer over multiple
invoke calls.

As well as generating the PSy layer code, PSyclone modifies the
Algorithm layer code, replacing ``invoke`` calls with calls to the
generated PSy layer so that the algorithm code is compilable and
linkable to the PSy layer and adding in the appropriate ``use``
statement. For example, the above ``integrate_one_kernel`` invoke is
translated into something like the following:
::

  ...
  use psy, only : invoke_0_integrate_one_kernel
  ...
  call invoke_0_integrate_one_kernel(arg1,arg2)
  ...

You may have noticed from other examples in this guide that an
algorithm specification in an invoke call references the metadata
``type`` in an invoke call, not the ``code`` directly; this is by
design.

For example, in the invoke call below, ``integrate_one_kernel`` is
used.
::

  ...
  call invoke(integrate_one_kernel(arg1,arg2))
  ...

``integrate_one_kernel`` is the name of the metadata type in the module, not
the name of the subroutine in the Kernel ...
::

  module integrate_one_module
    ...
    type, extends(kernel_type) :: integrate_one_kernel
      ...
    end type
    ...
  contains
    ...
    subroutine integrate_one_code(...)
    ...
    end subroutine integrate_one_code
    ...
  end module integrate_one_module

Named Invokes
+++++++++++++

PSyclone permits the user to optionally specify a label for an invoke
call like so:
::

  ...
  call invoke(integrate_one_kernel(arg1,arg2), &
              name="compute something")
  ...

The ``name`` argument to the invoke call is optional. If supplied it
must be a string literal. The content of this string (with any spaces
replaced by '_' characters) is used in naming the corresponding
PSy-layer routine generated by PSyclone. So, for the above example,
the generated PSy-layer subroutine will be named
"invoke_compute_something." Each invoke label must currently be unique
within an Algorithm source file. Note that, in keeping with the
Fortran language, labels are not case sensitive and, after having any
spaces replaced by underscores, must be valid Fortran
names (e.g. ``name="compute(1)"`` is invalid). In the future it is
intended that the labelling of invokes will help to support
invoke-specific optimisations to be applied as well as enabling more
readable profiling output. It may also be used to instruct PSyclone to
just generate a single subroutine to implement all invokes that share
the same label.

Limitations
-----------

In order to re-write the Algorithm layer, as just described, PSyclone
must obviously be able to parse the invoke calls. Since the Fortran
expression parser used by PSyclone is relatively simple, this means
there are limitations on what Fortran may be used when specifying
kernel arguments in an invoke call. Since these limitations can have
a direct impact on the natural science code, the PSyclone developers
endeavour to keep them to a minimum.

The current list of known limitations/restrictions on the form of
kernel arguments within an invoke is:

 * No arithmetic expressions (e.g. ``kernel_type(a+b)`` or ``kernel_type(-a)``)
 * No named (optional) arguments (e.g. ``kernel_type(fn(my_arg=a))``)

If you encounter any other limitations (or have a burning desire to use one
of the above forms) then please contact the PSyclone developers.
