!/===========================================================================/
! Copyright (c) 2007, The University of Massachusetts Dartmouth 
! Produced at the School of Marine Science & Technology 
! Marine Ecosystem Dynamics Modeling group
! All rights reserved.
!
! FVCOM has been developed by the joint UMASSD-WHOI research team. For 
! details of authorship and attribution of credit please see the FVCOM
! technical manual or contact the MEDM group.
!
! 
! This file is part of FVCOM. For details, see http://fvcom.smast.umassd.edu 
! The full copyright notice is contained in the file COPYRIGHT located in the 
! root directory of the FVCOM code. This original header must be maintained
! in all distributed versions.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
! AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO,
! THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR
! PURPOSE ARE DISCLAIMED.  
!
!/---------------------------------------------------------------------------/
! CVS VERSION INFORMATION
! $Id$
! $Name$
! $Revision$
!/===========================================================================/

MODULE MOD_OBCS3

# if !defined (SEMI_IMPLICIT)
   USE ALL_VARS
   USE MOD_PREC
   USE MOD_OBCS

   USE MOD_MEANFLOW
   USE MOD_OBCS2

   IMPLICIT NONE
   SAVE

!--Nonlinear Velocity Open Boundary Condition Arrays
   REAL(SP), ALLOCATABLE :: FLUXOBN2(:),CXOBC(:),CYOBC(:)
   REAL(SP), ALLOCATABLE :: FLUXOBC2D_X(:),     FLUXOBC2D_Y(:)
   REAL(SP), ALLOCATABLE :: OBC2D_X_TIDE(:),    OBC2D_Y_TIDE(:)
   REAL(SP), ALLOCATABLE :: FLUXOBC3D_X(:,:),   FLUXOBC3D_Y(:,:)
   REAL(SP), ALLOCATABLE :: FLUXOBC3D_X_2(:,:), FLUXOBC3D_Y_2(:,:)
   CONTAINS


!=========================================================================|
   SUBROUTINE ALLOC_OBC3_DATA

   IMPLICIT NONE

   ALLOCATE(FLUXOBN2(0:IOBCN))                 ;FLUXOBN2      = ZERO
   ALLOCATE(CXOBC(0:NT))                       ;CXOBC         = ZERO
   ALLOCATE(CYOBC(0:NT))                       ;CYOBC         = ZERO
   ALLOCATE(FLUXOBC2D_X(0:nmfcell_i))          ;FLUXOBC2D_X   = ZERO
   ALLOCATE(FLUXOBC2D_Y(0:nmfcell_i))          ;FLUXOBC2D_Y   = ZERO
   ALLOCATE(FLUXOBC3D_X(0:nmfcell_i,1:KBM1))   ;FLUXOBC3D_X   = ZERO
   ALLOCATE(FLUXOBC3D_Y(0:nmfcell_i,1:KBM1))   ;FLUXOBC3D_Y   = ZERO
   ALLOCATE(FLUXOBC3D_X_2(0:nmfcell_i,1:KBM1)) ;FLUXOBC3D_X_2 = ZERO
   ALLOCATE(FLUXOBC3D_Y_2(0:nmfcell_i,1:KBM1)) ;FLUXOBC3D_Y_2 = ZERO

   ALLOCATE(OBC2D_X_TIDE(0:nmfcell),OBC2D_Y_TIDE(0:nmfcell)) 

   RETURN
   END SUBROUTINE ALLOC_OBC3_DATA
!==========================================================================|

!==========================================================================|
   SUBROUTINE ZERO_OBC3

   IMPLICIT NONE

   integer :: I

   IF (nmfcell > 0) THEN
      DO I = 0, nmfcell
         OBC2D_X_TIDE(I) = 0.0_SP
         OBC2D_Y_TIDE(I) = 0.0_SP
      END DO
   END IF

   RETURN
   END SUBROUTINE ZERO_OBC3
!==========================================================================|


!==============================================================================|
   SUBROUTINE SETUP_OBC3

#  if defined (SPHERICAL)
   USE MOD_SPHERICAL
#  endif
# if defined (MULTIPROCESSOR)
   USE MOD_PAR  
# endif
   IMPLICIT NONE

   INTEGER  :: I, I1, I2, J, IC, N1, N2, N3
   REAL(SP) :: DXN,DYN,DXC,DYC,CROSS
