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:
Scalar variables inside loops are not made private when parallelising using OpenMP;
Labelled do-loops are not handled (i.e. they will be put inside a ‘CodeBlock’ in the PSyIR);
Loops are currently only permitted to contain one kernel. This restriction will have to be lifted in order to permit loop fusion;
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;