Release 6.2 of the NAG Fortran Compiler limits execution to a single image, i.e. there is no parallel execution. Coarray programs that require multiple images to operate correctly cannot be executed successfully in this release.
A coarray has a “corank”, which is the number of “codimensions” it has. Each codimension has a lower “cobound” and an upper cobound, determining the “coshape”. The upper cobound of the last codimension is “*”; rather like an assumed-size array. The “cosubscripts” determine the image index of the reference, in the same way that the subscripts of an array determine the array element number. Again, like an assumed-size array, the image index must be less than or equal to the number of images.
A coarray can be a scalar or an array. If cannot have the POINTER attribute, but it can have pointer components.
As well as variables, coarray components are possible. In this case, the component must be an ALLOCATABLE coarray, and any variable with such a component must be a dummy argument or have the SAVE attribute.
REAL a[100,*] REAL,CODIMENSION[-10:10,-10:*] :: b CODIMENSION c[*]declares the coarray A to have corank 2 with lower “cobounds” both 1 and the first upper cobound 100, the coarray B to have corank 2 with lower cobounds both −10 and the first upper cobound 10, and the coarray C to have corank 1 and lower cobound 1. Note that for non-allocatable coarrays, the coarray-spec must always declare the last upper cobound with an asterisk, as this will vary depending on the number of images.
An ALLOCATABLE coarray is declared with a deferred-coshape-spec, for example,
REAL,ALLOCATABLE :: d[:,:,:,:]declares the coarray D to have corank 4.
REAL,SAVE :: e[*]the coindexed object e refers to the copy of E on image 1, and e refers to the copy of E on image 13. For a more complicated example: given
REAL,SAVE :: f[10,21:30,0:*]the reference f[3,22,1] refers to the copy of F on image 113. There is no correlation between image numbers and any topology of the computer, so it is probably best to avoid complicated codimensions, especially if different coarrays have different coshape.
When a coarray is an array, you cannot put the cosubscripts directly after the array name, but must use array section notation instead. For example, with
REAL,SAVE :: g(10,10)[*]the reference g[inum] is invalid, to refer to the whole array G on image INUM you need to use g(:,:)[inum] instead.
Similarly, to access a single element of G, the cosubscripts follow the subscripts, e.g. g(i,j)[inum].
Finally, note that when a coarray is accessed, whether by its own image or remotely, the segment ordering rules (see next section) must be obeyed. This is to avoid nonsense answers from data races.
If a coarray is defined (assigned a value) in a segment on image I, another image J is only allowed to reference or define it in a segment that follows the segment on I.
The image control statements, and their synchronisation effects, are as follows.
Note that image control statements have side-effects, and therefore are not permitted in pure procedures or within DO CONCURRENT constructs.
REAL,ALLOCATABLE :: x(:,:,:)[:,:] ... ALLOCATE(x(100,100,3)[1:10,*])Note that the last upper cobound must be an asterisk, the same as when declaring an explicit-coshape coarray.
When allocating a coarray there is a synchronisation: all images must execute the same ALLOCATE statement, and all the bounds, type parameters, and cobounds of the coarray must be the same on all images.
Similarly, there is a synchronisation when a coarray is deallocated, whether by a DEALLOCATE statement or automatic deallocation by an END statement; every image must execute the same statement.
Note that the usual automatic reallocation of allocatable variables in an intrinsic assignment statement, e.g. when the expression is an array of a different shape, is not available for coarrays. An allocatable coarray variable being assigned to must already be allocated and be conformable with the expression; furthermore, if it has deferred type parameters they must have the same values, and if it is polymorphic it must have the same dynamic type.
CRITICAL ...do something END CRITICALIf an image I arrives at the CRITICAL statement while another image J is executing the block of the construct, it will wait until image J has executed the END CRITICAL statement before continuing. Thus the CRITICAL — END CRITICAL segment on image I follows the equivalent segment on image J.
As a construct, this may have a name, e.g.
critsec: CRITICAL ... END CRITICAL critsecThe name has no effect on the operation of the construct. Each CRITICAL construct is separate from all others, and has no effect on their execution.
Execution of the segment after a LOCK statement successfully locks the variable follows execution of the segment before the UNLOCK statement on the image that unlocked it. For example,
INTEGER FUNCTION get_sequence_number() USE iso_fortran_env INTEGER :: number = 0 TYPE(lock_type) lock[*] LOCK(lock) number = number + 1 get_sequence_number = number UNLOCK(lock) END FUNCTIONIf the variable lock on image 1 is locked when the LOCK statement is executed, it will wait for it to become unlocked before continuing. Thus the function get_sequence_number() provides an one-sided ordering relation: the segment following a call that returned the value N will follow every segment that preceded a call that returned a value less than N.
Conditional locking is provided with the ACQUIRED_LOCK= specifier; if this specifier is present, the executing image only acquires the lock if it was previously unlocked. For example,
LOGICAL gotit LOCK(lock,ACQUIRED_LOCK=gotit) IF (gotit) THEN ! We have the lock. ELSE ! We do not have the lock - some other image does. END IF
It is an error for an image to try to LOCK a variable that is already locked to that image, or to UNLOCK a variable that is already unlocked, or that is locked to another image. If the STAT= specifier is used, these errors will return the values STAT_LOCKED, STAT_UNLOCKED, or STAT_LOCKED_OTHER_IMAGE respectively (these named constants are provided by the intrinsic module ISO_FORTRAN_ENV).
MODULE stopping USE iso_fortran_env LOGICAL(atomic_logical_kind),PRIVATE :: stop_flag[*] = .FALSE. CONTAINS SUBROUTINE make_it_stop CALL atomic_define(stop_flag,.TRUE._atomic_logical_kind) END SUBROUTINE LOGICAL FUNCTION please_stop() CALL atomic_ref(please_stop,stop_flag) END FUNCTION END MODULEIn this example, it is perfectly valid for any image to call make_it_stop, and for any other image to invoke the function please_stop(), without any regard for segments. (On a distributed memory machine it might take some time for changes to the atomic variable to be visible on other images, but they should eventually get the message.)
Note that ordinary assignment and referencing should not be mixed with calls to the atomic subroutines, as ordinary assignment and referencing are always subject to the segment ordering rules.
When normal termination has been initiated on all images, the program terminates.
The ERROR STOP statement initiates error termination.
The FAIL IMAGE statement itself is not very useful when the number of images is equal to one, as it inevitably causes complete program failure.
In a data object designator, a part (component or base object) that is a coarray can include an image selector: part-name [ ( section-subscript-list ) ] [ image-selector ]where part-name identifies a coarray, and image-selector is
left-bracket cosubscript-list [ , image-selector-spec ] right-bracketThe number of cosubscripts must be equal to the corank of part-name. If image-selector appears and part-name is an array, section-subscript-list must also appear. The optional image-selector-spec is Fortran 2018 (part of the fault tolerance feature), and is a comma-separated list of one or more of the following specifiers:
STAT = scalar-int-variable
TEAM = team-value
TEAM_NUMBER = scalar-int-expression
[ construct-name : ] CRITICAL [ ( [ sync-stat-list ] ) ]
END CRITICAL [ construct-name ]
The block is not permitted to contain:
FAIL IMAGE statement:
FAIL IMAGENote: This statement is Fortran 2018.
LOCK ( lock-variable [ , lock-stat-list ] )where lock-stat-list is a comma-separated list of one or more of the following:
ACQUIRED_LOCK = scalar-logical-variable
ERRMSG = scalar-default-character-variable
STAT = scalar-int-variable
SYNC ALL statement:
SYNC ALL [ ( [ sync-stat-list ] ) ]
SYNC IMAGES statement:
SYNC IMAGES ( image-set [ , sync-stat-list ] )where image-set is an asterisk, or an integer expression that is scalar or of rank one.
SYNC MEMORY statement:
SYNC MEMORY [ ( [ sync-stat-list ] ) ]
UNLOCK ( lock-variable [ , sync-stat-list ] )
SUBROUTINE ATOMIC_DEFINE(ATOM, VALUE, STAT)
SUBROUTINE ATOMIC_REF(VALUE, ATOM, STAT)
INTEGER FUNCTION IMAGE_INDEX(COARRAY, SUB)
FUNCTION LCOBOUND(COARRAY, DIM , KIND)
SUBROUTINE MOVE_ALLOC(FROM, TO, STAT, ERRMSG) ! Revised
INTEGER FUNCTION NUM_IMAGES()This intrinsic function returns the number of images. In this release of the NAG Fortran Compiler, the value will always be equal to one.
INTEGER FUNCTION THIS_IMAGE()Returns the image index of the executing image.
FUNCTION THIS_IMAGE(COARRAY)Returns an array of type Integer with default kind, with the size equal to the corank of COARRAY, which may be a coarray of any type. The values returned are the cosubscripts for COARRAY that correspond to the executing image.
INTEGER FUNCTION THIS_IMAGE(COARRAY, DIM)
FUNCTION UCOBOUND(COARRAY, DIM, KIND)
If DIM appears, the result is scalar, being the value of the upper cobound of that codimension of COARRAY. If DIM does not appear, the result is a vector of length N containing all the upper cobounds of COARRAY. The actual argument for DIM must not itself be an optional dummy argument.
Note that if COARRAY has corank N>1, and the number of images in the current execution is not an integer multiple of the coextents up to codimension N−1, the images do not make a full rectangular pattern. In this case, the value of the last upper cobound is the maximum value that a cosubscript can take for that codimension; e.g. with a coarray-spec of [1:3,1:*] and four images in the execution, the last upper cobound will be equal to 2 because the cosubscripts [1,2] are valid even though [2,2] and [2,3] are not.