program  main,14

! **********************************************************************
! **********************************************************************
! ****                                                              ****
! ****     Program to merge eta_hdf data into GEOS5 restarts        ****
! ****                                                              ****
! **** Note:  ANA files are interpolated/binned to the Model        ****
! ****        BKG restart resolution.  The resulting blended        ****
! ****        restarts are then remapped to the Model topography.   ****
! ****  26Feb2007 Todling - calc ple from top down                  ****
! ****                                                              ****
! **********************************************************************
! **********************************************************************

      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice_ana
      type ( dynamics_lattice_type ) lattice_bkg
#ifdef mpi
      include 'mpif.h'
#endif
      integer  comm,myid,npes,ierror

      integer  imaglobal,jmaglobal
      integer  imbglobal,jmbglobal
      integer  npex,npey

      integer headr1(6)
      integer headr2(5)
      integer nymd,nhms,nymd_bkg,nhms_bkg
      integer ima,jma,lm
      integer imb,jmb

      integer ntime,nvars,ngatts,timinc
      real,    allocatable ::    lat(:)
      real,    allocatable ::    lon(:)
      real,    allocatable ::    lev(:)
      real,    allocatable :: vrange(:,:)
      real,    allocatable :: prange(:,:)
      integer, allocatable :: yymmdd(:)
      integer, allocatable :: hhmmss(:)
      integer, allocatable ::  kmvar(:)
      integer, allocatable ::   nloc(:)

      character*128  dynrst, anaeta, moistrst, topofile
      character*128  tag
      character*128  title
      character*128  source
      character*128  contact
      character*128  levunits
      character*128, allocatable ::  vname(:)
      character*128, allocatable :: vtitle(:)
      character*128, allocatable :: vunits(:)

! ANA and BKG Variables
! ---------------------
      real, allocatable ::   dp_ana(:,:,:)
      real, allocatable ::    u_ana(:,:,:) ,    u_bkg(:,:,:),   u_bkg0(:,:,:)
      real, allocatable ::    v_ana(:,:,:) ,    v_bkg(:,:,:),   v_bkg0(:,:,:)
      real, allocatable ::  thv_ana(:,:,:) ,  thv_bkg(:,:,:)
      real, allocatable ::                     th_bkg(:,:,:)
      real, allocatable ::   pk_ana(:,:,:) ,   pk_bkg(:,:,:)
      real, allocatable ::  ple_ana(:,:,:) ,  ple_bkg(:,:,:), ple_bkg0(:,:,:)
      real, allocatable ::  pke_ana(:,:,:) ,  pke_bkg(:,:,:)
      real, allocatable ::    q_ana(:,:,:) ,    q_bkg(:,:,:)
      real, allocatable ::   o3_ana(:,:,:) ,   o3_bkg(:,:,:)
      real, allocatable ::   ps_ana(:,:)
      real, allocatable :: phis_ana(:,:)   , phis_bkg(:,:)
      real, allocatable :: phis_tmp(:,:)

      real,   allocatable ::   glo(:,:)
      real*8, allocatable ::    ak(:)
      real*8, allocatable ::    bk(:)

      real    kappa, tauiau
      real    undefa,undefb,rgas,rvap,eps,grav

      character*120, allocatable :: arg(:)
      character*8    date
      character*2    hour
      integer n,nargs,iargc,i,j,L,ID,rc,iostat,method

C **********************************************************************
C ****                 Initialize MPI Environment                   ****
C **********************************************************************

      call timebeg ('main')

#ifdef mpi
      call mpi_init                ( ierror ) ; comm = mpi_comm_world
      call mpi_comm_rank ( comm,myid,ierror )
      call mpi_comm_size ( comm,npes,ierror )
      npex = nint ( sqrt( float(npes) ) )
      npey = npex
      do while ( npex*npey .ne. npes )
         npex = npex-1
         npey = nint ( float(npes)/float(npex) )
      enddo
#else
      comm = 0
      npes = 1
      npex = 1
      npey = 1
      myid = 0
#endif

! **********************************************************************
! ****                      Initialize Filenames                    ****
! **********************************************************************

      kappa = 2.0/7.0
      grav  = 9.8

           tag = 'ana'
        dynrst = 'x'
      moistrst = 'x'
      anaeta   = 'x'
      topofile = 'x'
      nymd     = -999
      nhms     = -999
      method   = -999

         nargs = iargc()
      if(nargs.eq.0) call usage(myid)
      allocate ( arg(nargs) )

      do n=1,nargs
      call getarg(n,arg(n))
      enddo
      do n=1,nargs
             if( trim(arg(n)).eq.'-h'        ) call usage(myid)
             if( trim(arg(n)).eq.'-help'     ) call usage(myid)
             if( trim(arg(n)).eq.'-H'        ) call usage(myid)
             if( trim(arg(n)).eq.'-Help'     ) call usage(myid)
             if( trim(arg(n)).eq.'-dynrst'   ) then
                                   dynrst  = trim(arg(n+1))
             endif
             if( trim(arg(n)).eq.'-moistrst' ) then
                                   moistrst = trim(arg(n+1))
             endif
             if( trim(arg(n)).eq.'-ana'      ) then
                                   anaeta   = trim(arg(n+1))
             endif
             if( trim(arg(n)).eq.'-topo'     ) then
                                   topofile = trim(arg(n+1))
             endif
             if( trim(arg(n)).eq.'-tag'      ) then
                                   tag     = trim(arg(n+1))
             endif
             if( trim(arg(n)).eq.'-divr'     ) method = 1
             if( trim(arg(n)).eq.'-diva'     ) method = 2
             if( trim(arg(n)).eq.'-nymd'     ) read(arg(n+1),*) nymd
             if( trim(arg(n)).eq.'-nhms'     ) read(arg(n+1),*) nhms
      enddo

      if( trim(anaeta)  .eq.'x' .or. 
     .    trim(dynrst)  .eq.'x' .or. 
     .    trim(moistrst).eq.'x' ) then
          if( myid.eq.0 ) print *, 'You must supply DYNRST, MOISTRST, and ANARST Files!'
          call my_finalize
          call exit (7)
          stop
      endif

! **********************************************************************
! ****    Read Dycore Internal Restart for RSLV, Date and Time      ****
! **********************************************************************

      if( myid.eq.0 ) then
          print *
          print *, 'Reading  ',trim(dynrst),' from PE: ',myid
          open (10, file=trim(dynrst),form='unformatted',access='sequential')
          read (10) headr1
          read (10) headr2
      endif
#ifdef mpi
      call mpi_bcast ( headr1,6,mpi_integer,0,comm,ierror )
      call mpi_bcast ( headr2,5,mpi_integer,0,comm,ierror )
#endif

      nymd_bkg = headr1(1)*10000
     .         + headr1(2)*100
     .         + headr1(3)
      nhms_bkg = headr1(4)*10000
     .         + headr1(5)*100
     .         + headr1(6)

      imbglobal = headr2(1)
      jmbglobal = headr2(2)
      lm        = headr2(3)

      if( nymd.eq.-999 ) nymd = nymd_bkg
      if( nhms.eq.-999 ) nhms = nhms_bkg

      write(date,101) nymd
      write(hour,102) nhms/10000
  101 format(i8.8)
  102 format(i2.2)

      call create_dynamics_lattice ( lattice_bkg,npex,npey )
      call   init_dynamics_lattice ( lattice_bkg,comm,imbglobal,jmbglobal,lm )

      imb = lattice_bkg%im( lattice_bkg%pei )
      jmb = lattice_bkg%jm( lattice_bkg%pej )

      allocate (    q_bkg(imb,jmb,lm)   )
      allocate (   o3_bkg(imb,jmb,lm)   )
      allocate (  thv_bkg(imb,jmb,lm)   )
      allocate (  pke_bkg(imb,jmb,lm+1) )
      allocate ( phis_bkg(imb,jmb)      )

      allocate (    u_bkg(imb,jmb,lm)   )
      allocate (    v_bkg(imb,jmb,lm)   )
      allocate (   th_bkg(imb,jmb,lm)   )
      allocate (  ple_bkg(imb,jmb,lm+1) )
      allocate (   pk_bkg(imb,jmb,lm)   )

      allocate (   u_bkg0(imb,jmb,lm)   )
      allocate (   v_bkg0(imb,jmb,lm)   )
      allocate ( ple_bkg0(imb,jmb,lm+1) )

      allocate ( ak(lm+1) )
      allocate ( bk(lm+1) )

      if( myid.eq.0 ) then
          read (10) ak
          read (10) bk
      endif
#ifdef mpi
      call mpi_bcast ( ak,lm+1,mpi_double_precision,0,comm,ierror )
      call mpi_bcast ( bk,lm+1,mpi_double_precision,0,comm,ierror )
#endif

      call read_fv (   u_bkg0,imb,jmb,lm  ,10,lattice_bkg )
      call read_fv (   v_bkg0,imb,jmb,lm  ,10,lattice_bkg )
      call read_fv ( ple_bkg0,imb,jmb,lm  ,10,lattice_bkg ) ! Skip theta
      call read_fv ( ple_bkg0,imb,jmb,lm+1,10,lattice_bkg )

      if( myid.eq.0 ) close(10)

! **********************************************************************
! ****                   Read Analysis ANA File                     ****
! **********************************************************************

      call timebeg(' read_ana')
      if( myid.eq.0 ) then
          print *, 'Reading  ANA File from PE: ',myid
          call gfio_open       ( trim(anaeta),1,ID,rc )
          call gfio_diminquire ( id,imaglobal,jmaglobal,lm,ntime,nvars,ngatts,rc )
      endif
#ifdef mpi
      call mpi_bcast ( imaglobal,1,  mpi_integer,0,comm,ierror )
      call mpi_bcast ( jmaglobal,1,  mpi_integer,0,comm,ierror )
      call mpi_bcast (        lm,1,  mpi_integer,0,comm,ierror )
      call mpi_bcast (     ntime,1,  mpi_integer,0,comm,ierror )
      call mpi_bcast (     nvars,1,  mpi_integer,0,comm,ierror )
#endif
      call create_dynamics_lattice ( lattice_ana,npex,npey )
      call   init_dynamics_lattice ( lattice_ana,comm,imaglobal,jmaglobal,lm )

      ima = lattice_ana%im( lattice_ana%pei )
      jma = lattice_ana%jm( lattice_ana%pej )

      allocate ( lon(imaglobal) )
      allocate ( lat(jmaglobal) )
      allocate ( lev(lm) )
      allocate ( yymmdd(ntime) )
      allocate ( hhmmss(ntime) )
      allocate (  vname(nvars) )
      allocate ( vtitle(nvars) )
      allocate ( vunits(nvars) )
      allocate (  kmvar(nvars) )
      allocate ( vrange(2,nvars) )
      allocate ( prange(2,nvars) )

      if( myid.eq.0 ) then
          call gfio_inquire ( id,imaglobal,jmaglobal,lm,ntime,nvars,
     .                        title,source,contact,undefa,
     .                        lon,lat,lev,levunits,
     .                        yymmdd,hhmmss,timinc,
     .                        vname,vtitle,vunits,kmvar,
     .                        vrange,prange,rc )
      endif
#ifdef mpi
      call mpi_bcast ( undefa,     1,lattice_ana%mpi_rkind,0,comm,ierror )
      call mpi_bcast ( lon,imaglobal,lattice_ana%mpi_rkind,0,comm,ierror )
#endif

      allocate (   ps_ana(ima,jma)      )
      allocate (   dp_ana(ima,jma,lm)   )
      allocate (   pk_ana(ima,jma,lm)   )
      allocate (  pke_ana(ima,jma,lm+1) )
      allocate (  thv_ana(ima,jma,lm)   )

      allocate ( phis_ana(ima,jma)      )
      allocate (    u_ana(ima,jma,lm)   )
      allocate (    v_ana(ima,jma,lm)   )
      allocate (    q_ana(ima,jma,lm)   )
      allocate (   o3_ana(ima,jma,lm)   )
      allocate (  ple_ana(ima,jma,lm+1) )

      call getit ( id,'phis' ,nymd,nhms,ima,jma,0,1 ,phis_ana,lattice_ana )
      call getit ( id,'ps'   ,nymd,nhms,ima,jma,0,1 ,  ps_ana,lattice_ana )
      call getit ( id,'delp' ,nymd,nhms,ima,jma,1,lm,  dp_ana,lattice_ana )
      call getit ( id,'uwnd' ,nymd,nhms,ima,jma,1,lm,   u_ana,lattice_ana )
      call getit ( id,'vwnd' ,nymd,nhms,ima,jma,1,lm,   v_ana,lattice_ana )
      call getit ( id,'theta',nymd,nhms,ima,jma,1,lm, thv_ana,lattice_ana )
      call getit ( id,'sphu' ,nymd,nhms,ima,jma,1,lm,   q_ana,lattice_ana )
      call getit ( id,'ozone',nymd,nhms,ima,jma,1,lm,  o3_ana,lattice_ana )

      if( myid.eq.0 ) call gfio_close ( id,rc )
      call timeend(' read_ana')

      ple_ana(:,:,1) = ak(1)
      do L=2,lm+1
      ple_ana(:,:,L) = ple_ana(:,:,L-1)+dp_ana(:,:,L-1)
      enddo

! Check for Indexing Consistency with Model
! -----------------------------------------
      if( myid.eq.0 ) print *, 'Analysis ANA File begins at Lon: ',lon(1)
      if( lon(1) .eq. 0.0 ) then
          if( myid.eq.0 ) print *, '         Flipping Horizontal Coordinate' 
          call hflip (phis_ana,ima,jma,1   ,lattice_ana )
          call hflip (   u_ana,ima,jma,lm  ,lattice_ana )
          call hflip (   v_ana,ima,jma,lm  ,lattice_ana )
          call hflip ( thv_ana,ima,jma,lm  ,lattice_ana )
          call hflip ( ple_ana,ima,jma,lm+1,lattice_ana )
          call hflip (   q_ana,ima,jma,lm  ,lattice_ana )
          call hflip (  o3_ana,ima,jma,lm  ,lattice_ana )
      endif

      deallocate ( lon )
      deallocate ( lat )
      deallocate ( lev )
      deallocate ( yymmdd )
      deallocate ( hhmmss )
      deallocate (  vname )
      deallocate ( vtitle )
      deallocate ( vunits )
      deallocate (  kmvar )
      deallocate ( vrange )
      deallocate ( prange )

      if( myid.eq.0 ) then
          print *
          print *, '    FV Restart filename: ',trim(dynrst)
          print *, '          FV resolution: ',imbglobal,jmbglobal,lm
          print *
          print *, '      Analysis filename: ',trim(anaeta)
          print *, '         ANA resolution: ',imaglobal,jmaglobal,lm
          print *
          print *, '                   Date: ',nymd,nhms
          print *, '                    Tag: ',trim(tag)
          print *
      endif

! **********************************************************************
! ****                  Create FV Restart Using ANA Data            ****
! **********************************************************************

      if( imaglobal.ne.imbglobal  .or. 
     .    jmaglobal.ne.jmbglobal  .or.
     .    trim(topofile).ne.'x' ) then

      if( trim(topofile).eq.'x' ) then
          if( myid.eq.0 ) print *, 'You must supply TOPO File at Model Resolution!'
          call my_finalize
          call exit (7)
          stop
      else
          if( myid.eq.0 ) print *, 'Reading  ',trim(topofile),' from PE: ',myid
          open  (10,file=trim(topofile),form='unformatted',access='sequential')
          call readit ( phis_bkg,imb,jmb,1,10,lattice_bkg,topofile,rc )
          phis_bkg = phis_bkg*grav
          close (10)
      endif
      allocate ( phis_tmp(imb,jmb) )

