*IF DEF,C96_1B,AND,DEF,MPP,AND,DEF,T3E                                     GPB2F404.399    
C ******************************COPYRIGHT******************************    GPB2F404.400    
C (c) CROWN COPYRIGHT 1997, METEOROLOGICAL OFFICE, All Rights Reserved.    GPB2F404.401    
C                                                                          GPB2F404.402    
C Use, duplication or disclosure of this code is subject to the            GPB2F404.403    
C restrictions as set forth in the contract.                               GPB2F404.404    
C                                                                          GPB2F404.405    
C                Meteorological Office                                     GPB2F404.406    
C                London Road                                               GPB2F404.407    
C                BRACKNELL                                                 GPB2F404.408    
C                Berkshire UK                                              GPB2F404.409    
C                RG12 2SZ                                                  GPB2F404.410    
C                                                                          GPB2F404.411    
C If no contract has been raised with this copy of the code, the use,      GPB2F404.412    
C duplication or disclosure of it is strictly prohibited.  Permission      GPB2F404.413    
C to do so must first be obtained in writing from the Head of Numerical    GPB2F404.414    
C Modelling at the above address.                                          GPB2F404.415    
C                                                                          GPB2F404.416    
!+ Parallel UM: Updates halo areas                                         GPB2F404.417    
!                                                                          GPB2F404.418    
! Subroutine interface:                                                    GPB2F404.419    

      SUBROUTINE SWAPBOUNDS(FIELD,X_SIZE_IN,Y_SIZE_IN,                      509GPB2F404.420    
     &                      X_OFF_IN,Y_OFF_IN,N_LEVELS_IN)                 GPB2F404.421    
                                                                           GPB2F404.422    
      IMPLICIT NONE                                                        GPB2F404.423    
!                                                                          GPB2F404.424    
! Description:                                                             GPB2F404.425    
! This routine fills the halo areas (of size X_OFF in the x dimension      GPB2F404.426    
! and Y_OFF in the y dimension) of the first N_LEVELS of the array         GPB2F404.427    
! FIELD with the appropriate data from adjacent processors.                GPB2F404.428    
! If *DEF,GLOBAL is set, a east-west wrap around of data will              GPB2F404.429    
! occur.                                                                   GPB2F404.430    
!                                                                          GPB2F404.431    
! Method:                                                                  GPB2F404.432    
! T3E: Data is directly transferred between FIELD arrays on                GPB2F404.433    
! neighbouring processors via shmem calls.                                 GPB2F404.434    
!                                                                          GPB2F404.435    
! Current Code Owner: Paul Burton                                          GPB2F404.436    
!                                                                          GPB2F404.437    
! History:                                                                 GPB2F404.438    
!  Model    Date     Modification history from model version 4.3           GPB2F404.439    
!  version                                                                 GPB2F404.440    
!    4.3    8/3/97   New optimised version of swapbouind  P.Burton         GPB2F404.441    
!                                                                          GPB2F404.442    
! Subroutine Arguments:                                                    GPB2F404.443    
                                                                           GPB2F404.444    
      INTEGER                                                              GPB2F404.445    
     &   X_SIZE_IN       ! IN  : X dimension of field (inc. halos)         GPB2F404.446    
     &,  Y_SIZE_IN       ! IN  : Y dimension of field (inc. halos)         GPB2F404.447    
     &,  X_OFF_IN        ! IN  : X halo size                               GPB2F404.448    
     &,  Y_OFF_IN        ! IN  : Y halo size                               GPB2F404.449    
     &,  N_LEVELS_IN     ! IN  : Number of levels to be swapped            GPB2F404.450    
                                                                           GPB2F404.451    
      REAL FIELD(X_SIZE_IN*Y_SIZE_IN,N_LEVELS_IN)                          GPB2F404.452    
!                     ! IN/OUT : Field to take place in                    GPB2F404.453    
!                     !          boundary data exchange.                   GPB2F404.454    
                                                                           GPB2F404.455    
! Parameters and Common blocks                                             GPB2F404.456    
                                                                           GPB2F404.457    
*CALL PARVARS                                                              GPB2F404.458    
                                                                           GPB2F404.459    
