!> @file
!> @brief Contains program for tide prediction, W3PRTIDE.
!>
!> @author F. Ardhuin @date 21-Apr-2020
!
#include "w3macros.h"
!/ ------------------------------------------------------------------- /
!> @brief Predicts tides (current or water level) to be used during
!>  run by ww3_shel or ww3_multi  (this takes much less memory).
!>
!> @author F. Ardhuin @date 21-Apr-2020
PROGRAM W3PRTIDE
  !/
  !/                  +-----------------------------------+
  !/                  | WAVEWATCH III           NOAA/NCEP |
  !/                  |           F. Ardhuin              |
  !/                  |                        FORTRAN 90 |
  !/                  | Last update :         21-Apr-2020 |
  !/                  +-----------------------------------+
  !/
  !/    29-Mar-2013 : Creation                            ( version 4.11 )
  !/    17-Oct-2013 : Manages missing data for UNST grids ( version 4.12 )
  !/    06-Jun-2018 : COMPUTE VNEIGH: calculate the number of connected
  !/                  triangles for a given point         ( version 6.04 )
  !/    21-Apr-2020 : MPI implementation                  ( version 7.13 )
  !/    21-Apr-2020 : bug fix for rectilinear grid        ( version 7.13 )
  !/     1-Feb-2020 : Improve indexing, A.Roland	        ( version 7.14 )

  !/
  !/    Copyright 2013 National Weather Service (NWS),
  !/       National Oceanic and Atmospheric Administration.  All rights
  !/       reserved.  WAVEWATCH III is a trademark of the NWS.
  !/       No unauthorized use without permission.
  !/
  !  1. Purpose :
  !
  !     Predicts tides (current or water level) to be used during
  !     run by ww3_shel or ww3_multi  (this takes much less memory).
  !
  !  2. Method :
  !
  !     See documented input file.
  !
  !  3. Parameters :
  !
  !     Local parameters.
  !     ----------------------------------------------------------------
  !       NDSI    Int.  Input unit number ("ww3_prtide.inp").
  !       NDSLL   Int.  Unit number(s) of long-lat file(s)
  !       NDSF    I.A.  Unit number(s) of input file(s).
  !       NDSDAT  Int.  Unit number for output data file.
  !       FLTIME  Log.  Time flag for input fields, if false, single
  !                     field, time read from NDSI.
  !       IDLALL  Int.  Layout indicator used by INA2R. +
  !       IDFMLL  Int.  Id. FORMAT indicator.           |
  !       FORMLL  C*16  Id. FORMAT.                     | Long-lat
  !       FROMLL  C*4   'UNIT' / 'NAME' indicator       |    file(s)
  !       NAMELL  C*40  Name of long-lat file(s)        +
  !       IDLAF   I.A.   +
  !       IDFMF   I.A.   |
  !       FORMF   C.A.   | Idem. fields file(s)
  !       FROMF   C*4    |
  !       NAMEF   C*50   +
  !       FORMT   C.A.  Format or time in field.
  !       XC      R.A.  Components of input vector field or first
  !                     input scalar field
  !       YC      R.A.  Components of input vector field or second
  !                     input scalar field
  !     ----------------------------------------------------------------
  !
  !  4. Subroutines used :
  !
  !      Name      Type  Module   Description
  !     ----------------------------------------------------------------
  !      W3NMOD    Subr. W3GDATMD Set number of model.
  !      W3SETG    Subr.   Id.    Point to selected model.
  !      W3NOUT    Subr. W3ODATMD Set number of model for output.
  !      W3SETO    Subr.   Id.    Point to selected model for output.
  !      ITRACE    Subr. W3SERVMD Subroutine tracing initialization.
  !      STRACE    Subr.   Id.    Subroutine tracing.
  !      NEXTLN    Subr.   Id.    Get next line from input filw
  !      EXTCDE    Subr.   Id.    Abort program as graceful as possible.
  !      STME21    Subr. W3TIMEMD Convert time to string.
  !      W3IOGR    Subr. W3IOGRMD Reading/writing model definition file.
  !      W3FLDO    Subr. W3FLDSMD Opening of WAVEWATCH III generic shell
  !                               data file.
  !      W3FLDG    Subr.   Id.    Reading/writing shell input data.
  !     ----------------------------------------------------------------
  !
  !  5. Called by :
  !
  !     None, stand-alone program.
  !
  !  6. Error messages :
  !
  !     - Checks on files and reading from file.
  !     - Checks on validity of input parameters.
  !
  !  7. Remarks :
  !
  !     - Input fields need to be continuous in longitude and latitude.
  !
  !  8. Structure :
  !
  !     ----------------------------------------------------
  !        To be updated ...
  !     ----------------------------------------------------
  !
  !  9. Switches :
  !
  !     !/S     Enable subroutine tracing.
  !     !/T     Enable test output,
  !
  !     !/NCO   NCEP NCO modifications for operational implementation.
  !
  ! 10. Source code :
  !
  !/ ------------------------------------------------------------------- /
  USE CONSTANTS
  !/
  !     USE W3GDATMD, ONLY: W3NMOD, W3SETG