! Construct A-Grid Winds
! ----------------------
          allocate ( glo(imaglobal,jmaglobal) )
          do L=1,lm
                                          call timebeg ('   Gather')
                                          call gather_2d  ( glo,u_ana(1,1,L),lattice_ana )
                                          call timeend ('   Gather')
                                          call timebeg (' dtoa')
              if( lattice_ana%myid.eq.0 ) call dtoa       ( glo,glo,imaglobal,jmaglobal,1,2 )
                                          call timeend (' dtoa')
                                          call timebeg ('   Scatter')
                                          call scatter_2d ( glo,u_ana(1,1,L),lattice_ana )
                                          call timeend ('   Scatter')
                                          call timebeg ('   Gather')
                                          call gather_2d  ( glo,v_ana(1,1,L),lattice_ana )
                                          call timeend ('   Gather')
                                          call timebeg (' dtoa')
              if( lattice_ana%myid.eq.0 ) call dtoa       ( glo,glo,imaglobal,jmaglobal,1,1 )
                                          call timeend (' dtoa')
                                          call timebeg ('   Scatter')
                                          call scatter_2d ( glo,v_ana(1,1,L),lattice_ana )
                                          call timeend ('   Scatter')
          enddo
          deallocate ( glo )

! Interpolate ANA Data to BKG Resolution
! --------------------------------------
      if( imaglobal.lt.imbglobal ) then
          if( myid.eq.0 ) print *, 'Interpolating ANA Data to BKG Resolution'
          call hinterp ( phis_ana,ima,jma,phis_tmp,imb,jmb,1   ,undefa,lattice_ana,lattice_bkg )
          call hinterp (    u_ana,ima,jma,   u_bkg,imb,jmb,lm  ,undefa,lattice_ana,lattice_bkg )
          call hinterp (    v_ana,ima,jma,   v_bkg,imb,jmb,lm  ,undefa,lattice_ana,lattice_bkg )
          call hinterp (  thv_ana,ima,jma, thv_bkg,imb,jmb,lm  ,undefa,lattice_ana,lattice_bkg )
          call hinterp (  ple_ana,ima,jma, ple_bkg,imb,jmb,lm+1,undefa,lattice_ana,lattice_bkg )
          call hinterp (    q_ana,ima,jma,   q_bkg,imb,jmb,lm  ,undefa,lattice_ana,lattice_bkg )
          call hinterp (   o3_ana,ima,jma,  o3_bkg,imb,jmb,lm  ,undefa,lattice_ana,lattice_bkg )
      endif

! Bin ANA Data to BKG Resolution
! ------------------------------
      if( imaglobal.gt.imbglobal ) then
          if( myid.eq.0 ) print *, 'Binning       ANA Data to BKG Resolution'
          call bin ( phis_ana,ima,jma,phis_tmp,imb,jmb,1   ,undefa, 0 ,lattice_ana,lattice_bkg )
          call bin (    u_ana,ima,jma,   u_bkg,imb,jmb,lm  ,undefa, 1 ,lattice_ana,lattice_bkg )
          call bin (    v_ana,ima,jma,   v_bkg,imb,jmb,lm  ,undefa, 1 ,lattice_ana,lattice_bkg )
          call bin (  thv_ana,ima,jma, thv_bkg,imb,jmb,lm  ,undefa, 0 ,lattice_ana,lattice_bkg )
          call bin (  ple_ana,ima,jma, ple_bkg,imb,jmb,lm+1,undefa, 0 ,lattice_ana,lattice_bkg )
          call bin (    q_ana,ima,jma,   q_bkg,imb,jmb,lm  ,undefa, 0 ,lattice_ana,lattice_bkg )
          call bin (   o3_ana,ima,jma,  o3_bkg,imb,jmb,lm  ,undefa, 0 ,lattice_ana,lattice_bkg )
      endif

! BKG and ANA Horizontal Resolutions Match
! ----------------------------------------
      if( imaglobal.eq.imbglobal .and. jmaglobal.eq.jmbglobal ) then
          phis_tmp = phis_ana
             u_bkg =    u_ana
             v_bkg =    v_ana
           thv_bkg =  thv_ana
           ple_bkg =  ple_ana
             q_bkg =    q_ana
            o3_bkg =   o3_ana
      endif

! Remap Based on TOPO Differences
! -------------------------------
      if( myid.eq.0 ) print *, 'Remapping Data to BKG Topography'
      call timebeg(' remap')
      call remap ( ple_bkg,
     .               u_bkg,
     .               v_bkg,
     .             thv_bkg,
     .               q_bkg,
     .              o3_bkg,
     .            phis_tmp,phis_bkg,ak,bk,imb,jmb,lm )
      call timeend(' remap')

! Construct D-Grid Winds
! ----------------------
          allocate ( glo(imbglobal,jmbglobal) )
          do L=1,lm
                                          call timebeg ('   Gather')
                                          call gather_2d  ( glo,u_bkg(1,1,L),lattice_bkg )
                                          call timeend ('   Gather')
                                          call timebeg (' atod')
              if( lattice_ana%myid.eq.0 ) call atod       ( glo,glo,imbglobal,jmbglobal,1,2 )
                                          call timeend (' atod')
                                          call timebeg ('   Scatter')
                                          call scatter_2d ( glo,u_bkg(1,1,L),lattice_bkg )
                                          call timeend ('   Scatter')
                                          call timebeg ('   Gather')
                                          call gather_2d  ( glo,v_bkg(1,1,L),lattice_bkg )
                                          call timeend ('   Gather')
                                          call timebeg (' atod')
              if( lattice_ana%myid.eq.0 ) call atod       ( glo,glo,imbglobal,jmbglobal,1,1 )
                                          call timeend (' atod')
                                          call timebeg ('   Scatter')
                                          call scatter_2d ( glo,v_bkg(1,1,L),lattice_bkg )
                                          call timeend ('   Scatter')
          enddo
          deallocate ( glo )

      else

! BKG and ANA Horizontal Resolutions Match
! ----------------------------------------
           u_bkg =   u_ana
           v_bkg =   v_ana
         thv_bkg = thv_ana
         ple_bkg = ple_ana
           q_bkg =   q_ana
          o3_bkg =  o3_ana

      endif

      deallocate (   u_ana )
      deallocate (   v_ana )
      deallocate ( thv_ana )
      deallocate ( ple_ana )
      deallocate (   q_ana )
      deallocate (  o3_ana )

! Construct PK Model Variable
! ---------------------------
      pke_bkg(:,:,:) = ple_bkg(:,:,:)**kappa

      do L=1,lm
       pk_bkg(:,:,L) = ( pke_bkg(:,:,L+1)-pke_bkg(:,:,L) )
     .               / ( kappa*log(ple_bkg(:,:,L+1)/ple_bkg(:,:,L)) )
      enddo

! Construct Dry Potential Temperature
! -----------------------------------
      rgas   = 8314.3/28.97
      rvap   = 8314.3/18.01
      eps    = rvap/rgas-1.0
      th_bkg = thv_bkg/(1+eps*q_bkg)

! Modify vertically integrated wind increment to be non-divergent
! ---------------------------------------------------------------

      call write_d ( u_bkg0,v_bkg0,ple_bkg0,imb,jmb,lm,lattice_bkg )  ! Background
      call write_d ( u_bkg ,v_bkg ,ple_bkg ,imb,jmb,lm,lattice_bkg )  ! Analysis before Adjustment

      if( method.eq.-999 ) then
          if( myid.eq.0 )       print *, 'No Wind Adjustment  Change to Divergence'
      else
          if( myid.eq.0 ) then
              if( method.eq.1 ) print *, 'Minimizing Relative Change to Divergence'
              if( method.eq.2 ) print *, 'Minimizing Absolute Change to Divergence'
                                print *, 'Calling Windfix'
          endif
          call timebeg (' windfix')
          call windfix ( u_bkg ,v_bkg ,ple_bkg ,
     .                   u_bkg0,v_bkg0,ple_bkg0,imb,jmb,lm,lattice_bkg,'D',method )
          call timeend (' windfix')
      endif

      call write_d ( u_bkg,v_bkg,ple_bkg,imb,jmb,lm,lattice_bkg )  ! Analysis after Adjustment


! **********************************************************************
! ****                 Write Dycore Internal Restart                ****
! **********************************************************************

      anaeta = trim(dynrst) // '.' // trim(tag) // '.' // date // '_' // hour // 'z'

      call timebeg(' writefv')
      if( myid.eq.0 ) then
          print *, 'Creating GEOS-5 fvcore_internal_restart: ',trim(anaeta)
          open (20,file=trim(anaeta),form='unformatted',access='sequential')
          write(20) headr1
          write(20) headr2
          write(20) ak
          write(20) bk
      endif

      call write_fv (   u_bkg,imb,jmb,lm  ,20,lattice_bkg )
      call write_fv (   v_bkg,imb,jmb,lm  ,20,lattice_bkg )
      call write_fv (  th_bkg,imb,jmb,lm  ,20,lattice_bkg )
      call write_fv ( ple_bkg,imb,jmb,lm+1,20,lattice_bkg )
      call write_fv (  pk_bkg,imb,jmb,lm  ,20,lattice_bkg )

      if( myid.eq.0 ) close (20)
      call timeend(' writefv')

! **********************************************************************
! ****     Merge Moist Internal Restart with Analysis ANA Data      ****
! **********************************************************************

      anaeta = trim(moistrst) // '.' // trim(tag) // '.' // date // '_' // hour // 'z'

      call timebeg(' writemois')
      if( myid.eq.0 ) then
          print *, 'Creating GEOS-5  moist_internal_restart: ',trim(anaeta)
          print *
      endif

      open  (10,file=trim(moistrst),form='unformatted',access='sequential')
      open  (20,file=trim(anaeta)  ,form='unformatted',access='sequential')

      allocate ( glo(imb,jmb) )

! First moist variable is SPHU
! ----------------------------
      do L=1,lm
         call readit ( glo,imb,jmb,1,10,lattice_bkg,moistrst,rc )
                       glo(:,:) = q_bkg(:,:,L)
         call writit ( glo,imb,jmb,1,20,lattice_bkg )
      enddo

! Copy Rest of Moist Internal State
! ---------------------------------
               rc =  0
      dowhile (rc.eq.0)
      do L=1,lm
                     call readit ( glo,imb,jmb,1,10,lattice_bkg,moistrst,rc )
         if(rc.eq.0) call writit ( glo,imb,jmb,1,20,lattice_bkg )
      enddo
      enddo

      deallocate ( glo )
      close (10)
      close (20)
      call timeend(' writemois')

! **********************************************************************
! ****                   Write Timing Information                   ****
! **********************************************************************

                      call timeend ('main')
      if( myid.eq.0 ) call timepri (6)
                      call my_finalize

      stop
      end


      subroutine getit ( id,name,nymd,nhms,im,jm,lbeg,lm,q,lattice ) 24,10
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice
      integer L,id,nymd,nhms,im,jm,img,jmg,lbeg,lm
      real   q(im,jm,lm)
      real,allocatable :: glo(:,:,:)
      character(*) name
      integer rc
      img = lattice%imglobal
      jmg = lattice%jmglobal
      allocate ( glo(img,jmg,lm) )
      if( lattice%myid.eq.0 ) then
          call gfio_getvar ( id,trim(name),nymd,nhms,img,jmg,lbeg,lm,glo,rc )
          if( rc.ne.0 ) print *, '!! Error Reading: ',trim(name),'  RC = ',rc
      endif
      call timebeg ('   Scatter')
      do L=1,lm
      call scatter_2d ( glo(1,1,L),q(1,1,L),lattice )
      enddo
      call timeend ('   Scatter')
      deallocate ( glo )
      return
      end


      subroutine readit ( q,im,jm,lm,ku,lattice,filename,rc ) 19,11
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice
#ifdef mpi
      include 'mpif.h'
#endif
      character(*) filename
      integer  im,jm,lm,L,ku,img,jmg,rc,ierror
      real   q(im,jm,lm)
      real,   allocatable :: glo(:,:)
      real*4, allocatable ::   a(:,:)
      img = lattice%imglobal
      jmg = lattice%jmglobal
      allocate ( glo(img,jmg) )
      allocate (   a(img,jmg) )
      do L=1,lm
         if( lattice%myid.eq.0 ) then
             read(ku,iostat=rc) a 
                          glo = a
         endif
#ifdef mpi
         call mpi_bcast ( rc,1,mpi_integer,0,lattice%comm,ierror )
