!
!     $Id: pdyn0.F90,v 1.1 2005/10/18 20:10:16 mbhat Exp $
!

!---(pdiag.f)-------generic CTM shell from UCIrvine (p-code 1.0,  1/31/95)
!---subroutines:  DYN0, GRDSET, AIRSET, PFILTR


      SUBROUTINE DYN0(LOOP) 1,1
!---------QDYN0 sets up the advective fields
!---CURRENTLY THIS IS CALLED FROM MAIN WITH
!---          LOOP=0 = SETUP,         OR LOOP=1 = CONTINUE
!---PLAN TO ELIMINATE LOOP=0 CALL!
!---THIS SET OF ARRAYS & COMMONS IS A TEMPORARY FIX TO MAKE THE
!---  NEW VERSION OF -DYN0- BASED ON ECMWF GRID, COMPATIBLE WITH
!---  THE OLD SET OF COMMONS, ETC TO BE USED IN FIRST LLNL VERSION (QZ=2.0)
      INTEGER LOOP
      LOGICAL LSP,LNP,LEW
      REAL*8 SUMA,SUMP,SUMQ,SUMU,SUMV,SUMW
      REAL*8 AIRD,AIRNEW,AIRX, XYZA,XYZB,XYA,XYB
      REAL*8 SUMXYZ,SUMAD0,SUMAW0,AIRWET,AIRH2O,AIRDRY,AIRQKG
      REAL*8 SUMAQ(36,24)
      REAL*8 PERR(36,24),MERR(36,24),AX(37,24),BX(36,25),DTWIND
!---
      COMMON /CCGRID/  &
     & AIRD(36,24,21),AIRNEW(36,24,21),AIRX(36,24,21),  &
     & XYZA(36,24,21),XYZB(36,24,21),XYA(36,24),XYB(36,24),  &
     & AIRDRY,AIRQKG,  &
     & YGRD(24),YDGRD(24),YEDG(25),YDEDG(25),XGRD(36),  &
     & XDGRD(36),XEDG(37),XDEDG(37),DLONG,AREAXY(36,24),  &
     & DISTX(25),DISTY(24), ETAA(22),ETAB(22),  &
     & UUU(37,24,21),VVV(36,25,21),PS(36,24),  &
     & AIRQG(36,24,21),AIRQ(36,24,21),PCTM(36,24), IMEPZ(24)
!---

!----------------------------------------
#        include "uci.h"
!xx$$
      save
!xx$$
!-----------------------------------------------------------------------

!----------------- UNITS OF AIR MASS AND TRACER = (kg)  ----------------
!----Air mass (kg) is given by area (m^2) * pressure thickness (Pa) / g0
!---- AREAXY(I,J) = area of (I,J) (m^2)
!---- PS(I,J)    = surf pressure (Pa) as reported by GCM
!---- AIRQ(I,J,K) = specific humidity of grid box (kg H2O / kg wet air) per GCM
!---- AIRQKG = local (I,J) kg of H2O at each level based on GCM P's & q's
!----           = PS(I,J)) * AIRQ(I,J,K)
!---- AIRD(I,J,K) = dry-air mass (kg) in each box as calculated in CTM
!----    at the beginning of each time step, updated at end of DYN0.
!---- PCTM(I,J) = inferred wet-air (total) surf press (Pa) calc. in CTM
!----              (using SUMAQ & AIRD-X-NEW)
!---- AIRNEW(I,J,K) = new dry-air mass in each CTM box after horizontal
!----       divergence (ALFA+BETA) over time step DTWIND (sec)
!---- AIRX(I,J,K) = expected dry-air mass in each CTM box after calculating
!----      the vertical divergence (GAMA)   (also used for GCM dry mass)
!----             = XYZA(I,J,K) + XYZB(I,J,K)*PCTM(I,J) - AIRQKG
!----
!----Assume that we have "wet-air" mass fluxes across each boundary
!----   U(I,J,K)   ==> (I,J,K) ==>  U(I+1,J,K)   (kg/s)
!----   V(I,J,K)   ==> (I,J,K) ==>  V(I,J+1,K)   (kg/s)
!---   DTWIND = time step (sec) that applies to the averaged wind fields
!---          i.e., the time between successive pressures.
!----Convert to "dry-air" mass flux in/out of box using average AIRQ at boundary
!----   ALFA(I,J,K)   ==> (I,J,K) ==>  ALFA(I+1,J,K)   (kg/s)
!----   BETA(I,J,K)   ==> (I,J,K) ==>  BETA(I,J+1,K)   (kg/s)
!----
!----Calculate convergence in each layer of dry air, compare with expected
!----   dry air mass (AIRX) and then calculate vertical dry-mass fluxes
!----   GAMA(I,J,K)   ==> (I,J,K) ==>  GAMA(I,J,K+1)    (kg/s)
!----
!----Horizontal pressure filter adjusts U & V to reduce error in (PCTM - PS)
!----     U + pressure filter ==> U#,  V + filter ==> V# (temporary)
!----   The pressure filter does nearest neighbor flux (adjusting ALFA/BETA)
!----
!----Time step for each of the operator-splitting calculations in U/V/W
!----   is determined by the number of U-V-W calls per time step (NDYN)
!----   and DTALFA/DTBETA/DTGAMA must be set for DYN2U/V/W  (in main driver)
!-----------------------------------------------------------------------
!----
!----Note that K->K+1 is downward (increasing pressure) and that boundaries:
!----   GAMA(I,J,1) = GAMA(I,J,KM+1) = 0   no flux across upper/lower boundaries
!----   BETA(I,1,K) = BETA(I,JM+1,K) = 0   no flux at S & N poles
!----   ALFA(1,J,K) = ALFA(IM+1,J,K) is NOT ZERO, but cyclic
!----Dimensions for ALFA, BETA, GAMA are extended by +1 beyond grid to allow
!----   simple formulation of fluxes in/out of final grid box.
!
!-----GCM input U,V,AIRQG,PSG is ALWAYS of GLOBAL dimensions (IMG x JMG x KMG)
!-----Indices of ALFA, BETA, GAMA, AIRQ & PS are always LOCAL (IM x JM x KM)
!-----Indices of tracer (STT), and diagnostics are local (w.r.t. WINDOW)
!-----WINDOW calculations are defined by an offset and size
!-----        I0 .ge.0 and IM+I0 .le. IMG
!-----        J0 .ge.0 and JM+J0 .le. JMG
!-----        K0 .ge.0 and KM+K0 .le. KMG
!-----The WINDOW calculation must allow for a boundary layer of grid boxes
!-----        IG(abs. coords) = IW(in window) + I0
!-----        JG(abs. coords) = JW(in window) + J0
!-----        KG(abs. coords) = KW(in window) + K0
!-----  vertical window (NEW) allows for an upper boundary with flow across
!-----  it and specified mixing ratio b.c.'s at KG = K0
!-------------------------------------------------------------------------
!
      KWACC  = KWACC+1