! Local variables                                                          GPB2F404.460    
                                                                           GPB2F404.461    
      INTEGER                                                              GPB2F404.462    
     &  X_SIZE     ! copies of arguments                                   GPB2F404.463    
     &, Y_SIZE     ! required for stream safe code                         GPB2F404.464    
     &, X_OFF      ! these variables are spatially seperated               GPB2F404.465    
     &, Y_OFF      ! from all communicated variables                       GPB2F404.466    
     &, N_LEVELS                                                           GPB2F404.467    
                                                                           GPB2F404.468    
      INTEGER                                                              GPB2F404.469    
     &  array_address ! address of my FIELD array                          GPB2F404.470    
     &, size_x        ! my X_SIZE                                          GPB2F404.471    
     &, size_y        ! my Y_SIZE                                          GPB2F404.472    
     &, align_vars(3) ! equivalenced copies of above 3 vars.               GPB2F404.473    
                                                                           GPB2F404.474    
      INTEGER                                                              GPB2F404.475    
     &  remote_address ! address of FIELD array on remote processor        GPB2F404.476    
     &, remote_size_x  ! remote array's X_SIZE                             GPB2F404.477    
     &, remote_size_y  ! remote array's Y_SIZE                             GPB2F404.478    
     &, remote_vars(3) ! equivalenced copies of above 3 vars.              GPB2F404.479    
                                                                           GPB2F404.480    
      EQUIVALENCE                                                          GPB2F404.481    
     &  (align_vars(1),array_address),                                     GPB2F404.482    
     &  (align_vars(2),size_x),                                            GPB2F404.483    
     &  (align_vars(3),size_y),                                            GPB2F404.484    
     &  (remote_vars(1),remote_address),                                   GPB2F404.485    
     &  (remote_vars(2),remote_size_x),                                    GPB2F404.486    
     &  (remote_vars(3),remote_size_y)                                     GPB2F404.487    
                                                                           GPB2F404.488    
      INTEGER       ! variables describing comms. pattern                  GPB2F404.489    
     &  el_len      ! length of element to send                            GPB2F404.490    
     &, n_els       ! number of elements to put/get                        GPB2F404.491    
     &, loc_start   ! start in local array                                 GPB2F404.492    
     &, rem_start   ! start in remote array                                GPB2F404.493    
     &, loc_stride  ! stride in local array                                GPB2F404.494    
     &, rem_stride  ! stride in remote array                               GPB2F404.495    
                                                                           GPB2F404.496    
      REAL                                                                 GPB2F404.497    
     &  remote_array((X_SIZE_IN+1)*(Y_SIZE_IN+1)*N_LEVELS_IN)              GPB2F404.498    
      POINTER (ptr,remote_array)                                           GPB2F404.499    
! remote_array is used to generate the address of the field array on       GPB2F404.500    
! the remote processor - so the size is made such that no out of           GPB2F404.501    
! bounds references will be made - nothing is physically writtten or       GPB2F404.502    
! read from this array. The size is defined assuming that the              GPB2F404.503    
! decomposition is such that the maximum difference between X_SIZE         GPB2F404.504    
! and Y_SIZE on neighbouring processors is no more than 1.                 GPB2F404.505    
! The Pointer ptr allows the address of remote_array to be set by          GPB2F404.506    
! changing the value of ptr. We will set ptr to the address of FIELD       GPB2F404.507    
! on the remote processor - so effectively allowing us to produce          GPB2F404.508    
! the address of any element of the remote FIELD array by generating       GPB2F404.509    
! the corresponding element of the remote_array array.                     GPB2F404.510    
                                                                           GPB2F404.511    
! Loop indexes                                                             GPB2F404.512    
                                                                           GPB2F404.513    
      INTEGER                                                              GPB2F404.514    
     &  k  ! loop over levels                                              GPB2F404.515    
     &, i  ! loop over columns in EW halo                                  GPB2F404.516    
     &, j  ! loop over rows in NS halo                                     GPB2F404.517    
                                                                           GPB2F404.518    