#endif
         if( rc.eq.0 ) then
             call timebeg ('   Scatter')
             call scatter_2d ( glo,q(1,1,L),lattice )
             call timeend ('   Scatter')
         else if( rc.gt.0 ) then
             if( lattice%myid.eq.0 ) print *, 'Error Reading File: ',trim(filename)
             call my_finalize
             call exit (7)
         endif
      enddo
      deallocate ( a,glo )
      return
      end
 

      subroutine writit ( q,im,jm,lm,ku,lattice ) 40,13
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice
      integer  im,jm,lm,L,ku,img,jmg
      real   q(im,jm,lm)
      real,   allocatable :: glo(:,:)
      real*4, allocatable ::   a(:,:)
      img = lattice%imglobal
      jmg = lattice%jmglobal
      allocate ( glo(img,jmg) )
      allocate (   a(img,jmg) )
      do L=1,lm
         call timebeg ('   Gather')
         call gather_2d ( glo,q(1,1,L),lattice )
         call timeend ('   Gather')
         if( lattice%myid.eq.0 ) then
                       a = glo
             write(ku) a
         endif
      enddo
      deallocate ( a,glo )
      return
      end
 

      subroutine read_fv ( q,im,jm,lm,ku,lattice ) 4,4
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice
      integer  im,jm,lm,L,ku,img,jmg
      real   q(im,jm,lm)
      real,   allocatable :: glo4(:,:)
      real*8, allocatable :: glo8(:,:)
      img = lattice%imglobal
      jmg = lattice%jmglobal
      allocate ( glo4(img,jmg) )
      allocate ( glo8(img,jmg) )
      do L=1,lm
         if( lattice%myid.eq.0 ) then
             read(ku) glo8
                      glo4 = glo8
         endif
         call timebeg ('   Scatter')
         call scatter_2d ( glo4,q(1,1,L),lattice )
         call timeend ('   Scatter')
      enddo
      deallocate ( glo4 )
      deallocate ( glo8 )
      return
      end
 

      subroutine write_fv ( q,im,jm,lm,ku,lattice ) 5,4
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice
      integer  im,jm,lm,L,ku,img,jmg
      real   q(im,jm,lm)
      real,   allocatable :: glo4(:,:)
      real*8, allocatable :: glo8(:,:)
      img = lattice%imglobal
      jmg = lattice%jmglobal
      allocate ( glo4(img,jmg) )
      allocate ( glo8(img,jmg) )
      do L=1,lm
         call timebeg ('   Gather')
         call gather_2d ( glo4,q(1,1,L),lattice )
         call timeend ('   Gather')
         if( lattice%myid.eq.0 ) then
                       glo8 = glo4
             write(ku) glo8
         endif
      enddo
      deallocate ( glo4 )
      deallocate ( glo8 )
      return
      end
 

      subroutine hflip ( q,im,jm,lm,lattice ) 58,14
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice
      integer    im,jm,lm,i,j,L,img,jmg
      real  q(im,jm,lm)
      real, allocatable :: glo(:,:)
      real, allocatable :: dum(:)
      img = lattice%imglobal
      jmg = lattice%jmglobal

      allocate ( glo(img,jmg) )
      allocate ( dum(img)     )

      do L=1,lm
         call timebeg ('   Gather')
         call gather_2d ( glo,q(1,1,L),lattice )
         call timeend ('   Gather')
         if( lattice%myid.eq.0 ) then
             do j=1,jmg
             do i=1,img/2
                dum(i) = glo(i+img/2,j)
                dum(i+img/2) = glo(i,j)
             enddo
                glo(:,j) = dum(:)
             enddo
         endif
         call timebeg ('   Scatter')
         call scatter_2d ( glo,q(1,1,L),lattice )
         call timeend ('   Scatter')
      enddo

      deallocate ( glo )
      deallocate ( dum )
      return
      end


      subroutine minmax (q,im,jm,L)
      real   q(im,jm)
      qmin = q(1,1)
      qmax = q(1,1)
      do j=1,jm
      do i=1,im
      qmin = min( qmin,q(i,j) )
      qmax = max( qmax,q(i,j) )
      enddo
      enddo
      print *, 'L: ',L,' qmin: ',qmin,' qmax: ',qmax
      return
      end


      subroutine usage ( myid ) 41,2
      integer  ierror
      if(myid.eq.0) then
         print *, "Usage:  "
         print *
         print *, " hdf2rs_$ARCH.x  -dynrst        FV internal_restart  "
         print *, "                 -moistrst   Moist internal_restart  "
         print *, "                 -ana        Analysis-Style ana.eta file   "
         print *, "                 -nymd       (Date  to Read From ANA.ETA File (YYYYMMDD),"
         print *, "                              Default: Date within DYNRST)"
         print *, "                 -nhms       (Time  to Read From ANA.ETA File (HHMMSS),"
         print *, "                              Default: Time within DYNRST)"
         print *, "                 -topo       (Optional Topography File if Different from ANA) "
         print *, "                 -divr       (Optional flag to Minimize Relative Adjustment of"
         print *, "                              Div.Inc.)"
         print *, "                 -diva       (Optional flag to Minimize Absolute Adjustment of"
         print *, "                              Div.Inc.)"
         print *
         print *
      endif
#ifdef mpi
      call mpi_finalize (ierror)
#endif
      stop
      end


      subroutine atod ( qa,qd,im,jm,lm,itype ) 6,24
 
C ******************************************************************
C ****                                                          ****
C ****  This program converts 'A' gridded data                  ****
C ****                     to 'D' gridded data.                 ****
C ****                                                          ****
C ****  The D-Grid Triplet is defined as:                       ****
C ****                                                          ****
C ****              u(i,j+1)                                    ****
C ****                |                                         ****
C ****     v(i,j)---delp(i,j)---v(i+1,j)                        ****
C ****                |                                         ****
C ****              u(i,j)                                      ****
C ****                                                          ****
C ****  Thus, v is shifted left (westward),                     ****
C ****        u is shifted down (southward)                     ****
C ****                                                          ****
C ****  An FFT shift transformation is made in x for itype = 1  ****
C ****  An FFT shift transformation is made in y for itype = 2  ****
C ****                                                          ****
C ******************************************************************

      real qa   (im,jm,lm)
      real qd   (im,jm,lm)

      real qax  (   im+2 ,lm)
      real  cx  (2*(im+2),lm)
      real qay  (   2*jm ,lm)
      real  cy  (2*(2*jm),lm)

      real    cosx (im/2), sinx(im/2)
      real    cosy (jm)  , siny(jm)
      real      trigx(3*(im+1))
      real      trigy(3*(2*jm))

      integer IFX (100)
      integer IFY (100)

      jmm1  = jm-1
      jp    = 2*jmm1

      imh   = im/2
      pi    = 4.0*atan(1.0)
      dx    = 2*pi/im
      dy    = pi/jmm1

C *********************************************************
C ****             shift left (-dx/2)                  ****
C *********************************************************

      if (itype.eq.1) then

         call fftfax (im,ifx,trigx)

         do k=1,imh 
         thx = k*dx*0.5
         cosx(k) = cos(thx)
         sinx(k) = sin(thx)
         enddo

      do j=1,jm
         do L=1,lm
         do i=1,im
         qax(i,L) = qa(i,j,L)
         enddo
         enddo
         call rfftmlt (qax,cx,trigx,ifx,1 ,im+2,im,lm,-1)

         do L=1,lm
         do k=1,imh 
         kr = 2*k+1
         ki = 2*k+2
         crprime = qax(kr,L)*cosx(k) + qax(ki,L)*sinx(k)
         ciprime = qax(ki,L)*cosx(k) - qax(kr,L)*sinx(k)
         qax(kr,L) = crprime
         qax(ki,L) = ciprime
         enddo
         enddo

         call rfftmlt (qax,cx,trigx,ifx,1 ,im+2,im,lm, 1)
         do L=1,lm
         do i=1,im
         qd(i,j,L) = qax(i,L)
         enddo
         enddo
      enddo

      endif

C *********************************************************
C ****             shift down (-dy/2)                  ****
C *********************************************************

      if (itype.eq.2) then

         call fftfax (jp,ify,trigy)

         do L=1,jmm1
         thy = L*dy*0.5
         cosy(L) = cos(thy)
         siny(L) = sin(thy)
         enddo

      do i=1,imh 
         do L=1,lm
         do j=1,jmm1
         qay(j,L)      =  qa(i,j+1,L)
         qay(j+jmm1,L) = -qa(i+imh,jm-j,L)
         enddo
         enddo

         call rfftmlt (qay,cy,trigy,ify,1 ,jp+2,jp,lm,-1)

         do L=1,lm
         do k=1,jmm1
         kr = 2*k+1
         ki = 2*k+2
         crprime = qay(kr,L)*cosy(k) + qay(ki,L)*siny(k)
         ciprime = qay(ki,L)*cosy(k) - qay(kr,L)*siny(k)
         qay(kr,L) = crprime
         qay(ki,L) = ciprime
         enddo
         enddo

         call rfftmlt (qay,cy,trigy,ify,1 ,jp+2,jp,lm, 1)

         do L=1,lm
         do j=1,jmm1
         qd(i,j+1,L)        =  qay(j,L)
         qd(i+imh,jm-j+1,L) = -qay(j+jmm1,L)
         enddo
         enddo
      enddo

      endif

      return
      end


      subroutine dtoa ( qd,qa,im,jm,lm,itype ) 14,18
 
C ******************************************************************
C ****                                                          ****
C ****  This program converts 'D' gridded data                  ****
C ****                     to 'A' gridded data.                 ****
C ****                                                          ****
C ****  The D-Grid Triplet is defined as:                       ****
C ****                                                          ****
C ****              u(i,j+1)                                    ****
C ****                |                                         ****
C ****     v(i,j)---delp(i,j)---v(i+1,j)                        ****
C ****                |                                         ****
C ****              u(i,j)                                      ****
C ****                                                          ****
C ****  Thus, v is shifted right (eastward),                    ****
C ****        u is shifted up   (northward)                     ****
C ****                                                          ****
C ****  An FFT shift transformation is made in x for itype = 1  ****
C ****  An FFT shift transformation is made in y for itype = 2  ****
C ****                                                          ****
C ******************************************************************

      real qa   (im,jm,lm)
      real qd   (im,jm,lm)

      real qax  (   im+2 ,lm)
      real  cx  (2*(im+2),lm)
      real qay  (   2*jm ,lm)
      real  cy  (2*(2*jm),lm)

      real    cosx (im/2), sinx(im/2)
      real    cosy (jm)  , siny(jm)
      real      trigx(3*(im+1))
      real      trigy(3*(2*jm))

      integer IFX (100)
      integer IFY (100)

      jmm1  = jm-1
      jp    = 2*jmm1

      imh   = im/2
      pi    = 4.0*atan(1.0)
      dx    = 2*pi/im
      dy    = pi/jmm1

C *********************************************************
C ****             shift right (dx/2)                  ****
C *********************************************************

      if (itype.eq.1) then

         call fftfax (im,ifx,trigx)

         do k=1,imh 
         thx = k*dx*0.5
         cosx(k) = cos(thx)
         sinx(k) = sin(thx)
         enddo

      do j=1,jm
         do L=1,lm
         do i=1,im
         qax(i,L) = qd(i,j,L)
         enddo
         enddo
         call rfftmlt (qax,cx,trigx,ifx,1 ,im+2,im,lm,-1)

         do L=1,lm
         do k=1,imh 
         kr = 2*k+1
         ki = 2*k+2
         crprime = qax(kr,L)*cosx(k) - qax(ki,L)*sinx(k)
         ciprime = qax(ki,L)*cosx(k) + qax(kr,L)*sinx(k)
         qax(kr,L) = crprime
         qax(ki,L) = ciprime
         enddo
         enddo

         call rfftmlt (qax,cx,trigx,ifx,1 ,im+2,im,lm, 1)
         do L=1,lm
         do i=1,im
         qa(i,j,L) = qax(i,L)
         enddo
         enddo
      enddo

      endif

C *********************************************************
C ****               shift up (dy/2)                   ****
C *********************************************************

      if (itype.eq.2) then

         call fftfax (jp,ify,trigy)

         do L=1,jmm1
         thy = L*dy*0.5
         cosy(L) = cos(thy)
         siny(L) = sin(thy)
         enddo

      do i=1,imh 
         do L=1,lm
         do j=1,jmm1
         qay(j,L)      =  qd(i,j+1,L)
         qay(j+jmm1,L) = -qd(i+imh,jm-j+1,L)
         enddo
         enddo

         call rfftmlt (qay,cy,trigy,ify,1 ,jp+2,jp,lm,-1)

         do L=1,lm
         do k=1,jmm1
         kr = 2*k+1
         ki = 2*k+2
         crprime = qay(kr,L)*cosy(k) - qay(ki,L)*siny(k)
         ciprime = qay(ki,L)*cosy(k) + qay(kr,L)*siny(k)
         qay(kr,L) = crprime
         qay(ki,L) = ciprime
         enddo
         enddo

         call rfftmlt (qay,cy,trigy,ify,1 ,jp+2,jp,lm, 1)

         do L=1,lm
         do j=1,jmm1
         qa(i,j+1,L)      =  qay(j,L)
         qa(i+imh,jm-j,L) = -qay(j+jmm1,L)
         enddo
         enddo

      enddo

         do L=1,lm
         do i=1,imh
         qa(i+imh,jm,L) = -qa(i,jm,L)
         qa(i,1,L)      = -qa(i+imh,1,L)
         enddo
         enddo
      endif

      return
      end


      subroutine rfftmlt (a,work,trigs,ifax,inc,jump,n,lot,isign) 28,16
      integer INC, JUMP, N, LOT, ISIGN
      real(kind=KIND(1.0)) A(N),WORK(N),TRIGS(N)
      integer IFAX(*)
!
!     SUBROUTINE "FFT991" - MULTIPLE REAL/HALF-COMPLEX PERIODIC
!     FAST FOURIER TRANSFORM
!
!     SAME AS FFT99 EXCEPT THAT ORDERING OF DATA CORRESPONDS TO
!     THAT IN MRFFT2
!
!     PROCEDURE USED TO CONVERT TO HALF-LENGTH COMPLEX TRANSFORM
!     IS GIVEN BY COOLEY, LEWIS AND WELCH (J. SOUND VIB., VOL. 12
!     (1970), 315-337)
!
!     A IS THE ARRAY CONTAINING INPUT AND OUTPUT DATA
!     WORK IS AN AREA OF SIZE (N+1)*LOT
!     TRIGS IS A PREVIOUSLY PREPARED LIST OF TRIG FUNCTION VALUES
!     IFAX IS A PREVIOUSLY PREPARED LIST OF FACTORS OF N/2
!     INC IS THE INCREMENT WITHIN EACH DATA 'VECTOR'
!         (E.G. INC=1 FOR CONSECUTIVELY STORED DATA)
!     JUMP IS THE INCREMENT BETWEEN THE START OF EACH DATA VECTOR
!     N IS THE LENGTH OF THE DATA VECTORS
!     LOT IS THE NUMBER OF DATA VECTORS
!     ISIGN = +1 FOR TRANSFORM FROM SPECTRAL TO GRIDPOINT
!           = -1 FOR TRANSFORM FROM GRIDPOINT TO SPECTRAL
!
!     ORDERING OF COEFFICIENTS:
!         A(0),B(0),A(1),B(1),A(2),B(2),...,A(N/2),B(N/2)
!         WHERE B(0)=B(N/2)=0; (N+2) LOCATIONS REQUIRED
!
!     ORDERING OF DATA:
!         X(0),X(1),X(2),...,X(N-1)
!
!     VECTORIZATION IS ACHIEVED ON CRAY BY DOING THE TRANSFORMS IN
!     PARALLEL
!
!     *** N.B. N IS ASSUMED TO BE AN EVEN NUMBER
!
!     DEFINITION OF TRANSFORMS:
!     -------------------------
!
!     ISIGN=+1: X(J)=SUM(K=0,...,N-1)(C(K)*EXP(2*I*J*K*PI/N))
!         WHERE C(K)=A(K)+I*B(K) AND C(N-K)=A(K)-I*B(K)
!
!     ISIGN=-1: A(K)=(1/N)*SUM(J=0,...,N-1)(X(J)*COS(2*J*K*PI/N))
!               B(K)=-(1/N)*SUM(J=0,...,N-1)(X(J)*SIN(2*J*K*PI/N))
!
! THE FOLLOWING CALL IS FOR MONITORING LIBRARY USE AT NCAR
!     CALL Q8QST4 ( 4HXLIB, 6HFFT99F, 6HFFT991, 10HVERSION 01)
!FPP$ NOVECTOR R
      integer NFAX, NH, NX, INK
      integer I, J, IBASE, JBASE, L, IGO, IA, LA, K, M, IB

      NFAX=IFAX(1)
      NX=N+1
      NH=N/2
      INK=INC+INC
      IF (ISIGN.EQ.+1) GO TO 30
!
!     IF NECESSARY, TRANSFER DATA TO WORK AREA
      IGO=50
      IF (MOD(NFAX,2).EQ.1) GOTO 40
      IBASE=1
      JBASE=1
      DO 20 L=1,LOT
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 10 M=1,N
      WORK(J)=A(I)
      I=I+INC
      J=J+1
   10 CONTINUE
      IBASE=IBASE+JUMP
      JBASE=JBASE+NX
   20 CONTINUE
!
      IGO=60
      GO TO 40
!
!     PREPROCESSING (ISIGN=+1)
!     ------------------------
!
   30 CONTINUE
      CALL FFT99A(A,WORK,TRIGS,INC,JUMP,N,LOT)
      IGO=60