!---------NREAD = no. hours between pressure fields (U & V are averaging time)
      DTWIND = (3600*NREAD)
      G0     = 9.81D0
      IMG    = IMX
      JMG    = JMX
      KM     = LM
!---------First need to map the full-grid values (__G) onto local(WINDOW) arrays
!---------NB need to have IMG=IM, JMG=JM, KMG=KM for full global calc.
      DO J=1,JM
        DO I=1,IM
          II0 = MOD(I+I0-1, IMG) + 1
!---------original for q-code:     PS(I,J) = PSG(II0,J+J0)--------------
          PS(I,J) = P(II0,J+J0)
          DO K=1,KM
            AIRQ(I,J,K) = AIRQG(II0,J+J0,K)
          ENDDO
        ENDDO
      ENDDO
!---------TEMP FIX OF WINDS:  NO WINDOWS ALLOWED
      G100 = 100.0/G0
      DO L=1,LM
      DO J=1,JMG
        DO I=1,IMG
          UUU(I,J,L) = U(I,J,L)*G100
        ENDDO
        UUU(IMG+1,J,L) = UUU(1,J,L)
      ENDDO
      ENDDO
!---------TEMP FIX OF WINDS:  NO WINDOWS ALLOWED
      DO L=1,LM
      DO I=1,IMG
        DO J=2,JMG
          VVV(I,J,L)   = V(I,J,L)*G100
        ENDDO
        VVV(I,1,L)     = 0.D0
        VVV(I,JMG+1,L) = 0.D0
      ENDDO
      ENDDO
!---------PROBLEMS WITH POLAR NOISE IN GISS 21-LAYER: temporary
!---V-8.2----scale V-field at polar box, proportional to area J=1/(1+2)
!---------divide polar convergence over J=1&2 and J=JMX-1&JMX (assume symmetry)
      DO L=1,LM
      DO I=1,IMG
        VVV(I,2,L)   = VVV(I,3,L)*AREAXY(I,1)/(AREAXY(I,1)+AREAXY(I,2))
        VVV(I,JMG,L) = VVV(I,JMG-1,L)*  &
     &                AREAXY(I,JMG)/(AREAXY(I,JMG)+AREAXY(I,JMG-1))
      ENDDO
      ENDDO
!--------------------------END OF TEMP FIX------------------------------

      DO K=1,KM
        DO J=1,JM
        DO I=1,IM+1
          II0 = MOD(I+I0-1, IMG) + 1
          ALFA(I,J,K) = UUU(II0,J+J0,K)
        ENDDO
        ENDDO
        DO I=1,IM
          II0 = MOD(I+I0-1, IMG) + 1
          DO J=1,JM+1
            BETA(I,J,K) = VVV(II0,J+J0,K)
          ENDDO
        ENDDO
      ENDDO
!---------DRY-AIR:  re-define ALFA & BETA to be dry-air flux (kg/s),
!---------cannot go beyond boundaries of WINDOW box:
      DO K=1,KM
        DO J=1,JM
          IF(J+J0.EQ.1 .OR. J+J0.EQ.JMG) THEN
!---------safety zero of ALFAs in polar boxes
            DO I=1,IM+1
              ALFA(I,J,K) = 0.0
            ENDDO
          ELSE
            DO I=2,IM
              AIRQAV = 0.5*(AIRQ(I-1,J,K)+AIRQ(I,J,K))
              ALFA(I,J,K) = ALFA(I,J,K)*(1.-AIRQAV)
            ENDDO
            IF(IM.LT.IMG) THEN     ! WINDOW
              ALFA(1,J,K) = ALFA(1,J,K)*(1.-AIRQ(1,J,K))
              ALFA(IM+1,J,K) = ALFA(IM+1,J,K)*(1.-AIRQ(IM,J,K))
            ELSE                    ! full cyclic grid
              AIRQAV = 0.5*(AIRQ(1,J,K)+AIRQ(IM,J,K))
              ALFA(1,J,K) = ALFA(1,J,K)*(1.-AIRQAV)
              ALFA(IM+1,J,K) = ALFA(1,J,K)
            ENDIF
          ENDIF
        ENDDO    ! end of J loop
        DO J=2,JM  ! interior J points
          DO I=1,IM
            AIRQAV = 0.5*(AIRQ(I,J-1,K)+AIRQ(I,J,K))
            BETA(I,J,K) = BETA(I,J,K)*(1.-AIRQAV)
          ENDDO
        ENDDO     ! end of J loop
        IF(J0.EQ.0) THEN       !flux into S.Pole = 0
          DO I=1,IM
            BETA(I,1,K) = 0.0
          ENDDO
        ELSE
          DO I=1,IM     !flux across southernmost WINDOW boundary
            BETA(I,1,K) = BETA(I,1,K)*(1.-AIRQ(I,1,K))
          ENDDO
        ENDIF
        IF(JM+J0.EQ.JMG) THEN  !flux out of N.Pole = 0
          DO I=1,IM
            BETA(I,JM+1,K) = 0.0
          ENDDO
        ELSE
          DO I=1,IM
            BETA(I,JM+1,K) = BETA(I,JM+1,K)*(1.-AIRQ(I,JM,K))
          ENDDO
        ENDIF
      ENDDO  ! end of K loop