! COMMON block                                                             GPB2F404.519    
! Only align_vars needs to be on COMMON. The other variables are           GPB2F404.520    
! there to ensure they are spatially seperated from any                    GPB2F404.521    
! communicated variables - so making the code stream safe                  GPB2F404.522    
                                                                           GPB2F404.523    
      COMMON /swapbnd_ss_common/                                           GPB2F404.524    
     &  align_vars                                                         GPB2F404.525    
                                                                           GPB2F404.526    
!------------------------------------------------------------------        GPB2F404.527    
! 0.0 Copy arguments into stream safe variables                            GPB2F404.528    
                                                                           GPB2F404.529    
      X_SIZE=X_SIZE_IN                                                     GPB2F404.530    
      Y_SIZE=Y_SIZE_IN                                                     GPB2F404.531    
      X_OFF=X_OFF_IN                                                       GPB2F404.532    
      Y_OFF=Y_OFF_IN                                                       GPB2F404.533    
      N_LEVELS=N_LEVELS_IN                                                 GPB2F404.534    
                                                                           GPB2F404.535    
!------------------------------------------------------------------        GPB2F404.536    
! 1.0 Set up the align_vars COMMON block with my local information         GPB2F404.537    
!     so that other processors can access it.                              GPB2F404.538    
                                                                           GPB2F404.539    
      array_address=LOC(FIELD) ! set to the start address of my            GPB2F404.540    
!                              ! FIELD array                               GPB2F404.541    
      size_x=X_SIZE                                                        GPB2F404.542    
      size_y=Y_SIZE                                                        GPB2F404.543    
                                                                           GPB2F404.544    
      CALL barrier()                                                       GPB2F404.545    
                                                                           GPB2F404.546    
! Once this barrier is passed we know that we can safely access            GPB2F404.547    
! remote align_vars                                                        GPB2F404.548    
                                                                           GPB2F404.549    
!------------------------------------------------------------------        GPB2F404.550    
! 2.0 First thing we'll do is East-West communications. We'll use          GPB2F404.551    
!     shmem_get as this means we don't have to barrier before              GPB2F404.552    
!     doing the North-South communications - as the get operation          GPB2F404.553    
!     ensures we've updated our EW halos before we start                   GPB2F404.554    
!     shmem_putting data in the North-South direction (this is             GPB2F404.555    
!     important for the corners - as we'll effectively be shifting         GPB2F404.556    
!     data from our EW neighbours to our NS neighbours).                   GPB2F404.557    
                                                                           GPB2F404.558    
      IF (X_OFF .GT. 0) THEN  ! EW halos exist                             GPB2F404.559    
                                                                           GPB2F404.560    
        n_els=Y_SIZE-2*Y_OFF ! number of rows of EW halo data              GPB2F404.561    
!                            ! (minus NS halos)                            GPB2F404.562    
        loc_stride=X_SIZE                                                  GPB2F404.563    
                                                                           GPB2F404.564    
                                                                           GPB2F404.565    
!--------------------------------                                          GPB2F404.566    
! 2.1 Get halo data from our Western neighbour                             GPB2F404.567    
                                                                           GPB2F404.568    
        IF (neighbour(PWest) .NE. NoDomain) THEN                           GPB2F404.569    
                                                                           GPB2F404.570    
! Get address and size information from my Western neighbour               GPB2F404.571    
                                                                           GPB2F404.572    
          CALL shmem_get(remote_vars,align_vars,3,neighbour(PWest))        GPB2F404.573    
                                                                           GPB2F404.574    
          ptr=remote_address ! address of FIELD on PE to West              GPB2F404.575    
                                                                           GPB2F404.576    
          rem_stride=remote_size_x                                         GPB2F404.577    
                                                                           GPB2F404.578    
          IF (X_OFF .EQ. 1) THEN  ! special optimised case                 GPB2F404.579    
                                                                           GPB2F404.580    
            loc_start=Y_OFF*X_SIZE + 1                                     GPB2F404.581    
                                                                           GPB2F404.582    
            DO k=1,N_LEVELS                                                GPB2F404.583    
                                                                           GPB2F404.584    
              rem_start=(k-1)*remote_size_x*remote_size_y +                GPB2F404.585    
     &                  (Y_OFF+1)*remote_size_x - 2*X_OFF + 1              GPB2F404.586    
                                                                           GPB2F404.587    
