!copyright (C) 2001  MSC-RPN COMM  %%%RPNPHY%%%
***S/P DIFUVDF
*

      SUBROUTINE DIFUVDF (TU, U, KU, GU, R, ALFA, BETA, S, SK,,2
     %                    TAU, TYPE, F, A, B, C, D, NU, NR, N, NK)
*
#include "impnone.cdk"
      INTEGER NU, NR, N, NK
      REAL TU(NU, NK), U(NU, NK), KU(NR, NK), GU(NR, NK), R(NR,NK)
      REAL ALFA(N), BETA(N), S(NK), SK(NK), TAU, F
      INTEGER TYPE
      REAL A(N, NK), B(N, NK), C(N, NK), D(N, NK)
*
*Author
*          R. Benoit (Mar 89)
*
*Object
*          to solve a vertical diffusion equation by finite
*          differences
*
*Arguments
*
*          - Output -
* TU       U tendency (D/DT U) due to the vertical diffusion and to
*          term R
*
*          - Input -
* U        variable to diffuse (U,V,T,Q,E)
* KU       diffusion coefficient
* GU       optional countergradient term
* R        optional inhomogeneous term
* ALFA     inhomogeneous term for the surface flux
* BETA     homogeneous term for the surface flux
* S        sigma coordinates of full levels
* SK       sigma coordinates of diffusion coefficient levels
* TAU      length of timestep
* TYPE     type of variable to diffuse (1='U',2='UT' or 3='E')
* F        waiting factor for time 'N+1'
* A        work space (N,NK)
* B        work space (N,NK)
* C        work space (N,NK)
* D        work space (N,NK)
* NU       1st dimension of TU and U
* NR       1st dimension of KU, GU and R
* N        number of columns to process
* NK       vertical dimension
*
*Notes
*          D/DT U = D(U) + R
*          D(U) = D/DS J(U)
*          J(U) = KU*(D/DS U + GU)
*          Limiting Conditions where S=ST: J=0(for 'U'), D=0(for 'UT'
*          and ST=1)
*          U=0(for 'E')
*          Limiting Conditions where S=SB: J=ALFA+BETA*U(S(NK))(for
*          'U'/'UT'), J=0(for 'E')
*          ST = S(1)-1/2 (S(2)-S(1)) (except for 'TU')
*          SB = SK(NK)
*
**
*
      INTEGER I, K, NKX
      REAL SC, SCTU, ST, SB, HM, HP, HD, KUM, KUP, SCK1
      EXTERNAL DIFUVD1, DIFUVD2
      LOGICAL DEBUG
      SAVE DEBUG
      DATA DEBUG /.FALSE./
*
      IF (DEBUG) THEN
         PRINT *,' S/R DIFUVDF..TAU,TYPE,F,NU,N,NK=',
     %   TAU,TYPE,F,NU,N,NK
         PRINT *,' S=',S
         PRINT *,' SK=',SK
         I=1
         PRINT *,' ALFA(',I,')=',ALFA(I)
         PRINT *,' BETA(',I,')=',BETA(I)
         PRINT *,' U(',I,',*)=',(K,U(I,K),K=1,NK)
         PRINT *,' KU(',I,',*)=',(K,KU(I,K),K=1,NK)
         PRINT *,' GU(',I,',*)=',(K,GU(I,K),K=1,NK)
         PRINT *,' R(',I,',*)=',(K,R(I,K),K=1,NK)
      ENDIF
      ST=S(1)
      SB=SK(NK)
*
      IF (TYPE.LE.2) THEN
         SC=1
         SCTU=0
         NKX=NK
         SCK1=1
         IF (TYPE.EQ.2) THEN
            SCK1=0
            ST=S(1)
         ENDIF
      ELSE IF (TYPE.EQ.3) THEN
         SC=1-F
         SCTU=1
         NKX=NK-1
      ELSE
         PRINT *,' S/R DIFUVDF. TYPE INCONNU= ',TYPE,' STOP...'
         CALL QQEXIT(1)
      ENDIF
*
* (1) CONSTRUIRE L'OPERATEUR TRIDIAGONAL DE DIFFUSION N=(A,B,C)
*                ET LE TERME CONTRE-GRADIENT (DANS D)
*
      IF (TYPE.LE.2) THEN
*
*     K=1
*
         HM=0
         HP=S(2)-S(1)
         HD=0.5*(S(1)+S(2))-ST
         DO 10 I=1,N
            A(I,1)=0
            B(I,1)=-SCK1*KU(I,1)/(HP*HD)
            C(I,1)=-SCK1*B(I,1)
10          D(I,1)=SCK1*KU(I,1)*GU(I,1)/HD
*
*     K=2...NK-1
*
         DO 11 K=2,NK-1,1
            HM=S(K)-S(K-1)
            HP=S(K+1)-S(K)
            HD=0.5*(HM+HP)
            DO 11 I=1,N
               A(I,K)=KU(I,K-1)/(HM*HD)
               B(I,K)=-(KU(I,K-1)/HM +KU(I,K)/HP)/HD
               C(I,K)=KU(I,K)/(HP*HD)