!----EPZ'S:
!------Average GCM quantities: PS, AIRQ, BETA
      DO J=1,JM
        IMZ = IMEPZ(J+J0)
        IF(IMZ.GT.1) THEN
!----average PS over EPz's
          DO IEPZ=1,IM,IMZ    ! # EPZ's = IM/IMZ
             SUMP = 0.D0
            DO I=IEPZ,IEPZ+IMZ-1 ! loop over I's in each EPZ
             SUMP = SUMP + PS(I,J)
            ENDDO
             SUMP = SUMP/REAL(IMZ) !SUMP=pressure (w-air) in box(I,J)
            DO I=IEPZ,IEPZ+IMZ-1
             PS(I,J) = SUMP
            ENDDO
          ENDDO
!----average AIRQ over EPZ's
          DO K=1,KM
            DO IEPZ=1,IM,IMZ ! # EPZ's = IM/IMZ
              SUMA = 0.D0
              SUMQ = 0.D0
              DO I=IEPZ,IEPZ+IMZ-1
!---- have not bothered to offset I since XYZA/B independent of I
                AWET = XYZA(I,J,K) + PS(I,J)*XYZB(I,J,K)
                SUMA = SUMA + AWET
                SUMQ = SUMQ + AIRQ(I,J,K)*AWET
              ENDDO
                SUMQ = SUMQ/SUMA
              DO I=IEPZ,IEPZ+IMZ-1
                AIRQ(I,J,K) = SUMQ
              ENDDO
            ENDDO
          ENDDO   ! end of K loop
        ENDIF  ! check on IMZ
      ENDDO  ! end of J loop

!----Diagnostics and use of PW() for z-code overlap
      DO J=1,JM
        DO I=1,IM
          PW(I,J) =  PS(I,J) - PTOP
          AIJ(I,J,1) = AIJ(I,J,1) + PS(I,J)
        ENDDO
      ENDDO
!---------SUMAQ(I,J): column integral of water (kg)---------------------
!---------check on air mass---------------------------------------------
      DO J=1,JM
      DO I=1,IM
        SUMAQ(I,J) = 0.D0
      ENDDO
      ENDDO
      SUMAD0 = 0.D0
      SUMAW0 = 0.D0
      DO K=1,KM
      DO J=1,JM
      DO I=1,IM
        AIRWET = XYZA(I,J,K) + PS(I,J)*XYZB(I,J,K)
        AIRH2O = AIRQ(I,J,K)*AIRWET
        SUMAQ(I,J) = SUMAQ(I,J) + AIRH2O
        SUMAD0 = SUMAD0 + AIRWET
        SUMAW0 = SUMAW0 + AIRH2O
      ENDDO
      ENDDO
      ENDDO
      SUMAD0 = SUMAD0 - SUMAW0
      IF(LPRT)      WRITE(lun13,'(A,1P,2E12.5,A,E12.5)')  &
     &   ' ---dry air:  init/now',AIRDRY,SUMAD0,'  ---H2O: now',SUMAW0
!---------smooth BETA's over EPZ's: (use closest to equator value for EPZ)
!---------i.e., BETA(3) is between boxes (2) and (3), average over IMEPZ(3)
      DO J=1,JM+1
        IF(2*(J+J0).LE.JMG) THEN
          IMZ = IMEPZ(J+J0)   ! S.Hem.
        ELSE
          IMZ = IMEPZ(J+J0-1) ! N.Hem.
        ENDIF
        IF(IMZ.GT.1 .AND. .NOT.(J+J0.EQ.1 .OR. J+J0.EQ.JMG+1)) THEN !skip poles
          DO K=1,KM
            DO IEPZ=1,IM,IMZ ! # EPZ's = IM/IMZ
                SUMV = 0.D0
              DO I=IEPZ,IEPZ+IMZ-1
                SUMV = SUMV + BETA(I,J,K)
              ENDDO
                SUMV = SUMV/REAL(IMZ)
              DO I=IEPZ,IEPZ+IMZ-1
                BETA(I,J,K) = SUMV
              ENDDO
            ENDDO
          ENDDO
        ENDIF   ! check on IMZ
      ENDDO   ! end of J loop

!---CTM CONVERGENCE:  DRY-AIR mass convergence into each CTM grid box:
      DO K=1,KM
        DO J=1,JM
          DO I=1,IM
!-------*****AD() IS THE ONLY AIR MASS CALC IN Z-CODE
            AIRD(I,J,K) = AD(I,J,K)
            AIRNEW(I,J,K) = AIRD(I,J,K) + DTWIND*  &
     &       (ALFA(I,J,K)-ALFA(I+1,J,K)+BETA(I,J,K)-BETA(I,J+1,K))
          ENDDO
        ENDDO
      ENDDO