! The iget call is strided shmem_get - the data for a whole column         GPB2F404.588    
! of one level of Western halo is got from the neighbouring                GPB2F404.589    
! processor by the single call.                                            GPB2F404.590    
                                                                           GPB2F404.591    
              CALL shmem_iget(                                             GPB2F404.592    
     &          FIELD(loc_start,k),remote_array(rem_start),                GPB2F404.593    
     &          loc_stride,rem_stride,                                     GPB2F404.594    
     &          n_els,neighbour(PWest))                                    GPB2F404.595    
                                                                           GPB2F404.596    
            ENDDO ! k : loop over levels                                   GPB2F404.597    
                                                                           GPB2F404.598    
          ELSE ! If the EW halos are greater than 1 - width                GPB2F404.599    
                                                                           GPB2F404.600    
            DO k=1,N_LEVELS  ! loop over levels                            GPB2F404.601    
                                                                           GPB2F404.602    
              DO i=1,X_OFF   ! loop over columns of halo                   GPB2F404.603    
                                                                           GPB2F404.604    
                loc_start=Y_OFF*X_SIZE + i                                 GPB2F404.605    
                                                                           GPB2F404.606    
                rem_start=(k-1)*remote_size_x*remote_size_y +              GPB2F404.607    
     &                    (Y_OFF+1)*remote_size_x - 2*X_OFF + i            GPB2F404.608    
                                                                           GPB2F404.609    
! The iget call is strided shmem_get - the data for a whole column         GPB2F404.610    
! of one level of Western halo is got from the neighbouring                GPB2F404.611    
! processor by the single call.                                            GPB2F404.612    
                                                                           GPB2F404.613    
                CALL shmem_iget(                                           GPB2F404.614    
     &            FIELD(loc_start,k),remote_array(rem_start),              GPB2F404.615    
     &            loc_stride,rem_stride,                                   GPB2F404.616    
     &            n_els,neighbour(PWest))                                  GPB2F404.617    
                                                                           GPB2F404.618    
              ENDDO ! i : loop over columns in Western halo                GPB2F404.619    
                                                                           GPB2F404.620    
            ENDDO ! k : loop over levels                                   GPB2F404.621    
                                                                           GPB2F404.622    
          ENDIF ! on the size of the EW halos                              GPB2F404.623    
                                                                           GPB2F404.624    
        ENDIF ! if we have a Western neighbour                             GPB2F404.625    
                                                                           GPB2F404.626    
!--------------------------------                                          GPB2F404.627    
! 2.2 Get halo data from our Eastern neighbour                             GPB2F404.628    
                                                                           GPB2F404.629    
        IF (neighbour(PEast) .NE. NoDomain) THEN                           GPB2F404.630    
                                                                           GPB2F404.631    
! Get address and size information from my Eastern neighbour               GPB2F404.632    
                                                                           GPB2F404.633    
          CALL shmem_get(remote_vars,align_vars,3,neighbour(PEast))        GPB2F404.634    
                                                                           GPB2F404.635    
          ptr=remote_address ! address of FIELD on PE to East              GPB2F404.636    
                                                                           GPB2F404.637    
          rem_stride=remote_size_x                                         GPB2F404.638    
                                                                           GPB2F404.639    
          IF (X_OFF .EQ. 1) THEN                                           GPB2F404.640    
                                                                           GPB2F404.641    
            loc_start=(Y_OFF+1)*X_SIZE - X_OFF + 1                         GPB2F404.642    
                                                                           GPB2F404.643    
            DO k=1,N_LEVELS  ! loop over levels                            GPB2F404.644    
                                                                           GPB2F404.645    
              rem_start=(k-1)*remote_size_x*remote_size_y +                GPB2F404.646    
     &                  Y_OFF*remote_size_x + X_OFF + 1                    GPB2F404.647    
                                                                           GPB2F404.648    