!
!     COMPLEX TRANSFORM
!     -----------------
!
   40 CONTINUE
      IA=1
      LA=1
      DO 80 K=1,NFAX
      IF (IGO.EQ.60) GO TO 60
   50 CONTINUE
      CALL VPASSM(A(IA),A(IA+INC),WORK(1),WORK(2),TRIGS, 
     *    INK,2,JUMP,NX,LOT,NH,IFAX(K+1),LA)
      IGO=60
      GO TO 70
   60 CONTINUE
      CALL VPASSM(WORK(1),WORK(2),A(IA),A(IA+INC),TRIGS, 
     *     2,INK,NX,JUMP,LOT,NH,IFAX(K+1),LA)
      IGO=50
   70 CONTINUE
      LA=LA*IFAX(K+1)
   80 CONTINUE
!
      IF (ISIGN.EQ.-1) GO TO 130
!
!     IF NECESSARY, TRANSFER DATA FROM WORK AREA
      IF (MOD(NFAX,2).EQ.1) GO TO 110
      IBASE=1
      JBASE=1
      DO 100 L=1,LOT
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 90 M=1,N
      A(J)=WORK(I)
      I=I+1
      J=J+INC
   90 CONTINUE
      IBASE=IBASE+NX
      JBASE=JBASE+JUMP
  100 CONTINUE
!
!     FILL IN ZEROS AT END
  110 CONTINUE
      IB=N*INC+1
!DIR$ IVDEP
      DO 120 L=1,LOT
      A(IB)=0.0
      A(IB+INC)=0.0
      IB=IB+JUMP
  120 CONTINUE
      GO TO 140
!
!     POSTPROCESSING (ISIGN=-1):
!     --------------------------
!
  130 CONTINUE
      CALL FFT99B(WORK,A,TRIGS,INC,JUMP,N,LOT)
!
  140 CONTINUE
      RETURN
      END


      subroutine fftfax (n,ifax,trigs) 15,10
      integer IFAX(13)
      integer N
      REAL(kind=KIND(1.0))      TRIGS(*)
!
! MODE 3 IS USED FOR REAL/HALF-COMPLEX TRANSFORMS.  IT IS POSSIBLE
! TO DO COMPLEX/COMPLEX TRANSFORMS WITH OTHER VALUES OF MODE, BUT
! DOCUMENTATION OF THE DETAILS WERE NOT AVAILABLE WHEN THIS ROUTINE
! WAS WRITTEN.
!
      integer I, MODE
      DATA MODE /3/
!FPP$ NOVECTOR R
      CALL FAX (IFAX, N, MODE)
      I = IFAX(1)
      IF (IFAX(I+1) .GT. 5 .OR. N .LE. 4) IFAX(1) = -99
      IF (IFAX(1) .LE. 0 ) WRITE(6,FMT="(//5X, ' FFTFAX -- INVALID N =', I5,/)") N
      IF (IFAX(1) .LE. 0 ) STOP 999
      CALL FFTRIG (TRIGS, N, MODE)
      RETURN
      END


      subroutine fft99a (a,work,trigs,inc,jump,n,lot) 6,1
      integer inc, jump, N, lot
      real(kind=KIND(1.0)) A(N),WORK(N)
      REAL(kind=KIND(1.0)) TRIGS(N)
!
!     SUBROUTINE FFT99A - PREPROCESSING STEP FOR FFT99, ISIGN=+1
!     (SPECTRAL TO GRIDPOINT TRANSFORM)
!
!FPP$ NOVECTOR R
      integer NH, NX, INK, IA, IB, JA, JB, K, L
      integer IABASE, IBBASE, JABASE, JBBASE
      real(kind=KIND(1.0)) C, S
      NH=N/2
      NX=N+1
      INK=INC+INC
!
!     A(0) AND A(N/2)
      IA=1
      IB=N*INC+1
      JA=1
      JB=2
!DIR$ IVDEP
      DO 10 L=1,LOT
      WORK(JA)=A(IA)+A(IB)
      WORK(JB)=A(IA)-A(IB)
      IA=IA+JUMP
      IB=IB+JUMP
      JA=JA+NX
      JB=JB+NX
   10 CONTINUE
!
!     REMAINING WAVENUMBERS
      IABASE=2*INC+1
      IBBASE=(N-2)*INC+1
      JABASE=3
      JBBASE=N-1
!
      DO 30 K=3,NH,2
      IA=IABASE
      IB=IBBASE
      JA=JABASE
      JB=JBBASE
      C=TRIGS(N+K)
      S=TRIGS(N+K+1)
!DIR$ IVDEP
      DO 20 L=1,LOT
      WORK(JA)=(A(IA)+A(IB))- 
     *     (S*(A(IA)-A(IB))+C*(A(IA+INC)+A(IB+INC)))
      WORK(JB)=(A(IA)+A(IB))+ 
     *     (S*(A(IA)-A(IB))+C*(A(IA+INC)+A(IB+INC)))
      WORK(JA+1)=(C*(A(IA)-A(IB))-S*(A(IA+INC)+A(IB+INC)))+ 
     *     (A(IA+INC)-A(IB+INC))
      WORK(JB+1)=(C*(A(IA)-A(IB))-S*(A(IA+INC)+A(IB+INC)))- 
     *     (A(IA+INC)-A(IB+INC))
      IA=IA+JUMP
      IB=IB+JUMP
      JA=JA+NX
      JB=JB+NX
   20 CONTINUE
      IABASE=IABASE+INK
      IBBASE=IBBASE-INK
      JABASE=JABASE+2
      JBBASE=JBBASE-2
   30 CONTINUE
!
      IF (IABASE.NE.IBBASE) GO TO 50
!     WAVENUMBER N/4 (IF IT EXISTS)
      IA=IABASE
      JA=JABASE
!DIR$ IVDEP
      DO 40 L=1,LOT
      WORK(JA)=2.0*A(IA)
      WORK(JA+1)=-2.0*A(IA+INC)
      IA=IA+JUMP
      JA=JA+NX
   40 CONTINUE
!
   50 CONTINUE
      RETURN
      END


      subroutine fft99b (work,a,trigs,inc,jump,n,lot) 6,1
      integer INC, JUMP, N, LOT
      real(kind=KIND(1.0)) WORK(N),A(N)
      REAL(kind=KIND(1.0))      TRIGS(N)
      integer NH, NX, INK, IA, IB, JA, JB, K, L
      integer IABASE, IBBASE, JABASE, JBBASE
      real(kind=KIND(1.0)) SCALE
      real(kind=KIND(1.0)) C, S
!
!     SUBROUTINE FFT99B - POSTPROCESSING STEP FOR FFT99, ISIGN=-1
!     (GRIDPOINT TO SPECTRAL TRANSFORM)
!
!FPP$ NOVECTOR R
      NH=N/2
      NX=N+1
      INK=INC+INC
!
!     A(0) AND A(N/2)
      SCALE=1.0/FLOAT(N)
      IA=1
      IB=2
      JA=1
      JB=N*INC+1
!DIR$ IVDEP
      DO 10 L=1,LOT
      A(JA)=SCALE*(WORK(IA)+WORK(IB))
      A(JB)=SCALE*(WORK(IA)-WORK(IB))
      A(JA+INC)=0.0
      A(JB+INC)=0.0
      IA=IA+NX
      IB=IB+NX
      JA=JA+JUMP
      JB=JB+JUMP
   10 CONTINUE
!
!     REMAINING WAVENUMBERS
      SCALE=0.5*SCALE
      IABASE=3
      IBBASE=N-1
      JABASE=2*INC+1
      JBBASE=(N-2)*INC+1
!
      DO 30 K=3,NH,2
      IA=IABASE
      IB=IBBASE
      JA=JABASE
      JB=JBBASE
      C=TRIGS(N+K)
      S=TRIGS(N+K+1)
!DIR$ IVDEP
      DO 20 L=1,LOT
      A(JA)=SCALE*((WORK(IA)+WORK(IB)) 
     *    +(C*(WORK(IA+1)+WORK(IB+1))+S*(WORK(IA)-WORK(IB))))
      A(JB)=SCALE*((WORK(IA)+WORK(IB)) 
     *    -(C*(WORK(IA+1)+WORK(IB+1))+S*(WORK(IA)-WORK(IB))))
      A(JA+INC)=SCALE*((C*(WORK(IA)-WORK(IB))-S*(WORK(IA+1)+WORK(IB+1)))
     *     +(WORK(IB+1)-WORK(IA+1)))
      A(JB+INC)=SCALE*((C*(WORK(IA)-WORK(IB))-S*(WORK(IA+1)+WORK(IB+1)))
     *     -(WORK(IB+1)-WORK(IA+1)))
      IA=IA+NX
      IB=IB+NX
      JA=JA+JUMP
      JB=JB+JUMP
   20 CONTINUE
      IABASE=IABASE+2
      IBBASE=IBBASE-2
      JABASE=JABASE+INK
      JBBASE=JBBASE-INK
   30 CONTINUE
!
      IF (IABASE.NE.IBBASE) GO TO 50
!     WAVENUMBER N/4 (IF IT EXISTS)
      IA=IABASE
      JA=JABASE
      SCALE=2.0*SCALE
!DIR$ IVDEP
      DO 40 L=1,LOT
      A(JA)=SCALE*WORK(IA)
      A(JA+INC)=-SCALE*WORK(IA+1)
      IA=IA+NX
      JA=JA+JUMP
   40 CONTINUE
!
   50 CONTINUE
      RETURN
      END


      subroutine fax (ifax,n,mode) 5,1
      integer IFAX(10)
      integer N, MODE
!FPP$ NOVECTOR R
      integer NN, K, L, INC, II, ISTOP, ITEM, NFAX, I
      NN=N
      IF (IABS(MODE).EQ.1) GO TO 10
      IF (IABS(MODE).EQ.8) GO TO 10
      NN=N/2
      IF ((NN+NN).EQ.N) GO TO 10
      IFAX(1)=-99
      RETURN
   10 K=1
!     TEST FOR FACTORS OF 4
   20 IF (MOD(NN,4).NE.0) GO TO 30
      K=K+1
      IFAX(K)=4
      NN=NN/4
      IF (NN.EQ.1) GO TO 80
      GO TO 20
!     TEST FOR EXTRA FACTOR OF 2
   30 IF (MOD(NN,2).NE.0) GO TO 40
      K=K+1
      IFAX(K)=2
      NN=NN/2
      IF (NN.EQ.1) GO TO 80
!     TEST FOR FACTORS OF 3
   40 IF (MOD(NN,3).NE.0) GO TO 50
      K=K+1
      IFAX(K)=3
      NN=NN/3
      IF (NN.EQ.1) GO TO 80
      GO TO 40
!     NOW FIND REMAINING FACTORS
   50 L=5
      INC=2
!     INC ALTERNATELY TAKES ON VALUES 2 AND 4
   60 IF (MOD(NN,L).NE.0) GO TO 70
      K=K+1
      IFAX(K)=L
      NN=NN/L
      IF (NN.EQ.1) GO TO 80
      GO TO 60
   70 L=L+INC
      INC=6-INC
      GO TO 60
   80 IFAX(1)=K-1
!     IFAX(1) CONTAINS NUMBER OF FACTORS
      NFAX=IFAX(1)
!     SORT FACTORS INTO ASCENDING ORDER
      IF (NFAX.EQ.1) GO TO 110
      DO 100 II=2,NFAX
      ISTOP=NFAX+2-II
      DO 90 I=2,ISTOP
      IF (IFAX(I+1).GE.IFAX(I)) GO TO 90
      ITEM=IFAX(I)
      IFAX(I)=IFAX(I+1)
      IFAX(I+1)=ITEM
   90 CONTINUE
  100 CONTINUE
  110 CONTINUE
      RETURN
      END


      subroutine fftrig (trigs,n,mode) 5,1
      REAL(kind=KIND(1.0))      TRIGS(*)
      integer N, MODE
!FPP$ NOVECTOR R
      real(kind=KIND(1.0)) PI
      integer IMODE, NN, L, I, NH, LA
      real(kind=KIND(1.0)) DEL, ANGLE
      PI=2.0*ASIN(1.0)
      IMODE=IABS(MODE)
      NN=N
      IF (IMODE.GT.1.AND.IMODE.LT.6) NN=N/2
      DEL=(PI+PI)/FLOAT(NN)
      L=NN+NN
      DO 10 I=1,L,2
      ANGLE=0.5*FLOAT(I-1)*DEL
      TRIGS(I)=COS(ANGLE)
      TRIGS(I+1)=SIN(ANGLE)
   10 CONTINUE
      IF (IMODE.EQ.1) RETURN
      IF (IMODE.EQ.8) RETURN
      DEL=0.5*DEL
      NH=(NN+1)/2
      L=NH+NH
      LA=NN+NN
      DO 20 I=1,L,2
      ANGLE=0.5*FLOAT(I-1)*DEL
      TRIGS(LA+I)=COS(ANGLE)
      TRIGS(LA+I+1)=SIN(ANGLE)
   20 CONTINUE
      IF (IMODE.LE.3) RETURN
      DEL=0.5*DEL
      LA=LA+NN
      IF (MODE.EQ.5) GO TO 40
      DO 30 I=2,NN
      ANGLE=FLOAT(I-1)*DEL
      TRIGS(LA+I)=2.0*SIN(ANGLE)
   30 CONTINUE
      RETURN
   40 CONTINUE
      DEL=0.5*DEL
      DO 50 I=2,N
      ANGLE=FLOAT(I-1)*DEL
      TRIGS(LA+I)=SIN(ANGLE)
   50 CONTINUE
      RETURN
      END


      subroutine vpassm (a,b,c,d,trigs,inc1,inc2,inc3,inc4,lot,n,ifac,la) 12,1
      integer INC1,INC2,INC3,INC4,LOT,N,IFAC,LA
      real(kind=KIND(1.0)) A(N),B(N),C(N),D(N)
      REAL(kind=KIND(1.0))      TRIGS(N)
!
!     SUBROUTINE "VPASSM" - MULTIPLE VERSION OF "VPASSA"
!     PERFORMS ONE PASS THROUGH DATA
!     AS PART OF MULTIPLE COMPLEX FFT ROUTINE
!     A IS FIRST REAL INPUT VECTOR
!     B IS FIRST IMAGINARY INPUT VECTOR
!     C IS FIRST REAL OUTPUT VECTOR
!     D IS FIRST IMAGINARY OUTPUT VECTOR
!     TRIGS IS PRECALCULATED TABLE OF SINES & COSINES
!     INC1 IS ADDRESSING INCREMENT FOR A AND B
!     INC2 IS ADDRESSING INCREMENT FOR C AND D
!     INC3 IS ADDRESSING INCREMENT BETWEEN As & Bs
!     INC4 IS ADDRESSING INCREMENT BETWEEN Cs & Ds
!     LOT IS THE NUMBER OF VECTORS
!     N IS LENGTH OF VECTORS
!     IFAC IS CURRENT FACTOR OF N
!     LA IS PRODUCT OF PREVIOUS FACTORS
!
      real(kind=KIND(1.0)) SIN36, COS36, SIN72, COS72, SIN60
      DATA SIN36/0.587785252292473/,COS36/0.809016994374947/, 
     *      SIN72/0.951056516295154/,COS72/0.309016994374947/,
     *      SIN60/0.866025403784437/
      integer M, IINK, JINK, JUMP, IBASE, JBASE, IGO, IA, JA, IB, JB
      integer IC, JC, ID, JD, IE, JE
      integer I, J, K, L, IJK, LA1, KB, KC, KD, KE
      real(kind=KIND(1.0)) C1, S1, C2, S2, C3, S3, C4, S4