!---reset ALFAs at interior pts of EPZ's to guarantee equal masses:
      DO K=1,KM
        DO J=1,JM
          IF(J+J0.NE.1  .AND. J+J0.NE.JMG) THEN  !not for poles
            IMZ = IMEPZ(J+J0)
            IF(IMZ.GT.1) THEN
              DO IEPZ=1,IM,IMZ !IEPZ strides thru EPZs: 1, 1+IMZ, 1+2*IMZ,..
                 SUMA = 0.D0
                DO I=IEPZ,IEPZ+IMZ-1 !I all boxes in a single EPZ
                 SUMA = SUMA + AIRNEW(I,J,K)
                ENDDO
                 SUMA = SUMA/REAL(IMZ)
                 ALFAX = (AIRNEW(IEPZ,J,K)-SUMA)/DTWIND
                DO I=IEPZ+1,IEPZ+IMZ-1
                 ALFA(I,J,K) = ALFA(I,J,K) + ALFAX
                 ALFAX = ALFAX + (AIRNEW(I,J,K) - SUMA)/DTWIND
                ENDDO
                DO I=IEPZ,IEPZ+IMZ-1
                  AIRNEW(I,J,K) = SUMA
                ENDDO
              ENDDO
            ENDIF
          ELSE       ! poles, just average AIRNEW
              SUMA = 0.D0
            DO I=1,IM
              SUMA = SUMA + AIRNEW(I,J,K)
            ENDDO
              SUMA = SUMA/REAL(IM)
            DO I=1,IM
              AIRNEW(I,J,K) = SUMA
            ENDDO
          ENDIF
        ENDDO   !J
      ENDDO   !K

!-----------------------------------------------------------------------
!--------------------------BEGIN FILTER of PRESSURE ERRORS--------------
!-----------------------------------------------------------------------
!---Define the error in surface pressure PERR expected at end of time step
!------filter by error in adjacent boxes, weight by areas, adjust ALFA & BETA
!
      IF(.NOT.LPFILT) GOTO 101
!
!---PCTM(I,J)= new CTM wet-air column based on dry-air convergence (Pascals)
!---PERR(I,J)= pressure-error between CTM-GCM at new time (before filter)
      DO J=1,JM
         DO I=1,IM
              SUMA = 0.D0
            DO K=1,KM
               SUMA = SUMA + AIRNEW(I,J,K)
            ENDDO
            PCTM(I,J) = (SUMA + SUMAQ(I,J) - XYA(I,J))/XYB(I,J)
            PERR(I,J) = PCTM(I,J) - PS(I,J)
            MERR(I,J) = PERR(I,J)*AREAXY(I,J+J0)*100.E0/G0
         ENDDO
      ENDDO
!-----------------------------------------------------------------------
      LSP = J0.EQ.0
      LNP = JM+J0.EQ.JMG
      LEW = IM.EQ.IMG
!     CALL PFILTR(MERR,AX,BX,IM,JM,IMG,JMG,IMEPZ(J0+1),LSP,LNP,LEW)
      CALL PFILTR(MERR,AX,BX,IM,JM,IMG,JMG,IMEPZ,LSP,LNP,LEW)
!---------Calculate corrections to ALFA & BETA from AX and BX:----------
      DO J=1,JM
       IF(J+J0.GT.1 .AND. J+J0.LT.JMG) THEN  ! NOT Poles
        DO I=1,IM+1
          IIX = MIN(I,IM)
          UFILT = AX(I,J)/(XYB(IIX,J)*DTWIND)
          DO K=1,KM
            ALFA(I,J,K) = ALFA(I,J,K) + UFILT*XYZB(IIX,J,K)
          ENDDO
        ENDDO
       ENDIF
      ENDDO
      DO J=1,JM+1
        JJX = J
        IF(J+J.GT.JM) JJX=J-1
        DO I=1,IM
          VFILT = BX(I,J)/(XYB(I,JJX)*DTWIND)
          DO K=1,KM
            BETA(I,J,K) = BETA(I,J,K) + VFILT*XYZB(I,JJX,K)
          ENDDO
        ENDDO
      ENDDO

!----Calculate the corrected AIRNEW's & PCTM after P-filter:
!---- has changed ALFA+BETAs and ctm surface pressure (PCTM)
      DO J=1,JM
        DO I=1,IM
          DO K=1,KM
            AIRNEW(I,J,K) = AIRD(I,J,K) + DTWIND*  &
     &        (ALFA(I,J,K)-ALFA(I+1,J,K)+BETA(I,J,K)-BETA(I,J+1,K))
          ENDDO
        ENDDO
      ENDDO

!---reset ALFAs at interior pts of EPZ's to guarantee equal masses:
      DO K=1,KM
        DO J=1,JM
          IF(J+J0.NE.1  .AND. J+J0.NE.JMG) THEN  !not for poles
            IMZ = IMEPZ(J+J0)
            IF(IMZ.GT.1) THEN
              DO IEPZ=1,IM,IMZ !IEPZ strides thru EPZs: 1, 1+IMZ, 1+2*IMZ,..
                 SUMA = 0.D0
                DO I=IEPZ,IEPZ+IMZ-1 !I all boxes in a single EPZ
                  SUMA = SUMA + AIRNEW(I,J,K)
                ENDDO
                  SUMA = SUMA/REAL(IMZ)
                  ALFAX = (AIRNEW(IEPZ,J,K)-SUMA)/DTWIND
                DO I=IEPZ+1,IEPZ+IMZ-1
                  ALFA(I,J,K) = ALFA(I,J,K) + ALFAX
                  ALFAX = ALFAX + (AIRNEW(I,J,K) - SUMA)/DTWIND
                ENDDO
                DO I=IEPZ,IEPZ+IMZ-1
                  AIRNEW(I,J,K) = SUMA
                ENDDO
              ENDDO
            ENDIF
          ELSE       ! poles, just average AIRNEW
              SUMA = 0.D0
            DO I=1,IM
              SUMA = SUMA + AIRNEW(I,J,K)
            ENDDO
              SUMA = SUMA/REAL(IM)
            DO I=1,IM
              AIRNEW(I,J,K) = SUMA
            ENDDO
          ENDIF
        ENDDO   !J
      ENDDO   !K