#ifdef W3_NL1
  USE W3ADATMD,ONLY: W3NAUX, W3SETA
#endif
  USE W3ODATMD, ONLY: IAPROC, NAPROC, NAPERR, NAPOUT
  USE W3ODATMD, ONLY: W3NOUT, W3SETO
  USE W3SERVMD, ONLY : ITRACE, NEXTLN, EXTCDE, STRSPLIT
#ifdef W3_S
  USE W3SERVMD, ONLY : STRACE
#endif
  USE W3TIMEMD
  USE W3ARRYMD, ONLY : INA2R, INA2I
  USE W3IOGRMD, ONLY: W3IOGR
  USE W3FLDSMD, ONLY: W3FLDO, W3FLDG, W3FLDD, W3FLDTIDE1, W3FLDTIDE2
  !/
  USE W3GDATMD
  USE W3GSRUMD
  USE W3ODATMD, ONLY: NDSE, NDST, NDSO, FNMPRE
  USE W3TIDEMD
  USE W3IDATMD
  !
  IMPLICIT NONE
  !
#ifdef W3_MPI
  INCLUDE "mpif.h"
#endif
  !/
  !/ ------------------------------------------------------------------- /
  !/ Local parameters
  !/
  INTEGER                 :: NDSI, NDSF, NDSM, NDSDAT, NDSTRC, NTRACE
  INTEGER                 :: IERR, IFLD, I, JJ, J, IX, IY
  INTEGER                 :: DTTST, NDSEN, PRTIDE_DT
  INTEGER                 :: TIDE_PRMF, FLAGTIDE, TINDEX
  INTEGER                 :: TIDEOK, TIDE_MAX, TIDE_MAXI
  INTEGER                 :: K, ICON, IX2, SUMOK, NBAD, ITER
  INTEGER                 :: IE, IP, IP2, II, IFOUND, ALREADYFOUND
  INTEGER                 :: TIDE_KD0, INT24, INTDYS       ! "Gregorian day constant"
#ifdef W3_MPI
  INTEGER                 :: IERR_MPI, IND, REST, SLICE
#endif
  INTEGER                 :: TIME(2), TIDE_START(2), TIDE_END(2)
  INTEGER                 :: INDMAX(70), PR_INDS(70)
  !
  INTEGER, ALLOCATABLE    :: BADPOINTS(:,:), VNEIGH(:,:), CONN(:)
#ifdef W3_MPI
  INTEGER, ALLOCATABLE    :: NELEM(:), CUMUL(:)
#endif
  !
  REAL                    :: WCURTIDEX, WCURTIDEY, TIDE_ARGX, TIDE_ARGY
  REAL                    :: AMPCOS, AMPSIN
  !
  REAL                    :: TIDE_FX(44),UX(44),VX(44), MAXVALCON(70)
  !
  REAL, ALLOCATABLE       :: FX(:,:), FY(:,:), FA(:,:)
#ifdef W3_MPI
  REAL, ALLOCATABLE       :: FX1D(:), FY1D(:), FA1D(:)
  REAL, ALLOCATABLE       :: FX1DL(:), FY1DL(:), FA1DL(:)
#endif
  !
  DOUBLE PRECISION        :: d1,h,TIDE_HOUR,HH,pp,s,p,enp,dh,dpp,ds,dp,dnp,tau
  !
  CHARACTER*256           :: FILENAMEXT
  CHARACTER               :: TIDECONSTNAMES*1024
  CHARACTER*23            :: IDTIME
  CHARACTER               :: COMSTR*1, IDFLD*3
  !
  CHARACTER(LEN=100)      :: TIDECON_PRNAMES(70), TIDECON_MAXNAMES(70)
  CHARACTER(LEN=100)      :: TIDECON_MAXVALS(70)
  !
  LOGICAL                 :: TIDEFILL
  !
  !/
  !/ ------------------------------------------------------------------- /
  !/

  !==========================================================
  !
  ! Initialization
  !
  !==========================================================

  !
  ! 1.a  Set number of models
  !
  CALL W3NMOD ( 1, 6, 6 )
  CALL W3SETG ( 1, 6, 6 )
