Subversion Repositories pvinversion.ecmwf

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

      PROGRAM z2s

c     Calculate secondary fields on z levels
c     Michael Sprenger / Summer 2006

      implicit none

c     ---------------------------------------------------------------
c     Declaration of variables
c     ---------------------------------------------------------------

c     Variables for output Z file  : height level
      character*80 cfn
      real         varmin(4),varmax(4),stag(4)
      integer      vardim(4)
      real         mdv
      integer      ndim
      integer      nx,ny,nz
      real         xmin,xmax,ymin,ymax,dx,dy
      integer      ntimes
      real         aklev(1000),bklev(1000)
      real         aklay(1000),bklay(1000)
      real         time
      real         pollon,pollat
      integer      idate(5)
      integer      nfields
      character*80 field_nam(100)
      real,allocatable, dimension (:,:,:,:) :: field_dat
      real,allocatable, dimension (:,:,:)   :: z3
      real,allocatable, dimension (:,:)     :: x2,y2,f2
      real,allocatable, dimension (:,:,:)   :: out
      real,allocatable, dimension (:,:,:)   :: inp
      integer      nvars
      character*80 vnam(100),varname
      integer      isok
      integer      cdfid,cstid

c     Parameter file
      character*80 fieldname
      integer      nfilt
      character*80 ofn,gri

c     Auxiliary variables
      integer      ierr,stat
      integer      i,j,k,n
      real,allocatable, dimension (:,:)   :: out2
      character*80 vnam2(100)
      integer      nvars2

c     ---------------------------------------------------------------
c     Preparations
c     ---------------------------------------------------------------

      print*,'*********************************************************'
      print*,'* z2s                                                   *'
      print*,'*********************************************************'

c     Read parameter file
      open(10,file='fort.10')
       read(10,*) fieldname
       read(10,*) ofn
       read(10,*) gri
       read(10,*) nfilt
      close(10)

c     Get grid description for Z file : height level
      call cdfopn(ofn,cdfid,ierr)
      if (ierr.ne.0) goto 998
      call getcfn(cdfid,cfn,ierr)
      if (ierr.ne.0) goto 998
      call cdfopn(cfn,cstid,ierr)
      if (ierr.ne.0) goto 998
      call getdef(cdfid,'T',ndim,mdv,vardim,
     >            varmin,varmax,stag,ierr)
      if (ierr.ne.0) goto 998
      nx  =vardim(1)
      ny  =vardim(2)
      nz  =vardim(3)
      xmin=varmin(1)
      ymin=varmin(2)
      call getlevs(cstid,nz,aklev,bklev,aklay,bklay,ierr)
      if (ierr.ne.0) goto 998
      call getgrid(cstid,dx,dy,ierr)
      if (ierr.ne.0) goto 998
      xmax=xmin+real(nx-1)*dx
      ymax=ymin+real(ny-1)*dy
      call gettimes(cdfid,time,ntimes,ierr)
      if (ierr.ne.0) goto 998
      call getstart(cstid,idate,ierr)
      if (ierr.ne.0) goto 998
      call getpole(cstid,pollon,pollat,ierr)
      if (ierr.ne.0) goto 998
      call getvars(cdfid,nvars,vnam,ierr)
      if (ierr.ne.0) goto 998
      call clscdf(cstid,ierr)
      if (ierr.ne.0) goto 998
      call clscdf(cdfid,ierr)
      if (ierr.ne.0) goto 998

c     Get a list of all variables on the GRID file
      if (trim(gri).ne.trim(ofn)) then
         call cdfopn(gri,cdfid,ierr)
         if (ierr.ne.0) goto 998
         call getvars(cdfid,nvars2,vnam2,ierr)
         if (ierr.ne.0) goto 998
         do i=1,nvars2
            vnam(nvars+i)=vnam2(i)
         enddo
         nvars=nvars+nvars2
      endif