!--------------------------end of pressure filter-----------------------
  101 CONTINUE

!---GAMA:  redistribute the new dry-air mass consistent with the
!---       new CTM surface pressure, rigid upper b.c., no change in PCTM
!---AIRX(I,J,K) = dry-air mass expected, based on PCTM
!---PCTM(I,J) & PERR(I,J)
      DO J=1,JM
        DO I=1,IM
           SUMA = 0.D0
          DO K=1,KM
           SUMA = SUMA + AIRNEW(I,J,K)
          ENDDO
           PCTM8 = (SUMA + SUMAQ(I,J) - XYA(I,J))/XYB(I,J)
           PCTM(I,J) = PCTM8
           PERR(I,J) = PCTM(I,J) - PS(I,J)
          DO K=1,KM
           AIRQKG =  AIRQ(I,J,K)*(XYZA(I,J,K)+XYZB(I,J,K)*PS(I,J))
           AIRX(I,J,K) = XYZA(I,J,K) + PCTM8*XYZB(I,J,K) - AIRQKG
          ENDDO
        ENDDO
      ENDDO

!---GAMA from top down to be consistent with AIRX, AIRNEW not reset!
      DO J=1,JM
        DO I=1,IM
            GAMA(I,J,KM+1) = 0.D0
          DO K=KM,2,-1
            GAMA(I,J,K) = GAMA(I,J,K+1) - (AIRNEW(I,J,K) - AIRX(I,J,K))
          ENDDO
!---N.B. GAMA(I,J,1) will not be exactly ZERO, but it must be set so!
            GAMA(I,J,1) = 0.D0
!---REPLACE SECTION for K=TOP:BOT for EC-model
!          GAMA(I,J,1) = 0.E0
!          DO K=1,KM-1
!            GAMA(I,J,K+1) = GAMA(I,J,K) + (AIRNEW(I,J,K) - AIRX(I,J,K))
!          ENDDO
!          GAMA(I,J,KM+1) = 0.E0
!---scale GAMA from kg over the wind-field time interval to kg/sec
          DO K=2,KM
             GAMA(I,J,K) = GAMA(I,J,K)/DTWIND
          ENDDO
        ENDDO
      ENDDO


!     WRITE OUT ENTIRE ARRAY
      IF(.FALSE.) THEN
        write(6,*) 'writing out pctm array'
        write(16,'(e16.6)') ((pctm(i,j),i=1,im),j=1,jm)
        write(6,*) 'writing out alfa array'
        write(16,'(e16.6)') (((alfa(i,j,k),i=1,im),j=1,jm ),k=1,km )
        write(6,*) 'writing out beta array'
        write(16,'(e16.6)') (((beta(i,j,k),i=1,im),j=1,jm ),k=1,km )
        write(6,*) 'writing out gama array'
        write(16,'(e16.6)') (((gama(i,j,k),i=1,im),j=1,jm ),k=1,km )
        call Esm_Flush(16)
      ENDIF

!---DIAGNOSTICS:
!---   mean winds  N.B. diagnostics are DRY-air winds ONLY!
!
!----accumulate zonal average U (m/s)
      DO K=1,KM
        DO J=1,JM
            SUMU = 0.D0
          DO I=1,IM
            SUMU = SUMU + ALFA(I,J,K)/AIRD(I,J,K)
          ENDDO
            AJL(J,K,1) = AJL(J,K,1) + SUMU*DISTX(J+J0)/REAL(IM)
        ENDDO
      ENDDO
!
!----accumulate zonal average V (m/s)
      DO K=1,KM
        DO J=2,JM
           SUMV = 0.D0
          DO I=1,IM
            SUMV = SUMV + BETA(I,J,K)/(AIRD(I,J-1,K)+AIRD(I,J,K))
          ENDDO
            AJL(J,K,2) = AJL(J,K,2) + SUMV*(DISTY(J+J0-1) +  &
     &           DISTY(J+J0))/REAL(IM)
        ENDDO     ! end of loop J=2,JM, now do J=1 & J=JM+1
          SUMV = 0.0
        DO I=1,IM
          SUMV = SUMV + BETA(I,1,K)/AIRD(I,1,K)
        ENDDO
          AJL(1,K,2)=AJL(1,K,2)+SUMV*DISTY(1+J0)/REAL(IM)
        IF(JM+1.LT.JMG) THEN
           SUMV = 0.D0
          DO I=1,IM
            SUMV = SUMV + BETA(I,JM+1,K)/AIRD(I,JM,K)
          ENDDO
           AJL(JM+1,K,2)=AJL(JM+1,K,2)+SUMV*DISTY(JM+J0)/REAL(IM)
        ENDIF
      ENDDO
!
!----accumulate zonal average Omega (Pascal/sec)
      DO K=1,KM