! The iget call is strided shmem_get - the data for a whole column         GPB2F404.649    
! of one level of Eastern halo is got from the neighbouring                GPB2F404.650    
! processor by the single call.                                            GPB2F404.651    
                                                                           GPB2F404.652    
              CALL shmem_iget(                                             GPB2F404.653    
     &          FIELD(loc_start,k),remote_array(rem_start),                GPB2F404.654    
     &          loc_stride,rem_stride,                                     GPB2F404.655    
     &          n_els,neighbour(PEast))                                    GPB2F404.656    
                                                                           GPB2F404.657    
            ENDDO ! k : loop over levels                                   GPB2F404.658    
                                                                           GPB2F404.659    
          ELSE ! If the EW halos are greater than 1 - width                GPB2F404.660    
                                                                           GPB2F404.661    
            DO k=1,N_LEVELS  ! loop over levels                            GPB2F404.662    
                                                                           GPB2F404.663    
              DO i=1,X_OFF   ! loop over columns of halo                   GPB2F404.664    
                                                                           GPB2F404.665    
                loc_start=(Y_OFF+1)*X_SIZE - X_OFF + i                     GPB2F404.666    
                                                                           GPB2F404.667    
                rem_start=(k-1)*remote_size_x*remote_size_y +              GPB2F404.668    
     &                    Y_OFF*remote_size_x + X_OFF + i                  GPB2F404.669    
                                                                           GPB2F404.670    
                                                                           GPB2F404.671    
! The iget call is strided shmem_get - the data for a whole column         GPB2F404.672    
! of one level of Eastern halo is got from the neighbouring                GPB2F404.673    
! processor by the single call.                                            GPB2F404.674    
                                                                           GPB2F404.675    
                CALL shmem_iget(                                           GPB2F404.676    
     &            FIELD(loc_start,k),remote_array(rem_start),              GPB2F404.677    
     &            loc_stride,rem_stride,                                   GPB2F404.678    
     &            n_els,neighbour(PEast))                                  GPB2F404.679    
                                                                           GPB2F404.680    
              ENDDO ! i : loop over columns in Eastern halo                GPB2F404.681    
                                                                           GPB2F404.682    
            ENDDO ! k : loop over levels                                   GPB2F404.683    
                                                                           GPB2F404.684    
          ENDIF ! on the size of the EW halos                              GPB2F404.685    
                                                                           GPB2F404.686    
        ENDIF ! if we have a Eastern neighbour                             GPB2F404.687    
                                                                           GPB2F404.688    
      ENDIF ! if an EW communication is required (EW halos exist)          GPB2F404.689    
                                                                           GPB2F404.690    
!------------------------------------------------------------------        GPB2F404.691    
! 3.0 Now we can do the North-South halo update. Now we can use            GPB2F404.692    
!     shmem_put to put the data into the halos.                            GPB2F404.693    
                                                                           GPB2F404.694    
      IF (Y_OFF .GT. 0) THEN  ! NS halos exist                             GPB2F404.695    
                                                                           GPB2F404.696    
        el_len=X_SIZE*Y_OFF                                                GPB2F404.697    
                                                                           GPB2F404.698    
!--------------------------------                                          GPB2F404.699    
! 3.1 Put halo data to our Northern neighbour                              GPB2F404.700    
                                                                           GPB2F404.701    
        IF (neighbour(PNorth) .NE. NoDomain) THEN                          GPB2F404.702    
                                                                           GPB2F404.703    
! Get address and size information from my Northern neighbour              GPB2F404.704    
                                                                           GPB2F404.705    
          CALL shmem_get(remote_vars,align_vars,3,neighbour(PNorth))       GPB2F404.706    
                                                                           GPB2F404.707    
          ptr=remote_address ! address of FIELD on PE to North             GPB2F404.708    
                                                                           GPB2F404.709    
          rem_stride=remote_size_x*remote_size_y                           GPB2F404.710    
                                                                           GPB2F404.711    
          loc_start=Y_OFF*X_SIZE + 1                                       GPB2F404.712    
                                                                           GPB2F404.713    
          rem_start=remote_size_x*(remote_size_y-Y_OFF) + 1                GPB2F404.714    
                                                                           GPB2F404.715    
          DO k=1,N_LEVELS ! loop over levels                               GPB2F404.716    
                                                                           GPB2F404.717    
            CALL shmem_put(                                                GPB2F404.718    
     &        remote_array(rem_start+(k-1)*rem_stride),                    GPB2F404.719    
     &        FIELD(loc_start,k),                                          GPB2F404.720    
     &        el_len,neighbour(PNorth))                                    GPB2F404.721    
                                                                           GPB2F404.722    
          ENDDO ! k : loop over levels                                     GPB2F404.723    
                                                                           GPB2F404.724    
                                                                           GPB2F404.725    
        ELSE ! if there is no Northern neighbour                           GPB2F404.726    
                                                                           GPB2F404.727    