#ifdef W3_NL1
  CALL W3NAUX (    6, 6 )
  CALL W3SETA ( 1, 6, 6 )
#endif
  CALL W3NOUT (    6, 6 )
  CALL W3SETO ( 1, 6, 6 )
  !
  ! 1.b  IO set-up.
  !
  NDSI   = 10
  NDSO   =  6
  NDSE   =  6
  NDST   =  6
  NDSM   = 11
  NDSDAT = 12
  NDSF   = 13
  !
  NDSTRC =  6
  NTRACE = 10
  TIDEFILL =.TRUE.
  CALL ITRACE ( NDSTRC, NTRACE )
  !
#ifdef W3_NCO
  !
  ! Redo according to NCO
  !
  NDSI   = 11
  NDSO   =  6
  NDSE   = NDSO
  NDST   = NDSO
  NDSM   = 12
  NDSDAT = 51
  NDSTRC = NDSO
#endif

#ifdef W3_S
  CALL STRACE (IENT, 'W3PRTIDE')
#endif

  !
  ! 1.c MPP initializations
  !
#ifdef W3_SHRD
  NAPROC = 1
  IAPROC = 1
#endif
  !
#ifdef W3_MPI
  CALL MPI_INIT      ( IERR_MPI )
  CALL MPI_COMM_SIZE ( MPI_COMM_WORLD, NAPROC, IERR_MPI )
  CALL MPI_COMM_RANK ( MPI_COMM_WORLD, IAPROC, IERR_MPI )
  IAPROC = IAPROC + 1  ! this is to have IAPROC between 1 and NAPROC
