Subversion Repositories pvinversion.ecmwf

Compare Revisions

No changes between revisions

Ignore whitespace Rev 2 → Rev 3

/trunk/pvin/inv_cart.f
0,0 → 1,1529
PROGRAM inv_cart
 
c ********************************************************************************
c * CALCULATES FOR A PV AND THETA DISTRIBUTION OTHER PROGNOSTIC FIELDS BY *
c * MEANS OF A PV INVERSION *
c * *
c * Rene Fehlmann 1994 / Code re-organization: Michael Sprenger, 2006 *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Declaration of variables, parameters, externals and common blocks
c --------------------------------------------------------------------------------
 
implicit none
 
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 Boundary conditions
real, allocatable,dimension (:,:) :: thetatop
real, allocatable,dimension (:,:) :: thetabot
real, allocatable,dimension (:,:) :: ua
real, allocatable,dimension (:,:) :: ub
real, allocatable,dimension (:,:) :: va
real, allocatable,dimension (:,:) :: vb
 
c Potentiual vorticity and stream function
real, allocatable,dimension (:,:,:) :: psi
real, allocatable,dimension (:,:,:) :: pv
 
c Auxiliary arrays for numerics
real, allocatable,dimension (:,:,:) :: a
real, allocatable,dimension (:,:,:) :: b
real, allocatable,dimension (:,:,:) :: c
 
c Input parameters
character*80 pvsrcfile
character*80 referfile
 
c Auxiliary variables
integer i,j,k
integer stat
 
c --------------------------------------------------------------------------------
c Preparations
c --------------------------------------------------------------------------------
 
print*,'********************************************************'
print*,'* INV_CART *'
print*,'********************************************************'
 