!
!FPP$ NOVECTOR R
      M=N/IFAC
      IINK=M*INC1
      JINK=LA*INC2
      JUMP=(IFAC-1)*JINK
      IBASE=0
      JBASE=0
      IGO=IFAC-1
      IF (IGO.GT.4) RETURN
      GO TO (10,50,90,130),IGO
!
!     CODING FOR FACTOR 2
!
   10 IA=1
      JA=1
      IB=IA+IINK
      JB=JA+JINK
      DO 20 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 15 IJK=1,LOT
      C(JA+J)=A(IA+I)+A(IB+I)
      D(JA+J)=B(IA+I)+B(IB+I)
      C(JB+J)=A(IA+I)-A(IB+I)
      D(JB+J)=B(IA+I)-B(IB+I)
      I=I+INC3
      J=J+INC4
   15 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
   20 CONTINUE
      IF (LA.EQ.M) RETURN
      LA1=LA+1
      JBASE=JBASE+JUMP
      DO 40 K=LA1,M,LA
      KB=K+K-2
      C1=TRIGS(KB+1)
      S1=TRIGS(KB+2)
      DO 30 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 25 IJK=1,LOT
      C(JA+J)=A(IA+I)+A(IB+I)
      D(JA+J)=B(IA+I)+B(IB+I)
      C(JB+J)=C1*(A(IA+I)-A(IB+I))-S1*(B(IA+I)-B(IB+I))
      D(JB+J)=S1*(A(IA+I)-A(IB+I))+C1*(B(IA+I)-B(IB+I))
      I=I+INC3
      J=J+INC4
   25 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
   30 CONTINUE
      JBASE=JBASE+JUMP
   40 CONTINUE
      RETURN
!
!     CODING FOR FACTOR 3
!
   50 IA=1
      JA=1
      IB=IA+IINK
      JB=JA+JINK
      IC=IB+IINK
      JC=JB+JINK
      DO 60 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 55 IJK=1,LOT
      C(JA+J)=A(IA+I)+(A(IB+I)+A(IC+I))
      D(JA+J)=B(IA+I)+(B(IB+I)+B(IC+I))
      C(JB+J)=(A(IA+I)-0.5*(A(IB+I)+A(IC+I)))-(SIN60*(B(IB+I)-B(IC+I)))
      C(JC+J)=(A(IA+I)-0.5*(A(IB+I)+A(IC+I)))+(SIN60*(B(IB+I)-B(IC+I)))
      D(JB+J)=(B(IA+I)-0.5*(B(IB+I)+B(IC+I)))+(SIN60*(A(IB+I)-A(IC+I)))
      D(JC+J)=(B(IA+I)-0.5*(B(IB+I)+B(IC+I)))-(SIN60*(A(IB+I)-A(IC+I)))
      I=I+INC3
      J=J+INC4
   55 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
   60 CONTINUE
      IF (LA.EQ.M) RETURN
      LA1=LA+1
      JBASE=JBASE+JUMP
      DO 80 K=LA1,M,LA
      KB=K+K-2
      KC=KB+KB
      C1=TRIGS(KB+1)
      S1=TRIGS(KB+2)
      C2=TRIGS(KC+1)
      S2=TRIGS(KC+2)
      DO 70 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 65 IJK=1,LOT
      C(JA+J)=A(IA+I)+(A(IB+I)+A(IC+I))
      D(JA+J)=B(IA+I)+(B(IB+I)+B(IC+I))
      C(JB+J)= 
     *     C1*((A(IA+I)-0.5*(A(IB+I)+A(IC+I)))-(SIN60*(B(IB+I)-B(IC+I)))) 
     *    -S1*((B(IA+I)-0.5*(B(IB+I)+B(IC+I)))+(SIN60*(A(IB+I)-A(IC+I))))
      D(JB+J)= 
     *     S1*((A(IA+I)-0.5*(A(IB+I)+A(IC+I)))-(SIN60*(B(IB+I)-B(IC+I)))) 
     *    +C1*((B(IA+I)-0.5*(B(IB+I)+B(IC+I)))+(SIN60*(A(IB+I)-A(IC+I))))
      C(JC+J)= 
     *     C2*((A(IA+I)-0.5*(A(IB+I)+A(IC+I)))+(SIN60*(B(IB+I)-B(IC+I)))) 
     *    -S2*((B(IA+I)-0.5*(B(IB+I)+B(IC+I)))-(SIN60*(A(IB+I)-A(IC+I))))
      D(JC+J)= 
     *     S2*((A(IA+I)-0.5*(A(IB+I)+A(IC+I)))+(SIN60*(B(IB+I)-B(IC+I)))) 
     *    +C2*((B(IA+I)-0.5*(B(IB+I)+B(IC+I)))-(SIN60*(A(IB+I)-A(IC+I))))
      I=I+INC3
      J=J+INC4
   65 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
   70 CONTINUE
      JBASE=JBASE+JUMP
   80 CONTINUE
      RETURN
!
!     CODING FOR FACTOR 4
!
   90 IA=1
      JA=1
      IB=IA+IINK
      JB=JA+JINK
      IC=IB+IINK
      JC=JB+JINK
      ID=IC+IINK
      JD=JC+JINK
      DO 100 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 95 IJK=1,LOT
      C(JA+J)=(A(IA+I)+A(IC+I))+(A(IB+I)+A(ID+I))
      C(JC+J)=(A(IA+I)+A(IC+I))-(A(IB+I)+A(ID+I))
      D(JA+J)=(B(IA+I)+B(IC+I))+(B(IB+I)+B(ID+I))
      D(JC+J)=(B(IA+I)+B(IC+I))-(B(IB+I)+B(ID+I))
      C(JB+J)=(A(IA+I)-A(IC+I))-(B(IB+I)-B(ID+I))
      C(JD+J)=(A(IA+I)-A(IC+I))+(B(IB+I)-B(ID+I))
      D(JB+J)=(B(IA+I)-B(IC+I))+(A(IB+I)-A(ID+I))
      D(JD+J)=(B(IA+I)-B(IC+I))-(A(IB+I)-A(ID+I))
      I=I+INC3
      J=J+INC4
   95 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
  100 CONTINUE
      IF (LA.EQ.M) RETURN
      LA1=LA+1
      JBASE=JBASE+JUMP
      DO 120 K=LA1,M,LA
      KB=K+K-2
      KC=KB+KB
      KD=KC+KB
      C1=TRIGS(KB+1)
      S1=TRIGS(KB+2)
      C2=TRIGS(KC+1)
      S2=TRIGS(KC+2)
      C3=TRIGS(KD+1)
      S3=TRIGS(KD+2)
      DO 110 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 105 IJK=1,LOT
      C(JA+J)=(A(IA+I)+A(IC+I))+(A(IB+I)+A(ID+I))
      D(JA+J)=(B(IA+I)+B(IC+I))+(B(IB+I)+B(ID+I))
      C(JC+J)= 
     *     C2*((A(IA+I)+A(IC+I))-(A(IB+I)+A(ID+I))) 
     *    -S2*((B(IA+I)+B(IC+I))-(B(IB+I)+B(ID+I)))
      D(JC+J)= 
     *     S2*((A(IA+I)+A(IC+I))-(A(IB+I)+A(ID+I))) 
     *    +C2*((B(IA+I)+B(IC+I))-(B(IB+I)+B(ID+I)))
      C(JB+J)= 
     *     C1*((A(IA+I)-A(IC+I))-(B(IB+I)-B(ID+I))) 
     *    -S1*((B(IA+I)-B(IC+I))+(A(IB+I)-A(ID+I)))
      D(JB+J)= 
     *     S1*((A(IA+I)-A(IC+I))-(B(IB+I)-B(ID+I))) 
     *    +C1*((B(IA+I)-B(IC+I))+(A(IB+I)-A(ID+I)))
      C(JD+J)= 
     *     C3*((A(IA+I)-A(IC+I))+(B(IB+I)-B(ID+I))) 
     *    -S3*((B(IA+I)-B(IC+I))-(A(IB+I)-A(ID+I)))
      D(JD+J)= 
     *     S3*((A(IA+I)-A(IC+I))+(B(IB+I)-B(ID+I))) 
     *    +C3*((B(IA+I)-B(IC+I))-(A(IB+I)-A(ID+I)))
      I=I+INC3
      J=J+INC4
  105 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
  110 CONTINUE
      JBASE=JBASE+JUMP
  120 CONTINUE
      RETURN
!
!     CODING FOR FACTOR 5
!
  130 IA=1
      JA=1
      IB=IA+IINK
      JB=JA+JINK
      IC=IB+IINK
      JC=JB+JINK
      ID=IC+IINK
      JD=JC+JINK
      IE=ID+IINK
      JE=JD+JINK
      DO 140 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 135 IJK=1,LOT
      C(JA+J)=A(IA+I)+(A(IB+I)+A(IE+I))+(A(IC+I)+A(ID+I))
      D(JA+J)=B(IA+I)+(B(IB+I)+B(IE+I))+(B(IC+I)+B(ID+I))
      C(JB+J)=(A(IA+I)+COS72*(A(IB+I)+A(IE+I))-COS36*(A(IC+I)+A(ID+I))) 
     *   -(SIN72*(B(IB+I)-B(IE+I))+SIN36*(B(IC+I)-B(ID+I)))
      C(JE+J)=(A(IA+I)+COS72*(A(IB+I)+A(IE+I))-COS36*(A(IC+I)+A(ID+I))) 
     *   +(SIN72*(B(IB+I)-B(IE+I))+SIN36*(B(IC+I)-B(ID+I)))
      D(JB+J)=(B(IA+I)+COS72*(B(IB+I)+B(IE+I))-COS36*(B(IC+I)+B(ID+I))) 
     *   +(SIN72*(A(IB+I)-A(IE+I))+SIN36*(A(IC+I)-A(ID+I)))
      D(JE+J)=(B(IA+I)+COS72*(B(IB+I)+B(IE+I))-COS36*(B(IC+I)+B(ID+I))) 
     *   -(SIN72*(A(IB+I)-A(IE+I))+SIN36*(A(IC+I)-A(ID+I)))
      C(JC+J)=(A(IA+I)-COS36*(A(IB+I)+A(IE+I))+COS72*(A(IC+I)+A(ID+I))) 
     *   -(SIN36*(B(IB+I)-B(IE+I))-SIN72*(B(IC+I)-B(ID+I)))
      C(JD+J)=(A(IA+I)-COS36*(A(IB+I)+A(IE+I))+COS72*(A(IC+I)+A(ID+I))) 
     *   +(SIN36*(B(IB+I)-B(IE+I))-SIN72*(B(IC+I)-B(ID+I)))
      D(JC+J)=(B(IA+I)-COS36*(B(IB+I)+B(IE+I))+COS72*(B(IC+I)+B(ID+I))) 
     *   +(SIN36*(A(IB+I)-A(IE+I))-SIN72*(A(IC+I)-A(ID+I)))
      D(JD+J)=(B(IA+I)-COS36*(B(IB+I)+B(IE+I))+COS72*(B(IC+I)+B(ID+I))) 
     *   -(SIN36*(A(IB+I)-A(IE+I))-SIN72*(A(IC+I)-A(ID+I)))
      I=I+INC3
      J=J+INC4
  135 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
  140 CONTINUE
      IF (LA.EQ.M) RETURN
      LA1=LA+1
      JBASE=JBASE+JUMP
      DO 160 K=LA1,M,LA
      KB=K+K-2
      KC=KB+KB
      KD=KC+KB
      KE=KD+KB
      C1=TRIGS(KB+1)
      S1=TRIGS(KB+2)
      C2=TRIGS(KC+1)
      S2=TRIGS(KC+2)
      C3=TRIGS(KD+1)
      S3=TRIGS(KD+2)
      C4=TRIGS(KE+1)
      S4=TRIGS(KE+2)
      DO 150 L=1,LA
      I=IBASE
      J=JBASE
!DIR$ IVDEP
      DO 145 IJK=1,LOT
      C(JA+J)=A(IA+I)+(A(IB+I)+A(IE+I))+(A(IC+I)+A(ID+I))
      D(JA+J)=B(IA+I)+(B(IB+I)+B(IE+I))+(B(IC+I)+B(ID+I))
      C(JB+J)= 
     *     C1*((A(IA+I)+COS72*(A(IB+I)+A(IE+I))-COS36*(A(IC+I)+A(ID+I))) 
     *       -(SIN72*(B(IB+I)-B(IE+I))+SIN36*(B(IC+I)-B(ID+I)))) 
     *    -S1*((B(IA+I)+COS72*(B(IB+I)+B(IE+I))-COS36*(B(IC+I)+B(ID+I))) 
     *       +(SIN72*(A(IB+I)-A(IE+I))+SIN36*(A(IC+I)-A(ID+I))))
      D(JB+J)= 
     *     S1*((A(IA+I)+COS72*(A(IB+I)+A(IE+I))-COS36*(A(IC+I)+A(ID+I))) 
     *       -(SIN72*(B(IB+I)-B(IE+I))+SIN36*(B(IC+I)-B(ID+I)))) 
     *    +C1*((B(IA+I)+COS72*(B(IB+I)+B(IE+I))-COS36*(B(IC+I)+B(ID+I))) 
     *       +(SIN72*(A(IB+I)-A(IE+I))+SIN36*(A(IC+I)-A(ID+I))))
      C(JE+J)= 
     *     C4*((A(IA+I)+COS72*(A(IB+I)+A(IE+I))-COS36*(A(IC+I)+A(ID+I))) 
     *       +(SIN72*(B(IB+I)-B(IE+I))+SIN36*(B(IC+I)-B(ID+I)))) 
     *    -S4*((B(IA+I)+COS72*(B(IB+I)+B(IE+I))-COS36*(B(IC+I)+B(ID+I))) 
     *       -(SIN72*(A(IB+I)-A(IE+I))+SIN36*(A(IC+I)-A(ID+I))))
      D(JE+J)= 
     *     S4*((A(IA+I)+COS72*(A(IB+I)+A(IE+I))-COS36*(A(IC+I)+A(ID+I))) 
     *       +(SIN72*(B(IB+I)-B(IE+I))+SIN36*(B(IC+I)-B(ID+I)))) 
     *    +C4*((B(IA+I)+COS72*(B(IB+I)+B(IE+I))-COS36*(B(IC+I)+B(ID+I))) 
     *       -(SIN72*(A(IB+I)-A(IE+I))+SIN36*(A(IC+I)-A(ID+I))))
      C(JC+J)= 
     *     C2*((A(IA+I)-COS36*(A(IB+I)+A(IE+I))+COS72*(A(IC+I)+A(ID+I))) 
     *       -(SIN36*(B(IB+I)-B(IE+I))-SIN72*(B(IC+I)-B(ID+I)))) 
     *    -S2*((B(IA+I)-COS36*(B(IB+I)+B(IE+I))+COS72*(B(IC+I)+B(ID+I))) 
     *       +(SIN36*(A(IB+I)-A(IE+I))-SIN72*(A(IC+I)-A(ID+I))))
      D(JC+J)= 
     *     S2*((A(IA+I)-COS36*(A(IB+I)+A(IE+I))+COS72*(A(IC+I)+A(ID+I))) 
     *       -(SIN36*(B(IB+I)-B(IE+I))-SIN72*(B(IC+I)-B(ID+I)))) 
     *    +C2*((B(IA+I)-COS36*(B(IB+I)+B(IE+I))+COS72*(B(IC+I)+B(ID+I))) 
     *       +(SIN36*(A(IB+I)-A(IE+I))-SIN72*(A(IC+I)-A(ID+I))))
      C(JD+J)= 
     *     C3*((A(IA+I)-COS36*(A(IB+I)+A(IE+I))+COS72*(A(IC+I)+A(ID+I))) 
     *       +(SIN36*(B(IB+I)-B(IE+I))-SIN72*(B(IC+I)-B(ID+I)))) 
     *    -S3*((B(IA+I)-COS36*(B(IB+I)+B(IE+I))+COS72*(B(IC+I)+B(ID+I))) 
     *       -(SIN36*(A(IB+I)-A(IE+I))-SIN72*(A(IC+I)-A(ID+I))))
      D(JD+J)= 
     *     S3*((A(IA+I)-COS36*(A(IB+I)+A(IE+I))+COS72*(A(IC+I)+A(ID+I))) 
     *       +(SIN36*(B(IB+I)-B(IE+I))-SIN72*(B(IC+I)-B(ID+I)))) 
     *    +C3*((B(IA+I)-COS36*(B(IB+I)+B(IE+I))+COS72*(B(IC+I)+B(ID+I))) 
     *       -(SIN36*(A(IB+I)-A(IE+I))-SIN72*(A(IC+I)-A(ID+I))))
      I=I+INC3
      J=J+INC4
  145 CONTINUE
      IBASE=IBASE+INC1
      JBASE=JBASE+INC2
  150 CONTINUE
      JBASE=JBASE+JUMP
  160 CONTINUE
      RETURN
      END


      subroutine bin ( qin,im_in,jm_in,qout,im_out,jm_out,lm,undef,msgn,lat_i,lat_o ) 52,40
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lat_i
      type ( dynamics_lattice_type ) lat_o