#endif
  !
  IF ( IAPROC .EQ. NAPERR ) THEN
    NDSEN  = NDSE
  ELSE
    NDSEN  = -1
  END IF
  !
  IF ( IAPROC .EQ. NAPOUT ) WRITE (NDSO,900)
  !
  OPEN (NDSI,FILE=TRIM(FNMPRE)//'ww3_prtide.inp',STATUS='OLD',        &
       ERR=800,IOSTAT=IERR)
  REWIND (NDSI)
  READ (NDSI,'(A)',END=801,ERR=802,IOSTAT=IERR) COMSTR
  IF (COMSTR.EQ.' ') COMSTR = '$'
  IF ( IAPROC .EQ. NAPOUT ) WRITE (NDSO,901) COMSTR

  !==========================================================
  !
  ! Read model definition file.
  !
  !==========================================================

  CALL W3IOGR ( 'READ', NDSM )
  IF ( IAPROC .EQ. NAPOUT ) WRITE (NDSO,902) GNAME
  ALLOCATE ( FX(NX,NY), FY(NX,NY), FA(NX,NY),  BADPOINTS(NX,NY) )

  !==========================================================
  !
  ! Read types from input file.
  !
  !==========================================================

  CALL NEXTLN ( COMSTR , NDSI , NDSEN )
  READ (NDSI,*,END=801,ERR=802,IOSTAT=IERR) IDFLD
  !
  IF ( IDFLD.EQ.'LEV' ) THEN
    IFLD    = 2
  ELSE IF ( IDFLD.EQ.'CUR' ) THEN
    IFLD    = 4
  ELSE
    WRITE (NDSE,1030) IDFLD
    CALL EXTCDE ( 1 )
  END IF
  !
  CALL NEXTLN ( COMSTR , NDSI , NDSEN )
  READ (NDSI,'(A)',END=801,ERR=802,IOSTAT=IERR) TIDECONSTNAMES
  CALL NEXTLN ( COMSTR , NDSI , NDSE )
  TIDECON_PRNAMES(:)=''
  CALL STRSPLIT(TIDECONSTNAMES,TIDECON_PRNAMES)
  !
  CALL NEXTLN ( COMSTR , NDSI , NDSEN )
  READ (NDSI,'(A)',END=801,ERR=802,IOSTAT=IERR) TIDECONSTNAMES
  TIDECON_MAXNAMES(:)=''
  CALL STRSPLIT(TIDECONSTNAMES,TIDECON_MAXNAMES)
  !
  CALL NEXTLN ( COMSTR , NDSI , NDSEN )
  TIDECON_MAXVALS(:)=''
  READ (NDSI,'(A)',END=801,ERR=802,IOSTAT=IERR) TIDECONSTNAMES
  CALL STRSPLIT(TIDECONSTNAMES,TIDECON_MAXVALS)
  !
  CALL NEXTLN ( COMSTR , NDSI , NDSEN )
  READ (NDSI,*,END=801,ERR=802,IOSTAT=IERR) TIDE_START,PRTIDE_DT,TIDE_END
  CALL NEXTLN ( COMSTR , NDSI , NDSEN )
  READ (NDSI,*,END=801,ERR=802,IOSTAT=IERR) FILENAMEXT
  !
  CALL W3FLDO ('READ', IDFLD, NDSF, NDST,     &
       NDSE, NX, NY, GTYPE,               &
       IERR, FILENAMEXT, '', TIDEFLAGIN=FLAGTIDE )
  !
  IF (FLAGTIDE.NE.1) GOTO 803
  !
  CALL VUF_SET_PARAMETERS

  !==========================================================
  !
  ! Read tidal amplitudes and phases
  !
  !==========================================================

  CALL W3FLDTIDE1 ( 'READ',  NDSF, NDST, NDSE, NX, NY, IDFLD, IERR )
  CALL W3FLDTIDE2 ( 'READ',  NDSF, NDST, NDSE, NX, NY, IDFLD, 0, IERR )
  CLOSE(NDSF)

  !

  IF (GTYPE.EQ.UNGTYPE) THEN

    COUNTRI = MAXVAL(CCON)
    ALLOCATE(VNEIGH(NX,2*COUNTRI))
    ALLOCATE(CONN(NX))
    VNEIGH(:,:) = 0
    CONN(:) = 0
    !
    J = 0
    DO IP = 1, NX
      IFOUND = 0
      DO II = 1, CCON(IP)
        J = J + 1
        IE = IE_CELL(J)
        IF (IP == TRIGP(1,IE)) THEN
          DO IP2=2,3
            ALREADYFOUND = 0
            DO I=1,IFOUND
              IF (VNEIGH(IP,I).EQ.TRIGP(IP2,IE)) ALREADYFOUND=ALREADYFOUND+1
            END DO
            IF (ALREADYFOUND.EQ.0) THEN
              IFOUND=IFOUND+1
              VNEIGH(IP,IFOUND)=TRIGP(IP2,IE)
            END IF
          END DO
        END IF

        IF (IP == TRIGP(2,IE)) THEN
          DO IP2=3,4
            ALREADYFOUND = 0
            DO I=1,IFOUND
              IF (VNEIGH(IP,I).EQ.TRIGP(MOD(IP2-1,3)+1,IE)) ALREADYFOUND=ALREADYFOUND+1
            END DO
            IF (ALREADYFOUND.EQ.0) THEN
              IFOUND=IFOUND+1
              VNEIGH(IP,IFOUND)=TRIGP(MOD(IP2-1,3)+1,IE)
            END IF
          END DO
        END IF

        IF (IP == TRIGP(3,IE)) THEN
          DO IP2=1,2
            ALREADYFOUND = 0
            DO I=1,IFOUND
              IF (VNEIGH(IP,I).EQ.TRIGP(IP2,IE)) ALREADYFOUND=ALREADYFOUND+1
            END DO
            IF (ALREADYFOUND.EQ.0) THEN
              IFOUND=IFOUND+1
              VNEIGH(IP,IFOUND)=TRIGP(IP2,IE)
            END IF
          END DO
        END IF
      END DO ! CCON
      ! CONN is a counter on connected points. In comparison with the number of connected triangle
      ! CCON, it will enable to spot whether a point belong to the contour
      !
      CONN(IP)=IFOUND
      DO I=2,IFOUND
        DO JJ=1,i-1
          IF (VNEIGH(IP,JJ).EQ. VNEIGH(IP,I)) THEN
            COUNTCON(IP)=COUNTCON(IP)-1
            VNEIGH(IP,I:IFOUND)=VNEIGH(IP,I+1:IFOUND+1)  ! removes the double point
          END IF
        END DO
      END DO
    END DO !NX

  END IF ! UNGTYPE

  !==========================================================
  !
  ! Apply the maximum threshold value to tidal constituents
  !
  !==========================================================

  CALL TIDE_FIND_INDICES_PREDICTION(TIDECON_PRNAMES,PR_INDS,TIDE_PRMF)
  TIDE_MAX=0
  TIDE_MAXI=0
  DO WHILE (len_trim(TIDECON_MAXNAMES(TIDE_MAXI+1)).NE.0)
    TIDE_MAXI=TIDE_MAXI+1
    DO J=1,TIDE_MF
      IF (TRIM(TIDECON_NAME(J)).EQ.TRIM(TIDECON_MAXNAMES(TIDE_MAXI))) THEN
        TIDE_MAX=TIDE_MAX+1
        INDMAX(TIDE_MAX)=J
        READ(TIDECON_MAXVALS(TIDE_MAXI),*) MAXVALCON(TIDE_MAX)
        IF (IAPROC.EQ.NAPOUT) THEN
          WRITE(NDSO,'(A,I8,A,F10.2)') &
               'Maximum allowed value for amplitude:',&
               J,TRIM(TIDECON_NAME(J)),MAXVALCON(TIDE_MAX)
        END IF
      END IF
    END DO
  END DO

  !==========================================================
  !
  ! Create the binary output file
  !
  !==========================================================

  FLAGTIDE = 0
  IF (IAPROC .EQ. NAPOUT) THEN
    CALL W3FLDO ('WRITE', IDFLD, NDSDAT, NDST, NDSE, NX, NY,      &
         GTYPE, IERR, 'ww3', TIDEFLAGIN=FLAGTIDE)
  END IF

  !==========================================================
  !
  ! Set arrays for MPI exchanges
  !
  !==========================================================