c     Check whether calculation of <fieldname> is supported
      if ( (fieldname.ne.'TH' ).and.
     >     (fieldname.ne.'NSQ')  .and.
     >     (fieldname.ne.'PV' )   .and.
     >     (fieldname.ne.'RHO')) then
         print*,'Variable not supported ',trim(fieldname)
         stop
      endif
      
c     Set dependencies
      if (fieldname.eq.'TH') then
         nfields=2
         field_nam(1)='T'
         field_nam(2)='P'
      else if (fieldname.eq.'RHO') then
         nfields=2
         field_nam(1)='T'
         field_nam(2)='P'
      else if (fieldname.eq.'NSQ') then
         nfields=2
         field_nam(1)='T'
         field_nam(2)='Q'
      else if (fieldname.eq.'PV') then
         nfields=4
         field_nam(1)='T'
         field_nam(2)='P'
         field_nam(3)='U'
         field_nam(4)='V'
      endif

c     Allocate memory
      allocate(field_dat(nfields,nx,ny,nz),stat=stat)
      if (stat.ne.0) print*,'error allocating field_dat'
      allocate(out(nx,ny,nz),stat=stat)
      if (stat.ne.0) print*,'error allocating out'
      allocate(inp(nx,ny,nz),stat=stat)
      if (stat.ne.0) print*,'error allocating inp'
      allocate(z3(nx,ny,nz),stat=stat)
      if (stat.ne.0) print*,'error allocating z3'
      allocate(x2(nx,ny),stat=stat)
      if (stat.ne.0) print*,'error allocating x2'
      allocate(y2(nx,ny),stat=stat)
      if (stat.ne.0) print*,'error allocating y2'
      allocate(f2(nx,ny),stat=stat)
      if (stat.ne.0) print*,'error allocating f2'

c     Allocate auxiliary fields
      allocate(out2(nx,ny),stat=stat)
      if (stat.ne.0) print*,'error allocating out2'
      
c     Read X grid
      varname='X'
      isok=0
      call check_varok (isok,varname,vnam,nvars)
      if (isok.eq.0) then
         print*,'Variable ',trim(varname),' missing... Stop'
         stop
      endif
      call cdfopn(gri,cdfid,ierr)
      if (ierr.ne.0) goto 998
      call getdat(cdfid,varname,time,0,x2,ierr)
      if (ierr.ne.0) goto 998
      print*,'R ',trim(varname),' ',trim(gri)
      call clscdf(cdfid,ierr)
      if (ierr.ne.0) goto 998

c     Read Y grid
      varname='Y'
      isok=0
      call check_varok (isok,varname,vnam,nvars)
      if (isok.eq.0) then
         print*,'Variable ',trim(varname),' missing... Stop'
         stop
      endif
      call cdfopn(gri,cdfid,ierr)
      if (ierr.ne.0) goto 998
      call getdat(cdfid,varname,time,0,y2,ierr)
      if (ierr.ne.0) goto 998
      print*,'R ',trim(varname),' ',trim(gri)
      call clscdf(cdfid,ierr)
      if (ierr.ne.0) goto 998
      
c     Read Coriolis parametzer
      varname='CORIOL'
      isok=0
      call check_varok (isok,varname,vnam,nvars)
      if (isok.eq.0) then
         print*,'Variable ',trim(varname),' missing... Stop'
         stop
      endif
      call cdfopn(gri,cdfid,ierr)
      if (ierr.ne.0) goto 998
      call getdat(cdfid,varname,time,0,f2,ierr)
      if (ierr.ne.0) goto 998
      print*,'R ',trim(varname),' ',trim(gri)
      call clscdf(cdfid,ierr)
      if (ierr.ne.0) goto 998      

c     Init height levels
      do i=1,nx
         do j=1,ny
            do k=1,nz
               z3(i,j,k)=aklay(k)
            enddo
         enddo
      enddo

c     Load needed variables
      do n=1,nfields

c        Check whether variable is available on file
         varname=field_nam(n)
         isok=0
         call check_varok (isok,varname,vnam,nvars)