#  if defined (SPHERICAL)
   REAL(DP) :: x1_dp,y1_dp,x2_dp,y2_dp,side
#  endif

 IF (IOBCN > 0) THEN
   DO I=1,IOBCN
     I1 = I_OBC_N(I)
     I2 = ADJN_OBC(I,1)
     DO J = 1, NTVE(I1)
       IC = NBVE(I1,J)
       N1 = NV(IC,1) ; N2 = NV(IC,2) ; N3 = NV(IC,3)
       IF( N1-I2 == 0 .OR. N2-I2 == 0 .OR. N3-I2 == 0)THEN
# if defined (SPHERICAL)
         x1_dp=VX(I1); y1_dp=VY(I1)
         x2_dp=VX(I2); y2_dp=VY(I2)
         CALL ARCX(x1_dp,y1_dp,x2_dp,y2_dp,side)
         DXN = side; DYN = (VY(I2)-VY(I1))*TPI

         x2_dp=XC(IC); y2_dp=YC(IC)
         CALL ARCX(x1_dp,y1_dp,x2_dp,y2_dp,side)
         DXC = side; DYC = (YC(IC)-VY(I1))*TPI
# else
         DXN = VX(I2)-VX(I1) ; DYN = VY(I2)-VY(I1)
         DXC = XC(IC)-VX(I1) ; DYC = YC(IC)-VY(I1)
# endif
         CROSS     =  SIGN(1.0_SP,DXC*DYN - DYC*DXN)
         CXOBC(IC) =  CROSS*DYN/SQRT(DXN**2 +DYN**2)
         CYOBC(IC) = -CROSS*DXN/SQRT(DXN**2 +DYN**2)
       END IF
     END DO

     IF(NADJN_OBC(I) > 1)THEN
       I2 = ADJN_OBC(I,2)
       DO J = 1, NTVE(I1)
         IC = NBVE(I1,J)
         N1 = NV(IC,1) ; N2 = NV(IC,2) ; N3 = NV(IC,3)
         IF( N1-I2 == 0 .OR. N2-I2 == 0 .OR. N3-I2 == 0)THEN
# if defined (SPHERICAL)
         x1_dp=VX(I1); y1_dp=VY(I1)
         x2_dp=VX(I2); y2_dp=VY(I2)
         CALL ARCX(x1_dp,y1_dp,x2_dp,y2_dp,side)
         DXN = side; DYN = (VY(I2)-VY(I1))*TPI

         x2_dp=XC(IC); y2_dp=YC(IC)
         CALL ARCX(x1_dp,y1_dp,x2_dp,y2_dp,side)
         DXC = side; DYC = (YC(IC)-VY(I1))*TPI
# else
         DXN = VX(I2)-VX(I1) ; DYN = VY(I2)-VY(I1)
         DXC = XC(IC)-VX(I1) ; DYC = YC(IC)-VY(I1)
# endif
           CROSS     = SIGN(1.0_SP,DXC*DYN - DYC*DXN)
           CXOBC(IC) = CROSS*DYN/SQRT(DXN**2 +DYN**2)
           CYOBC(IC) =-CROSS*DXN/SQRT(DXN**2 +DYN**2)
         END IF
       END DO
     END IF
   END DO
 END IF

   RETURN
   END SUBROUTINE SETUP_OBC3

!==============================================================================|
   SUBROUTINE FLUX_OBN2D(KKT)

   IMPLICIT NONE

   INTEGER, INTENT(IN)  :: KKT
   INTEGER  :: I,I1,N1,N2,N3,C1,C2
   REAL(SP) :: E1_X,E1_Y,E2_X,E2_Y
   REAL(SP) :: FLUXF_OBC_1,FLUXF_OBC_2
# if defined (SPHERICAL)
   REAL(DP) X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE
# endif