#ifdef W3_MPI
  SLICE=NX/NAPROC
  REST=MOD(NX,NAPROC)
  IF(REST.GE.IAPROC) SLICE=SLICE+1
#endif

#ifdef W3_MPI
  ! set total 1D array (nx)
  ALLOCATE ( FX1D(NX), FY1D(NX), FA1D(NX))
  FX1D(:)=0.
  FY1D(:)=0.
  FA1D(:)=0.
#endif

#ifdef W3_MPI
  ! set local 1D array (slice)
  ALLOCATE(FX1DL(SLICE))
  ALLOCATE(FY1DL(SLICE))
  ALLOCATE(FA1DL(SLICE))
  FX1DL(:)=0.
  FY1DL(:)=0.
  FA1DL(:)=0.
#endif


#ifdef W3_MPI
  ! set arrays for number of elements per MPI proc
  ALLOCATE(NELEM(NAPROC))
  ALLOCATE(CUMUL(NAPROC))
  NELEM(1) = NX / NAPROC
  IF (REST .GT. 0) NELEM(1) = NELEM(1) + 1
  CUMUL(1) = 0
  DO I=2,NAPROC
    CUMUL(I)=CUMUL(I-1)+NELEM(I-1)
    NELEM(I) = NX / NAPROC
    IF (REST .GT. I-1) NELEM(I) = NELEM(I) + 1
  END DO
#endif

#ifdef W3_MPIT
  WRITE(100+IAPROC,*) "Number of points for this processor ", IAPROC, " : ", NELEM(IAPROC), ' / ', NX
  WRITE(100+IAPROC,*) "Cumul of points for this processor ", IAPROC, " : ", CUMUL(IAPROC), ' / ', NX