!       WRITE(lun13,'(12HNTAU/K/PLEV=,I5,I2,1PE12.5)') NTAU,K,PLEV(K,1)
        DO J=1,JM
          SUMA = G0 /(100. *PLEV(K,1) *AREAXY(1,J+J0) *REAL(IM))
          SUMW = 0.D0
          DO I=1,IM
            SUMW = SUMW + GAMA(I,J,K)
          ENDDO
          AJL(J,K,3) = AJL(J,K,3) + SUMW *SUMA
        ENDDO
      ENDDO
!
      RETURN
      END
!
!---------subroutine  GRDSET--------------------------------------------
!

      SUBROUTINE GRDSET 1
!
!---------GRDSET sets up the grids
!---------THIS SET OF ARRAYS & COMMONS IS A TEMPORARY FIX TO MAKE THE
!---------NEW VERSION OF -DYN0- BASED ON ECMWF GRID, COMPATIBLE WITH
!---------THE OLD SET OF COMMONS, ETC TO BE USED IN FIRST LLNL VERSION (QZ=2.0)
      REAL*8 AIRD,AIRNEW,AIRX, XYZA,XYZB,XYA,XYB
      REAL*8 SUMXYZ,SUMAD0,SUMAW0,AIRWET,AIRH2O,AIRDRY,AIRQKG
!
      COMMON /CCGRID/  &
     & AIRD(36,24,21),AIRNEW(36,24,21),AIRX(36,24,21),  &
     & XYZA(36,24,21),XYZB(36,24,21),XYA(36,24),XYB(36,24),  &
     & AIRDRY,AIRQKG,  &
     & YGRD(24),YDGRD(24),YEDG(25),YDEDG(25),XGRD(36),  &
     & XDGRD(36),XEDG(37),XDEDG(37),DLONG,AREAXY(36,24),  &
     & DISTX(25),DISTY(24), ETAA(22),ETAB(22),  &
     & UUU(37,24,21),VVV(36,25,21),PS(36,24),  &
     & AIRQG(36,24,21),AIRQ(36,24,21),PCTM(36,24), IMEPZ(24)
!-----------------------------------------------------------------------
#        include "uci.h"
!xx$$
      save
!xx$$
!-----------------------------------------------------------------------
!---------AREAXY(I,J) = area of (I,J) (m^2)
!---------pressure at I,J,K is  ETTA(K) + ETTB(K)*PS(I,J)---------------
!-------------------------------------------------------------------------
!
!---------this initialization is temporary, transition to new notation
      IMG = IMX
      JMG = JMX
      KM  = LM
      DO J=1,JMG
        IMEPZ(J) = IMRSLV(J)
      ENDDO
!----------------------GRID---------------------------------------------
!---------fix for GISS 21 layer
!---------ECMWF:    A0 = 6371000.d0
!---------ECMWF:    G0 = 9.80665d0
      A0 = 6375000.
      G0 = 9.81D0
      PI = 3.141592653589793D0
      ONEPI = PI
      PI180 = 180.D0/ONEPI
!---------GISS fix sigma-coords into hybrid eta-a and eta-b:
      DO L=1,LTM+1
        ETAA(L) = (1.E0 - SIGE(L))*PTOP
        ETAB(L) = SIGE(L)
      ENDDO
      DO L=LTM+2,LM+1
        ETAA(L) = SIGE(L)*PTOP
        ETAB(L) = 0.0
      ENDDO
!---------YGRD IS A SPECIAL CASE FOR REGULAR GISS GRID
      YEDG0 = 180.D0 /REAL(JMG-1)
      YDEDG(1) = -90. - YEDG0*0.5
      DO J=2,JMG
        YDEDG(J) = YDEDG(J-1) + YEDG0
      ENDDO
      YDEDG(1) = -90.
      YDEDG(JMG+1) = +90
      DO J=1,JMG+1
        YEDG(J) = SIN(YDEDG(J)/PI180)
      ENDDO
      DO J=1,JMG
        YGRD(J) = 0.5D0*(YEDG(J+1)+YEDG(J))
        YDGRD(J) = 0.5D0*(YDEDG(J+1)+YDEDG(J))
      ENDDO
      DLONG = 2.D0*ONEPI/REAL(IMG)
      XDEG0 = 0.D0
      DO I=1,IMG
        XGRD(I) = DLONG*REAL(I-1) + XDEG0/PI180
        XDGRD(I) = PI180*XGRD(I)
        IF(XDGRD(I).GT.180.D0) XDGRD(I) = XDGRD(I) - 360.D0
      ENDDO
      XEDG(1) = XGRD(1) - 0.5D0*DLONG
      DO I=2,IMG
        XEDG(I) = 0.5D0*(XGRD(I-1)+XGRD(I))
      ENDDO
      XEDG(IMG+1) = XGRD(IMG) + 0.5D0*DLONG
      DO I=1,IMG+1
        XDEDG(I) = PI180*XEDG(I)
        IF(XDEDG(I).GT.180.D0) XDEDG(I) = XDEDG(I) - 360.D0
      ENDDO
!---------areas:
       DO J=1,JMG
         DISTY(J) = A0*(YDEDG(J+1)-YDEDG(J))/PI180
       ENDDO
       DO J=1,JMG+1
         DISTX(J) = A0*DLONG*SQRT(1.D0 - YEDG(J)*YEDG(J))
       ENDDO
       DO J=1,JMG
         DISTX(J) = 0.5*(DISTX(J)+DISTX(J+1))
       ENDDO
       DO J=1,JMG
         DO I=1,IMG
           AREAXY(I,J) = A0*A0*(YEDG(J+1)-YEDG(J))*(XEDG(I+1)-XEDG(I))
         ENDDO
       ENDDO