!   IF (IOBCN > 0) THEN
!   DO I = 1, IOBCN
!     IF(NADJN_OBC(I) == 1)THEN
!       N1 = I_OBC_N(I)
!       N2 = ADJN_OBC(I,1)
!       I1 = I_OBC_NODE(N1)
!
!       E1_Y = VY(N1)-VY(N2)
!#      if defined (SPHERICAL)
!       X1_DP = VX(N2)
!       Y1_DP = VY(N2)
!       X2_DP = VX(N1)
!       Y2_DP = VY(N1)
!       CALL ARCX(X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE)
!       E1_X = SIDE
!       E1_Y = TPI*E1_Y
!#      else
!       E1_X = VX(N1)-VX(N2)
!#      endif
!       
!       C1 = I_OBC_CELL2(ADJC_OBC(I,1)) 
!       FLUXF_OBC_1 = 0.5_SP*SQRT(E1_X**2+E1_Y**2)*  &
!                   (UANP(C1)*CXOBC(ADJC_OBC(I,1))+VANP(C1)*CYOBC(ADJC_OBC(I,1)))
!
!       FLUXOBN2(I) = -FLUXF_OBC_1*(H(N1)+ELT(I1)+ELP(I1)) 
!
!     ELSE
!       N1   = I_OBC_N(I)
!       N2   = ADJN_OBC(I,1)
!       N3   = ADJN_OBC(I,2)
!       I1   = I_OBC_NODE(N1)
!
!       E1_Y = VY(N1)-VY(N2)
!#      if defined (SPHERICAL)
!       X1_DP = VX(N2)
!       Y1_DP = VY(N2)
!       X2_DP = VX(N1)
!       Y2_DP = VY(N1)
!       CALL ARCX(X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE)
!       E1_X = SIDE
!       E1_Y = TPI*E1_Y
!#      else
!       E1_X = VX(N1)-VX(N2)
!#      endif
!
!       E2_Y = VY(N1)-VY(N3)
!#      if defined (SPHERICAL)
!       X1_DP = VX(N3)
!       Y1_DP = VY(N3)
!       X2_DP = VX(N1)
!       Y2_DP = VY(N1)
!       CALL ARCX(X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE)
!       E2_X = SIDE
!       E2_Y = TPI*E2_Y
!#      else
!       E2_X = VX(N1)-VX(N3)
!#      endif
!
!       C1 = I_OBC_CELL2(ADJC_OBC(I,1)) 
!       C2 = I_OBC_CELL2(ADJC_OBC(I,2)) 
!       FLUXF_OBC_1 = 0.5_SP*SQRT(E1_X**2+E1_Y**2)*  &
!                   (UANP(C1)*CXOBC(ADJC_OBC(I,1))+VANP(C1)*CYOBC(ADJC_OBC(I,1)))
!       FLUXF_OBC_2 = 0.5_SP*SQRT(E2_X**2+E2_Y**2)*  &
!                   (UANP(C2)*CXOBC(ADJC_OBC(I,2))+VANP(C2)*CYOBC(ADJC_OBC(I,2)))
!
!       FLUXOBN2(I) = -(FLUXF_OBC_1+FLUXF_OBC_2)*(H(N1)+ELT(I1)+ELP(I1)) 
!     END IF
!   END DO
!   END IF   

   IF (nmfcell > 0) THEN
     DO I = 1, nmfcell
        C1= I_OBC_NODE2(NODE_MFCELL(I,1))
        C2= I_OBC_NODE2(NODE_MFCELL(I,2))
        FLUXOBN2(C1) = FLUXOBN2(C1) - MFQDIS(I)*RDISMF(I,1)
        FLUXOBN2(C2) = FLUXOBN2(C2) - MFQDIS(I)*RDISMF(I,2)
     END DO
   END IF

   RETURN
   END SUBROUTINE FLUX_OBN2D


!==============================================================================|
   SUBROUTINE FLUX_OBC2D

#  if defined (SPHERICAL)
   USE MOD_SPHERICAL
#  endif
   IMPLICIT NONE

   INTEGER  :: I,II,I1,I2,J,J1,J2,ITMP,JTMP
   REAL(DP)  DX12,DY12,TMP1,DTMP
   REAL(SP) :: FLUXF_OBC_1,FLUXF_OBC_2
# if defined (SPHERICAL)
   REAL(DP) X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE
