Subversion Repositories pvinversion.ecmwf

Rev

Blame | Last modification | View Log | Download | RSS feed

      PROGRAM main_calc_qgpv

c     ********************************************************************************
c     * CALCULATE QUASI-GEOSTROPHIC PV ACCORDING TO ITS DEFINITION                   *
c     * Michael Sprenger / Summer, Autumn 2006                                       *
c     ********************************************************************************

c     --------------------------------------------------------------------------------
c     Declaration of variables, parameters, externals and common blocks
c     --------------------------------------------------------------------------------

      implicit none

c     Input and output file
      character*80   diagfile
      character*80   referfile

c     Grid parameters
      integer        nx,ny,nz
      real           xmin,ymin,zmin,xmax,ymax,zmax
      real           dx,dy,dz
      real           deltax,deltay,deltaz
      real           mdv
      real,          allocatable,dimension (:,:) :: coriol

c     Reference state 
      real,   allocatable,dimension (:) :: nsqref
      real,   allocatable,dimension (:) :: thetaref
      real,   allocatable,dimension (:) :: rhoref
      real,   allocatable,dimension (:) :: pressref
      real,   allocatable,dimension (:) :: zref

c     3d fields for calculation of qgPV 
      real,allocatable,dimension (:,:,:) :: qgpv,th,uu,vv

c     Auxiliary variables
      integer      i,j,k
      integer      stat
      character*80 varname

c     --------------------------------------------------------------------------------
c     Input
c     --------------------------------------------------------------------------------

      print*,'********************************************************'
      print*,'* CALC_QGPV                                            *'
      print*,'********************************************************'

c     Read parameter file
      open(10,file='fort.10')
       read(10,*) diagfile
       read(10,*) referfile
      close(10) 
      print*
      print*,trim(diagfile)
      print*,trim(referfile)
      print*

c     Get lat/lon gid parameters from input file
      call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
     >               diagfile)
      print*,'Read_Dim: nx,ny,nz         = ',nx,ny,nz
      print*,'          dx,dy,dz         = ',dx,dy,dz
      print*,'          xmin,ymin,zmin   = ',xmin,ymin,zmin
      print*,'          mdv              = ',mdv
      print*

c     Count from 0, not from 1: consistent with <inv_cart.f>.
      nx=nx-1
      ny=ny-1
      nz=nz-1

c     Allocate memory for Coriolis parameters
      allocate(coriol(0:nx,0:ny),STAT=stat)
      if (stat.ne.0) print*,'error allocating coriol'