!---------calculate air mass factors for each grid box:
!---------air mass (I,J,K) in kg = XYZA() + XYZB()*surface pressure (mbar)
      SUMXYZ = 0.D0
      DO K=1,KM
      DO J=1,JM
        JOFF = J+J0
        DO I=1,IM
          IOFF = MOD(I+I0-1,IMG)+1
!---set up for ECMWF inverse grid and Pascals (NOT mbar)
!         XYZA(I,J,K) = (ETAA(K+1)-ETAA(K))*AREAXY(IOFF,JOFF)/G0
!         XYZB(I,J,K) = (ETAB(K+1)-ETAB(K))*AREAXY(IOFF,JOFF)/G0
!---set for GISS grid, from bottom up, (will goto EC version)
          XYZA(I,J,K) =-(ETAA(K+1)-ETAA(K))*AREAXY(IOFF,JOFF)*1.E2/G0
          XYZB(I,J,K) =-(ETAB(K+1)-ETAB(K))*AREAXY(IOFF,JOFF)*1.E2/G0
          SUMXYZ = SUMXYZ + XYZB(I,J,K)
        ENDDO
      ENDDO
      ENDDO
      DO J=1,JM
      DO I=1,IM
        XYA(I,J) = 0.D0
        XYB(I,J) = 0.D0
        DO K=1,KM
          XYA(I,J) = XYA(I,J) + XYZA(I,J,K)
          XYB(I,J) = XYB(I,J) + XYZB(I,J,K)
        ENDDO
      ENDDO
      ENDDO
      WRITE(lun13,'(A,1PE10.3)')   '  Air Mass  kg/mbar:',SUMXYZ
      RETURN
      END
!
!---------subroutines  AIRSET-------------------------------------------
!

      SUBROUTINE AIRSET 1
!---------AIRSET sets up the air mass-----------------------------------
      REAL*8 AIRD,AIRNEW,AIRX, XYZA,XYZB,XYA,XYB
      REAL*8 SUMXYZ,SUMAD0,SUMAW0,AIRWET,AIRH2O,AIRDRY,AIRQKG
!-----------------------------------------------------------------------
      COMMON /CCGRID/  &
     & AIRD(36,24,21),AIRNEW(36,24,21),AIRX(36,24,21),  &
     & XYZA(36,24,21),XYZB(36,24,21),XYA(36,24),XYB(36,24),  &
     & AIRDRY,AIRQKG,  &
     & YGRD(24),YDGRD(24),YEDG(25),YDEDG(25),XGRD(36),  &
     & XDGRD(36),XEDG(37),XDEDG(37),DLONG,AREAXY(36,24),  &
     & DISTX(25),DISTY(24), ETAA(22),ETAB(22),  &
     & UUU(37,24,21),VVV(36,25,21),PS(36,24),  &
     & AIRQG(36,24,21),AIRQ(36,24,21),PCTM(36,24), IMEPZ(24)
!-----------------------------------------------------------------------
#        include "uci.h"
!xx$$
      save
!xx$$
!-----------------------------------------------------------------------
!---------UNITS OF AIR MASS AND TRACER = (kg)  -------------------------
!---------Air mass (kg) is given by area (m^2) * pressure thickness (Pa) / g0
!
!     KWACC = KWACC+1
!
!---------GISS 21-layer, no q's, SET WATER MIXING RATIO SMALL EVERYWHERE:
      IMG   = IMX
      JMG   = JMX
      KM    = LM
      G0    = 9.81D0
!     write(6,*) 'Airset: airqg set to 0.d0'
      DO J=1,JM
        DO I=1,IM
          DO K=1,KM
            AIRQG(I,J,K) = 1.0D-6
!           AIRQG(I,J,K) = 0.d0
          ENDDO
        ENDDO
      ENDDO
!----------------------INITIALIZE---------------------------------------
!---------AIRD() = air mass at beginning of time step
!---------SUMAD0 = initialized dry-air mass (kg), this quantity
!---------         is assumed to be conserved throughout the run and is
!---------         used to reset AIRD()
      SUMAD0 = 0.D0
      SUMAW0 = 0.D0
!---------First need to map the full-grid values (__G) onto local(WINDOW) arrays
!---------NB need to have IMG=IM, JMG=JM, KMG=KM for full global calc.
      DO J=1,JM
        DO I=1,IM
          II0 = MOD(I+I0-1, IMG) + 1
!---------original for q-code:     PS(I,J) = PSG(II0,J+J0)--------------
          PS(I,J) = P(II0,J+J0)
          DO K=1,KM
            AIRQ(I,J,K) = AIRQG(II0,J+J0,K)
          ENDDO
        ENDDO
      ENDDO
!
      DO K=1,KM
        DO J=1,JM
          DO I=1,IM
            AIRWET = XYZA(I,J,K) + PS(I,J)*XYZB(I,J,K)
            AIRH2O = AIRQ(I,J,K)*AIRWET
            AIRD(I,J,K) = AIRWET - AIRH2O
            SUMAD0 = SUMAD0 + AIRD(I,J,K)
            SUMAW0 = SUMAW0 + AIRH2O
!---------temporary, duplication of AD() and AIRD() for current version
!rt            AD(I,J,K) = AIRD(I,J,K)
!
          ENDDO
        ENDDO
      ENDDO
!rt
      AIRDRY = SUMAD0
      IF (.NOT. LCONT)  THEN
        DO K=1,KM
          DO J=1,JM
            DO I=1,IM
              AD(I,J,K) = AIRD(I,J,K)
            ENDDO
          ENDDO
        ENDDO
      ENDIF