11             D(I,K)=(KU(I,K)*GU(I,K)-KU(I,K-1)*GU(I,K-1))/HD
*
*     K=NK
*
         HM=S(NK)-S(NK-1)
         HP=0
         HD=SB-0.5*(S(NK-1)+S(NK))
         DO 12 I=1,N
            A(I,NK)=KU(I,NK-1)/(HM*HD)
            B(I,NK)=-(KU(I,NK-1)/HM + 0)/HD
            C(I,NK)=0
12          D(I,NK)=(0-KU(I,NK-1)*GU(I,NK-1))/HD
*
*
      ELSE IF (TYPE.EQ.3) THEN
*
*     TYPE='E'
*
*     K=1
*
         HM=S(2)-S(1)
         HP=SK(2)-SK(1)
         HD=0.5*(SK(2)+SK(1)) -S(1)
         DO 13 I=1,N
            KUM=0.5*KU(I,1)
            KUP=0.5*(KU(I,1)+KU(I,2))
            A(I,1)=KUM/(HM*HD)
            B(I,1)=-(KUM/HM+KUP/HP)/HD
            C(I,1)=KUP/(HP*HD)
13          D(I,1)=(KUP*(GU(I,1)+GU(I,2))-KUM*GU(I,1))/(2*HD)
*
*     K=2...NK-2
*
         DO 14 K=2,NK-2,1
            HM=SK(K)-SK(K-1)
            HP=SK(K+1)-SK(K)
            HD=0.5*(HM+HP)
            DO 14 I=1,N
               KUM=0.5*(KU(I,K-1)+KU(I,K))
               KUP=0.5*(KU(I,K+1)+KU(I,K))
               A(I,K)=KUM/(HM*HD)
               B(I,K)=-(KUM/HM +KUP/HP)/HD
               C(I,K)=KUP/(HP*HD)
14             D(I,K)=(KUP*(GU(I,K)+GU(I,K+1))
     %                -KUM*(GU(I,K-1)+GU(I,K)))/(2*HD)
*
*     K=NK-1=NKX
*
         HM=SK(NK-1)-SK(NK-2)
         HP=0
         HD=SB-0.5*(SK(NK-1)+SK(NK-2))
         DO 15 I=1,N
            KUM=0.5*(KU(I,NK-1)+KU(I,NK-2))
            KUP=0
            A(I,NKX)=KUM/(HM*HD)
            B(I,NKX)=-(KUM/HM + 0)/HD
            C(I,NKX)=0
15          D(I,NKX)=(0-KUM*(GU(I,NK-1)+GU(I,NK-2)))/(2*HD)
*
      ENDIF
*
*
* (2) CALCULER LE COTE DROIT D=TAU*(SC*N(U)+R+D/DS(KU*GU))
*
      IF (DEBUG) THEN
         PRINT *,' ETAPE(2) DE DIFUVDF'
         I=1
         PRINT *,' A(',I,',*)=',(K,A(I,K),K=1,NK)
         PRINT *,' B(',I,',*)=',(K,B(I,K),K=1,NK)
         PRINT *,' C(',I,',*)=',(K,C(I,K),K=1,NK)
         PRINT *,' D(',I,',*)=',(K,D(I,K),K=1,NK)
      ENDIF
      CALL DIFUVD1 (D, SC, A, B, C, U, D, N, NU, NKX)
      DO 20 K=1,NKX
         DO 20 I=1,N
20       D(I,K)=TAU*(D(I,K)+R(I,K))  +SCTU*U(I,K)
      IF (DEBUG) THEN
         PRINT *,' ETAPE(2) DE DIFUVDF. D FINAL'
         I=1
         PRINT *,' D(',I,',*)=',(K,D(I,K),K=1,NK)
      ENDIF
*
* (3) CALCULER OPERATEUR DU COTE GAUCHE
*
      DO 30 K=1,NKX
         DO 30 I=1,N
            A(I,K)= -F*TAU*A(I,K)
            B(I,K)=1-F*TAU*B(I,K)
30          C(I,K)= -F*TAU*C(I,K)
*
* (4) AJOUTER TERME DE FLUX DE SURFACE POUR TYPE='U'/'UT'
*
      IF (TYPE.LE.2) THEN
         HD=SB-0.5*(S(NK-1)+S(NK))
         DO 40 I=1,N
            B(I,NKX)=B(I,NKX)-F*TAU*BETA(I)/HD
40          D(I,NKX)=D(I,NKX)+(ALFA(I)+BETA(I)*U(I,NKX))*TAU/HD
      ENDIF
*
* (5) RESOUDRE SYSTEME TRIDIAGONAL [A,B,C] X = D. METTRE X DANS TU.
*
      CALL DIFUVD2 (TU, A, B, C, D, D, NU, N, NKX)
*
* (6) OBTENIR TENDANCE
*
      DO 60 K=1,NKX
         DO 60 I=1,N
60       TU(I,K)=(TU(I,K)-SCTU*U(I,K))/TAU
*     K=NKX+1..NK
      DO 70 K=NKX+1,NK
         DO 70 I=1,N
70       TU(I,K)=0
*
      RETURN
      END