# endif

   IF (nmfcell_i > 0) THEN
     DO I = 1, nmfcell_i
       II= I_MFCELL_N(I)
       ITMP=0
       DO J=1,3
         IF(NBE(II,J) == 0) THEN
           JTMP=J
           ITMP=ITMP+1
         END IF
       END DO
       IF (ITMP /= 1) THEN
         PRINT*,'something is wrong here 2'
         CALL PSTOP
       END IF
    
       J1=JTMP+1-INT((JTMP+1)/4)*3
       J2=JTMP+2-INT((JTMP+2)/4)*3
       I1=NV(II,J1)
       I2=NV(II,J2)
       DY12=VY(I1)-VY(I2)
#      if defined (SPHERICAL)
       X1_DP = VX(I2)
       Y1_DP = VY(I2)
       X2_DP = VX(I1)
       Y2_DP = VY(I1)
       CALL ARCX(X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE)
       DX12 = SIDE
       DY12 = TPI*DY12
#      else
       DX12=VX(I1)-VX(I2)
#      endif

       DTMP = 0.5_SP*(H(I1)+H(I2)+ELT(I_OBC_NODE(I1))+ELT(I_OBC_NODE(I2)))    ! May be a problem, should be replaced by D
!       TMP1 = -(UANT(I)*cos(ANGLEMF(I))+VANT(I)*sin(ANGLEMF(I))*(SQRT(DX12**2+DY12**2))
       TMP1 = UANT(I) * DY12 - VANT(I) * DX12
       FLUXOBC2D_X(I) = DTMP * TMP1 * UANT(I)
       FLUXOBC2D_Y(I) = DTMP * TMP1 * VANT(I)

     END DO
   END IF

   END SUBROUTINE FLUX_OBC2D


!==============================================================================|
   SUBROUTINE FLUX_OBC3D

#  if defined (SPHERICAL)
   USE MOD_SPHERICAL
#  endif
   IMPLICIT NONE

   INTEGER  :: I,II,I1,I2,J,J1,J2,K,ITMP,JTMP
   REAL(DP)  DX12,DY12,TMP1,DTMP
   REAL(SP) :: UTMP,VTMP
# if defined (SPHERICAL)
   REAL(DP) X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE
# endif

   IF (nmfcell > 0) THEN

! 2-D and 3-D adjustment
      OBC2D_X_TIDE = OBC2D_X_TIDE/FLOAT(ISPLIT)
      OBC2D_Y_TIDE = OBC2D_Y_TIDE/FLOAT(ISPLIT)
                                                                                                                         
      DO I = 1, nmfcell
         II= I_MFCELL_N(I)
         ITMP=0
         DO J=1,3
           IF(NBE(II,J) == 0 .and. ISONB(nv(II,J)) /= 2) THEN
             JTMP=J
             ITMP=ITMP+1
           END IF
         END DO
         IF (ITMP /= 1) THEN
           PRINT*,'something is wrong here 3'
           CALL PSTOP
         END IF

         J1=JTMP+1-INT((JTMP+1)/4)*3
         J2=JTMP+2-INT((JTMP+2)/4)*3
         I1=NV(II,J1)
         I2=NV(II,J2)
         DTMP =	0.5_SP*(H(I1)+H(I2)+ELTDT(I_OBC_NODE(I1))+ELTDT(I_OBC_NODE(I2)))      ! May be a problem, should be replaced by D

         UTMP = 0.0_SP ; VTMP = 0.0_SP
         DO K=1,KBM1
            UTMP = UTMP + UNT(I,K)*DZ1(II,K)
            VTMP = VTMP + VNT(I,K)*DZ1(II,K)
         END DO
         UTMP = UTMP * DTMP
         VTMP = VTMP * DTMP
         DO K=1,KBM1
           UNT(I,K) = UNT(I,K) - (UTMP-OBC2D_X_TIDE(I))/DTMP
           VNT(I,K) = VNT(I,K) - (VTMP-OBC2D_Y_TIDE(I))/DTMP
         END DO
      END DO
   END IF

   IF (nmfcell_i > 0) THEN
     DO I = 1, nmfcell_i
       II= I_MFCELL_N(I)
       ITMP=0
       DO J=1,3
         IF(NBE(II,J) == 0) THEN
           JTMP=J
           ITMP=ITMP+1
         END IF
       END DO
       J1=JTMP+1-INT((JTMP+1)/4)*3
       J2=JTMP+2-INT((JTMP+2)/4)*3
       I1=NV(II,J1)
       I2=NV(II,J2)
       DY12=VY(I1)-VY(I2)
#      if defined (SPHERICAL)
       X1_DP = VX(I2)
       Y1_DP = VY(I2)
       X2_DP = VX(I1)
       Y2_DP = VY(I1)
       CALL ARCX(X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE)
       DX12 = SIDE
       DY12 = TPI*DY12
#      else
       DX12=VX(I1)-VX(I2)
#      endif

       DTMP = 0.5_SP*(H(I1)+H(I2)+ELTDT(I_OBC_NODE(I1))+ELTDT(I_OBC_NODE(I2)))       ! May be a problem, should be replaced by D
       DO K =1, KBM1
!          TMP1 = -(UNT(I,K)*cos(ANGLEMF(I))+VNT(I,K)*sin(ANGLEMF(I))*(SQRT(DX12**2+DY12**2))
          TMP1 = UNT(I,K) * DY12 - VNT(I,K) * DX12
          FLUXOBC3D_X(I,K) = DTMP * TMP1 * UNT(I,K)
          FLUXOBC3D_Y(I,K) = DTMP * TMP1 * VNT(I,K)
       END DO
     END DO

   END IF

   END SUBROUTINE FLUX_OBC3D


!==============================================================================|
   SUBROUTINE FLUX_OBC3D_2

   USE ALL_VARS
   USE MOD_OBCS
   USE MOD_OBCS2

#  if defined (SPHERICAL)
   USE MOD_SPHERICAL
#  endif
   IMPLICIT NONE

   INTEGER  :: I,II,I1,I2,J,J1,J2,K,ITMP,JTMP
   REAL(DP)  DX12,DY12,TMP1,DTMP
   REAL(SP) :: UTMP,VTMP
# if defined (SPHERICAL)
   REAL(DP) X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE
# endif

   IF (nmfcell > 0) THEN

! 2-D and 3-D adjustment
      DO I = 1, nmfcell
       II= I_MFCELL_N(I)
         UTMP   = SUM(UNT(I,1:KBM1)*DZ1(II,1:KBM1))
         VTMP   = SUM(VNT(I,1:KBM1)*DZ1(II,1:KBM1))
         UNT(I,1:KBM1) = UNT(I,1:KBM1) + (UANT(I) - UTMP) 
         VNT(I,1:KBM1) = VNT(I,1:KBM1) + (VANT(I) - VTMP) 
      END DO
   END IF

   IF (nmfcell_i > 0) THEN
     DO I = 1, nmfcell_i
       II= I_MFCELL_N(I)
       ITMP=0
       DO J=1,3
         IF(NBE(II,J) == 0) THEN
           JTMP=J
           ITMP=ITMP+1
         END IF
       END DO
       J1=JTMP+1-INT((JTMP+1)/4)*3
       J2=JTMP+2-INT((JTMP+2)/4)*3
       I1=NV(II,J1)
       I2=NV(II,J2)
       DY12=VY(I1)-VY(I2)
#      if defined (SPHERICAL)
       X1_DP = VX(I2)
       Y1_DP = VY(I2)
       X2_DP = VX(I1)
       Y2_DP = VY(I1)
       CALL ARCX(X1_DP,Y1_DP,X2_DP,Y2_DP,SIDE)
       DX12 = SIDE
       DY12 = TPI*DY12
#      else
       DX12=VX(I1)-VX(I2)
#      endif

       DTMP = 0.5_SP*(H(I1)+H(I2)+ELTDT(I_OBC_NODE(I1))+ELTDT(I_OBC_NODE(I2)))          ! May be a problem, should be replaced by D
       DO K =1, KBM1
!          TMP1 = -(UNT(I,K)*cos(ANGLEMF(I))+VNT(I,K)*sin(ANGLEMF(I))*(SQRT(DX12**2+DY12**2))
          TMP1 = UNT(I,K) * DY12 - VNT(I,K) * DX12
          FLUXOBC3D_X_2(I,K) = DTMP * TMP1 * UNT(I,K)
          FLUXOBC3D_Y_2(I,K) = DTMP * TMP1 * VNT(I,K)
       END DO
     END DO

   END IF

   END SUBROUTINE FLUX_OBC3D_2

# endif
!========================================================================
END MODULE MOD_OBCS3