!rt
!
!      CALL TRASET
      WRITE(lun13,'(A,1P,2E12.5)') ' Initialize Air: dry+water(kg):'  &
     &                         ,SUMAD0,SUMAW0
      RETURN
      END
!
!

      SUBROUTINE PFILTR(XERR,AX,BX,NA,NB,NAM,NBM,NZONA,LSP,LNP,LEW) 1
!
      IMPLICIT NONE
      LOGICAL  LSP,LNP,LEW
      INTEGER  NA,NB,NAM,NBM,NZONA(*)
      REAL*8   XERR(NAM,NBM),AX(NAM+1,NBM),BX(NAM,NBM+1)
!-----------------------------------------------------------------------
!   LSP = .T. if J=1 is S.POLE,    LNP = .T. if J=NB is N.POLE
!   LEW = .T. if I=1 connects to I=NA
!   NZONA(J) = # of boxes in extended zones,  offset by J0 when passed
!-----------------------------------------------------------------------
      INTEGER I,IA,NAZ,J,J1,J2,NFLTR
      REAL*8  X0(160,160)
      REAL*8  SUMA,FNAZ8
!xx$$
      save
!xx$$
!---------Initialize corrective column mass flows (kg):  AX->alfa, BX->beta
      DO J=1,NB+1
        DO I=1,NA
          BX(I,J) = 0.D0
        ENDDO
      ENDDO
      DO J=1,NB
        DO I=1,NA+1
          AX(I,J) = 0.D0
        ENDDO
      ENDDO
      DO J=1,NB
        DO I=1,NA
          X0(I,J) = XERR(I,J)
        ENDDO
      ENDDO
!---------Iterate over mass-error filter, accumulate corrections in AX & BX
      DO 99 NFLTR=1,5
!---------must average XERR over EPZs, make sure that NZONA is offset by J0
      DO J=1,NB
        NAZ        = NZONA(J)
        IF(NAZ.GT.1) THEN
          DO IA=1,NA,NAZ
            SUMA   = 0.D0
            DO I=IA,IA+NAZ-1
              SUMA = SUMA + XERR(I,J)
            ENDDO
            SUMA   = SUMA/REAL(NAZ)
            DO I=IA,IA+NAZ-1
              XERR(I,J) = SUMA
            ENDDO
          ENDDO
        ENDIF
      ENDDO
!---------calculate BX = N-S filter, N-S wind between boxes (J-1) & (J)
      DO J=3,NB-1
      DO I=1,NA
        BX(I,J) = BX(I,J) + 0.125D0*(XERR(I,J-1) - XERR(I,J))
      ENDDO
      ENDDO
!---------enhance the filtering by factor of 2 ONLY into/out-of polar caps
      IF (LSP) THEN
        DO I=1,NA
          BX(I,2) = BX(I,2) + 0.25D0*(XERR(I,1) - XERR(I,2))
        ENDDO
       ELSE
         DO I=1,NA
           BX(I,1) = BX(I,1) - 0.125D0*XERR(I,1)
           BX(I,2) = BX(I,2) + 0.125D0*(XERR(I,1) - XERR(I,2))
         ENDDO
      ENDIF
      IF(LNP) THEN
        DO I=1,NA
          BX(I,NB) = BX(I,NB) + 0.25D0*(XERR(I,NB-1) - XERR(I,NB))
        ENDDO
       ELSE
         DO I=1,NA
           BX(I,NB+1) = BX(I,NB+1) + 0.125D0*XERR(I,NB)
           BX(I,NB) = BX(I,J) + 0.125D0*(XERR(I,NB-1) - XERR(I,NB))
         ENDDO
      ENDIF
!---------need N-S flux across boundaries if window calc.(assume XERR=0 outside)
!---------NB for optimal matrix/looping, it would be best to define XERR=0
!---------for an oversized array XERR(0:IM+1,0:JM+1)
!---------calculate AX = E-W filter
      J1      = 1
      J2      = NB
      IF (LSP)  J1 = 2
      IF (LNP)  J2 = NB -1
      DO J=J1,J2
!---------calculate pressure-filter E-W wind between boxes (I-1) & (I)
!---------enhance filtered wind by size of EPZ, will redistribute later within
        NAZ = NZONA(J)
        FNAZ8 = NAZ*0.125D0
        DO I=2,NA
          AX(I,J) = AX(I,J) + FNAZ8*(XERR(I-1,J) - XERR(I,J))
        ENDDO
!---------calculate pressure-filter E-W wind at edges I=1 & I=NA+1
        IF(LEW) THEN        ! CYCLIC
          AX(NA+1,J) = AX(NA+1,J) + FNAZ8*(XERR(NA,J) - XERR(1,J))
          AX(1,J)    = AX(1,J)    + FNAZ8*(XERR(NA,J) - XERR(1,J))
        ELSE                ! WINDOW, assume zero error outside window
          AX(1,J)    = AX(1,J)    - FNAZ8*XERR(1,J)
          AX(NA+1,J) = AX(NA+1,J) + FNAZ8*XERR(NA,J)
        ENDIF
!---------N.B. the AX()'s are NOT correct within EPZs, but ONLY at boundaries
!---------would need to fix below
!        IF(NAZ.GT.1) THEN   ! redistribute AX() at boundaries within EPZs
!
!        ENDIF
      ENDDO
!---------Update the mass error (XERR)
      DO J=1,NB
        DO I=1,NA
          XERR(I,J) = X0(I,J) +AX(I,J) -AX(I+1,J) +BX(I,J) -BX(I,J+1)
        ENDDO
      ENDDO
   99 CONTINUE
      RETURN
      END