c        Variable is available on file
         if (isok.eq.1) then

            call cdfopn(ofn,cdfid,ierr)
            if (ierr.ne.0) goto 998
            call getdat(cdfid,varname,time,0,inp,ierr)
            if (ierr.ne.0) goto 998
            print*,'R ',trim(varname),' ',trim(ofn)
            call clscdf(cdfid,ierr)
            if (ierr.ne.0) goto 998
            
            do i=1,nx
               do j=1,ny
                  do k=1,nz
                     field_dat(n,i,j,k)=inp(i,j,k)
                  enddo
               enddo
            enddo
            
         else            
            print*,'Variable missing : ',trim(varname)
            stop
         endif

      enddo

c     Change unit of pressure from hPa to Pa
      n=0
      do i=1,nfields
         if (field_nam(i).eq.'P') n=i
      enddo
      if (n.ne.0) then
         do i=1,nx
            do j=1,ny
               do k=1,nz
                  field_dat(n,i,j,k)=100.*field_dat(n,i,j,k)
               enddo
            enddo
         enddo
      endif

c     ----------------------------------------------------------------
c     Calculations
c     ----------------------------------------------------------------

c     Call to the defining routines
      if (fieldname.eq.'RHO') then

         print*,'C ',trim(fieldname)
         call calc_rho (out,                                 ! RHO
     >                  field_dat(1,:,:,:),                  ! T
     >                  field_dat(2,:,:,:),                  ! P
     >                  nx,ny,nz,mdv)

      else if (fieldname.eq.'TH') then

         print*,'C ',trim(fieldname)
         call calc_theta (out,                               ! TH
     >                    field_dat(1,:,:,:),                ! T
     >                    field_dat(2,:,:,:),                ! P
     >                    nx,ny,nz,mdv)

       else if (fieldname.eq.'NSQ') then

          print*,'C ',trim(fieldname)
          call calc_nsq (out,                                 ! NSQ
     >                   field_dat(1,:,:,:),                  ! T
     >                   field_dat(2,:,:,:),                  ! Q
     >                   z3,                                  ! Z      
     >                   nx,ny,nz,mdv)
      
       else if (fieldname.eq.'PV') then

          print*,'C ',trim(fieldname)
          call calc_pv (out,                                  ! PV
     >                  field_dat(1,:,:,:),                   ! T
     >                  field_dat(2,:,:,:),                   ! P
     >                  field_dat(3,:,:,:),                   ! U
     >                  field_dat(4,:,:,:),                   ! V
     >                  z3,x2,y2,f2,                          ! Z,X,Y,CORIOL
     >                  nx,ny,nz,mdv)

       endif

c      Horizontal filtering of the resulting fields
       print*,'F ',trim(fieldname)
       do k=1,nz
          
          do i=1,nx
             do j=1,ny
                out2(i,j)=out(i,j,k)
             enddo
          enddo
          do n=1,nfilt     
             call filt2d (out2,out2,nx,ny,1.,mdv,0,0,0,0)
          enddo

          do i=1,nx
             do j=1,ny
                out(i,j,k)=out2(i,j)
             enddo
          enddo
          
       enddo

c     ----------------------------------------------------------------
c     Save result onto netcdf file
c     ----------------------------------------------------------------
       
      call cdfwopn(ofn,cdfid,ierr)
      if (ierr.ne.0) goto 998
      isok=0
      varname=fieldname
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) then
         call putdef(cdfid,varname,ndim,mdv,vardim,
     >               varmin,varmax,stag,ierr)
         if (ierr.ne.0) goto 998
      endif
      call putdat(cdfid,varname,time,0,out,ierr)
      if (ierr.ne.0) goto 998
      print*,'W ',trim(varname),' ',trim(ofn)
      call clscdf(cdfid,ierr)
      if (ierr.ne.0) goto 998


c     ----------------------------------------------------------------
c     Exception handling
c     ----------------------------------------------------------------
   
      stop

 998  print*,'Problem with netcdf file'
      stop

      end

       