c Read parameter file
open(10,file='fort.10')
read(10,*) pvsrcfile
read(10,*) referfile
close(10)
print*
print*,trim(pvsrcfile)
 
 
c Get lat/lon gid parameters from input file
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> pvsrcfile)
print*
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
nx=nx-1
ny=ny-1
nz=nz-1
c Allocate memory for boundary conditions
allocate(thetatop(0:nx,0:ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array thetatop ***'
allocate(thetabot(0:nx,0:ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array thetabot ***'
allocate(ua(0:nx,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ua ***'
allocate(ub(0:nx,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ub ***'
allocate(va(0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array va ***'
allocate(vb(0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array vb ***'
 
c Allocate memory for 3d PV and stream function
allocate(psi(0:nx,0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array psi ***'
allocate(pv(0:nx,0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array pv ***'
 
c Alllocate memory for matrix elements for inversion operator
allocate(a(0:nx,0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array a ***'
allocate(b(0:nx,0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array b ***'
allocate(c(0:nx,0:ny,0:nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array c ***'
 
c Allocate memory for reference profile
allocate(nsqref(0:2*nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array nsqref ***'
allocate(thetaref(0:2*nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array thetaref ***'
allocate(rhoref(0:2*nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array rhoref ***'
allocate(pressref(0:2*nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array pressref ***'
allocate(zref(0:2*nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array zref ***'
 
c Allocate memory for Coriolis parameter
allocate(coriol(0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating coriol'
 
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
 
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
 
c Read input fields from netcdf
call read_inp (pv,thetabot,thetatop,ua,ub,va,vb,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,
> pvsrcfile)
 
c --------------------------------------------------------------------------------
c Perform the inversion
c --------------------------------------------------------------------------------
 
C Init matrix elements for inversion
call matrixel(a,b,c,coriol,nx,ny,nz,nsqref,rhoref,
> deltax,deltay,deltaz)
 
c Inversion
call sor(psi,nsqref,thetatop,thetabot,thetaref,rhoref,coriol,
> pv,ua,ub,va,vb,a,b,c,nx,ny,nz,deltax,deltay,deltaz)
 
c --------------------------------------------------------------------------------
c Output
c --------------------------------------------------------------------------------
 
c Write output to netcdf
print*
call write_out (psi,thetabot,thetatop,ua,ub,va,vb,
> nx,ny,nz,deltax,deltay,deltaz,
> coriol,thetaref,rhoref,pressref,pvsrcfile)
 
 
END
 
 
c ********************************************************************************
c * NETCDF AND ASCII INPUT AND OUTPUT *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Output to netcdf file
c --------------------------------------------------------------------------------
 
SUBROUTINE write_out (psi,thetabot,thetatop,ua,ub,va,vb,nx,ny,nz,
> dx,dy,dz,coriol,thetaref,rhoref,pref,
> pvsrcfile)
 
c Write the result of the inversion to output netcdf
c
c psi : streamm function as calculated from inversion
c thetabot,thetatop : potential temperature at lower and upper boundary
c ua,ub : Zonal wind at western and eastern boundary
c va,vb : Meridional wind at southern and northern boundary
c nx,ny,nz : Grid dimension in x, y and z direction
c dx,dy,dz : Grid resolution
c coriol : Coriolis parameter
c thetaref : Reference profile of potential temperature
c rhoref : Reference profile of density
c pref : Reference profile of pressure
c pvsrcfile : Name of the output netcdf file
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real psi(0:nx,0:ny,0:nz)
real thetatop(0:nx,0:ny)
real thetabot(0:nx,0:ny)
real ua(0:nx,0:nz)
real ub(0:nx,0:nz)
real va(0:ny,0:nz)
real vb(0:ny,0:nz)
character*(30) pvsrcfile
real dx,dy,dz
real thetaref(0:2*nz)
real rhoref(0:2*nz)
real pref(0:2*nz)
real coriol(0:nx,0:ny)
c Numerical and physical parameters
real eps
parameter (eps=0.01)
real g
parameter (g=9.81)
real preunit
parameter (preunit=0.01)
real kappa
parameter (kappa=0.286)
 
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,jj,kk
real tmp(0:nx,0:ny,0:nz)
real pr (0:nx,0:ny,0:nz)
real th (0:nx,0:ny,0:nz)
integer ntimes
real time(200)
character*80 vnam(100),varname
integer nvars
integer isok,ierr
real meanpsi,meancnt
 
c Get grid description
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='QGPV'
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 cdfwopn(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
isok=0
varname='PSI'
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 997
endif
isok=0
varname='U'
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 997
endif
isok=0
varname='V'
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 997
endif
isok=0
varname='TH'
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 997
endif
isok=0
varname='T'
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 997
endif
isok=0
varname='P'
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 997
endif
 
c Write stream function
varname='PSI'
call putdat(cdfid,varname,time(1),0,psi,ierr)
if (stat.ne.0) goto 997
print*,'W PSI ',trim(pvsrcfile)
 
c Calculate and write velocity U: keep southern and northern boundary
do k=0,nz
do i=0,nx
do j=1,ny-1
tmp(i,j,k)=(psi(i,j-1,k)-psi(i,j+1,k))/
> (2.*dy*coriol(i,j))
enddo
tmp(i,0,k) =ua(i,k)
tmp(i,ny,k)=ub(i,k)
enddo
enddo
varname='U'
call putdat(cdfid,varname,time(1),0,tmp,ierr)
if (stat.ne.0) goto 997
print*,'W U ',trim(pvsrcfile)
 
C Calculate and write velocity V: keep western and eastern boundary
do k=0,nz
do j=0,ny
do i=1,nx-1
tmp(i,j,k)=(psi(i+1,j,k)-psi(i-1,j,k))/
> (2.*dx*coriol(i,j))
enddo
tmp(0,j,k)=va(j,k)
tmp(nx,j,k)=vb(j,k)
enddo
enddo
varname='V'
call putdat(cdfid,varname,time(1),0,tmp,ierr)
if (stat.ne.0) goto 997
print*,'W V ',trim(pvsrcfile)
c Calculate and write potential temperature: keep lower and upper boundary
c Potential temperature is needed for calculation of temperature: keep it
do i=0,nx
do j=0,ny
th(i,j,0)=thetabot(i,j)
do k=1,nz-1
th(i,j,k)=thetaref(2*k)*
> (psi(i,j,k+1)-psi(i,j,k-1))/(2.*dz*g)
 
enddo
th(i,j,nz)=thetatop(i,j)
enddo
enddo
varname='TH'
call putdat(cdfid,varname,time(1),0,th,ierr)
if (stat.ne.0) goto 997
print*,'W TH ',trim(pvsrcfile)
 
c Calculate and write pressure: The pressure is directly proportional to the
c streamfunction. But the streamfunction is determined only up to an additive
c constant. Shift the streamfunction in such a way that it vanish in the mean
c on the boundaries. Pressure is needed for calculation of temperature: keep it
meanpsi=0.
meancnt=0.
do i=0,nx
do j=0,ny
meanpsi=meanpsi+psi(i,j,0)+psi(i,j,nz)
meancnt=meancnt+2
enddo
enddo
do i=0,nx
do k=0,nz
meanpsi=meanpsi+psi(i,0,k)+psi(i,ny,k)
meancnt=meancnt+2
enddo
enddo
do j=0,ny
do k=0,nz
meanpsi=meanpsi+psi(0,j,k)+psi(nx,j,k)
meancnt=meancnt+2
enddo
enddo
meanpsi=meanpsi/meancnt
do i=0,nx
do j=0,ny
do k=0,nz
kk=2*k
pr(i,j,k)=preunit*rhoref(kk)*(psi(i,j,k)-meanpsi)
enddo
enddo
enddo
varname='P'
call putdat(cdfid,varname,time(1),0,pr,ierr)
if (stat.ne.0) goto 997
print*,'W P ',trim(pvsrcfile)
 
c Calculate and write temperature
do i=0,nx
do j=0,ny
do k=0,nz
kk=2*k
tmp(i,j,k)=((pref(kk)/1000.)**kappa) *
> (th(i,j,k)+kappa*thetaref(kk)*pr(i,j,k)/pref(kk))
enddo
enddo
enddo
varname='T'
call putdat(cdfid,varname,time(1),0,tmp,ierr)
if (stat.ne.0) goto 997
print*,'W T ',trim(pvsrcfile)
 
c Close output netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
 
return
 
c Exception handling
997 print*,'Problem with output netcdf file... Stop'
stop
 
end
 
 
c --------------------------------------------------------------------------------
c Read the reference file
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 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='QGPV'
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 Read the input netcdf file
c --------------------------------------------------------------------------------
 
SUBROUTINE read_inp (pv,thetabot,thetatop,ua,ub,va,vb,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,
> pvsrcfile)
 
c Read all needed field from netcdf file <pvsrcfile>. The input fields are:
c pv : quasigeostrophic potential vorticity
c thetabot,thetatop : potential temperature at lower and upper boundary
c ua,ub : Zonal wind at western and eastern boundary
c va,vb : Meridional wind at southern and northern boundary
c The grid is specified by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed
c whether the input files are consitent with this grid. The input netcdf file must
c contain the variables <QGPV,THETA,U,V>. If the netcdf file also contains the fields
c <DQGPV,DTHETA,DU,DV>, these increments are added to <QGPV,THETA,U,V>.
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real pv(0:nx,0:ny,0:nz)
real thetatop(0:nx,0:ny)
real thetabot(0:nx,0:ny)
real ua(0:nx,0:nz)
real ub(0:nx,0:nz)
real va(0:ny,0:nz)
real vb(0:ny,0:nz)
character*(30) pvsrcfile
real dx,dy,dz,xmin,ymin,zmin
 
c Numerical and physical parameters
real eps
parameter (eps=0.01)
 
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 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='TH'
call check_varok(isok,varname,vnam,nvars)
varname='U'
call check_varok(isok,varname,vnam,nvars)
varname='V'
call check_varok(isok,varname,vnam,nvars)
varname='QGPV'
call check_varok(isok,varname,vnam,nvars)
if (isok.ne.4) goto 998
 
c Get the grid parameters
varname='QGPV'
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 consitent
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(nx)-dx).gt.eps).or.
> (abs((varmax(2)-varmin(2))/real(ny)-dy).gt.eps).or.
> (abs((varmax(3)-varmin(3))/real(nz)-dz).gt.eps) ) then
print*,'Input grid inconsitency...'
print*,'xmin : ',xmin,varmin(1)
print*,'ymin : ',ymin,varmin(2)
print*,'zmin : ',zmin,varmin(3)
print*,'dx : ',dx,(varmax(1)-varmin(1))/real(nx)
print*,'dy : ',dy,(varmax(2)-varmin(2))/real(ny)
print*,'dz : ',dz,(varmax(3)-varmin(3))/real(nz)
print*,'nx : ',nx
print*,'ny : ',ny
print*,'nz : ',nz
goto 998
endif
 
c THETA: Load upper and lower boundary values
varname='TH'
call getdat(cdfid,varname,time(1),0,tmp,stat)
print*,'R TH ',trim(pvsrcfile)
if (stat.ne.0) goto 998
do i=0,nx
do j=0,ny
if ( abs(tmp(i,j,0)-misdat).lt.eps ) then
thetabot(i,j)=0.
else
thetabot(i,j)=tmp(i,j,0)
endif
if ( abs(tmp(i,j,nz)-misdat).lt.eps ) then
thetatop(i,j)=0.
else
thetatop(i,j)=tmp(i,j,nz)
endif
enddo
enddo
 
c U: Load zonal velocity at southern and northern boundary
varname='U'
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
call getdat(cdfid,varname,time(1),0,tmp,stat)
print*,'R U ',trim(pvsrcfile)
if (stat.ne.0) goto 998
do i=0,nx
do k=0,nz
if ( abs(tmp(i,0,k)-misdat).lt.eps ) then
ua(i,k)=0.
else
ua(i,k)=tmp(i,0,k)
endif
if ( abs(tmp(i,ny,k)-misdat).lt.eps ) then
ub(i,k)=0.
else
ub(i,k)=tmp(i,ny,k)
endif
enddo
enddo
 
c Load meridional velocity at western and eastern boundary
varname='V'
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
call getdat(cdfid,varname,time(1),0,tmp,stat)
print*,'R V ',trim(pvsrcfile)
if (stat.ne.0) goto 998
do j=0,ny
do k=0,nz
if ( abs(tmp(0,j,k)-misdat).lt.eps ) then
va(j,k)=0.
else
va(j,k)=tmp(0,j,k)
endif
if ( abs(tmp(nx,j,k)-misdat).lt.eps ) then
vb(j,k)=0.
else
vb(j,k)=tmp(nx,j,k)
endif
enddo
enddo
 
c Load qgPV
varname='QGPV'
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
call getdat(cdfid,varname,time(1),0,tmp,stat)
print*,'R QGPV ',trim(pvsrcfile)
if (stat.ne.0) goto 998
do i=0,nx
do j=0,ny
do k=0,nz
if ( abs(tmp(i,j,k)-misdat).lt.eps ) then
pv(i,j,k)=0.
else
pv(i,j,k)=tmp(i,j,k)
endif
enddo
enddo
enddo
 
c Close input netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
 
return
 
c Exception handling
998 print*,'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 * INVERSION ROUTINES *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c SOR algorithm (successive over relaxation)
c --------------------------------------------------------------------------------
 
SUBROUTINE sor(psi,nsq,thetatop,thetabot,thetaref,rhoref,
> coriol,pv,ua,ub,va,vb,a,b,c,nx,ny,nz,dx,dy,dz)
 
c Solve the qgPV equation by succesive over relaxation (SOR). The subroutine
c parameters are:
c
c psi : Streamfunction, i.e. result of the PV inversion
c nsq,rhoref,thetaref : Reference profile
c thetatop,thetabot : Upper and lower boundary condition
c pv : quasigeostrophic potential vorticity (qgPV)
c ua,ub,va,vb : lateral boundary condition for wind
c a,b,c : Matrices for the inversion operator
c nx,ny,nz,dx,dy,dz : Grid specification
c coriol : Coriolis parameter
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real dx,dy,dz
real psi (0:nx,0:ny,0:nz)
real nsq (0:2*nz)
real thetatop(0:nx,0:ny)
real thetabot(0:nx,0:ny)
real thetaref(0:2*nz)
real rhoref (0:2*nz)
real pv (0:nx,0:ny,0:nz)
real ua (0:nx,0:nz)
real ub (0:nx,0:nz)
real va (0:ny,0:nz)
real vb (0:ny,0:nz)
real a (0:nx,0:ny,0:nz)
real b (0:nx,0:ny,0:nz)
real c (0:nx,0:ny,0:nz)
real coriol (0:nx,0:ny)
 
c Numerical and physical parameters
real maxspec
parameter (maxspec=2.0)
integer nofiter
parameter (nofiter=500)
real omega
parameter (omega=1.81)
c Auxiliary variables
integer counter
integer i,j,k
real deltasq,psigauge
real specx,specy,specz
real helpx,helpy,helpz
 
c Init the output array
do i=0,nx
do j=0,ny
do k=0,nz
psi(i,j,k)=0.
enddo
enddo
enddo
 
c Calculate the spectrum of the matrix
i=nx/2
specx=4.*a(i,0,0)/
> (2.*a(i,0,0)+b(i,0,0)+b(i,1,0)+c(i,0,0)+c(i,0,1))
specy=2.*(b(i,0,0)+b(i,1,0))/
> (2.*a(i,0,0)+b(i,0,0)+b(i,1,0)+c(i,0,0)+c(i,0,1))
specz=2.*(c(i,0,0)+c(i,0,1))/
> (2.*a(i,0,0)+b(i,0,0)+b(i,1,0)+c(i,0,0)+c(i,0,1))
do k=1,nz-2
do j=1,ny-2
 
helpx=4.*a(i,j,k)/
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k)+c(i,j,k-1))
if (helpx.gt.specx) specx=helpx
helpy=2.*(b(i,j,k)+b(i,j+1,k))/
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k)+c(i,j,k-1))
if (helpy.gt.specy) specy=helpy
 
helpz=2.*(c(i,j,k)+c(i,j,k+1))/
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k)+c(i,j,k-1))
if (helpz.gt.specz) specz=helpz
 
enddo
enddo
 
c Check whether the dimensions of the grid are sufficient
print *
print *, 'Spectrum of the matrix in each direction '
print *, 'Spectrum = ', specx, specy, specz
print *
if ((maxspec*specx.lt.specy).or.(maxspec*specx.lt.specz)) then
print*,' Nx too small... Stop'
stop
endif
if ((maxspec*specy.lt.specx).or.(maxspec*specy.lt.specz)) then
print*,'Ny too small... Stop'
stop
endif
if ((maxspec*specz.lt.specx).or.(maxspec*specz.lt.specy)) then
print*,'Nz too small... Stop'
stop
endif
 
c Calculate error: control variable for the iteration
psigauge=0.
deltasq=0.
do k=1,nz-1
do i=1,nx-1
do j=1,ny-1
deltasq=deltasq+(-pv(i,j,k)+(
> a(i,j,k)*(psi(i+1,j,k)+psi(i-1,j,k)-
> 2.*psi(i,j,k)) +
> b(i,j,k)*(psi(i,j+1,k)-psi(i,j,k))-
> b(i,j-1,k)*(psi(i,j,k)-psi(i,j-1,k))+
> c(i,j,k)*(psi(i,j,k+1)-psi(i,j,k))-
> c(i,j,k-1)*(psi(i,j,k)-psi(i,j,k-1))
> )/(dx*dy*dz*rhoref(2*k)))**2.
enddo
enddo
enddo
print 102, 'psigauge', psigauge, 'deltasq',
> deltasq/(real(nx)*real(ny)*real(nz))
 
c Iterations
do counter=1,nofiter
 
C Perform one iteration step
call psiappsor(omega,pv,psi,nsq,rhoref,thetatop,
> thetabot,thetaref,coriol,ua,ub,va,vb,
> a,b,c,nx,ny,nz,dx,dy,dz)
 
 
c Adjustment
if (mod(counter,100).eq.0) then
psigauge=0.
do i=0,nx
do j=0,ny
if (psi(i,j,0).lt.psigauge) then
psigauge=psi(i,j,0)
endif
enddo
enddo
do k=0,nz
do i=0,nx
do j=0,ny
psi(i,j,k)=psi(i,j,k)-psigauge
enddo
enddo
enddo
endif
 
c Calculate error: control variable for the iteration
if (mod(counter,nofiter/10).eq.0) then
deltasq=0.
do k=1,nz-1
do i=1,nx-1
do j=1,ny-1
deltasq=deltasq+(-pv(i,j,k)+(
> a(i,j,k)*(psi(i+1,j,k)+psi(i-1,j,k)-
> 2.*psi(i,j,k)) +
> b(i,j,k)*(psi(i,j+1,k)-psi(i,j,k))-
> b(i,j-1,k)*(psi(i,j,k)-psi(i,j-1,k))+
> c(i,j,k)*(psi(i,j,k+1)-psi(i,j,k))-
> c(i,j,k-1)*(psi(i,j,k)-psi(i,j,k-1))
> )/(dx*dy*dz*rhoref(2*k)))**2.
enddo
enddo
enddo
print 102, 'psigauge', psigauge, 'deltasq',
> deltasq/(real(nx)*real(ny)*real(nz))
endif
 
enddo
 
return
 
c Format specifications
102 format (a11, ' = ',e10.3,a11, ' = ',e10.3)
 
end
 
c --------------------------------------------------------------------------------
c SOR algorithm (successive over relaxation)
c --------------------------------------------------------------------------------
 
subroutine psiappsor(omega,pv,psi,nsq,rhoref,thetatop,
> thetabot,thetaref,coriol,ua,ub,va,vb,
> a,b,c,nx,ny,nz,dx,dy,dz)
 
c Perform one relaxation step
c
c psi : Streamfunction, i.e. result of the PV inversion
c nsq,rhoref,thetaref : Reference profile
c thetatop,thetabot : Upper and lower boundary condition
c pv : quasigeostrophic potential vorticity (qgPV)
c ua,ub,va,vb : lateral boundary condition for wind
c a,b,c : Matrices for the inversion operator
c nx,ny,nz,dx,dy,dz : Grid specification
c nofiter : Number of iterations
c omega : Relaxation parameter
c coriol : Coriolis parameter
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real pv(0:nx,0:ny,0:nz)
real psi(0:nx,0:ny,0:nz)
real nsq(0:2*nz)
real rhoref(0:2*nz)
real thetatop(0:nx,0:ny)
real thetabot(0:nx,0:ny)
real thetaref(0:2*nz)
real ua(0:nx,0:nz)
real ub(0:nx,0:nz)
real va(0:ny,0:nz)
real vb(0:ny,0:nz)
real a(0:nx,0:ny,0:nz)
real b(0:nx,0:ny,0:nz)
real c(0:nx,0:ny,0:nz)
real coriol(0:nx,0:ny)
real dx,dy,dz
real omega
 
c Numerical and physical parameters
real g
parameter (g=9.81)
 
c Auxiliary variables
integer i,j,k
real dxy,dxz,dyz,dxyz
 
c Set the area and volume infinitesimals for integration
dxy=dx*dy
dxz=dx*dz
dyz=dy*dz
dxyz=dx*dy*dz
 
c Inner
do k=1,nz-1
do i=1,nx-1
do j=1,ny-1
psi(i,j,k)=omega*(-dxyz*
> rhoref(2*k)*pv(i,j,k)+a(i,j,k)*
> (psi(i+1,j,k)+psi(i-1,j,k))+b(i,j,k)*
> psi(i,j+1,k)+b(i,j-1,k)*psi(i,j-1,k)+c(i,j,k)*
> psi(i,j,k+1)+c(i,j,k-1)*psi(i,j,k-1))/
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k-1)+
> c(i,j,k))+(1.-omega)*psi(i,j,k)
enddo
enddo
enddo
 
c ZY plane
do k=1,nz-1
do j=1,ny-1
psi(0,j,k)=omega*(-dyz*
> rhoref(2*k)*(dx*pv(0,j,k)+va(j,k))+
> a(0,j,k)*psi(1,j,k)+
> b(0,j,k)*psi(0,j+1,k)+b(0,j-1,k)*psi(0,j-1,k)+
> c(0,j,k)*psi(0,j,k+1)+c(0,j,k-1)*psi(0,j,k-1))/
> (a(0,j,k)+b(0,j,k)+b(0,j-1,k)+c(0,j,k-1)+c(0,j,k))
> +(1.-omega)*psi(0,j,k)
c
psi(nx,j,k)=omega*(-dyz*
> rhoref(2*k)*(dx*pv(nx,j,k)-vb(j,k))+
> a(nx,j,k)*psi(nx-1,j,k)+
> b(nx,j,k)*psi(nx,j+1,k)+b(nx,j-1,k)*psi(nx,j-1,k)+
> c(nx,j,k)*psi(nx,j,k+1)+c(nx,j,k-1)*psi(nx,j,k-1))/
> (a(nx,j,k)+b(nx,j-1,k)+b(nx,j,k)+c(nx,j,k-1)+c(nx,j,k))
> +(1.-omega)*psi(nx,j,k)
enddo
enddo
 
c ZX plane
do k=1,nz-1
do i=1,nx-1
psi(i,0,k)=omega*(-dxz*
> rhoref(2*k)*(dy*pv(i,0,k)-ua(i,k))+
> a(i,0,k)*(psi(i+1,0,k)+psi(i-1,0,k))+
> b(i,0,k)*psi(i,1,k)+
> c(i,0,k)*psi(i,0,k+1)+c(i,0,k-1)*psi(i,0,k-1))/
> (2.*a(i,0,k)+b(i,0,k)+c(i,0,k-1)+c(i,0,k))
> +(1.-omega)*psi(i,0,k)
c
psi(i,ny,k)=omega*(-dxz*
> rhoref(2*k)*(dy*pv(i,ny,k)+ub(i,k))+
> a(i,ny-1,k)*(psi(i+1,ny,k)+psi(i-1,ny,k))+
> b(i,ny-1,k)*psi(i,ny-1,k)+
> c(i,ny-1,k)*psi(i,ny,k+1)+c(i,ny-1,k-1)*
> psi(i,ny,k-1))/(2.*a(i,ny-1,k)+b(i,ny-1,k)+
> c(i,ny-1,k-1)+c(i,ny-1,k))
> +(1.-omega)*psi(i,ny,k)
enddo
enddo
 
c XY plane
do i=1,nx-1
do j=1,ny-1
psi(i,j,0)=omega*(-dxy*rhoref(0)*(
> dz*pv(i,j,0)+g*coriol(i,j)*thetabot(i,j)/
> (nsq(0)*thetaref(0)))+
> a(i,j,0)*(psi(i+1,j,0)+psi(i-1,j,0))+
> b(i,j,0)*psi(i,j+1,0)+b(i,j-1,0)*psi(i,j-1,0)+
> c(i,j,0)*psi(i,j,1))/
> (2.*a(i,j,0)+b(i,j-1,0)+b(i,j,0)+c(i,j,0))
> +(1.-omega)*psi(i,j,0)
c
psi(i,j,nz)=omega*(-dxy*rhoref(2*nz)*(
> dz*pv(i,j,nz)-g*coriol(i,j)*thetatop(i,j)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(i,j,nz)*(psi(i+1,j,nz)+psi(i-1,j,nz))+
> b(i,j,nz)*psi(i,j+1,nz)+b(i,j-1,nz)*psi(i,j-1,nz)+
> c(i,j,nz-1)*psi(i,j,nz-1))/
> (2.*a(i,j,nz)+b(i,j-1,nz)+b(i,j,nz)+c(i,j,nz-1))
> +(1.-omega)*psi(i,j,nz)
enddo
enddo
 
c Y edges
do j=1,ny-1
psi(0,j,0)=omega*(-dy*rhoref(0)*(dxz*pv(0,j,0)+
> dz*va(j,0)+dx*g*coriol(0,j)*thetabot(0,j)/
> (nsq(0)*thetaref(0)))+
> a(0,j,0)*psi(1,j,0)+
> b(0,j,0)*psi(0,j+1,0)+b(0,j-1,0)*psi(0,j-1,0)+
> c(0,j,0)*psi(0,j,1))/
> (a(0,j,0)+b(0,j-1,0)+b(0,j,0)+c(0,j,0))
> +(1.-omega)*psi(0,j,0)
c
psi(nx,j,0)=omega*(-dy*rhoref(0)*(dxz*pv(nx,j,0)-
> dz*vb(j,0)+dx*g*coriol(nx,j)*thetabot(nx,j)/
> (nsq(0)*thetaref(0)))+
> a(nx,j,0)*psi(nx-1,j,0)+
> b(nx,j,0)*psi(nx,j+1,0)+b(nx,j-1,0)*psi(nx,j-1,0)+
> c(nx,j,0)*psi(nx,j,1))/
> (a(nx,j,0)+b(nx,j-1,0)+b(nx,j,0)+c(nx,j,0))
> +(1.-omega)*psi(nx,j,0)
c
psi(0,j,nz)=omega*(-dy*rhoref(2*nz)*(dxz*pv(0,j,nz)+
> dz*va(j,nz)-dx*g*coriol(0,j)*thetatop(0,j)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(0,j,nz)*psi(1,j,nz)+
> b(0,j,nz)*psi(0,j+1,nz)+b(0,j-1,nz)*psi(0,j-1,nz)+
> c(0,j,nz-1)*psi(0,j,nz-1))/
> (a(0,j,nz)+b(0,j-1,nz)+b(0,j,nz)+c(0,j,nz-1))
> +(1.-omega)*psi(0,j,nz)
c
psi(nx,j,nz)=omega*(-dy*rhoref(2*nz)*(dxz*pv(nx,j,nz)-
> dz*vb(j,nz)-dx*g*coriol(nx,j)*thetatop(nx,j)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(nx,j,nz)*psi(nx-1,j,nz)+
> b(nx,j,nz)*psi(nx,j+1,nz)+b(nx,j-1,nz)*psi(nx,j-1,nz)+
> c(nx,j,nz-1)*psi(nx,j,nz-1))/
> (a(nx,j,nz)+b(nx,j-1,nz)+b(nx,j,nz)+c(nx,j,nz-1))
> +(1.-omega)*psi(nx,j,nz)
enddo
 
c X edges
do i=1,nx-1
psi(i,0,0)=omega*(-dx*rhoref(0)*(dyz*pv(i,0,0)-
> dz*ua(i,0)+dy*g*coriol(i,0)*thetabot(i,0)/
> (nsq(0)*thetaref(0)))+
> a(i,0,0)*(psi(i+1,0,0)+psi(i-1,0,0))+
> b(i,0,0)*psi(i,1,0)+
> c(i,0,0)*psi(i,0,1))/
> (2.*a(i,0,0)+b(i,0,0)+c(i,0,0))
> +(1.-omega)*psi(i,0,0)
c
psi(i,ny,0)=omega*(-dx*rhoref(0)*(dyz*pv(i,ny,0)+
> dz*ub(i,0)+dy*g*coriol(i,ny)*thetabot(i,ny)/
> (nsq(0)*thetaref(0)))+
> a(i,ny,0)*(psi(i+1,ny,0)+psi(i-1,ny,0))+
> b(i,ny-1,0)*psi(i,ny-1,0)+
> c(i,ny,0)*psi(i,ny,1))/
> (2.*a(i,ny,0)+b(i,ny-1,0)+c(i,ny,0))
> +(1.-omega)*psi(i,ny,0)
c
psi(i,0,nz)=omega*(-dx*rhoref(2*nz)*(dyz*pv(i,0,nz)-
> dz*ua(i,nz)-dy*g*coriol(i,0)*thetatop(i,0)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(i,0,nz)*(psi(i+1,0,nz)+psi(i-1,0,nz))+
> b(i,0,nz)*psi(i,1,nz)+
> c(i,0,nz-1)*psi(i,0,nz-1))/
> (2.*a(i,0,nz)+b(i,0,nz)+c(i,0,nz-1))
> +(1.-omega)*psi(i,0,nz)
c
psi(i,ny,nz)=omega*(-dx*rhoref(2*nz)*(dyz*pv(i,ny,nz)+
> dz*ub(i,nz)-dy*g*coriol(i,ny)*thetatop(i,ny)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(i,ny,nz)*(psi(i+1,ny,nz)+psi(i-1,ny,nz))+
> b(i,ny-1,nz)*psi(i,ny-1,nz)+
> c(i,ny,nz-1)*psi(i,ny,nz-1))/
> (2.*a(i,ny,nz)+b(i,ny-1,nz)+c(i,ny,nz-1))
> +(1.-omega)*psi(i,ny,nz)
enddo
 
c Z edges
do k=1,nz-1
psi(0,0,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(0,0,k)+
> dy*va(0,k)-dx*ua(0,k))+
> a(0,0,k)*psi(1,0,k)+
> b(0,0,k)*psi(0,1,k)+
> c(0,0,k)*psi(0,0,k+1)+c(0,0,k-1)*psi(0,0,k-1))/
> (a(0,0,k)+b(0,0,k)+c(0,0,k-1)+c(0,0,k))
> +(1.-omega)*psi(0,0,k)
c
psi(nx,0,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(nx,0,k)-
> dy*vb(0,k)-dx*ua(nx,k))+
> a(nx,0,k)*psi(nx-1,0,k)+
> b(nx,0,k)*psi(nx,1,k)+
> c(nx,0,k)*psi(nx,0,k+1)+c(nx,0,k-1)*psi(nx,0,k-1))/
> (a(nx,0,k)+b(nx,0,k)+c(nx,0,k-1)+c(nx,0,k))
> +(1.-omega)*psi(nx,0,k)
c
psi(0,ny,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(0,ny,k)+
> dy*va(ny,k)+dx*ub(0,k))+
> a(0,ny,k)*psi(1,ny,k)+
> b(0,ny-1,k)*psi(0,ny-1,k)+
> c(0,ny,k)*psi(0,ny,k+1)+c(0,ny,k-1)*psi(0,ny,k-1))/
> (a(0,ny,k)+b(0,ny-1,k)+c(0,ny,k-1)+c(0,ny,k))
> +(1.-omega)*psi(0,ny,k)
c
psi(nx,ny,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(nx,ny,k)-
> dy*vb(ny,k)+dx*ub(nx,k))+
> a(nx,ny,k)*psi(nx-1,ny,k)+
> b(nx,ny-1,k)*psi(nx,ny-1,k)+
> c(nx,ny,k)*psi(nx,ny,k+1)+c(nx,ny,k-1)*psi(nx,ny,k-1))/
> (a(nx,ny,k)+b(nx,ny-1,k)+c(nx,ny,k-1)+c(nx,ny,k))
> +(1.-omega)*psi(nx,ny,k)
enddo
 
c Points
psi(0,0,0)=omega*(-rhoref(0)*(dxyz*pv(0,0,0)+dyz*va(0,0)-
> dxz*ua(0,0)+dxy*g*coriol(0,0)*thetabot(0,0)/
> (nsq(0)*thetaref(0)))+
> a(0,0,0)*psi(1,0,0)+
> b(0,0,0)*psi(0,1,0)+
> c(0,0,0)*psi(0,0,1))/
> (a(0,0,0)+b(0,0,0)+c(0,0,0))+
> (1.-omega)*psi(0,0,0)
c
psi(nx,0,0)=omega*(-rhoref(0)*(dxyz*pv(nx,0,0)-dyz*vb(0,0)-
> dxz*ua(nx,0)+dxy*g*coriol(nx,0)*thetabot(nx,0)/
> (nsq(0)*thetaref(0)))+
> a(nx,0,0)*psi(nx-1,0,0)+
> b(nx,0,0)*psi(nx,1,0)+
> c(nx,0,0)*psi(nx,0,1))/
> (a(nx,0,0)+b(nx,0,0)+c(nx,0,0))+
> (1.-omega)*psi(nx,0,0)
c
psi(0,ny,0)=omega*(-rhoref(0)*(dxyz*pv(0,ny,0)+dyz*va(ny,0)+
> dxz*ub(0,0)+dxy*g*coriol(0,ny)*thetabot(0,ny)/
> (nsq(0)*thetaref(0)))+
> a(0,ny,0)*psi(1,ny,0)+
> b(0,ny-1,0)*psi(0,ny-1,0)+
> c(0,ny,0)*psi(0,ny,1))/
> (a(0,ny,0)+b(0,ny-1,0)+c(0,ny,0))+
> (1.-omega)*psi(0,ny,0)
c
psi(nx,ny,0)=omega*(-rhoref(0)*(dxyz*pv(nx,ny,0)-dyz*vb(ny,0)+
> dxz*ub(nx,0)+dxy*g*coriol(nx,ny)*thetabot(nx,ny)/
> (nsq(0)*thetaref(0)))+
> a(nx,ny,0)*psi(nx-1,ny,0)+
> b(nx,ny-1,0)*psi(nx,ny-1,0)+
> c(nx,ny,0)*psi(nx,ny,1))/
> (a(nx,ny,0)+b(nx,ny-1,0)+c(nx,ny,0))+
> (1.-omega)*psi(nx,ny,0)
c
psi(0,0,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(0,0,nz)+dyz*va(0,nz)-
> dxz*ua(0,nz)-dxy*g*coriol(0,0)*thetatop(0,0)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(0,0,nz)*psi(1,0,nz)+
> b(0,0,nz)*psi(0,1,nz)+
> c(0,0,nz-1)*psi(0,0,nz-1))/
> (a(0,0,nz)+b(0,0,nz)+c(0,0,nz-1))+
> (1.-omega)*psi(0,0,nz)
c
psi(nx,0,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(nx,0,nz)-dyz*vb(0,nz)
> -dxz*ua(nx,nz)-dxy*g*coriol(nx,0)*thetatop(nx,0)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(nx,0,nz)*psi(nx-1,0,nz)+
> b(nx,0,nz)*psi(nx,1,nz)+
> c(nx,0,nz-1)*psi(nx,0,nz-1))/
> (a(nx,0,nz)+b(nx,0,nz)+c(nx,0,nz-1))+
> (1.-omega)*psi(nx,0,nz)
c
psi(0,ny,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(0,ny,nz)+
> dyz*va(ny,nz)+dxz*ub(0,nz)-
> dxy*g*coriol(0,ny)*thetatop(0,ny)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(0,ny,nz)*psi(1,ny,nz)+
> b(0,ny-1,nz)*psi(0,ny-1,nz)+
> c(0,ny,nz-1)*psi(0,ny,nz-1))/
> (a(0,ny,nz)+b(0,ny-1,nz)+c(0,ny,nz-1))+
> (1.-omega)*psi(0,ny,nz)
c
psi(nx,ny,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(nx,ny,nz)-
> dyz*vb(ny,nz)+dxz*ub(nx,nz)-
> dxy*g*coriol(nx,ny)*thetatop(nx,ny)/
> (nsq(2*nz)*thetaref(2*nz)))+
> a(nx,ny,nz)*psi(nx-1,ny,nz)+
> b(nx,ny-1,nz)*psi(nx,ny-1,nz)+
> c(nx,ny,nz-1)*psi(nx,ny,nz-1))/
> (a(nx,ny,nz)+b(nx,ny-1,nz)+c(nx,ny,nz-1))+
> (1.-omega)*psi(nx,ny,nz)
c
 
end
 
c --------------------------------------------------------------------------------
c Init matrix elements for the inversion
c --------------------------------------------------------------------------------
 
subroutine matrixel(a,b,c,coriol,nx,ny,nz,nsq,rhoref,dx,dy,dz)
 
c Define the coefficients for the inversion problem (see page 119ff in Rene's
c dissertation).
 
implicit none
 
c Declaration of subroutine parameters
integer nx,nz,ny
real a (0:nx,0:ny,0:nz)
real b (0:nx,0:ny,0:nz)
real c (0:nx,0:ny,0:nz)
real coriol(0:nx,0:ny)
real nsq (0:2*nz)
real rhoref(0:2*nz)
real dx,dy,dz
 
c Auxiliary variables
integer i,j,k
 
c Calculate coefficients
do i=0,nx
do j=0,ny
do k=0,nz
a(i,j,k)=dy*dz*rhoref(2*k)/(dx*coriol(i,j))
if (j.lt.ny) then
b(i,j,k)=dx*dz*rhoref(2*k)/
> (dy*0.5*(coriol(i,j)+coriol(i,j+1)))
else
b(i,j,k)=0.
endif
if (k.lt.nz) then
c(i,j,k)=dx*dy*rhoref(2*k+1)*coriol(i,j)/
> (dz*nsq(2*k+1))
else
c(i,j,k)=0.
endif
enddo
enddo
enddo
 
end
 
 
 
 
Property changes:
Added: svn:executable
/trunk/pvin/inv_cart.m
0,0 → 1,259
% -------------------------------------------------------------------------
% Load files
% -------------------------------------------------------------------------
 
% Base directory and filename
base = '/net/rossby/lhome/sprenger/PV_Inversion_Tool/run/';
folder = base;
filename = 'ANO_20060115_18';
disp([folder filename])
 
% First image (otherwise first image is not correctly written)
figname = [base '/test.eps'];
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% Load variables from file (on model levels)
z_th = cdf_loadV(folder,filename,'TH');
z_uu = cdf_loadV(folder,filename,'U');
z_vv = cdf_loadV(folder,filename,'V');
z_qgpv = cdf_loadV(folder,filename,'QGPV');
z_psi = cdf_loadV(folder,filename,'PSI');
 
% -------------------------------------------------------------------------
% Plot stream function
% -------------------------------------------------------------------------
 
for ilev=1:z_psi.nz
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set the geographical projection
m_proj('Equidistant Cylindrical','long',[z_psi.lonmin z_psi.lonmax],'lat',[z_psi.latmin z_psi.latmax]);
 
% Scale the plotting field for color map
fld=squeeze(z_psi.var(ilev,:,:));
c_map = scale_col(-4000:500:4000,fld);
 
% Plot Stream Function PSI
lat=z_psi.ymin + (0:z_psi.ny-1) * z_psi.dy;
lon=z_psi.xmin + (0:z_psi.nx-1) * z_psi.dx;
[C,h]=m_contourf(lon,lat,c_map.data,c_map.xtick);
for icnt = 1: length(h)
set( h(icnt), 'EdgeColor', 'none' )
end
 
% Add color bar
colormap('default');
ctb(['/home/sprenger/ECFC_STE_Forecast/ctb_isen'],c_map.xtick,1);
caxis(c_map.caxis);
q=colorbar('vert');
set(q,'ytick',c_map.xtick,'YTickLabel',c_map.label);
 
% Add the grid and the coast lines to the plot
m_grid;
m_coast('linewidth',1,'color','k');
title(num2str(z_psi.aklay(ilev)));
 
% Save figure
pre='';
if ( z_psi.aklay(ilev) < 10 )
pre='0';
end
if ( z_psi.aklay(ilev) < 100 )
pre=[pre '0' ];
end
if ( z_psi.aklay(ilev) < 1000 )
pre=[pre '0' ];
end
if ( z_psi.aklay(ilev) < 10000 )
pre=[pre '0' ];
end
 
figname = [ base '/sf_2d_' filename '_' pre num2str(z_psi.aklay(ilev)) '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% End loop over all levels
end
 
% -------------------------------------------------------------------------
% Plot anomaly of potential temperature
% -------------------------------------------------------------------------
 
for ilev=1:z_th.nz
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set the geographical projection
m_proj('Equidistant Cylindrical','long',[z_th.lonmin z_th.lonmax],'lat',[z_th.latmin z_th.latmax]);
 
% Scale the plotting field for color map
fld=squeeze(z_th.var(ilev,:,:));
c_map = scale_col(-20:2.5:20,fld);
 
% Plot potential temperature
lat=z_th.ymin + (0:z_th.ny-1) * z_th.dy;
lon=z_th.xmin + (0:z_th.nx-1) * z_th.dx;
[C,h]=m_contourf(lon,lat,c_map.data,c_map.xtick);
for icnt = 1: length(h)
set( h(icnt), 'EdgeColor', 'none' )
end
 
% Add color bar
colormap('default');
ctb(['/home/sprenger/ECFC_STE_Forecast/ctb_isen'],c_map.xtick,1);
caxis(c_map.caxis);
q=colorbar('vert');
set(q,'ytick',c_map.xtick,'YTickLabel',c_map.label);
 
% Add the grid and the coast lines to the plot
m_grid;
m_coast('linewidth',1,'color','k');
title(num2str(z_th.aklay(ilev)));
 
% Save figure
pre='';
if ( z_th.aklay(ilev) < 10 )
pre='0';
end
if ( z_th.aklay(ilev) < 100 )
pre=[pre '0' ];
end
if ( z_th.aklay(ilev) < 1000 )
pre=[pre '0' ];
end
if ( z_th.aklay(ilev) < 10000 )
pre=[pre '0' ];
end
 
figname = [ base '/ta_2d_' filename '_' pre num2str(z_th.aklay(ilev)) '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% End loop over all levels
end
 
% -------------------------------------------------------------------------
% Plot anomaly of meridional wind
% -------------------------------------------------------------------------
 
for ilev=1:z_vv.nz
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set the geographical projection
m_proj('Equidistant Cylindrical','long',[z_vv.lonmin z_vv.lonmax],'lat',[z_vv.latmin z_vv.latmax]);
 
% Scale the plotting field for color map
fld=squeeze(z_vv.var(ilev,:,:));
c_map = scale_col(-30:3:30,fld);
 
% Plot potential temperature
lat=z_vv.ymin + (0:z_vv.ny-1) * z_vv.dy;
lon=z_vv.xmin + (0:z_vv.nx-1) * z_vv.dx;
[C,h]=m_contourf(lon,lat,c_map.data,c_map.xtick);
for icnt = 1: length(h)
set( h(icnt), 'EdgeColor', 'none' )
end
 
% Add color bar
colormap('default');
ctb(['/home/sprenger/ECFC_STE_Forecast/ctb_isen'],c_map.xtick,1);
caxis(c_map.caxis);
q=colorbar('vert');
set(q,'ytick',c_map.xtick,'YTickLabel',c_map.label);
 
% Add the grid and the coast lines to the plot
m_grid;
m_coast('linewidth',1,'color','k');
title(num2str(z_vv.aklay(ilev)));
 
% Save figure
pre='';
if ( z_vv.aklay(ilev) < 10 )
pre='0';
end
if ( z_vv.aklay(ilev) < 100 )
pre=[pre '0' ];
end
if ( z_vv.aklay(ilev) < 1000 )
pre=[pre '0' ];
end
if ( z_vv.aklay(ilev) < 10000 )
pre=[pre '0' ];
end
 
figname = [ base '/va_2d_' filename '_' pre num2str(z_vv.aklay(ilev)) '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% End loop over all levels
end
 
% -------------------------------------------------------------------------
% Plot anomaly of zonal wind
% -------------------------------------------------------------------------
 
for ilev=1:z_uu.nz
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set the geographical projection
m_proj('Equidistant Cylindrical','long',[z_uu.lonmin z_uu.lonmax],'lat',[z_uu.latmin z_uu.latmax]);
 
% Scale the plotting field for color map
fld=squeeze(z_uu.var(ilev,:,:));
c_map = scale_col(-30:3:30,fld);
 
% Plot potential temperature
lat=z_uu.ymin + (0:z_uu.ny-1) * z_uu.dy;
lon=z_uu.xmin + (0:z_uu.nx-1) * z_uu.dx;
[C,h]=m_contourf(lon,lat,c_map.data,c_map.xtick);
for icnt = 1: length(h)
set( h(icnt), 'EdgeColor', 'none' )
end
 
% Add color bar
colormap('default');
ctb(['/home/sprenger/ECFC_STE_Forecast/ctb_isen'],c_map.xtick,1);
caxis(c_map.caxis);
q=colorbar('vert');
set(q,'ytick',c_map.xtick,'YTickLabel',c_map.label);
 
% Add the grid and the coast lines to the plot
m_grid;
m_coast('linewidth',1,'color','k');
title(num2str(z_uu.aklay(ilev)));
 
% Save figure
pre='';
if ( z_uu.aklay(ilev) < 10 )
pre='0';
end
if ( z_uu.aklay(ilev) < 100 )
pre=[pre '0' ];
end
if ( z_uu.aklay(ilev) < 1000 )
pre=[pre '0' ];
end
if ( z_uu.aklay(ilev) < 10000 )
pre=[pre '0' ];
end
 
figname = [ base '/ua_2d_' filename '_' pre num2str(z_uu.aklay(ilev)) '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% End loop over all levels
end
Property changes:
Added: svn:executable
/trunk/pvin/prep_iteration.f
0,0 → 1,513
PROGRAM prep_iteration
 
c ************************************************************************
c * Prepare the next step for the PV inversion *
c * Michael Sprenger / Summer, Autumn 2006 *
c ************************************************************************
 
implicit none
 
c ------------------------------------------------------------------------
c Declaration of variables and parameters
c ------------------------------------------------------------------------
c Input and output file
character*80 anomafile
character*80 iterafile
 
c Grid parameters
integer nx,ny,nz
real xmin,ymin,zmin,xmax,ymax,zmax
real dx,dy,dz
real mdv
 
c Numerical epsilon and other variables
real eps
parameter (eps=0.01)
real alpha
 
c 3d arrays
real,allocatable,dimension (:,:,:) :: v_iter,v_anom
real,allocatable,dimension (:,:,:) :: u_iter,u_anom
real,allocatable,dimension (:,:,:) :: t_iter,t_anom
real,allocatable,dimension (:,:,:) :: p_iter,p_anom
 
c Auciliary variables
integer i,j,k
integer stat
character*80 varname
character*80 name
 
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
 
print*,'********************************************************'
print*,'* PREP_ITERATION *'
print*,'********************************************************'
 
c Read parameter file
open(10,file='fort.10')
read(10,*) iterafile
read(10,*) anomafile
read(10,*) name,alpha
if ( trim(name).ne.'ALPHA' ) stop
close(10)
print*
print*,trim(anomafile)
print*,trim(iterafile)
print*
 
c Get lat/lon gid parameters from input file
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> anomafile)
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 3d arrays
allocate(u_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating u_anom'
allocate(v_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating v_anom'
allocate(t_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating t_anom'
allocate(p_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating p_anom'
allocate(u_iter (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating u_iter'
allocate(v_iter (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating v_iter'
allocate(t_iter (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating t_iter'
allocate(p_iter (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating p_iter'
c Read anomaly and iteration fields
varname='U'
call read_inp (u_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='V'
call read_inp (v_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='T'
call read_inp (t_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='P'
call read_inp (p_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='U'
call read_inp (u_iter,varname,iterafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='V'
call read_inp (v_iter,varname,iterafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='T'
call read_inp (t_iter,varname,iterafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='P'
call read_inp (p_iter,varname,iterafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
 
c --------------------------------------------------------------------------------
c Modify the iteration fields
c --------------------------------------------------------------------------------
 
do i=0,nx
do j=0,ny
do k=0,nz
 
c Update zonal velocity
if ((abs(u_anom(i,j,k)-mdv).gt.eps).and.
> (abs(u_iter(i,j,k)-mdv).gt.eps)) then
u_iter(i,j,k)=u_iter(i,j,k)-alpha*u_anom(i,j,k)
else
u_iter(i,j,k)=mdv
endif
 
c Update meridional velocity
if ((abs(v_anom(i,j,k)-mdv).gt.eps).and.
> (abs(v_iter(i,j,k)-mdv).gt.eps)) then
v_iter(i,j,k)=v_iter(i,j,k)-alpha*v_anom(i,j,k)
else
v_iter(i,j,k)=mdv
endif
 
c Update temperature
if ((abs(t_anom(i,j,k)-mdv).gt.eps).and.
> (abs(t_iter(i,j,k)-mdv).gt.eps)) then
t_iter(i,j,k)=t_iter(i,j,k)-alpha*t_anom(i,j,k)
else
t_iter(i,j,k)=mdv
endif
 
c Update pressure
if ((abs(p_anom(i,j,k)-mdv).gt.eps).and.
> (abs(p_iter(i,j,k)-mdv).gt.eps)) then
p_iter(i,j,k)=p_iter(i,j,k)-alpha*p_anom(i,j,k)
else
p_iter(i,j,k)=mdv
endif
 
enddo
enddo
enddo
 
 
c --------------------------------------------------------------------------------
c Write output
c --------------------------------------------------------------------------------
 
varname='U'
call write_inp (u_iter,varname,iterafile,nx,ny,nz)
varname='V'
call write_inp (v_iter,varname,iterafile,nx,ny,nz)
varname='T'
call write_inp (t_iter,varname,iterafile,nx,ny,nz)
varname='P'
call write_inp (p_iter,varname,iterafile,nx,ny,nz)
 
 
end
 
 
 
 
c ********************************************************************************
c * NETCDF INPUT AND 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
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 for reference profile
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 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
 
 
Property changes:
Added: svn:executable
/trunk/pvin/pv_to_qgpv.f
0,0 → 1,894
PROGRAM pv_to_qgpv
 
c ********************************************************************************
c * TRANSFORM ERTEL'S PV TO QUASI-GEOSTROPHIC PV *
c * Rene Fehlmann 1994 / Code re-organization: Michael Sprenger, 2006 *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Declaration of variables, parameters, externals and common blocks
c --------------------------------------------------------------------------------
 
implicit none
 
c Input and output file
character*80 pvsrcfile
character*80 referfile
character*80 anomafile
 
c Grid parameters
integer nx,ny,nz
real xmin,ymin,zmin,xmax,ymax,zmax
real dx,dy,dz
real mdv
 
c Numerical and physical parameters
real pi180 ! Pi/180
parameter (pi180=3.141592654/180.)
real rerd ! Earth's radius
parameter (rerd=6.371229e6)
real eps ! Numerical epsilon
parameter (eps=0.01)
real scale ! Scale for PV unit
parameter (scale=1e6)
real minagl ! No PV and qgPV below this height AGL
parameter (minagl=1000.)
 
c Reference state and grid parameters
real, allocatable,dimension (:) :: nsqref
real, allocatable,dimension (:) :: thetaref
real, allocatable,dimension (:) :: rhoref
real, allocatable,dimension (:) :: pressref
real, allocatable,dimension (:) :: zref
real, allocatable,dimension (:,:) :: coriol
real, allocatable,dimension (:,:) :: oro
real deltax,deltay,deltaz
 
c 3d fields for calculation of qgPV and Ertel's PV
real,allocatable,dimension (:,:,:) :: qgpv,pv1,pv2,pv
 
c Auxiliary variables
real zpos
integer i,j,k
integer stat
character*80 varname
integer istep
real mean,rmsq,min,max
integer step
real,allocatable,dimension (:,:) :: tmp
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
 
print*,'********************************************************'
print*,'* PV_TO_QGPV *'
print*,'********************************************************'
 
 
c Read parameter file
open(10,file='fort.10')
read(10,*) pvsrcfile
read(10,*) referfile
read(10,*) anomafile
close(10)
print*
print*,trim(pvsrcfile)
print*,trim(referfile)
print*,trim(anomafile)
print*
 
c Get lat/lon gid parameters from input file
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> pvsrcfile)
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 reference profile and grid parameters
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'
allocate(coriol (0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating coriol'
allocate(oro (0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating oro'
c Allocate memory for calculation of qgPV and Ertel's PV
allocate(pv1 (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv1'
allocate(pv2 (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv2'
allocate(pv (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv'
allocate(qgpv(0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating qgpv'
 
c Allocate memory for temporary array
allocate(tmp(0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating tmp'
 
c --------------------------------------------------------------------------------
c Calculate the qgPV from Ertel's PV and put it onto file
c --------------------------------------------------------------------------------
 
c Read data from file
varname='PV'
call read_inp (pv1,varname,pvsrcfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='PV_AIM'
call read_inp (pv2,varname,pvsrcfile,
> 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,oro,
> referfile)
 
c If the PV is negative, set it to zero
do i=0,nx
do j=0,ny
do k=0,nz
if (pv1(i,j,k).lt.0.) pv1(i,j,k)=0.
if (pv2(i,j,k).lt.0.) pv2(i,j,k)=0.
enddo
enddo
enddo
 
c Get the difference of Ertel's PV and set all missing values to 0
do i=0,nx
do j=0,ny
do k=0,nz
if ((abs(pv1(i,j,k)-mdv).gt.eps).and.
> (abs(pv2(i,j,k)-mdv).gt.eps)) then
pv(i,j,k)=pv1(i,j,k)-pv2(i,j,k)
else
pv(i,j,k)=0.
endif
enddo
enddo
enddo
 
c Calculate qgPV
call epv_to_qgpv (qgpv,pv,
> rhoref,pressref,nsqref,thetaref,
> nx,ny,nz,mdv)
 
c Set values on the boundaries to zero
do i=0,nx
do j=0,ny
qgpv(i,j, 0)=0.
qgpv(i,j,nz)=0.
enddo
enddo
do i=0,nx
do k=0,nz
qgpv(i, 0,k)=0.
qgpv(i,ny,k)=0.
enddo
enddo
do j=0,ny
do k=0,nz
qgpv( 0,j,k)=0.
qgpv(nx,j,k)=0.
enddo
enddo
 
c Set all values to zero which are too near to the surface
do i=0,nx
do j=0,ny
do k=0,nz
zpos=zmin+real(k)*dz
if (zpos.lt.(oro(i,j)+minagl)) then
pv(i,j,k)=0.
qgpv(i,j,k)=0.
endif
enddo
enddo
enddo
 
c Write result to netcdf file
varname='QGPV'
call write_inp (qgpv,varname,anomafile,nx,ny,nz)
varname='PV'
call write_inp (pv,varname,anomafile,nx,ny,nz)
 
c Write some info
print*
print*,'PV -> qgPV: k z min max mean rmsq'
step=nz/10
if (step.lt.1) step=1
do k=0,nz,step
do i=0,nx
do j=0,ny
tmp(i,j)=qgpv(i,j,k)
enddo
enddo
call calc_error(min,max,mean,rmsq,tmp,nx,ny)
write(*,'(8x,i3,f10.1,4f10.2)')
> k,zmin+real(k)*dz,scale*min,scale*max,
> scale*mean,scale*rmsq
enddo
print*
 
c --------------------------------------------------------------------------------
c Format specifications
c --------------------------------------------------------------------------------
 
111 format (5f20.9)
106 format (2f20.9)
end
 
 
c ********************************************************************************
c * NETCDF INPUT AND 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 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 PV
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='PV'
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 for reference profile
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 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,oro,
> 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 oro : Height of orography (m)
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)
real oro (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='ORO'
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,oro,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)-x(i-1))
count=count+1.
enddo
enddo
deltax=mean/count
 
mean=0.
count=0.
do j=1,ny
do i=0,nx
mean=mean+abs(y(j)-y(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='PV'
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 * CALCULATION *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Calculate qgPV from Ertels's PV
c --------------------------------------------------------------------------------
 
subroutine epv_to_qgpv (qgpv,pv,
> rhoref,pressref,nsqref,thetaref,
> nx,ny,nz,mdv)
 
c Calculate the qgPV from Ertel's PV according to equation 2.11 p16, Thesis
c from Rene Fehlmann.
 
implicit none
c Declaration of subroutine parameters
integer nx,ny,nz
real qgpv(0:nx,0:ny,0:nz),pv(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 mdv
 
c Numerical epsilon
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
 
c Calculation
do i=0,nx
do j=0,ny
do k=0,nz
 
kk=2*k
if (( abs(rhoref(kk) -mdv).gt.eps).and.
> ( abs(thetaref(kk)-mdv).gt.eps).and.
> ( abs(nsqref(kk) -mdv).gt.eps).and.
> ( abs(pv(i,j,k) -mdv).gt.eps)) then
 
qgpv(i,j,k)=rhoref(kk)*g*pv(i,j,k)/thetaref(kk)/
> nsqref(kk)/scale
else
qgpv(i,j,k)=0.
endif
 
enddo
enddo
enddo
 
end
 
c --------------------------------------------------------------------------------
c Calculate error statistics
c --------------------------------------------------------------------------------
 
subroutine calc_error (min,max,mean,rmsq,tmp,nx,ny)
 
c Calculate the error statistics for the two-dimensional error field <tmp>. The
c following error measures are calculated: the minimum <min>, the maximum <max>,
c the mean <mean>, the root-mean square <rmsq>
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny
real tmp(0:nx,0:ny)
real mean,rmsq
real min,max
 
c Auxiliary variables
integer i,j
real sum
integer cnt
 
c Calculate the minimum and maximum
min=tmp(0,0)
max=tmp(0,0)
do i=0,nx
do j=0,ny
if (tmp(i,j).lt.min) min=tmp(i,j)
if (tmp(i,j).gt.max) max=tmp(i,j)
enddo
enddo
 
c Calculate the mean
sum=0.
cnt=0
do i=0,nx
do j=0,ny
cnt=cnt+1
sum=sum+tmp(i,j)
enddo
enddo
if (cnt.ge.1) then
mean=sum/real(cnt)
else
mean=0.
endif
 
c Calculate rmsq
rmsq=0.
cnt=0
do i=0,nx
do j=0,ny
cnt=cnt+1
rmsq=rmsq+(tmp(i,j)-mean)**2
enddo
enddo
if (cnt.ge.1) then
rmsq=1./real(cnt)*sqrt(rmsq)
else
rmsq=0.
endif
 
end
 
 
Property changes:
Added: svn:executable
/trunk/pvin/pv_to_qgpv.m
0,0 → 1,81
 
folder ='/lhome/sprenger/PV_Inversion_Tool/';
filename='Z1_20060115_18';
 
% --------------------------------------------------------------------------
% Plot qgPV anomaly (horizontal sections)
% --------------------------------------------------------------------------
 
% Base directory and filename
base = '/net/rossby/lhome/sprenger/PV_Inversion_Tool/';
folder = base;
filename = 'Z1_20060115_18';
disp([folder filename])
 
% First image (otherwise first image is not correctly written)
figname = [base '/test.eps'];
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% Load variables from file (on model levels)
m_pv = cdf_loadV(folder,filename,'QGPV_ANOM');
 
% Loop over all levels
for ilev=1:m_pv.nz
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set the geographical projection
m_proj('Equidistant Cylindrical','long',[m_pv.lonmin m_pv.lonmax],'lat',[m_pv.latmin m_pv.latmax]);
 
% Scale the plotting field for color map
fld=1e6*squeeze(m_pv.var(ilev,:,:));
c_map = scale_col(0:50:600,fld);
 
% Plot PV
lat=m_pv.ymin + (0:m_pv.ny-1) * m_pv.dy;
lon=m_pv.xmin + (0:m_pv.nx-1) * m_pv.dx;
[C,h]=m_contourf(lon,lat,c_map.data,c_map.xtick);
for icnt = 1: length(h)
set( h(icnt), 'EdgeColor', 'none' )
end
 
% Add color bar
colormap('default');
ctb(['/home/sprenger/ECFC_STE_Forecast/ctb_isen'],c_map.xtick,1);
caxis(c_map.caxis);
q=colorbar('hori');
set(q,'xtick',c_map.xtick,'XTickLabel',c_map.label);
 
% Add the grid and the coast lines to the plot
m_grid;
m_coast('linewidth',1,'color','k');
title(num2str(m_pv.aklay(ilev)));
 
% Save figure
pre='';
if ( m_pv.aklay(ilev) < 10 )
pre='0';
end
if ( m_pv.aklay(ilev) < 100 )
pre=[pre '0' ];
end
if ( m_pv.aklay(ilev) < 1000 )
pre=[pre '0' ];
end
if ( m_pv.aklay(ilev) < 10000 )
pre=[pre '0' ];
end
 
figname = [ base '/qg_2d_' filename '_' pre num2str(m_pv.aklay(ilev)) '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% End loop over all levels
end
 
 
Property changes:
Added: svn:executable
/trunk/pvin/z2s.f
0,0 → 1,978
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
Property changes:
Added: svn:executable