#ifdef mpi
      include 'mpif.h'
#endif
      integer  comm,myid,npes
      integer  imgi,jmgi,imgo,jmgo

      integer   im_in ,jm_in ,msgn, lm
      integer   im_out,jm_out, L
      real      undef
      real    qin(im_in ,jm_in ,lm)
      real   qout(im_out,jm_out,lm)

      real, allocatable :: glo_i(:,:,:)
      real, allocatable :: glo_o(:,:,:)

c Temporary Array for Binning
c ---------------------------
      integer     imax
      integer     jmax
      parameter ( imax = 360*12 )
      parameter ( jmax = 180*12 )
      real qbin ( imax,jmax )

      integer index(lm),ierror
 
      call timebeg (' bin')

      comm = lat_i%comm
      myid = lat_i%myid
      npes = lat_i%nx * lat_i%ny

      imgi = lat_i%imglobal
      jmgi = lat_i%jmglobal
      imgo = lat_o%imglobal
      jmgo = lat_o%jmglobal

      allocate ( glo_i(imgi,jmgi,lm) )
      allocate ( glo_o(imgo,jmgo,lm) )

      call timebeg ('   Gather')
      do L=1,lm
      call gather_2d ( glo_i(1,1,L),qin(1,1,L),lat_i )
      enddo
      call timeend ('   Gather')
#ifdef mpi
      call mpi_bcast ( glo_i,imgi*jmgi*lm,lat_i%mpi_rkind,0,comm,ierror )
#endif

      do L=1,lm
      index(L) = mod(L-1,npes)
      enddo

      do L=1,lm
c Parse Arbitray Field (im,jm) to 5'x5' Variable
c ----------------------------------------------
      call timebeg ('  bin_q')
      if( index(L).eq.myid ) call bin_q ( glo_i(1,1,L),imgi,jmgi,qbin,imax,jmax )
      call timeend ('  bin_q')
 
c Bin 10'x10' Variable to Output Field (im_out,jm_out)
c ----------------------------------------------------
      call timebeg ('  ave_q')
      if( index(L).eq.myid ) call ave_q ( qbin,imax,jmax,glo_o(1,1,L),imgo,jmgo,undef,msgn )
      call timeend ('  ave_q')
      enddo

#ifdef mpi
      call mpi_barrier (comm,ierror)
      do L=1,lm
      call mpi_bcast ( glo_o(1,1,L),imgo*jmgo,lat_o%mpi_rkind,index(L),comm,ierror )
      enddo
      call mpi_barrier (comm,ierror)
#endif
      call timebeg ('   Scatter')
      do L=1,lm
      call scatter_2d ( glo_o(1,1,L),qout(1,1,L),lat_o )
      enddo
      call timeend ('   Scatter')

      deallocate ( glo_i )
      deallocate ( glo_o )

      call timeend (' bin')

      return
      end


      subroutine ave_q ( qbin,imax,jmax,q,im,jm,undef,msgn ) 2,22
C***********************************************************************
C
C  PURPOSE:
C  ========
C    Average a (10m X 10m) input array to an output array (im,jm)
C
C  INPUT:
C  ======
C    qbin ....... Input array (imax,jmax)
C    msgn ....... Integer Flag for scalar (0) or vector (1)
C
C  OUTPUT:
C  =======
C    q .......... Output array (im,jm)
C    im ......... Longitudinal dimension of q
C    jm ......... Latitudinal  dimension of q
C
C  NOTES:
C  ======
C    Input array qbin represents values within a 5min X 5min grid-box.
C             Each box is referenced by the latitude and longitude of
C             its southwest corner, not its center point.  Thus,
C             the quantity associated with a coordinate actually
C             represents the quantity centered to the northeast of that point.
C
C    Output array q(im,jm) is assumed to be on an A-grid.
C                 q(i,j)   represents the value at the center of the grid-box.
C                 q(1,j)   is located at lon=-180.
C                 q(i,1)   is located at lat=-90.
C                 q(i,jm)  is located at lat=+90.
C
C***********************************************************************
C*                  GODDARD LABORATORY FOR ATMOSPHERES                 *
C***********************************************************************

      implicit none
      integer im,jm,msgn
      real  q(im,jm)
      real  dlam(im), dphi(jm)

      integer     imax
      integer     jmax
      real qbin ( imax,jmax )

      integer i,j,ibeg,iend,jbeg,jend
      integer ii,jj,itmp
      real    sum1,sum2
      real    zlat,zlon
      real    lon1,lon2,wx
      real    lat1,lat2,wy
      real    lonbeg,lonend,lat,coslat
      real    latbeg,latend
      real    undef 
      real    pi,dz 
      real    lon_cmp(im)
      real    lat_cmp(jm)
      logical defined

      pi   = 4.*atan(1.0)
      dlam = 2*pi/ im
      dphi =   pi/(jm-1)
      dz   =   pi/(jmax)

c Compute Computational Lambda's and Phi's
c ----------------------------------------
      lon_cmp(1) = -pi
      do i=2,im
      lon_cmp(i) = lon_cmp(i-1) + dlam(i-1)
      enddo
      lat_cmp(1) = -pi*0.5
      do j=2,jm-1
      lat_cmp(j) = lat_cmp(j-1) + dphi(j-1)
      enddo
      lat_cmp(jm) =  pi*0.5