c     ****************************************************************
c     * SUBROUTINE SECTION: AUXILIARY ROUTINES                       *
c     ****************************************************************     

c     ----------------------------------------------------------------
c     Check whether variable is found on netcdf file
c     ----------------------------------------------------------------

      subroutine check_varok (isok,varname,varlist,nvars)

c     Check whether the variable <varname> is in the list <varlist(nvars)>. 
c     If this is the case, <isok> is incremented by 1. Otherwise <isok> 
c     keeps its value.

      implicit none

c     Declaraion of subroutine parameters
      integer      isok
      integer      nvars
      character*80 varname
      character*80 varlist(nvars)

c     Auxiliary variables
      integer      i

c     Main
      do i=1,nvars
         if (trim(varname).eq.trim(varlist(i))) isok=isok+1
      enddo

      end


c     ****************************************************************
c     * SUBROUTINE SECTION: CALCULATE SECONDARY FIELDS               *
c     ****************************************************************

c     -----------------------------------------------------------------
c     Calculate density
c     -----------------------------------------------------------------

      subroutine calc_rho (rho3,t3,p3,
     >                     nx,ny,nz,mdv)

c     Calculate the density <rho3> (in kg/m^3) from temperature <t3> 
c     (in deg C) and pressure <p3> (in hPa).

      implicit none
      
c     Declaration of subroutine parameters
      integer   nx,ny,nz
      real      mdv
      real      rho3(nx,ny,nz)
      real      t3  (nx,ny,nz)
      real      p3  (nx,ny,nz)

c     Declaration of physical constants
      real      eps 
      parameter (eps=0.01)
      real      rd
      parameter (rd=287.)
      real      tzero
      parameter (tzero=273.15)

c     Auxiliary variables
      integer   i,j,k
      
c     Calculation
      do i=1,nx
         do j=1,ny
            do k=1,nz
            
               if ((abs(t3(i,j,k)-mdv).gt.eps).and.
     >             (abs(p3(i,j,k)-mdv).gt.eps)) then
               
                  rho3(i,j,k)=1./rd*p3(i,j,k)/(t3(i,j,k)+tzero)

               else
                  rho3(i,j,k)=mdv
               endif
               
            enddo
         enddo
      enddo

      end


c     -----------------------------------------------------------------
c     Calculate potential temperature
c     -----------------------------------------------------------------

      subroutine calc_theta (th3,t3,p3,
     >                       nx,ny,nz,mdv)

c     Calculate potential temperature <th3> (in K) from temperature <t3> 
c     (in deg C) and pressure <p3> (in hPa). 
    
      implicit none

c     Declaration of subroutine parameters
      integer   nx,ny,nz
      real      mdv
      real      th3(nx,ny,nz)
      real      t3 (nx,ny,nz)
      real      p3 (nx,ny,nz)
      
c     Declaration of physical constants
      real      rdcp,tzero,p0
      parameter (rdcp=0.286)
      parameter (tzero=273.15)
      parameter (p0=100000.)
      real      eps
      parameter (eps=0.01)
      
c     Auxiliary variables
      integer  i,j,k

c     Calculation
      do i=1,nx
         do j=1,ny
            do k=1,nz
            
               if ((abs(t3(i,j,k)-mdv).gt.eps).and.
     >             (abs(p3(i,j,k)-mdv).gt.eps)) then
               
                  th3(i,j,k)=(t3(i,j,k)+tzero)*( (p0/p3(i,j,k))**rdcp )

               else
                  th3(i,j,k)=mdv
               endif
               
            enddo
         enddo
      enddo

      end

c     -----------------------------------------------------------------
c     Calculate stratification
c     -----------------------------------------------------------------

      subroutine calc_nsq (nsq3,t3,q3,
     >                     z3,nx,ny,nz,mdv)