#endif

  !==========================================================
  !
  ! Loop on time steps
  !
  !==========================================================

  DTTST  = DSEC21 ( TIDE_START , TIDE_END )
  IF ( DTTST .LE. 0. .OR. PRTIDE_DT .LT. 1 ) GOTO 888
  TIME = TIDE_START
  TIDE_KD0= 2415020
  !
  TINDEX = 1
  !
  DO
    DTTST  = DSEC21 ( TIME, TIDE_END )
    IF ( DTTST .LT. 0. ) GOTO 888
    !
    CALL STME21 ( TIME , IDTIME )
    IF ( IAPROC .EQ. NAPOUT ) WRITE (NDSO,973) IDTIME

    TIDE_HOUR = TIME2HOURS(TIME)
    !
    !*  THE ASTRONOMICAL ARGUMENTS ARE CALCULATED
    !
    d1=TIDE_HOUR/24.d0
    d1=d1-dfloat(TIDE_kd0)-0.5d0
    CALL ASTR(d1,h,pp,s,p,enp,dh,dpp,ds,dp,dnp)
    INT24=24
    INTDYS=int((TIDE_HOUR+0.00001)/INT24)
    HH=TIDE_HOUR-dfloat(INTDYS*INT24)
    TAU=HH/24.D0+H-S

    !==========================================================
    !
    ! Treatment of 'bad points' at first time step
    !
    !==========================================================

    BADPOINTS(:,:)=0
    NBAD =0

    IF (TINDEX.EQ.1) THEN
      DO IY = 1, NY
        DO IX=1, NX
          TIDEOK=1
          DO I=1,TIDE_MAX
            IF (ABS(TIDAL_CONST(IX,IY,INDMAX(I),1,1)) .GT.MAXVALCON(I) .OR. &
                 ABS(TIDAL_CONST(IX,IY,INDMAX(I),2,1)) .GT.MAXVALCON(I)) THEN
              TIDEOK = 0
              WRITE(NDSO,'(A,I8,F10.2,A,2F10.2)') &
                   '[BAD POINT] GREATER THAN THRESHOLD ', MAXVALCON(I), &
                   ' AT INDEX ', INDMAX(I),                             &
                   ' WITH X-Y COMPONENTS : ', ABS(TIDAL_CONST(IX,IY,INDMAX(I),1:2,1))
            END IF
            BADPOINTS(IX,IY) = BADPOINTS(IX,IY) + (1-TIDEOK)
          END DO

          IF (BADPOINTS(IX,IY).GT.0) THEN
            NBAD = NBAD +1
            WRITE(NDSE,*) 'BAD POINT:',IX,IY,NBAD, &
                 TIDAL_CONST(IX,IY,:,1,1),'##',TIDAL_CONST(IX,IY,:,2,1)
          END IF
        END DO
      END DO
      !
      DO ITER=1,2
        DO IY = 1, NY
          DO IX= 1, NX
            IF (BADPOINTS(IX,IY).GT.0) THEN
              TIDAL_CONST(IX,IY,:,1,1)=0
              TIDAL_CONST(IX,IY,:,2,1)=0


              IF (TIDEFILL.AND.(GTYPE.EQ.UNGTYPE)) THEN

                !
                ! Performs a vector sum of tidal constituents over neighbor nodes
                !
                DO J=1, TIDE_MF
                  DO K=1, 2
                    AMPCOS = 0
                    AMPSIN = 0
                    SUMOK = 0
                    DO ICON=1,COUNTCON(IX)
                      IX2=VNEIGH(IX,ICON)
                      IF (BADPOINTS(IX2,IY).EQ.0) THEN
                        SUMOK = SUMOK + 1
                        AMPCOS = AMPCOS+TIDAL_CONST(IX2,IY,J,K,1)*COS(TIDAL_CONST(IX2,IY,J,K,2)*DERA)
                        AMPSIN = AMPSIN+TIDAL_CONST(IX2,IY,J,K,1)*SIN(TIDAL_CONST(IX2,IY,J,K,2)*DERA)
                      END IF
                    END DO
                    IF (SUMOK.GT.1) THEN
                      !
                      ! Finalizes the amplitude and phase calculation from COS and SIN. Special case for mean value Z0.
                      !
                      IF (TIDECON_NAME(J).NE.'Z0   ') THEN
                        TIDAL_CONST(IX,IY,J,K,1) = SQRT(AMPCOS**2+AMPSIN**2)/SUMOK
                        TIDAL_CONST(IX,IY,J,K,2) = ATAN2(AMPSIN,AMPCOS)/DERA
                      ELSE
                        TIDAL_CONST(IX,IY,J,K,1) = AMPCOS/SUMOK
                        TIDAL_CONST(IX,IY,J,K,2) = 0.
                      END IF
                      IF(K.EQ.2.AND.J.EQ.TIDE_MF) THEN
                        NBAD=NBAD-1
                        BADPOINTS(IX,IY) = 0
                      END IF
                    ENDIF
                  END DO
                END DO
              END IF
            END IF
          END DO
        END DO
      END DO
      IF ( IAPROC .EQ. NAPOUT ) WRITE(NDSE,*) 'Number of remaining bad points:',NBAD
    END IF

    !==========================================================
    !
    ! For currents: 2 components
    !
    !==========================================================

    IF (IFLD.EQ.4) THEN
      DO IY = 1, NY
#ifdef W3_MPI
        IND=0
        DO IX=CUMUL(IAPROC)+1,CUMUL(IAPROC)+NELEM(IAPROC)
#endif
#ifdef W3_SHRD
          DO IX=1,NX
#endif
            CALL SETVUF_FAST(h,pp,s,p,enp,dh,dpp,ds,dp,dnp,tau,REAL(YGRD(IY,IX)),TIDE_FX,UX,VX)
            WCURTIDEX = 0.
            WCURTIDEY = 0.
            DO I=1,TIDE_PRMF
              J=PR_INDS(I)
              IF (TRIM(TIDECON_NAME(J)).EQ.'Z0') THEN
                WCURTIDEX = WCURTIDEX+TIDAL_CONST(IX,IY,J,1,1)
                WCURTIDEY = WCURTIDEY+TIDAL_CONST(IX,IY,J,2,1)
              ELSE
                TIDE_ARGX=(VX(J)+UX(J))*twpi-TIDAL_CONST(IX,IY,J,1,2)*DERA
                TIDE_ARGY=(VX(J)+UX(J))*twpi-TIDAL_CONST(IX,IY,J,2,2)*DERA
                WCURTIDEX = WCURTIDEX+TIDE_FX(J)*TIDAL_CONST(IX,IY,J,1,1)*COS(TIDE_ARGX)
                WCURTIDEY = WCURTIDEY+TIDE_FX(J)*TIDAL_CONST(IX,IY,J,2,1)*COS(TIDE_ARGY)
              END IF
            END DO
            IF (ABS(WCURTIDEX).GT.10..OR.ABS(WCURTIDEY).GT.10.)  THEN
              WRITE(NDSE,*) &
                   'WARNING: VERY STRONG CURRENT... BAD CONSTITUENTS?', &
                   IX, WCURTIDEX, WCURTIDEY ,  TIDAL_CONST(IX,IY,:,1,1),'##',TIDAL_CONST(IX,IY,:,2,1)
              STOP
            END IF