! Fill in the halo with dummy data                                         GPB2F404.728    
                                                                           GPB2F404.729    
          DO k = 1,N_LEVELS                                                GPB2F404.730    
            DO j = 1,Y_OFF                                                 GPB2F404.731    
              DO i = 1,X_SIZE                                              GPB2F404.732    
                FIELD((j-1)*X_SIZE+i,k) = FIELD(Y_OFF*X_SIZE+i,k)          GPB2F404.733    
              END DO                                                       GPB2F404.734    
            END DO                                                         GPB2F404.735    
          END DO                                                           GPB2F404.736    
                                                                           GPB2F404.737    
        ENDIF ! if we have a Northern neighbour                            GPB2F404.738    
                                                                           GPB2F404.739    
!--------------------------------                                          GPB2F404.740    
! 3.2 Put halo data to our Southern neighbour                              GPB2F404.741    
                                                                           GPB2F404.742    
        IF (neighbour(PSouth) .NE. NoDomain) THEN                          GPB2F404.743    
                                                                           GPB2F404.744    
! Get address and size information from my Northern neighbour              GPB2F404.745    
                                                                           GPB2F404.746    
          CALL shmem_get(remote_vars,align_vars,3,neighbour(PSouth))       GPB2F404.747    
                                                                           GPB2F404.748    
          ptr=remote_address ! address of FIELD on PE to South             GPB2F404.749    
                                                                           GPB2F404.750    
          rem_stride=remote_size_x*remote_size_y                           GPB2F404.751    
                                                                           GPB2F404.752    
          loc_start=X_SIZE*(Y_SIZE-2*Y_OFF)+1                              GPB2F404.753    
                                                                           GPB2F404.754    
          rem_start=1                                                      GPB2F404.755    
                                                                           GPB2F404.756    
          DO k=1,N_LEVELS ! loop over levels                               GPB2F404.757    
                                                                           GPB2F404.758    
            CALL shmem_put(                                                GPB2F404.759    
     &        remote_array(rem_start+(k-1)*rem_stride),                    GPB2F404.760    
     &        FIELD(loc_start,k),                                          GPB2F404.761    
     &        el_len,neighbour(PSouth))                                    GPB2F404.762    
                                                                           GPB2F404.763    
          ENDDO ! k : loop over levels                                     GPB2F404.764    
                                                                           GPB2F404.765    
        ELSE ! if we have no Southern neighbour                            GPB2F404.766    
                                                                           GPB2F404.767    
          DO k = 1,N_LEVELS                                                GPB2F404.768    
            DO j = 1,Y_OFF                                                 GPB2F404.769    
              DO i = 1,X_SIZE                                              GPB2F404.770    
                FIELD((Y_SIZE-j)*X_SIZE+i,k) =                             GPB2F404.771    
     &            FIELD((Y_SIZE-Y_OFF-1)*X_SIZE+i,k)                       GPB2F404.772    
              END DO                                                       GPB2F404.773    
            END DO                                                         GPB2F404.774    
          END DO                                                           GPB2F404.775    
                                                                           GPB2F404.776    
        ENDIF ! if we have a Southern neighbour                            GPB2F404.777    
                                                                           GPB2F404.778    
      ENDIF ! if a NS communication is required (NS halos exist)           GPB2F404.779    
                                                                           GPB2F404.780    
      CALL barrier()                                                       GPB2F404.781    
                                                                           GPB2F404.782    
! Now all the halos are updated it is safe to continue                     GPB2F404.783    
                                                                           GPB2F404.784    
      RETURN                                                               GPB2F404.785    
                                                                           GPB2F404.786    
      END                                                                  GPB2F404.787    
*ENDIF                                                                     GPB2F404.788