c     Calculate stratification <nsq3> on the model grid. The grid is
c     specified in the horizontal by <xmin,ymin,dx,dy,nx,ny>. The number
c     of vertical levels is <nz>. The input field are: temperature <t3>, 
c     specific humidity <q3>, height <z3> and horizontal grid <x2>, <y2>. 

      implicit none
      
c     Declaration of subroutine parameters
      integer   nx,ny,nz
      real      nsq3(nx,ny,nz)
      real      t3  (nx,ny,nz)
      real      q3  (nx,ny,nz)
      real      z3  (nx,ny,nz)
      real      x2  (nx,ny)
      real      y2  (nx,ny)
      real      mdv

c     Physical and numerical parameters
      real      scale
      parameter (scale=1.)
      real      g
      parameter (g=9.80665)
      real      eps
      parameter (eps=0.01)
      real      tzero
      parameter (tzero=273.15)
      real      kappa
      parameter (kappa=0.6078)
      real      cp
      parameter (cp=1005.)
      real      zerodiv
      parameter (zerodiv=0.0000000001)
      real      R
      parameter (R=287.)

c     Auxiliary variables
      real      tv   (nx,ny,nz)
      real      dtvdz(nx,ny,nz)
      integer   i,j,k
      real      scaledz

c     Calculate 3d virtual temperature
      do k=1,nz
         do i=1,nx
            do j=1,ny
               if ((abs(t3(i,j,k)-mdv).gt.eps).and.
     >             (abs(q3(i,j,k)-mdv).gt.eps)) 
     >         then
                  tv(i,j,k) = (t3(i,j,k)+tzero)*(1.+kappa*q3(i,j,k))
               else
                  tv(i,j,k) = mdv
               endif
            enddo
         enddo
      enddo

c     Vertical derivative of virtual temperature
      call  deriv (dtvdz,tv,'z',z3,x2,y2,nx,ny,nz,mdv)

c     Stratification
      do i=1,nx
         do j=1,ny
            do k=1,nz
               if ((abs(dtvdz(i,j,k)-mdv).gt.eps).and.
     >             (abs(tv   (i,j,k)-mdv).gt.eps)) 
     >         then
                  nsq3(i,j,k) = g/tv(i,j,k) * (dtvdz(i,j,k) + g/cp)  
               else
                  nsq3(i,j,k) = mdv
               endif
           enddo
        enddo
      enddo

      end
          
c     -----------------------------------------------------------------
c     Calculate potential vorticity
c     -----------------------------------------------------------------

      subroutine calc_pv (pv3,t3,p3,u3,v3,
     >                    z3,x2,y2,f2,nx,ny,nz,mdv)

c     Calculate potential vorticity <pv3> on the model grid. The grid is
c     specified in the horizontal by <xmin,ymin,dx,dy,nx,ny>. The number
c     of vertical levels is <nz>. The input field are: potential temperature
c     <th3>, horizontal wind <u3> and <v3>, density <rho3>, height <z3>. 
c     The terms including the vertical velocity are neglected in the calculation 
c     of the PV. 

      implicit none
      
c     Declaration of subroutine parameters
      integer   nx,ny,nz
      real      pv3 (nx,ny,nz)
      real      t3  (nx,ny,nz)
      real      p3  (nx,ny,nz)
      real      u3  (nx,ny,nz)
      real      v3  (nx,ny,nz)
      real      z3  (nx,ny,nz)
      real      x2  (nx,ny)
      real      y2  (nx,ny)
      real      f2  (nx,ny)

      real      mdv

c     Physical and numerical parameters
      real      scale
      parameter (scale=1.E6)
      real      omega
      parameter (omega=7.292E-5)
      real      pi180
      parameter (pi180=3.141592654/180.)
      real      eps
      parameter (eps=0.01)
      
c     Auxiliary variables
      real      dtdz(nx,ny,nz)
      real      dtdx(nx,ny,nz)
      real      dtdy(nx,ny,nz)
      real      dudz(nx,ny,nz)
      real      dvdz(nx,ny,nz)
      real      dvdx(nx,ny,nz)
      real      dudy(nx,ny,nz)
      real      rho3(nx,ny,nz)
      real      th3 (nx,ny,nz)

      integer   i,j,k

