
! $Id: extrapol.F 5101 2024-07-23 06:22:55Z abarral $

C
C
      SUBROUTINE extrapol (pfild, kxlon, kylat, pmask,
     .                   norsud, ldper, knbor, pwork)
      IMPLICIT none
c
c OASIS routine (Adaptation: Laurent Li, le 14 mars 1997)
c Fill up missed values by using the neighbor points
c
      INTEGER kxlon, kylat ! longitude and latitude dimensions (Input)
      INTEGER knbor ! minimum neighbor number (Input)
      LOGICAL norsud ! True if field is from North to South (Input)
      LOGICAL ldper ! True if take into account the periodicity (Input)
      REAL pmask ! mask value (Input)
      REAL pfild(kxlon,kylat) ! field to be extrapolated (Input/Output)
      REAL pwork(kxlon,kylat) ! working space
c
      REAL zwmsk
      INTEGER incre, idoit, i, j, k, inbor, ideb, ifin, ilon, jlat
      INTEGER ix(9), jy(9) ! index arrays for the neighbors coordinates
      REAL zmask(9)
C
C  We search over the eight closest neighbors
C
C            j+1  7  8  9
C              j  4  5  6    Current point 5 --> (i,j)
C            j-1  1  2  3
C                i-1 i i+1
c
c
      IF (norsud) THEN
         DO j = 1, kylat
         DO i = 1, kxlon
            pwork(i,j) = pfild(i,kylat-j+1)
         ENDDO
         ENDDO
         DO j = 1, kylat
         DO i = 1, kxlon
            pfild(i,j) = pwork(i,j)
         ENDDO
         ENDDO
      ENDIF
c
      incre = 0
c
      DO j = 1, kylat
      DO i = 1, kxlon
         pwork(i,j) = pfild(i,j)
      ENDDO
      ENDDO
c
C* To avoid problems in floating point tests
      zwmsk = pmask - 1.0
c
200   CONTINUE
      incre = incre + 1
      DO j = 1, kylat
      DO i = 1, kxlon
      IF (pfild(i,j)> zwmsk) THEN
         pwork(i,j) = pfild(i,j)
         inbor = 0
         ideb = 1
         ifin = 9
C
C* Fill up ix array
         ix(1) = MAX (1,i-1)
         ix(2) = i
         ix(3) = MIN (kxlon,i+1)
         ix(4) = MAX (1,i-1)
         ix(5) = i
         ix(6) = MIN (kxlon,i+1)
         ix(7) = MAX (1,i-1)
         ix(8) = i
         ix(9) = MIN (kxlon,i+1)
C
C* Fill up iy array
         jy(1) = MAX (1,j-1)
         jy(2) = MAX (1,j-1)
         jy(3) = MAX (1,j-1)
         jy(4) = j
         jy(5) = j
         jy(6) = j
         jy(7) = MIN (kylat,j+1)
         jy(8) = MIN (kylat,j+1)
         jy(9) = MIN (kylat,j+1)
C
C* Correct latitude bounds if southernmost or northernmost points
         IF (j == 1) ideb = 4
         IF (j == kylat) ifin = 6
C
C* Account for periodicity in longitude
C
         IF (ldper) THEN 
            IF (i == kxlon) THEN
               ix(3) = 1
               ix(6) = 1
               ix(9) = 1
            ELSE IF (i == 1) THEN
               ix(1) = kxlon
               ix(4) = kxlon
               ix(7) = kxlon
            ENDIF
         ELSE
            IF (i == 1) THEN
               ix(1) = i
               ix(2) = i + 1
               ix(3) = i
               ix(4) = i + 1
               ix(5) = i
               ix(6) = i + 1
            ENDIF 
            IF (i == kxlon) THEN
               ix(1) = i -1
               ix(2) = i
               ix(3) = i - 1
               ix(4) = i
               ix(5) = i - 1
               ix(6) = i
            ENDIF
C
            IF (i == 1 .OR. i == kxlon) THEN 
               jy(1) = MAX (1,j-1)
               jy(2) = MAX (1,j-1)
               jy(3) = j
               jy(4) = j
               jy(5) = MIN (kylat,j+1)
               jy(6) = MIN (kylat,j+1)
C
               ideb = 1
               ifin = 6
               IF (j == 1) ideb = 3
               IF (j == kylat) ifin = 4
            ENDIF
         ENDIF ! end for ldper test
C
C* Find unmasked neighbors
C
         DO k = ideb, ifin
            zmask(k) = 0.
            ilon = ix(k)
            jlat = jy(k)
            IF (pfild(ilon,jlat) < zwmsk) THEN
               zmask(k) = 1.
               inbor = inbor + 1
            ENDIF
      END DO
C
C* Not enough points around point P are unmasked; interpolation on P 
C  will be done in a future CALL to extrap.
C
         IF (inbor >= knbor) THEN
            pwork(i,j) = 0.
            DO k = ideb, ifin
               ilon = ix(k)
               jlat = jy(k)
               pwork(i,j) = pwork(i,j)
     $                      + pfild(ilon,jlat) * zmask(k)/ REAL(inbor)
            ENDDO
         ENDIF
C
      ENDIF
      END DO
      END DO
C
C*    3. Writing back unmasked field in pfild
C        ------------------------------------
C
C* pfild then contains:
C     - Values which were not masked
C     - Interpolated values from the inbor neighbors
C     - Values which are not yet interpolated
C
      idoit = 0
      DO j = 1, kylat
      DO i = 1, kxlon
         IF (pwork(i,j) > zwmsk) idoit = idoit + 1
         pfild(i,j) = pwork(i,j)
      ENDDO
      ENDDO
c
      IF (idoit /= 0) GOTO 200
ccc      PRINT*, "Number of extrapolation steps incre =", incre
c
      IF (norsud) THEN
         DO j = 1, kylat
         DO i = 1, kxlon
            pwork(i,j) = pfild(i,kylat-j+1)
         ENDDO
         ENDDO
         DO j = 1, kylat
         DO i = 1, kxlon
            pfild(i,j) = pwork(i,j)
         ENDDO
         ENDDO
      ENDIF
c
      RETURN
      END