#ifdef W3_MPI
            IND=IND+1
            FX1DL(IND) = WCURTIDEX
            FY1DL(IND) = WCURTIDEY
            FA1DL(IND) = 0.
          END DO ! NX
#endif
#ifdef W3_SHRD
          FX(IX,IY) = WCURTIDEX
          FY(IX,IY) = WCURTIDEY
          FA(IX,IY) = 0.
        END DO ! NX
#endif

        !
        ! Gather from other MPI tasks
        !

#ifdef W3_MPI
        IF (NAPROC.GT.1) THEN
          CALL MPI_GATHERV(FX1DL, SLICE, MPI_REAL, FX1D, NELEM, &
               CUMUL, MPI_REAL, NAPOUT-1, MPI_COMM_WORLD, IERR_MPI)
          CALL MPI_GATHERV(FY1DL, SLICE, MPI_REAL, FY1D, NELEM, &
               CUMUL, MPI_REAL, NAPOUT-1, MPI_COMM_WORLD, IERR_MPI)
          CALL MPI_GATHERV(FA1DL, SLICE, MPI_REAL, FA1D, NELEM, &
               CUMUL, MPI_REAL, NAPOUT-1, MPI_COMM_WORLD, IERR_MPI)
        ELSE
          FX1D = FX1DL
          FY1D = FY1DL
          FA1D = FA1DL
        END IF
#endif

        !
        ! Convert from 1D to 2D array
        !
#ifdef W3_MPI
        IF (IAPROC .EQ. NAPOUT) THEN
          IND=0
          DO IX=1,NX
            IND=IND+1
            FX(IX,IY)=FX1D(IND)
            FY(IX,IY)=FY1D(IND)
            FA(IX,IY)=FA1D(IND)
          END DO
        END IF
#endif

      END DO ! NY
    END IF ! IFLD.EQ.4


    !==========================================================
    !
    ! For water levels: only 1 component
    !
    !==========================================================

    IF (IFLD.EQ.2) THEN
      DO IY = 1, NY
#ifdef W3_MPI
        IND=0
        DO IX=CUMUL(IAPROC)+1,CUMUL(IAPROC)+NELEM(IAPROC)
#endif
#ifdef W3_SHRD
          DO IX=1,NX
#endif
            CALL SETVUF_FAST(h,pp,s,p,enp,dh,dpp,ds,dp,dnp,tau,REAL(YGRD(IY,IX)),TIDE_FX,UX,VX)
            !
            ! Removes unlikely values ...
            !
            IF (TINDEX.EQ.1) THEN
              TIDEOK=1
              DO I=1,TIDE_MAX
                IF (ABS(TIDAL_CONST(IX,IY,INDMAX(I),1,1)) .GT.MAXVALCON(I)) &
                     TIDEOK = 0
              END DO
              IF (TIDEOK.EQ.0) THEN
                WRITE(NDSE,*) 'BAD POINT:',IX,IY, TIDAL_CONST(IX,IY,:,1,1)
                TIDAL_CONST(IX,IY,:,1,1)=0
              END IF
            END IF

            WCURTIDEX = 0.
            DO I=1,TIDE_PRMF
              J=PR_INDS(I)
              IF (TRIM(TIDECON_NAME(J)).EQ.'Z0') THEN
                WCURTIDEX = WCURTIDEX+TIDAL_CONST(IX,IY,J,1,1)
              ELSE
                TIDE_ARGX=(VX(J)+UX(J))*twpi-TIDAL_CONST(IX,IY,J,1,2)*DERA
                WCURTIDEX = WCURTIDEX+TIDE_FX(J)*TIDAL_CONST(IX,IY,J,1,1)*COS(TIDE_ARGX)
              END IF
            END DO
#ifdef W3_MPI
            IND=IND+1
            FX1DL(IND) = 0.
            FY1DL(IND) = 0.
            FA1DL(IND) = WCURTIDEX
          END DO ! NX
#endif
#ifdef W3_SHRD
          FX(IX,IY) = 0.
          FY(IX,IY) = 0.
          FA(IX,IY) = WCURTIDEX
        END DO ! NX