c     Calculate density and potential temperature
      call calc_rho   (rho3,t3,p3,nx,ny,nz,mdv)
      call calc_theta (th3 ,t3,p3,nx,ny,nz,mdv)

c     Calculate needed derivatives
      call deriv (dudz, u3,'z',z3,x2,y2,nx,ny,nz,mdv)
      call deriv (dvdz, v3,'z',z3,x2,y2,nx,ny,nz,mdv)
      call deriv (dtdz,th3,'z',z3,x2,y2,nx,ny,nz,mdv)
      call deriv (dtdx,th3,'x',z3,x2,y2,nx,ny,nz,mdv)
      call deriv (dtdy,th3,'y',z3,x2,y2,nx,ny,nz,mdv)     
      call deriv (dvdx, v3,'x',z3,x2,y2,nx,ny,nz,mdv)
      call deriv (dudy, u3,'y',z3,x2,y2,nx,ny,nz,mdv)     

c     Calculate potential vorticity
      do j=1,ny
         do i=1,nx
            do k=1,nz

c              Evaluate PV formula with missing data check
               if ((abs(dtdz(i,j,k)-mdv).gt.eps).and.
     >             (abs(dudz(i,j,k)-mdv).gt.eps).and.
     >             (abs(dtdy(i,j,k)-mdv).gt.eps).and.
     >             (abs(dvdz(i,j,k)-mdv).gt.eps).and.
     >             (abs(rho3(i,j,k)-mdv).gt.eps).and.              
     >             (abs(dtdx(i,j,k)-mdv).gt.eps).and.
     >             (abs(dvdx(i,j,k)-mdv).gt.eps).and.
     >             (abs(dudy(i,j,k)-mdv).gt.eps)) then

                  pv3(i,j,k)=scale*1./rho3(i,j,k)*
     >                   ((dvdx(i,j,k)-dudy(i,j,k)+f2(i,j))*dtdz(i,j,k)
     >                                         +dudz(i,j,k)*dtdy(i,j,k)
     >                                         -dvdz(i,j,k)*dtdx(i,j,k))
               else
                  pv3(i,j,k)=mdv
               endif

            enddo
         enddo
      enddo

      end


c     ****************************************************************
c     * SUBROUTINE SECTION: GRID HANDLING                            *
c     ****************************************************************

c     -----------------------------------------------------------------
c     Horizontal and vertical derivatives for 3d fields
c     -----------------------------------------------------------------

      subroutine deriv (df,f,direction,
     >                  z3,x2,y2,nx,ny,nz,mdv)

c     Calculate horizontal and vertical derivatives of the 3d field <f>.
c     The direction of the derivative is specified in <direction> 
c         'x','y'          : Horizontal derivative in x and y direction
c         'p','z','t','m'  : Vertical derivative (pressure, height, theta, model)
c     The 3d field <z3> specifies the isosurfaces along which the horizontal 
c     derivatives are calculated or the levels for the vertical derivatives.

      implicit none

c     Input and output parameters
      integer    nx,ny,nz
      real       df (nx,ny,nz)
      real       f  (nx,ny,nz)
      real       z3 (nx,ny,nz)
      real       x2 (nx,ny)
      real       y2 (nx,ny)
      character  direction
      real       mdv
      
c     Numerical and physical parameters
      real       pi180
      parameter  (pi180=3.141592654/180.)
      real       zerodiv
      parameter  (zerodiv=0.00000001)
      real       eps
      parameter  (eps=0.01) 

c     Auxiliary variables
      integer    i,j,k
      real       vmin,vmax
      real       scale,lat
      real       vu,vl,vuvl,vlvu
      integer    o,u,w,e,n,s