c     Allocate memory for reference profile
      allocate(rhoref  (0:2*nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating rhoref'
      allocate(pressref(0:2*nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating pressref'
      allocate(thetaref(0:2*nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating thetaref'
      allocate(nsqref  (0:2*nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating nsqref'
      allocate(zref    (0:2*nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating zref'
         
c     Allocate memory for 3d fields
      allocate(qgpv(0:nx,0:ny,0:nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating qgpv'
      allocate(uu(0:nx,0:ny,0:nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating uu'
      allocate(vv(0:nx,0:ny,0:nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating vv'
      allocate(th(0:nx,0:ny,0:nz),STAT=stat)
      if (stat.ne.0) print*,'error allocating th'
      

c     --------------------------------------------------------------------------------
c     Calculate the qgPV from definition and put it onto file
c     --------------------------------------------------------------------------------

c     Read data from file
      varname='U'
      call read_inp (uu,varname,diagfile,
     >               nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
      varname='V'
      call read_inp (vv,varname,diagfile,
     >               nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
      varname='TH'
      call read_inp (th,varname,diagfile,
     >               nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)

c     Read reference profile and grid parameters
      call read_ref (nsqref,rhoref,thetaref,pressref,zref,
     >               nx,ny,nz,deltax,deltay,deltaz,coriol,
     >               referfile)
      deltax=1000.*deltax
      deltay=1000.*deltay
      print*,'Deltax,deltay,deltaz =',deltax,deltay,deltaz

c     Calculate qgPV
      print*,'C qgPV'
      call calc_qgpv (qgpv,uu,vv,th,
     >                rhoref,pressref,nsqref,thetaref,coriol,
     >                nx,ny,nz,deltax,deltay,deltaz,mdv)

c     Write result to netcdf file
      varname='QGPV_DIA'
      call write_inp (qgpv,varname,diagfile,nx,ny,nz)

      end

c     ********************************************************************************
c     * NETCDF OUTPUT                                                                *
c     ********************************************************************************

c     --------------------------------------------------------------------------------
c     Write input field to netcdf
c     --------------------------------------------------------------------------------

      SUBROUTINE write_inp (field,fieldname,pvsrcfile,nx,ny,nz)

c     Read <fieldname> from netcdf file <pvsrcfile> into <field>. The grid is specified 
c     by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the input 
c     files are consitent with this grid. 

      implicit   none

c     Declaration of subroutine parameters
      integer              nx,ny,nz
      real                 field (0:nx,0:ny,0:nz)
      character*80         fieldname
      character*80         pvsrcfile

c     Auxiliary variables
      integer              cdfid,stat
      integer              vardim(4)
      real                 misdat
      real                 varmin(4),varmax(4),stag(4)
      integer              ndimin,outid,i,j,k
      real                 max_th
      real                 tmp(0:nx,0:ny,0:nz)
      integer              ntimes
      real                 time(200)       
      integer              nvars
      character*80         vnam(100),varname
      integer              isok

c     Get grid parameters from THETA
      call cdfopn(pvsrcfile,cdfid,stat)
      if (stat.ne.0) goto 998
      call getvars(cdfid,nvars,vnam,stat)
      if (stat.ne.0) goto 998
      isok=0
      varname='TH'
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 998
      call getdef(cdfid,varname,ndimin,misdat,vardim,
     >            varmin,varmax,stag,stat)    
      if (stat.ne.0) goto 998
      time(1)=0.
      call gettimes(cdfid,time,ntimes,stat)  
      if (stat.ne.0) goto 998
      call clscdf(cdfid,stat)
      if (stat.ne.0) goto 998

c     Save variables (write definition, if necessary)
      call cdfwopn(pvsrcfile,cdfid,stat)
      if (stat.ne.0) goto 998
      isok=0
      varname=fieldname
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) then
         call putdef(cdfid,varname,ndimin,misdat,vardim,
     >               varmin,varmax,stag,stat)
         if (stat.ne.0) goto 998
      endif
      call putdat(cdfid,varname,time(1),0,field,stat)
      print*,'W ',trim(varname),' ',trim(pvsrcfile)
      if (stat.ne.0) goto 998

c     Close input netcdf file
      call clscdf(cdfid,stat)
      if (stat.ne.0) goto 998
      
      return

c     Exception handling
 998  print*,'Write_Inp: Problem with input netcdf file... Stop'
      stop

      end

c     --------------------------------------------------------------------------------
c     Read input fields 
c     --------------------------------------------------------------------------------

      SUBROUTINE read_inp (field,fieldname,pvsrcfile,
     >                     nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)

c     Read <fieldname> from netcdf file <pvsrcfile> into <field>. The grid is specified 
c     by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the input 
c     files are consitent with this grid. The missing data value is set to <mdv>.

      implicit   none

c     Declaration of subroutine parameters
      integer              nx,ny,nz
      real                 field(0:nx,0:ny,0:nz)
      character*80         fieldname
      character*80         pvsrcfile
      real                 dx,dy,dz,xmin,ymin,zmin
      real                 mdv

c     Numerical and physical parameters
      real                 eps
      parameter            (eps=0.01)

c     Auxiliary variables
      integer              cdfid,stat,cdfid99
      integer              vardim(4)
      real                 misdat
      real                 varmin(4),varmax(4),stag(4)
      integer              ndimin,outid,i,j,k
      real                 max_th
      real                 tmp(nx,ny,nz)
      integer              ntimes
      real                 time(200)       
      integer              nvars
      character*80         vnam(100),varname
      integer              isok

c     Open the input netcdf file
      call cdfopn(pvsrcfile,cdfid,stat)
      if (stat.ne.0) goto 998

c     Check whether needed variables are on file
      call getvars(cdfid,nvars,vnam,stat)
      if (stat.ne.0) goto 998
      isok=0
      varname=trim(fieldname)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 998

c     Get the grid parameters from theta     
      call getdef(cdfid,varname,ndimin,misdat,vardim,
     >            varmin,varmax,stag,stat)    
      if (stat.ne.0) goto 998
      time(1)=0.
      call gettimes(cdfid,time,ntimes,stat)  
      if (stat.ne.0) goto 998

c     Check whether grid parameters are consistent
      if ( (vardim(1).ne.(nx+1)).or.
     >     (vardim(2).ne.(ny+1)).or.
     >     (vardim(3).ne.(nz+1)).or.
     >     (abs(varmin(1)-xmin).gt.eps).or.
     >     (abs(varmin(2)-ymin).gt.eps).or.
     >     (abs(varmin(3)-zmin).gt.eps).or.
     >     (abs((varmax(1)-varmin(1))/real(vardim(1)-1)-dx).gt.eps).or.
     >     (abs((varmax(2)-varmin(2))/real(vardim(2)-1)-dy).gt.eps).or.
     >     (abs((varmax(3)-varmin(3))/real(vardim(3)-1)-dz).gt.eps) ) 
     >then
         print*,'Input grid inconsitency...'
         print*,'  Nx      = ',vardim(1),nx+1
         print*,'  Ny      = ',vardim(2),ny+1
         print*,'  Nz      = ',vardim(3),nz+1
         print*,'  Varminx = ',varmin(1),xmin
         print*,'  Varminy = ',varmin(2),ymin
         print*,'  Varminz = ',varmin(3),zmin
         print*,'  Dx      = ',(varmax(1)-varmin(1))/real(nx-1),dx
         print*,'  Dy      = ',(varmax(2)-varmin(2))/real(ny-1),dy
         print*,'  Dz      = ',(varmax(3)-varmin(3))/real(nz-1),dz
         goto 998
      endif

c     Load variables
      call getdef(cdfid,varname,ndimin,misdat,vardim,
     >            varmin,varmax,stag,stat)
      if (stat.ne.0) goto 998
      call getdat(cdfid,varname,time(1),0,field,stat)
      print*, 'R ',trim(varname),' ',trim(pvsrcfile)
      if (stat.ne.0) goto 998

c     Close input netcdf file
      call clscdf(cdfid,stat)
      if (stat.ne.0) goto 998

c     Set missing data value to <mdv>
      do i=1,nx
         do j=1,ny
            do k=1,nz
               if (abs(field(i,j,k)-misdat).lt.eps) then
                  field(i,j,k)=mdv
               endif
            enddo
         enddo
      enddo

      return

c     Exception handling
 998  print*,'Read_Inp: Problem with input netcdf file... Stop'
      stop

      end

c     --------------------------------------------------------------------------------
c     Read refernece profile from netcdf
c     --------------------------------------------------------------------------------

      SUBROUTINE read_ref (nsqref,rhoref,thetaref,pressref,zref,
     >                     nx,ny,nz,deltax,deltay,deltaz,coriol,
     >                     pvsrcfile) 

c     Read the reference profile from file
c
c         thetaref             : Reference potential temperature (K)
c         pressref             : Reference pressure (Pa)
c         rhoref               : Reference density (kg/m^3)
c         nsqref               : Stratification (s^-1)
c         zref                 : Reference height (m)
c         nx,nny,nz            : Grid dimension in x,y,z direction
c         deltax,deltay,deltaz : Grid spacings used for calculations (m)
c         coriol               : Coriolis parameter (s^-1)
c         pvsrcfile            : Input file

      implicit   none

c     Declaration of subroutine parameters
      integer              nx,ny,nz
      real                 nsqref  (0:2*nz)
      real                 thetaref(0:2*nz)
      real                 rhoref  (0:2*nz)
      real                 pressref(0:2*nz)
      real                 zref    (0:2*nz)
      real                 deltax,deltay,deltaz
      real                 coriol  (0:nx,0:ny)
      character*80         pvsrcfile

c     Numerical and physical parameters
      real                 eps
      parameter            (eps=0.01)

c     Auxiliary variables
      integer              cdfid,stat
      integer              vardim(4)
      real                 misdat
      integer              ndimin
      real                 varmin(4),varmax(4),stag(4)
      integer              i,j,k,nf1
      integer              ntimes
      real                 time(200)  
      character*80         vnam(100),varname
      integer              nvars
      integer              isok,ierr
      real                 x(0:nx,0:ny),y(0:nx,0:ny)
      real                 mean,count

c     Get grid description from topography
      call cdfopn(pvsrcfile,cdfid,stat)
      if (stat.ne.0) goto 997
      call getvars(cdfid,nvars,vnam,stat)
      if (stat.ne.0) goto 997
      isok=0
      varname='ORO'
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdef(cdfid,varname,ndimin,misdat,vardim,
     >            varmin,varmax,stag,stat)    
      if (stat.ne.0) goto 997
      time(1)=0.
      call gettimes(cdfid,time,ntimes,stat)  
      if (stat.ne.0) goto 997
      call clscdf(cdfid,stat)
      if (stat.ne.0) goto 997

c     Open output netcdf file
      call cdfopn(pvsrcfile,cdfid,stat)
      if (stat.ne.0) goto 997
      
c     Create the variable if necessary
      call getvars(cdfid,nvars,vnam,stat)
      if (stat.ne.0) goto 997

c     Read data from netcdf file
      isok=0
      varname='NSQREF'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,nsqref,stat)
      if (stat.ne.0) goto 997

      isok=0
      varname='RHOREF'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,rhoref,stat)
      if (stat.ne.0) goto 997
 
      isok=0
      varname='THETAREF'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,thetaref,stat)
      if (stat.ne.0) goto 997

      isok=0
      varname='PREREF'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,pressref,stat)
      if (stat.ne.0) goto 997

      isok=0
      varname='ZREF'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,zref,stat)
      if (stat.ne.0) goto 997

      isok=0
      varname='CORIOL'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,coriol,stat)
      if (stat.ne.0) goto 997

      isok=0
      varname='X'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,x,stat)
      if (stat.ne.0) goto 997

      isok=0
      varname='Y'
      print*,'R ',trim(varname),' ',trim(pvsrcfile)
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 997
      call getdat(cdfid,varname,time(1),0,y,stat)
      if (stat.ne.0) goto 997

c     Close  netcdf file
      call clscdf(cdfid,stat)
      if (stat.ne.0) goto 997

c     Determine the grid spacings <deltax, deltay, deltaz>
      mean=0.
      count=0.
      do i=1,nx
         do j=0,ny
            mean=mean+abs(x(i,j)-x(i-1,j))
            count=count+1.
         enddo
      enddo
      deltax=mean/count

      mean=0.
      count=0.
      do j=1,ny
         do i=0,nx
            mean=mean+abs(y(i,j)-y(i,j-1))
            count=count+1.
         enddo
      enddo
      deltay=mean/count

      mean=0.
      count=0.
      do k=1,nz-1
         mean=mean+abs(zref(k+1)-zref(k-1))
         count=count+1.
      enddo
      deltaz=mean/count

      return

c     Exception handling
 997  print*,'Read_Ref: Problem with input netcdf file... Stop'
      stop

      end


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)>. If this is 
C     the case, <isok> is incremented by 1. Otherwise <isok> 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     Get grid parameters
c     --------------------------------------------------------------------------------

      subroutine read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
     >                     pvsrcfile)

c     Get the grid parameters from the variable <THETA> on the input file <pvsrcfile>.
c     The grid parameters are
c        nx,ny,nz                : Number of grid points in x, y and z direction
c        xmin,ymin,zmin          : Minimum domain coordinates in x, y and z direction
c        xmax,ymax,zmax          : Maximal domain coordinates in x, y and z direction
c        dx,dy,dz                : Horizontal and vertical resolution
c     Additionally, it is checked whether the vertical grid is equally spaced. If ok,
c     the grid paramters are transformed from lon/lat to distance (in meters)

      implicit none

c     Declaration of subroutine parameters
      character*80   pvsrcfile
      integer        nx,ny,nz
      real           dx,dy,dz
      real           xmin,ymin,zmin,xmax,ymax,zmax
      real           mdv

c     Numerical epsilon and other physical/geoemtrical parameters
      real           eps
      parameter      (eps=0.01)

c     Auxiliary variables
      integer        cdfid,cstid
      integer        ierr
      character*80   vnam(100),varname
      integer        nvars
      integer        isok
      integer        vardim(4)
      real           misdat
      real           varmin(4),varmax(4),stag(4)
      real           aklev(1000),bklev(1000),aklay(1000),bklay(1000)
      real           dh
      character*80   csn
      integer        ndim
      integer        i

c     Get all grid parameters
      call cdfopn(pvsrcfile,cdfid,ierr)
      if (ierr.ne.0) goto 998
      call getvars(cdfid,nvars,vnam,ierr)
      if (ierr.ne.0) goto 998
      isok=0
      varname='TH'
      call check_varok(isok,varname,vnam,nvars)
      if (isok.eq.0) goto 998
      call getcfn(cdfid,csn,ierr)
      if (ierr.ne.0) goto 998
      call cdfopn(csn,cstid,ierr)
      if (ierr.ne.0) goto 998
      call getdef(cdfid,varname,ndim,misdat,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)
      zmin=varmin(3)
      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=varmax(1)
      ymax=varmax(2)
      zmax=varmax(3)
      dz=(zmax-zmin)/real(nz-1)
      call clscdf(cstid,ierr)
      if (ierr.ne.0) goto 998
      call clscdf(cdfid,ierr)
      if (ierr.ne.0) goto 998

c     Check whether the grid is equallay spaced in the vertical
      do i=1,nz-1
         dh=aklev(i+1)-aklev(i)
         if (abs(dh-dz).gt.eps) then
            print*,'Aklev: Vertical grid must be equally spaced... Stop'
            print*,(aklev(i),i=1,nz)
            stop
         endif
         dh=aklay(i+1)-aklay(i)
         if (abs(dh-dz).gt.eps) then
            print*,'Aklay: Vertical grid must be equally spaced... Stop'
            print*,(aklay(i),i=1,nz)
            stop
         endif
      enddo

c     Set missing data value
      mdv=misdat

      return

c     Exception handling
 998  print*,'Read_Dim: Problem with input netcdf file... Stop'
      stop

      end



c     --------------------------------------------------------------------------------
c     Calculate qgPV  from wind and theta 
c     --------------------------------------------------------------------------------       

      subroutine calc_qgpv (qgpv,uu,vv,th,
     >                      rhoref,pressref,nsqref,thetaref,coriol,
     >                      nx,ny,nz,deltax,deltay,deltaz,mdv)

c     Calculate qgPV from  wind and potential temperature according to
c     equation 2.9 p 16 Thesis Rene Fehlmann. Note a cartesian grid with
c     equidistant grid spacings <deltax,deltay,deltaz> is assumend. No
c     'correction' is made for spherical geoemtry.

      implicit none
 
c     Declaration of subroutine parameters
      integer   nx,ny,nz
      real      qgpv(0:nx,0:ny,0:nz)
      real      uu(0:nx,0:ny,0:nz)
      real      vv(0:nx,0:ny,0:nz)
      real      th(0:nx,0:ny,0:nz)
      real      rhoref(0:2*nz)
      real      nsqref(0:2*nz)
      real      thetaref(0:2*nz)
      real      pressref(0:2*nz)
      real      deltax,deltay,deltaz
      real      mdv
      real      coriol(0:nx,0:ny)

c     Numerical epsilon and physical constants
      real       g
      parameter  (g=9.81)
      real       eps
      parameter  (eps=0.01)
      real       scale
      parameter  (scale=1e6)

c     Auxiliary variables
      integer  i,j,k
      integer  kk,jj
      real     dvdx(0:nx,0:ny,0:nz)
      real     dudy(0:nx,0:ny,0:nz)
      real     dtdz(0:nx,0:ny,0:nz)
      real     t1,t2
      
c     Calculate horizontal derivatives dudy and dvdx of velocity
      do k=0,nz
         do j=0,ny
            do i=0,nx
               
c              Calculate dudy
               if (j.eq.0) then
                  if ( (abs(uu(i,1,k)-mdv).gt.eps).and.
     >                 (abs(uu(i,0,k)-mdv).gt.eps)) then
                     dudy(i,0,k)=(uu(i,1,k)-uu(i,0,k))/deltay
                  else
                     dudy(i,0,k)=mdv
                  endif
               elseif (j.eq.ny) then
                  if ( (abs(uu(i,ny,  k)-mdv).gt.eps).and.
     >                 (abs(uu(i,ny-1,k)-mdv).gt.eps)) then
                     dudy(i,ny,k)=(uu(i,ny,k)-uu(i,ny-1,k))/deltay
                  else
                     dudy(i,ny,k)=mdv
                  endif
               else
                  if ( (abs(uu(i,j+1,k)-mdv).gt.eps).and.
     >                 (abs(uu(i,j-1,k)-mdv).gt.eps)) then
                     dudy(i,j,k)=(uu(i,j+1,k)-uu(i,j-1,k))/(2.*deltay)
                  else
                     dudy(i,j,k)=mdv
                  endif
               endif

c              Calculate dvdx
               if (i.eq.0) then
                  if ((abs(vv(1,j,k)-mdv).gt.eps).and.
     >                (abs(vv(0,j,k)-mdv).gt.eps)) then
                     dvdx(0,j,k)=(vv(1,j,k)-vv(0,j,k))/deltax
                  else
                     dvdx(0,j,k)=mdv
                  endif
               elseif (i.eq.nx) then
                  if ((abs(vv(nx,  j,k)-mdv).gt.eps).and.
     >                (abs(vv(nx-1,j,k)-mdv).gt.eps)) then
                     dvdx(nx,j,k)=(vv(nx,j,k)-vv(nx-1,j,k))/deltax
                  else
                     dvdx(nx,j,k)=mdv
                  endif
               else
                  if ((abs(vv(i+1,j,k)-mdv).gt.eps).and.
     >                (abs(vv(i-1,j,k)-mdv).gt.eps)) then
                     dvdx(i,j,k)=(vv(i+1,j,k)-vv(i-1,j,k))/(2.*deltax)
                  else
                     dvdx(i,j,k)=mdv
                  endif
               endif

            enddo               
         enddo
      enddo

c     Calculate vertical derivative of potential temperature
      do i=0,nx
         do j=0,ny
            do k=0,nz

               if (k.eq.0) then
                  if ((abs(th(i,j,2)-mdv).gt.eps).and.
     >                (abs(th(i,j,1)-mdv).gt.eps)) then
                     t1=rhoref(2)*th(i,j,1)/thetaref(2)/nsqref(2)*g
                     t2=rhoref(0)*th(i,j,0)/thetaref(0)/nsqref(0)*g
                     dtdz(i,j,0)=(t1-t2)/deltaz
                  else
                     dtdz(i,j,0)=mdv
                  endif
              else if (k.eq.nz) then
                 if ((abs(th(i,j,nz  )-mdv).gt.eps).and.
     >               (abs(th(i,j,nz-1)-mdv).gt.eps)) then
                    kk=2*nz
                    t1=rhoref(kk  )*th(i,j,nz  )/
     >                     thetaref(kk)/nsqref(kk)*g
                    t2=rhoref(kk-2)*th(i,j,nz-1)/
     >                     thetaref(kk-2)/nsqref(kk-2)*9.8
                    dtdz(i,j,nz)=(t1-t2)/deltaz
                 else
                    dtdz(i,j,nz)=mdv
                 endif
              else
                 if ((abs(th(i,j,k+1)-mdv).gt.eps).and. 
     >               (abs(th(i,j,k  )-mdv).gt.eps).and.
     >               (abs(th(i,j,k-1)-mdv).gt.eps)) then
                    kk=2*k
                    t1=rhoref(kk+1)*(th(i,j,k)+th(i,j,k+1))/2.
     >                 /thetaref(kk+1)/nsqref(kk+1)*g
                    t2=rhoref(kk-1)*(th(i,j,k)+th(i,j,k-1))/2.
     >                 /thetaref(kk-1)/nsqref(kk-1)*g
                    dtdz(i,j,k)=(t1-t2)/deltaz
                 else
                    dtdz(i,j,k)=mdv
                 endif
              endif
              
           enddo
        enddo
      enddo
      
c     Calculate qgPV
      do i=0,nx
         do j=0,ny
            do k=0,nz
               
               kk=2*k

               if ((abs(dudy(i,j,k)-mdv).gt.eps).and. 
     >             (abs(dvdx(i,j,k)-mdv).gt.eps).and.
     >             (abs(dtdz(i,j,k)-mdv).gt.eps)) then
                  
                  qgpv(i,j,k)=-dudy(i,j,k)+dvdx(i,j,k)+ 
     >                        coriol(i,j)*dtdz(i,j,k)/rhoref(kk)
               else
                  qgpv(i,j,k)=mdv
               endif
             
            enddo
         enddo
      enddo

      end