#endif



        !
        ! Gather from other MPI tasks
        !

#ifdef W3_MPI
        IF (NAPROC.GT.1) THEN
          CALL MPI_GATHERV(FX1DL, SLICE, MPI_REAL, FX1D, NELEM,&
               CUMUL, MPI_REAL, NAPOUT-1, MPI_COMM_WORLD, IERR_MPI)
          CALL MPI_GATHERV(FY1DL, SLICE, MPI_REAL, FY1D, NELEM,&
               CUMUL, MPI_REAL, NAPOUT-1, MPI_COMM_WORLD, IERR_MPI)
          CALL MPI_GATHERV(FA1DL, SLICE, MPI_REAL, FA1D, NELEM,&
               CUMUL, MPI_REAL, NAPOUT-1, MPI_COMM_WORLD, IERR_MPI)
        ELSE
          FX1D = FX1DL
          FY1D = FY1DL
          FA1D = FA1DL
        END IF
#endif

        !
        ! Convert from 1D to 2D array
        !
#ifdef W3_MPI
        IF (IAPROC .EQ. NAPOUT) THEN
          IND=0
          DO IX=1,NX
            IND=IND+1
            FX(IX,IY)=FX1D(IND)
            FY(IX,IY)=FY1D(IND)
            FA(IX,IY)=FA1D(IND)
          END DO
        END IF
#endif

      END DO ! NY
    END IF ! IFLD.EQ.2


    !==========================================================
    !
    ! Write into binary output file
    !
    !==========================================================

    IF (IAPROC .EQ. NAPOUT) THEN

      !        WHERE(FX.NE.FX) FX = 0.
      !        WHERE(FY.NE.FY) FY = 0.
      !        WHERE(FA.NE.FA) FA = 0.

      CALL W3FLDG ('WRITE', IDFLD, NDSDAT, NDST, NDSE, NX, NY,  &
           NX, NY, TIME, TIME, TIME, FX, FY, FA, TIME,  &
           FX, FY, FA, IERR)
    END IF

    !==========================================================
    !
    ! Increment the clock
    !
    !==========================================================

    CALL TICK21 ( TIME, FLOAT(PRTIDE_DT) )
    TINDEX = TINDEX +1

  END DO
  !
  GOTO 888
  !
  ! Error escape locations
  !
800 CONTINUE
  WRITE (NDSE,1000) IERR
  CALL EXTCDE ( 40 )
  !
801 CONTINUE
  WRITE (NDSE,1001)
  CALL EXTCDE ( 41 )
  !
802 CONTINUE
  WRITE (NDSE,1002) IERR
  CALL EXTCDE ( 42 )
  !
803 CONTINUE
  WRITE (NDSE,1003)
  CALL EXTCDE ( 43 )
  !
888 CONTINUE
  IF ( IAPROC .EQ. NAPOUT ) WRITE (NDSO,999)
#ifdef W3_MPI
  CALL MPI_FINALIZE  ( IERR_MPI )
#endif

  !
  ! Formats
  !
900 FORMAT (/15X,'  *** WAVEWATCH III  tide prediction ***  '/       &
       15X,'==============================================='/)
901 FORMAT ( '  Comment character is ''',A,''''/)
902 FORMAT ( '  Grid name : ',A/)
973 FORMAT ( '           Time : ',A)
  !
999 FORMAT(/'  End of program '/                                     &
       ' ========================================='/           &
       '         WAVEWATCH III Input preprocessing '/)
  !
1000 FORMAT (/' *** WAVEWATCH III ERROR IN W3PRTIDE : '/              &
       '     ERROR IN OPENING INPUT FILE'/                     &
       '     IOSTAT =',I5/)
  !
1001 FORMAT (/' *** WAVEWATCH III ERROR IN W3PRTIDE : '/              &
       '     PREMATURE END OF INPUT FILE'/)
  !
1002 FORMAT (/' *** WAVEWATCH III ERROR IN W3PRTIDE : '/              &
       '     ERROR IN READING FROM INPUT FILE'/                &
       '     IOSTAT =',I5/)
  !
1003 FORMAT (/' *** WAVEWATCH III ERROR IN W3PRTIDE : '/              &
       '     THE INPUT FILE DOES NOT CONTAIN TIDAL DATA'/)
  !
1030 FORMAT (/' *** WAVEWATCH III ERROR IN W3PRTIDE : '/              &
       '     ILLEGAL FIELD ID -->',A,'<--'/)
  !
  !/
  !/ End of W3PRTIDE ----------------------------------------------------- /
  !/
END PROGRAM W3PRTIDE