c     Vertical derivative
      if ((direction.eq.'z').or.
     >    (direction.eq.'th').or.
     >    (direction.eq.'p').or.
     >    (direction.eq.'m').and.
     >    (nz.gt.1)) then

         do i=1,nx
            do j=1,ny
               do k=1,nz
                  
                  o=k+1
                  if (o.gt.nz) o=nz
                  u=k-1
                  if (u.lt.1) u=1                  

                  if ((abs(f(i,j,o)-mdv).gt.eps).and.
     >                (abs(f(i,j,u)-mdv).gt.eps).and.
     >                (abs(f(i,j,k)-mdv).gt.eps)) then

                     vu = z3(i,j,k)-z3(i,j,o)
                     vl = z3(i,j,u)-z3(i,j,k)
                     vuvl = vu/(vl+zerodiv)
                     vlvu = 1./(vuvl+zerodiv)

                     df(i,j,k) = 1./(vu+vl)
     >                           * (vuvl*(f(i,j,u)-f(i,j,k)) 
     >                           +  vlvu*(f(i,j,k)-f(i,j,o))) 

                  else
                     df(i,j,k) = mdv
                  endif

               enddo
            enddo
         enddo
              
c     Horizontal derivative in the y direction: 3d
      elseif (direction.eq.'y') then
         
         do i=1,nx
            do j=1,ny
               do k=1,nz
                  
                  s=j-1
                  if (s.lt.1) s=1
                  n=j+1
                  if (n.gt.ny) n=ny

                  if ((abs(f(i,n,k)-mdv).gt.eps).and.
     >                (abs(f(i,j,k)-mdv).gt.eps).and.
     >                (abs(f(i,s,k)-mdv).gt.eps)) then  
 
                     vu = 1000.*(y2(i,j)-y2(i,n))
                     vl = 1000.*(y2(i,s)-y2(i,j))
                     vuvl = vu/(vl+zerodiv)
                     vlvu = 1./(vuvl+zerodiv)
 
                     df(i,j,k) =  1./(vu+vl)
     >                            * (vuvl*(f(i,s,k)-f(i,j,k))
     >                            +  vlvu*(f(i,j,k)-f(i,n,k)))

                  else
                     df(i,j,k) = mdv
                  endif

               enddo
            enddo
         enddo

c     Horizontal derivative in the x direction: 3d
      elseif (direction.eq.'x') then

         do i=1,nx
            do j=1,ny
               do k=1,nz
                  
                  w=i-1
                  if (w.lt.1) w=1
                  e=i+1
                  if (e.gt.nx) e=nx

                  if ((abs(f(w,j,k)-mdv).gt.eps).and.
     >                (abs(f(i,j,k)-mdv).gt.eps).and.
     >                (abs(f(e,j,k)-mdv).gt.eps)) then  
 
                     vu = 1000.*(x2(i,j)-x2(e,j))
                     vl = 1000.*(x2(w,j)-x2(i,j))
                     vuvl = vu/(vl+zerodiv)
                     vlvu = 1./(vuvl+zerodiv)
 
                     df(i,j,k) =  1./(vu+vl)
     >                            * (vuvl*(f(w,j,k)-f(i,j,k))
     >                            +  vlvu*(f(i,j,k)-f(e,j,k)))

                  else
                     df(i,j,k) = mdv
                  endif

               enddo
            enddo
         enddo
            
c     Undefined direction for derivative
      else
         
         print*,'Invalid direction of derivative... Stop'
         stop
      
      endif

      end

c     -----------------------------------------------------------------
c     Horizontal filter
c     -----------------------------------------------------------------

      subroutine filt2d (a,af,nx,ny,fil,misdat,
     &                   iperx,ipery,ispol,inpol)

