NEMO API

In contrast to the other APIs supported by PSyclone, the NEMO API is designed to work with source code that does not follow the PSyKAl separation of concerns. Instead, the NEMO source code is treated as if it were a manually written PSy layer with all kernels in-lined. This approach relies upon the NEMO Coding Conventions [nem13] in order to reason about the code being processed. Rather than construct an InvokeSchedule for the PSy layer from scratch (as is done for other APIs), the InvokeSchedule is constructed by parsing the supplied Fortran code and generating a higher-level representation.

Note

the NEMO API is currently only a prototype. The known issues are listed in Limitations.

Algorithm

Since NEMO source is treated as a pre-existing PSy layer, this API does not have the concept of an Algorithm layer.

Constructing the PSyIR

Transformations in PSyclone are applied to an Intermediate Representation, the “PSyIR.” In contrast to the other APIs where the PSyIR is constructed from scratch, for NEMO PSyclone must parse the existing Fortran and create a higher-level representation of it. This is done using rules based upon the NEMO Coding Conventions [nem13]. These rules are described in the following sections.

Loops

Explicit

PSyclone recognises the following loop types, based on the name of the loop variable:

Loop type

Loop variable

Vertical levels

jk

Latitude

ji

Longitude

jj

Tracer species

jn

PSyclone currently assumes that each of these loop types may be safely parallelised. In practice this will not always be the case (e.g. when performing a tri-diagonal solve) and this implementation will need to be refined.

Implicit

The use of Fortran array notation is encouraged in the NEMO Coding Conventions [nem13] (section 4.2) and is employed throughout the NEMO code base. The Coding Conventions mandate that the shape of every array in such expressions must be specified, e.g.:

onedarraya(:) = onedarrayb(:) + onedarrayc(:)
twodarray (:,:) = scalar * anothertwodarray(:,:)

PSyclone therefore also recognises the loops implied by this notation.

Note, not all uses of Fortran array notation in NEMO imply a loop. For instance:

ascalar = afunc(twodarray(:,:))

is actually a function call which is passed a reference to twodarray. However, if the quantity being assigned to is actually an array, e.g.:

twodarray2(:,:) = afunc(twodarray(:,:))

then this does represent a loop. However, currently PSyclone does not recognise any occurrences of array notation that are themselves within an array access or function call. It is therefore not yet possible to transform such implicit loops into explicit loops. It is hoped that this limitation will be removed in future releases of PSyclone by adding the ability to discover the interface to functions such as afunc and thus determining whether they return scalar or array quantities.

Example

A typical fragment of NEMO source code (taken from the traldf_iso routine) is shown below:

DO jn = 1, kjpt
 zdit (1,:,:) = 0._wp     ;     zdit (jpi,:,:) = 0._wp
 zdjt (1,:,:) = 0._wp     ;     zdjt (jpi,:,:) = 0._wp

 DO jk = 1, jpkm1
    DO jj = 1, jpjm1
       DO ji = 1, fs_jpim1
          zdit(ji,jj,jk) = ( ptb(ji+1,jj  ,jk,jn) - ptb(ji,jj,jk,jn) ) * umask(ji,jj,jk)
          zdjt(ji,jj,jk) = ( ptb(ji  ,jj+1,jk,jn) - ptb(ji,jj,jk,jn) ) * vmask(ji,jj,jk)
       END DO
    END DO
 END DO

PSyclone uses fparser2 to parse such source code and then generates the PSy Intermediate Representation of it:

Loop[type='tracers',field_space='None',it_space='None']
    Loop[type='None',field_space='None',it_space='None']
    Loop[type='None',field_space='None',it_space='None']
    Loop[type='None',field_space='None',it_space='None']
    Loop[type='None',field_space='None',it_space='None']
    Loop[type='levels',field_space='None',it_space='None']
        Loop[type='lat',field_space='None',it_space='None']
            Loop[type='lon',field_space='None',it_space='None']
                CodedKern[]

Limitations

The NEMO API is currently under development. Here we list the current, known limitations/issues:

  1. Scalar variables inside loops are not made private when parallelising using OpenMP;

  2. Labelled do-loops are not handled (i.e. they will be put inside a ‘CodeBlock’ in the PSyIR);

  3. Loops are currently only permitted to contain one kernel. This restriction will have to be lifted in order to permit loop fusion;

  4. The psyir.nodes.Node base class now has an _ast property to hold a pointer into the associated fparser2 AST. However, the psyGen.Kern class already has an _fp2_ast property that points to the whole fparser2 AST of the kernel code. This will be rationalised in #241;