c Compute average away from poles
c -------------------------------
      do j=2,jm-1
      do i=1,im

      zlat = lat_cmp(j)
      zlon = lon_cmp(i)

      latbeg = zlat-dphi(j-1)/2
      latend = zlat+dphi(j)  /2
      if( i.eq.1 ) then
      lonbeg = zlon-dlam(im) /2
      else
      lonbeg = zlon-dlam(i-1)/2
      endif
      lonend = zlon+dlam(i)  /2
      
      ibeg = 1.+(lonbeg+pi)  /dz
      iend = 1.+(lonend+pi)  /dz
      jbeg = 1.+(latbeg+pi/2)/dz
      jend = 1.+(latend+pi/2)/dz

      sum1 = 0
      sum2 = 0
      do jj=jbeg,jend
      lat = -pi/2+(jj-0.5)*dz
      coslat = cos(lat)
      lat1 = -pi/2  + (jj-1)*dz
      lat2 = -pi/2  +  jj   *dz
                           wy = 1.0
      if( lat1.lt.latbeg ) wy = (lat2-latbeg)/dz
      if( lat2.gt.latend ) wy = (latend-lat1)/dz

         if(ibeg.ge.1) then
           do ii=ibeg,iend
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                wx = 1.0
           if( lon1.lt.lonbeg ) wx = (lon2-lonbeg)/dz
           if( lon2.gt.lonend ) wx = (lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
         else
                 itmp = 1.+(lonbeg+0.1*dz+3*pi)/dz
           do ii=itmp,imax
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                     wx = 1.0
           if( lon1.lt.lonbeg+2*pi ) wx = (lon2-lonbeg-2*pi)/dz
           if( lon2.gt.lonend+2*pi ) wx = (2*pi+lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
           do ii=1,iend
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                wx = 1.0
           if( lon1.lt.lonbeg ) wx = (lon2-lonbeg)/dz
           if( lon2.gt.lonend ) wx = (lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
         endif

      enddo
      q(i,j) = sum1/sum2
      enddo
      enddo

c Compute average at South Pole
c -----------------------------
         j=1
      do i=1,im

      zlat = lat_cmp(j)
      zlon = lon_cmp(i)

      latbeg = zlat
      latend = zlat+dphi(j)  /2
      if( i.eq.1 ) then
      lonbeg = zlon-dlam(im) /2
      else
      lonbeg = zlon-dlam(i-1)/2
      endif
      lonend = zlon+dlam(i)  /2
      
      ibeg = 1.+(lonbeg+pi)  /dz
      iend = 1.+(lonend+pi)  /dz
      jbeg = 1
      jend = 1.+(latend+pi/2)/dz

      sum1 = 0
      sum2 = 0
      do jj=jbeg,jend
      lat = -pi/2+(jj-0.5)*dz
      coslat = cos(lat)
      lat1 = -pi/2  + (jj-1)*dz
      lat2 = -pi/2  +  jj   *dz
                           wy = 1.0
      if( lat1.lt.latbeg ) wy = (lat2-latbeg)/dz
      if( lat2.gt.latend ) wy = (latend-lat1)/dz

         if(ibeg.ge.1) then
           do ii=ibeg,iend
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                wx = 1.0
           if( lon1.lt.lonbeg ) wx = (lon2-lonbeg)/dz
           if( lon2.gt.lonend ) wx = (lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
         else
                 itmp = 1.+(lonbeg+0.1*dz+3*pi)/dz
           do ii=itmp,imax
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                     wx = 1.0
           if( lon1.lt.lonbeg+2*pi ) wx = (lon2-lonbeg-2*pi)/dz
           if( lon2.gt.lonend+2*pi ) wx = (2*pi+lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
           do ii=1,iend
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                wx = 1.0
           if( lon1.lt.lonbeg ) wx = (lon2-lonbeg)/dz
           if( lon2.gt.lonend ) wx = (lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
         endif

      enddo
      q(i,j) = sum1/sum2
      enddo

c Compute average at North Pole
c -----------------------------
         j=jm
      do i=1,im

      zlat = lat_cmp(j)
      zlon = lon_cmp(i)

      latbeg = zlat-dphi(j-1)/2
      latend = zlat
      if( i.eq.1 ) then
      lonbeg = zlon-dlam(im) /2
      else
      lonbeg = zlon-dlam(i-1)/2
      endif
      lonend = zlon+dlam(i)  /2
      
      ibeg = 1.+(lonbeg+pi)  /dz
      iend = 1.+(lonend+pi)  /dz
      jbeg = 1.+(latbeg+pi/2)/dz
      jend = jmax

      sum1 = 0
      sum2 = 0
      do jj=jbeg,jend
      lat = -pi/2+(jj-0.5)*dz
      coslat = cos(lat)
      lat1 = -pi/2  + (jj-1)*dz
      lat2 = -pi/2  +  jj   *dz
                           wy = 1.0
      if( lat1.lt.latbeg ) wy = (lat2-latbeg)/dz
      if( lat2.gt.latend ) wy = (latend-lat1)/dz

         if(ibeg.ge.1) then
           do ii=ibeg,iend
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                wx = 1.0
           if( lon1.lt.lonbeg ) wx = (lon2-lonbeg)/dz
           if( lon2.gt.lonend ) wx = (lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
         else
                 itmp = 1.+(lonbeg+0.1*dz+3*pi)/dz
           do ii=itmp,imax
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                     wx = 1.0
           if( lon1.lt.lonbeg+2*pi ) wx = (lon2-lonbeg-2*pi)/dz
           if( lon2.gt.lonend+2*pi ) wx = (2*pi+lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
           do ii=1,iend
           if( defined(qbin(ii,jj),undef) ) then
           lon1 = -pi  + (ii-1)*dz
           lon2 = -pi  +  ii   *dz
                                wx = 1.0
           if( lon1.lt.lonbeg ) wx = (lon2-lonbeg)/dz
           if( lon2.gt.lonend ) wx = (lonend-lon1)/dz
           sum1 = sum1 + qbin(ii,jj)*coslat*wx*wy
           sum2 = sum2 +             coslat*wx*wy
           endif
           enddo
         endif

      enddo
      q(i,j) = sum1/sum2
      enddo

c Average Pole Values
c -------------------
      if( msgn.eq.0 ) then
      sum1 = 0
         j = 0
      do i=1,im
         if( defined(q(i,1),undef) ) then
             sum1 = sum1 + q(i,1)
                j = j + 1
         endif
      enddo
      if( j.ne.0 ) then
      q(:,1) = sum1/j
      else
      q(:,1) = undef
      endif

      sum2 = 0
         j = 0
      do i=1,im
         if( defined(q(i,jm),undef) ) then
             sum2 = sum2 + q(i,jm)
                j = j + 1
         endif
      enddo
      if( j.ne.0 ) then
      q(:,jm) = sum2/j
      else
      q(:,jm) = undef
      endif

      endif

      return
      end

      subroutine bin_q ( q,im,jm,qbin,imax,jmax ) 2
C***********************************************************************
C
C  PURPOSE:
C  ========
C    Compute a 5min X 5min binned array from an input array q(im,jm)
C
C  INPUT:
C  ======
C    q .......... Input array(im,jm)
C    im ......... Longitudinal dimension of q
C    jm ......... Latitudinal  dimension of q
C
C  OUTPUT:
C  =======
C    qbin ....... Output array (imax,jmax)
C
C  NOTES:
C  ======
C    Input array q(im,jm) is assumed to be on an A-grid.
C                q(i,j)   represents the value at the center of the grid-box.
C                q(1,j)   is located at lon=-180.
C                q(i,1)   is located at lat=-90.
C                q(i,jm)  is located at lat=+90.
C
C    Output array qbin represents values within a 5min X 5min grid-box.
C             Each box is referenced by the latitude and longitude of
C             its southwest corner, not its center point.  Thus,
C             the quantity associated with a coordinate actually
C             represents the quantity centered to the northeast of that point.
C
C***********************************************************************
C*                  GODDARD LABORATORY FOR ATMOSPHERES                 *
C***********************************************************************

      implicit none
      integer im,jm
      real  q(im,jm)

      integer     imax
      integer     jmax
      real qbin ( imax,jmax )

      integer i,j,ii,jj,ibeg,iend,jbeg,jend
      real    zlatc,zlonc
      real    lonbeg,lonend,lat
      real    latbeg,latend
      real    pi,dl,dp,dz 

      pi = 4.*atan(1.0)
      dl = 2*pi/im
      dp = pi/(jm-1)
      dz = pi/(jmax)
      
      do j=1,jmax
      do i=1,imax

      zlatc = -pi/2+(j-0.5)*dz  ! Latitude  at center of bin box
      zlonc = -pi  +(i-0.5)*dz  ! Longitude at center of bin box

c Find bounding lat and lon on IMxJM grid
c ---------------------------------------
      iend   = nint( 1.+(zlonc+pi)/dl )
      lonend = -pi + (iend-1)*dl
      if( lonend.ge.zlonc ) then
          lonbeg = -pi + (iend-2)*dl
      else
          iend   = iend+1
          lonbeg = lonend
          lonend = -pi + (iend-1)*dl
      endif
      ibeg = iend-1

      jend   = nint( 1.+(zlatc+pi/2)/dp )
      latend = -pi/2 + (jend-1)*dp
      if( latend.ge.zlatc ) then
          latbeg = -pi/2 + (jend-2)*dp
      else
          jend   = jend+1
          latbeg = latend
          latend = -pi/2 + (jend-1)*dp
      endif
      jbeg = jend-1


      if(iend.gt.im) iend=iend-im

      if( zlonc.le.lonbeg+0.5*dl ) then
          ii = ibeg
      else
          ii = iend
      endif
      if( zlatc.le.latbeg+0.5*dp ) then
          jj = jbeg
      else
          jj = jend
      endif

      qbin(i,j) = q(ii,jj)
      
      enddo
      enddo

      return
      end


      subroutine hinterp ( qin,iin,jin,qout,iout,jout,mlev,undef,lat_i,lat_o ) 39,31
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lat_i
      type ( dynamics_lattice_type ) lat_o
#ifdef mpi
      include 'mpif.h'
#endif
      integer  comm,myid,npes

      integer    iin,jin,       iout,jout, mlev
      real   qin(iin,jin,mlev), qout(iout,jout,mlev)
      real undef,pi,dlin,dpin,dlout,dpout,lon,lat
      integer i,j,L,loc
      integer index(mlev),ierror
      integer imgi,jmgi,imgo,jmgo

      real, allocatable :: glo_i(:,:,:)
      real, allocatable :: glo_o(:,:,:)
      real, allocatable ::  lons(:), dlam(:)
      real, allocatable ::  lats(:), dphi(:)

      call timebeg (' hinterp')

      comm = lat_i%comm
      myid = lat_i%myid
      npes = lat_i%nx * lat_i%ny

      imgi = lat_i%imglobal
      jmgi = lat_i%jmglobal
      imgo = lat_o%imglobal
      jmgo = lat_o%jmglobal

      allocate ( glo_i(imgi,jmgi,mlev) )
      allocate ( glo_o(imgo,jmgo,mlev) )
      allocate (  lons(imgo*jmgo) )
      allocate (  lats(imgo*jmgo) )
      allocate (  dlam(imgi) )
      allocate (  dphi(jmgi) )

      do L=1,mlev
      index(L) = mod(L-1,npes)
      enddo

      pi = 4.0*atan(1.0)
      dlin = 2*pi/ imgi
      dpin =   pi/(jmgi-1)
      dlam(:) = dlin
      dphi(:) = dpin

      dlout = 2*pi/ imgo
      dpout =   pi/(jmgo-1)
      
      loc = 0
      do j=1,jmgo
      do i=1,imgo
      loc = loc + 1
      lon = -pi + (i-1)*dlout
      lons(loc) = lon
      enddo
      enddo

      loc = 0
      do j=1,jmgo
      lat = -pi/2.0 + (j-1)*dpout
      do i=1,imgo
      loc = loc + 1
      lats(loc) = lat
      enddo
      enddo

      call timebeg ('   Gather')
      do L=1,mlev
      call gather_2d ( glo_i(1,1,L),qin(1,1,L),lat_i )
      enddo
      call timeend ('   Gather')
#ifdef mpi
      call mpi_bcast ( glo_i,imgi*jmgi*mlev,lat_i%mpi_rkind,0,comm,ierror )
#endif

      do L=1,mlev
      if( index(L).eq.myid ) then
          call interp_h ( glo_i(1,1,L),imgi,jmgi,1,dlam,dphi,
     .                    glo_o(1,1,L),imgo*jmgo,lons,lats,undef )
      endif
      enddo

#ifdef mpi
      call mpi_barrier (comm,ierror)
      do L=1,mlev
      call mpi_bcast ( glo_o(1,1,L),imgo*jmgo,lat_o%mpi_rkind,index(L),comm,ierror )
      enddo
      call mpi_barrier (comm,ierror)
#endif
      call timebeg ('   Scatter')
      do L=1,mlev
      call scatter_2d ( glo_o(1,1,L),qout(1,1,L),lat_o )
      enddo
      call timeend ('   Scatter')

      deallocate ( glo_i )
      deallocate ( glo_o )
      deallocate (  lons )
      deallocate (  lats )
      deallocate (  dlam )
      deallocate (  dphi )

      call timeend (' hinterp')
      return
      end


      function defined ( q,undef ) 776
      implicit none
      logical  defined
      real     q,undef
      defined = abs(q-undef).gt.0.1*undef
      return
      end


      subroutine interp_h ( q_cmp,im,jm,lm,dlam,dphi, 6
     .                      q_geo,irun,lon_geo,lat_geo,undef )
C***********************************************************************
C
C  PURPOSE:
C  ========
C    Performs a horizontal interpolation from a field on a computational grid
C    to arbitrary locations.
C
C  INPUT:
C  ======
C    q_cmp ...... Field q_cmp(im,jm,lm) on the computational grid
C    im ......... Longitudinal dimension of q_cmp
C    jm ......... Latitudinal  dimension of q_cmp
C    lm ......... Vertical     dimension of q_cmp
C    dlam ....... Computational Grid Delta Lambda
C    dphi ....... Computational Grid Delta Phi
C    irun ....... Number of Output Locations
C    lon_geo .... Longitude Location of Output
C    lat_geo .... Latitude  Location of Output
C
C  OUTPUT:
C  =======
C    q_geo ...... Field q_geo(irun,lm) at arbitrary locations
C
C
C***********************************************************************
C*                  GODDARD LABORATORY FOR ATMOSPHERES                 *
C***********************************************************************

      implicit none

c Input Variables
c ---------------
      integer im,jm,lm,irun

      real      q_geo(irun,lm)
      real    lon_geo(irun)
      real    lat_geo(irun)

      real    q_cmp(im,jm,lm)
      real     dlam(im)
      real     dphi(jm)

c Local Variables
c ---------------
      integer  i,j,l,m,n
      integer, allocatable       :: ip1(:), ip0(:), im1(:), im2(:)
      integer, allocatable       :: jp1(:), jp0(:), jm1(:), jm2(:)

      integer ip1_for_jp1, ip0_for_jp1, im1_for_jp1, im2_for_jp1
      integer ip1_for_jm2, ip0_for_jm2, im1_for_jm2, im2_for_jm2
      integer jm2_for_jm2, jp1_for_jp1

c Bi-Linear Weights
c -----------------
      real, allocatable       ::    wl_ip0jp0 (:)
      real, allocatable       ::    wl_im1jp0 (:)
      real, allocatable       ::    wl_ip0jm1 (:)
      real, allocatable       ::    wl_im1jm1 (:)

c Bi-Cubic Weights
c ----------------
      real, allocatable       ::    wc_ip1jp1 (:)
      real, allocatable       ::    wc_ip0jp1 (:)
      real, allocatable       ::    wc_im1jp1 (:)
      real, allocatable       ::    wc_im2jp1 (:)
      real, allocatable       ::    wc_ip1jp0 (:)
      real, allocatable       ::    wc_ip0jp0 (:)
      real, allocatable       ::    wc_im1jp0 (:)
      real, allocatable       ::    wc_im2jp0 (:)
      real, allocatable       ::    wc_ip1jm1 (:)
      real, allocatable       ::    wc_ip0jm1 (:)
      real, allocatable       ::    wc_im1jm1 (:)
      real, allocatable       ::    wc_im2jm1 (:)
      real, allocatable       ::    wc_ip1jm2 (:)
      real, allocatable       ::    wc_ip0jm2 (:)
      real, allocatable       ::    wc_im1jm2 (:)
      real, allocatable       ::    wc_im2jm2 (:)

      real    ux, ap1, ap0, am1, am2
      real    uy, bp1, bp0, bm1, bm2

      real    lon_cmp(im)
      real    lat_cmp(jm)
      real    q_tmp(irun)

      real    pi,d
      real    lam,lam_ip1,lam_ip0,lam_im1,lam_im2
      real    phi,phi_jp1,phi_jp0,phi_jm1,phi_jm2
      real    dl,dp,phi_np,lam_0
      real    lam_geo, lam_cmp
      real    phi_geo, phi_cmp
      real    undef
      integer im1_cmp,icmp
      integer jm1_cmp,jcmp

c Initialization
c --------------
      pi = 4.*atan(1.)
      dl = 2*pi/ im     ! Uniform Grid Delta Lambda
      dp =   pi/(jm-1)  ! Uniform Grid Delta Phi

c Allocate Memory for Weights and Index Locations
c -----------------------------------------------
      allocate ( wl_ip0jp0(irun) , wl_im1jp0(irun) )
      allocate ( wl_ip0jm1(irun) , wl_im1jm1(irun) )
      allocate ( wc_ip1jp1(irun) , wc_ip0jp1(irun) , wc_im1jp1(irun) , wc_im2jp1(irun) )
      allocate ( wc_ip1jp0(irun) , wc_ip0jp0(irun) , wc_im1jp0(irun) , wc_im2jp0(irun) )
      allocate ( wc_ip1jm1(irun) , wc_ip0jm1(irun) , wc_im1jm1(irun) , wc_im2jm1(irun) )
      allocate ( wc_ip1jm2(irun) , wc_ip0jm2(irun) , wc_im1jm2(irun) , wc_im2jm2(irun) )
      allocate (       ip1(irun) ,       ip0(irun) ,       im1(irun) ,       im2(irun) )
      allocate (       jp1(irun) ,       jp0(irun) ,       jm1(irun) ,       jm2(irun) )

c Compute Input Computational-Grid Latitude and Longitude Locations
c -----------------------------------------------------------------
      lon_cmp(1) = -pi
      do i=2,im
      lon_cmp(i) = lon_cmp(i-1) + dlam(i-1)
      enddo
      lat_cmp(1) = -pi*0.5
      do j=2,jm-1
      lat_cmp(j) = lat_cmp(j-1) + dphi(j-1)
      enddo
      lat_cmp(jm) =  pi*0.5

c Compute Weights for Computational to Geophysical Grid Interpolation
c -------------------------------------------------------------------
      do i=1,irun
      lam_cmp = lon_geo(i)
      phi_cmp = lat_geo(i)

c Determine Indexing Based on Computational Grid
c ----------------------------------------------
      im1_cmp = 1
      do icmp = 2,im
      if( lon_cmp(icmp).lt.lam_cmp ) im1_cmp = icmp
      enddo
      jm1_cmp = 1
      do jcmp = 2,jm
      if( lat_cmp(jcmp).lt.phi_cmp ) jm1_cmp = jcmp
      enddo

      im1(i) = im1_cmp
      ip0(i) = im1(i) + 1
      ip1(i) = ip0(i) + 1
      im2(i) = im1(i) - 1

      jm1(i) = jm1_cmp
      jp0(i) = jm1(i) + 1
      jp1(i) = jp0(i) + 1
      jm2(i) = jm1(i) - 1

c Fix Longitude Index Boundaries
c ------------------------------
      if(im1(i).eq.im) then
      ip0(i) = 1
      ip1(i) = 2
      endif
      if(im1(i).eq.1) then
      im2(i) = im
      endif
      if(ip0(i).eq.im) then
      ip1(i) = 1
      endif


c Compute Immediate Surrounding Coordinates
c -----------------------------------------
      lam     =  lam_cmp
      phi     =  phi_cmp

c Compute and Adjust Longitude Weights
c ------------------------------------
      lam_im2 =  lon_cmp(im2(i))
      lam_im1 =  lon_cmp(im1(i))
      lam_ip0 =  lon_cmp(ip0(i))
      lam_ip1 =  lon_cmp(ip1(i))

      if( lam_im2.gt.lam_im1 ) lam_im2 = lam_im2 - 2*pi
      if( lam_im1.gt.lam_ip0 ) lam_ip0 = lam_ip0 + 2*pi
      if( lam_im1.gt.lam_ip1 ) lam_ip1 = lam_ip1 + 2*pi
      if( lam_ip0.gt.lam_ip1 ) lam_ip1 = lam_ip1 + 2*pi


c Compute and Adjust Latitude Weights   
c Note:  Latitude Index Boundaries are Adjusted during Interpolation
c ------------------------------------------------------------------
      phi_jm2 =  lat_cmp(jm2(i))
      phi_jm1 =  lat_cmp(jm1(i))
      phi_jp0 =  lat_cmp(jp0(i))
      phi_jp1 =  lat_cmp(jp1(i))

      if( jm2(i).eq.0    ) phi_jm2 = phi_jm1 - dphi(1)
      if( jm1(i).eq.jm   ) then
                           phi_jp0 = phi_jm1 + dphi(jm-1)
                           phi_jp1 = phi_jp0 + dphi(jm-2)
      endif
      if( jp1(i).eq.jm+1 ) phi_jp1 = phi_jp0 + dphi(jm-1)


c Bi-Linear Weights
c -----------------
              d    = (lam_ip0-lam_im1)*(phi_jp0-phi_jm1)
      wl_im1jm1(i) = (lam_ip0-lam    )*(phi_jp0-phi    )/d
      wl_ip0jm1(i) = (lam    -lam_im1)*(phi_jp0-phi    )/d
      wl_im1jp0(i) = (lam_ip0-lam    )*(phi    -phi_jm1)/d
      wl_ip0jp0(i) = (lam    -lam_im1)*(phi    -phi_jm1)/d

c Bi-Cubic Weights
c ----------------
      ap1 = ( (lam    -lam_ip0)*(lam    -lam_im1)*(lam    -lam_im2) )
     .    / ( (lam_ip1-lam_ip0)*(lam_ip1-lam_im1)*(lam_ip1-lam_im2) )
      ap0 = ( (lam_ip1-lam    )*(lam    -lam_im1)*(lam    -lam_im2) )
     .    / ( (lam_ip1-lam_ip0)*(lam_ip0-lam_im1)*(lam_ip0-lam_im2) )
      am1 = ( (lam_ip1-lam    )*(lam_ip0-lam    )*(lam    -lam_im2) )
     .    / ( (lam_ip1-lam_im1)*(lam_ip0-lam_im1)*(lam_im1-lam_im2) )
      am2 = ( (lam_ip1-lam    )*(lam_ip0-lam    )*(lam_im1-lam    ) )
     .    / ( (lam_ip1-lam_im2)*(lam_ip0-lam_im2)*(lam_im1-lam_im2) )

      bp1 = ( (phi    -phi_jp0)*(phi    -phi_jm1)*(phi    -phi_jm2) )
     .    / ( (phi_jp1-phi_jp0)*(phi_jp1-phi_jm1)*(phi_jp1-phi_jm2) )
      bp0 = ( (phi_jp1-phi    )*(phi    -phi_jm1)*(phi    -phi_jm2) )
     .    / ( (phi_jp1-phi_jp0)*(phi_jp0-phi_jm1)*(phi_jp0-phi_jm2) )
      bm1 = ( (phi_jp1-phi    )*(phi_jp0-phi    )*(phi    -phi_jm2) )
     .    / ( (phi_jp1-phi_jm1)*(phi_jp0-phi_jm1)*(phi_jm1-phi_jm2) )
      bm2 = ( (phi_jp1-phi    )*(phi_jp0-phi    )*(phi_jm1-phi    ) )
     .    / ( (phi_jp1-phi_jm2)*(phi_jp0-phi_jm2)*(phi_jm1-phi_jm2) )

      wc_ip1jp1(i) = bp1*ap1
      wc_ip0jp1(i) = bp1*ap0
      wc_im1jp1(i) = bp1*am1
      wc_im2jp1(i) = bp1*am2

      wc_ip1jp0(i) = bp0*ap1
      wc_ip0jp0(i) = bp0*ap0
      wc_im1jp0(i) = bp0*am1
      wc_im2jp0(i) = bp0*am2

      wc_ip1jm1(i) = bm1*ap1
      wc_ip0jm1(i) = bm1*ap0
      wc_im1jm1(i) = bm1*am1
      wc_im2jm1(i) = bm1*am2

      wc_ip1jm2(i) = bm2*ap1
      wc_ip0jm2(i) = bm2*ap0
      wc_im1jm2(i) = bm2*am1
      wc_im2jm2(i) = bm2*am2

      enddo

c Interpolate Computational-Grid Quantities to Geophysical Grid
c -------------------------------------------------------------
      do L=1,lm
      do i=1,irun

      if( lat_geo(i).le.lat_cmp(2)     .or.
     .    lat_geo(i).ge.lat_cmp(jm-1) ) then

c 1st Order Interpolation at Poles
c --------------------------------
      if( q_cmp( im1(i),jm1(i),L ).ne.undef  .and.
     .    q_cmp( ip0(i),jm1(i),L ).ne.undef  .and.
     .    q_cmp( im1(i),jp0(i),L ).ne.undef  .and.
     .    q_cmp( ip0(i),jp0(i),L ).ne.undef ) then

      q_tmp(i) = wl_im1jm1(i) * q_cmp( im1(i),jm1(i),L )
     .         + wl_ip0jm1(i) * q_cmp( ip0(i),jm1(i),L )
     .         + wl_im1jp0(i) * q_cmp( im1(i),jp0(i),L )
     .         + wl_ip0jp0(i) * q_cmp( ip0(i),jp0(i),L )

      else
      q_tmp(i) = undef
      endif

      else

c Cubic Interpolation away from Poles
c -----------------------------------
      if( q_cmp( ip1(i),jp0(i),L ).ne.undef  .and.
     .    q_cmp( ip0(i),jp0(i),L ).ne.undef  .and.
     .    q_cmp( im1(i),jp0(i),L ).ne.undef  .and.
     .    q_cmp( im2(i),jp0(i),L ).ne.undef  .and.

     .    q_cmp( ip1(i),jm1(i),L ).ne.undef  .and.
     .    q_cmp( ip0(i),jm1(i),L ).ne.undef  .and.
     .    q_cmp( im1(i),jm1(i),L ).ne.undef  .and.
     .    q_cmp( im2(i),jm1(i),L ).ne.undef  .and.

     .    q_cmp( ip1(i),jp1(i),L ).ne.undef  .and.
     .    q_cmp( ip0(i),jp1(i),L ).ne.undef  .and.
     .    q_cmp( im1(i),jp1(i),L ).ne.undef  .and.
     .    q_cmp( im2(i),jp1(i),L ).ne.undef  .and.

     .    q_cmp( ip1(i),jm2(i),L ).ne.undef  .and.
     .    q_cmp( ip0(i),jm2(i),L ).ne.undef  .and.
     .    q_cmp( im1(i),jm2(i),L ).ne.undef  .and.
     .    q_cmp( im2(i),jm2(i),L ).ne.undef ) then

      q_tmp(i) = wc_ip1jp1(i) * q_cmp( ip1(i),jp1(i),L )
     .         + wc_ip0jp1(i) * q_cmp( ip0(i),jp1(i),L )
     .         + wc_im1jp1(i) * q_cmp( im1(i),jp1(i),L )
     .         + wc_im2jp1(i) * q_cmp( im2(i),jp1(i),L )

     .         + wc_ip1jp0(i) * q_cmp( ip1(i),jp0(i),L )
     .         + wc_ip0jp0(i) * q_cmp( ip0(i),jp0(i),L )
     .         + wc_im1jp0(i) * q_cmp( im1(i),jp0(i),L )
     .         + wc_im2jp0(i) * q_cmp( im2(i),jp0(i),L )

     .         + wc_ip1jm1(i) * q_cmp( ip1(i),jm1(i),L )
     .         + wc_ip0jm1(i) * q_cmp( ip0(i),jm1(i),L )
     .         + wc_im1jm1(i) * q_cmp( im1(i),jm1(i),L )
     .         + wc_im2jm1(i) * q_cmp( im2(i),jm1(i),L )

     .         + wc_ip1jm2(i) * q_cmp( ip1(i),jm2(i),L )
     .         + wc_ip0jm2(i) * q_cmp( ip0(i),jm2(i),L )
     .         + wc_im1jm2(i) * q_cmp( im1(i),jm2(i),L )
     .         + wc_im2jm2(i) * q_cmp( im2(i),jm2(i),L )

      elseif( q_cmp( im1(i),jm1(i),L ).ne.undef  .and.
     .        q_cmp( ip0(i),jm1(i),L ).ne.undef  .and.
     .        q_cmp( im1(i),jp0(i),L ).ne.undef  .and.
     .        q_cmp( ip0(i),jp0(i),L ).ne.undef ) then

      q_tmp(i) = wl_im1jm1(i) * q_cmp( im1(i),jm1(i),L )
     .         + wl_ip0jm1(i) * q_cmp( ip0(i),jm1(i),L )
     .         + wl_im1jp0(i) * q_cmp( im1(i),jp0(i),L )
     .         + wl_ip0jp0(i) * q_cmp( ip0(i),jp0(i),L )

      else
      q_tmp(i) = undef
      endif

      endif
      enddo

c Load Temp array into Output array
c ---------------------------------
      do i=1,irun
      q_geo(i,L) = q_tmp(i)
      enddo
      enddo

      deallocate ( wl_ip0jp0 , wl_im1jp0 )
      deallocate ( wl_ip0jm1 , wl_im1jm1 )
      deallocate ( wc_ip1jp1 , wc_ip0jp1 , wc_im1jp1 , wc_im2jp1 )
      deallocate ( wc_ip1jp0 , wc_ip0jp0 , wc_im1jp0 , wc_im2jp0 )
      deallocate ( wc_ip1jm1 , wc_ip0jm1 , wc_im1jm1 , wc_im2jm1 )
      deallocate ( wc_ip1jm2 , wc_ip0jm2 , wc_im1jm2 , wc_im2jm2 )
      deallocate (       ip1 ,       ip0 ,       im1 ,       im2 )
      deallocate (       jp1 ,       jp0 ,       jm1 ,       jm2 )

      return
      end


      subroutine remap ( ple,u,v,thv,q,o3,phis_in,phis_out,ak,bk,im,jm,lm ) 5,10

C***********************************************************************
C
C  Purpose
C     Driver for remapping fields to new topography
C
C  Argument Description
C     ple ...... model edge pressure
C     u  ....... model zonal      wind
C     v  ....... model meridional wind
C     thv  ..... model virtual potential  temperature
C     q  ....... model specific   humidity
C     o3  ...... model ozone
C     phis_in... model surface geopotential (input)
C     phis_out.. model surface geopotential (output)
C     ak ....... model vertical   dimension
C     bk ....... model vertical   dimension
C
C     im ....... zonal      dimension
C     jm ....... meridional dimension
C     lm ....... meridional dimension
C
C***********************************************************************
C*                  GODDARD LABORATORY FOR ATMOSPHERES                 *
C***********************************************************************

      implicit none
      integer  im,jm,lm

c Input variables
c ---------------
      real      ple(im,jm,lm+1)
      real        u(im,jm,lm)
      real        v(im,jm,lm)
      real      thv(im,jm,lm)
      real        q(im,jm,lm)
      real       o3(im,jm,lm)
      real phis_in (im,jm)
      real phis_out(im,jm)

      real*8     ak(lm+1)
      real*8     bk(lm+1)

c Local variables
c ---------------
      real  ps     (im,jm)
      real  phi    (im,jm,lm+1)
      real  pke    (im,jm,lm+1)
      real  ple_out(im,jm,lm+1)
      real  pke_out(im,jm,lm+1)

      real    u_out(im,jm,lm)
      real    v_out(im,jm,lm)
      real  thv_out(im,jm,lm)
      real    q_in (im,jm,lm,2)
      real    q_out(im,jm,lm,2)

      real    kappa,cp,rgas,eps,rvap
      integer i,j,L,n

      kappa = 2.0/7.0
      rgas  = 8314.3/28.97
      rvap  = 8314.3/18.01
      eps   = rvap/rgas-1.0
      cp    = rgas/kappa

c Construct Input Heights
c -----------------------
      pke(:,:,:) = ple(:,:,:)**kappa 

      phi(:,:,lm+1) = phis_in(:,:)
      do L=lm,1,-1
      phi(:,:,L) = phi(:,:,L+1) + cp*thv(:,:,L)*( pke(:,:,L+1)-pke(:,:,L) )
      enddo
      
c Compute new surface pressure consistent with output topography
c --------------------------------------------------------------
      do j=1,jm
      do i=1,im
           L = lm
           do while ( phi(i,j,L).lt.phis_out(i,j) )
           L = L-1
           enddo
           ps(i,j) = ple(i,j,L+1)*( 1+(phi(i,j,L+1)-phis_out(i,j))/(cp*thv(i,j,L)*pke(i,j,L+1)) )**(1.0/kappa)
      enddo
      enddo

c Construct fv pressure variables using new surface pressure
c ----------------------------------------------------------
      do L=1,lm+1
      do j=1,jm
      do i=1,im
       ple_out(i,j,L) = ak(L) + bk(L)*ps(i,j)
      enddo
      enddo
      enddo
      pke_out(:,:,:) = ple_out(:,:,:)**kappa 

c Map original fv state onto new eta grid
c ---------------------------------------
      q_in(:,:,:,1) =  q(:,:,:)
      q_in(:,:,:,2) = o3(:,:,:)

      call gmap ( im,jm,2 , kappa,
     .            lm, pke    ,ple    ,u    ,v    ,thv    ,q_in ,
     .            lm, pke_out,ple_out,u_out,v_out,thv_out,q_out)

      ple(:,:,:) = ple_out(:,:,:)
        u(:,:,:) =   u_out(:,:,:)
        v(:,:,:) =   v_out(:,:,:)
      thv(:,:,:) = thv_out(:,:,:)
        q(:,:,:) =   q_out(:,:,:,1)
       o3(:,:,:) =   q_out(:,:,:,2)

      return
      end

      subroutine write_d ( u,v,ple,im,jm,lm,lattice ) 3,15
      use dynamics_lattice_module
      implicit none
      type ( dynamics_lattice_type ) lattice

      integer   im,jm,lm
      real    u(im,jm,lm)
      real    v(im,jm,lm)
      real   dp(im,jm,lm)
      real  div(im,jm,lm)
      real  ple(im,jm,lm+1)

      integer index(lm),ierror

      real, allocatable ::  uglo(:,:,:)
      real, allocatable ::  vglo(:,:,:)
      real, allocatable :: dpglo(:,:,:)
      real, allocatable ::  dglo(:,:,:)

      real, allocatable ::   sum1(:,:)
      real*4, allocatable ::  dum(:,:)

      integer L, comm, myid, npes
      integer img, jmg

      img  = lattice%imglobal
      jmg  = lattice%jmglobal
      comm = lattice%comm
      myid = lattice%myid
      npes = lattice%nx * lattice%ny

      do L=1,lm
      index (L) = mod(L-1,npes)
      dp(:,:,L) = ( ple(:,:,L+1)-ple(:,:,L) )
      enddo
 
      allocate (  uglo(img,jmg,lm) )
      allocate (  vglo(img,jmg,lm) )
      allocate (  dglo(img,jmg,lm) )
      allocate ( dpglo(img,jmg,lm) )
      allocate (   dum(img,jmg) )
      allocate (   sum1(im,jm)  )

! Construct A-Grid Winds
! ----------------------
      do L=1,lm
             call gather_2d (  uglo(1,1,L), u(1,1,L),lattice )
             call gather_2d (  vglo(1,1,L), v(1,1,L),lattice )
             call gather_2d ( dpglo(1,1,L),dp(1,1,L),lattice )
         if( lattice%myid.eq.0 ) then
             call dtoa      ( uglo(1,1,L),uglo(1,1,L),img,jmg,1,2 )
             call dtoa      ( vglo(1,1,L),vglo(1,1,L),img,jmg,1,1 )
         endif
      enddo
#ifdef mpi
      call mpi_bcast (  uglo,img*jmg*lm,lattice%mpi_rkind,0,comm,ierror )
      call mpi_bcast (  vglo,img*jmg*lm,lattice%mpi_rkind,0,comm,ierror )
      call mpi_bcast ( dpglo,img*jmg*lm,lattice%mpi_rkind,0,comm,ierror )
#endif

c Compute Mass-Weighted Divergence
c --------------------------------
      do L=1,lm
      if( index(L).eq.myid ) call getdiv (uglo(1,1,L),vglo(1,1,L),dpglo(1,1,L),dglo(1,1,L),img,jmg )               
      enddo
#ifdef mpi
      call mpi_barrier (comm,ierror)
      do L=1,lm
      call mpi_bcast ( dglo(1,1,L),img*jmg,lattice%mpi_rkind,index(L),comm,ierror )
      enddo
      call mpi_barrier (comm,ierror)
#endif
      do L=1,lm
      call scatter_2d ( dglo(1,1,L),div(1,1,L),lattice )
      enddo

c Modify Divergence (to force vanishing vertical integral)
c --------------------------------------------------------
        sum1(:,:) = 0.0
      do L=1,lm
        sum1(:,:) = sum1(:,:) + div(:,:,L)
      enddo

c Gather and Broadcast Divergence
c -------------------------------
      call gather_2d ( dglo(1,1,1),sum1,lattice )

      if( lattice%myid.eq.0 ) then
                    dum(:,:) = dglo(:,:,1)
          write(33) dum
      endif

      deallocate ( sum1,dum )
      deallocate ( uglo,vglo,dglo,dpglo )
      return
      end