c     Apply a conservative diffusion operator onto the 2d field a,
c     with full missing data checking.
c
c     a     real   inp  array to be filtered, dimensioned (nx,ny)
c     af    real   out  filtered array, dimensioned (nx,ny), can be
c                       equivalenced with array a in the calling routine
c     f1    real        workarray, dimensioned (nx+1,ny)
c     f2    real        workarray, dimensioned (nx,ny+1)
c     fil   real   inp  filter-coeff., 0<afil<=1. Maximum filtering with afil=1
c                       corresponds to one application of the linear filter.
c     misdat real  inp  missing-data value, a(i,j)=misdat indicates that
c                       the corresponding value is not available. The
c                       misdat-checking can be switched off with with misdat=0.
c     iperx int    inp  periodic boundaries in the x-direction (1=yes,0=no)
c     ipery int    inp  periodic boundaries in the y-direction (1=yes,0=no)
c     inpol int    inp  northpole at j=ny  (1=yes,0=no)
c     ispol int    inp  southpole at j=1   (1=yes,0=no)
c
c     Christoph Schaer, 1993

c     argument declaration
      integer     nx,ny
      real        a(nx,ny),af(nx,ny),fil,misdat
      integer     iperx,ipery,inpol,ispol

c     local variable declaration
      integer     i,j,is
      real        fh
      real        f1(nx+1,ny),f2(nx,ny+1)

c     compute constant fh
      fh=0.125*fil

c     compute fluxes in x-direction
      if (misdat.eq.0.) then
        do j=1,ny
        do i=2,nx
          f1(i,j)=a(i-1,j)-a(i,j)
        enddo
        enddo
      else
        do j=1,ny
        do i=2,nx
          if ((a(i,j).eq.misdat).or.(a(i-1,j).eq.misdat)) then
            f1(i,j)=0.
          else
            f1(i,j)=a(i-1,j)-a(i,j)
          endif
        enddo
        enddo
      endif
      if (iperx.eq.1) then
c       do periodic boundaries in the x-direction
        do j=1,ny
          f1(1,j)=f1(nx,j)
          f1(nx+1,j)=f1(2,j)
        enddo
      else
c       set boundary-fluxes to zero
        do j=1,ny
          f1(1,j)=0.
          f1(nx+1,j)=0.
        enddo
      endif

c     compute fluxes in y-direction
      if (misdat.eq.0.) then
        do j=2,ny
        do i=1,nx
          f2(i,j)=a(i,j-1)-a(i,j)
        enddo
        enddo
      else
        do j=2,ny
        do i=1,nx
          if ((a(i,j).eq.misdat).or.(a(i,j-1).eq.misdat)) then
            f2(i,j)=0.
          else
            f2(i,j)=a(i,j-1)-a(i,j)
          endif
        enddo
        enddo
      endif
c     set boundary-fluxes to zero
      do i=1,nx
        f2(i,1)=0.
        f2(i,ny+1)=0.
      enddo
      if (ipery.eq.1) then
c       do periodic boundaries in the x-direction
        do i=1,nx
          f2(i,1)=f2(i,ny)
          f2(i,ny+1)=f2(i,2)
        enddo
      endif
      if (iperx.eq.1) then
        if (ispol.eq.1) then
c         do south-pole
          is=(nx-1)/2
          do i=1,nx
            f2(i,1)=-f2(mod(i-1+is,nx)+1,2)
          enddo
        endif
        if (inpol.eq.1) then
c         do north-pole
          is=(nx-1)/2
          do i=1,nx
            f2(i,ny+1)=-f2(mod(i-1+is,nx)+1,ny)
          enddo
        endif
      endif

c     compute flux-convergence -> filter
      if (misdat.eq.0.) then
        do j=1,ny
        do i=1,nx
            af(i,j)=a(i,j)+fh*(f1(i,j)-f1(i+1,j)+f2(i,j)-f2(i,j+1))
        enddo
        enddo
      else
        do j=1,ny
        do i=1,nx
          if (a(i,j).eq.misdat) then
            af(i,j)=misdat
          else
            af(i,j)=a(i,j)+fh*(f1(i,j)-f1(i+1,j)+f2(i,j)-f2(i,j+1))
          endif
        enddo
        enddo
      endif
      end