Subversion Repositories pvinversion.ecmwf

Compare Revisions

No changes between revisions

Ignore whitespace Rev 2 → Rev 5

/tags/1.0/install.csh
0,0 → 1,193
# ----- Load modules --------------------------
 
module load netcdf/4.2.1-pgf90
module list
 
# ---- set some directories and other stuff ---
 
set mode = $1
set svnpath=https://svn.iac.ethz.ch/pub/pvinversion.ecmwf/
set bdir = ${PWD}
 
# ----- Set libraries and includes ------------
 
set libs = "-L ${bdir}/lib"
set libs = "${libs} -lcdfio"
set libs = "${libs} -lcdfplus"
set libs = "${libs} -lipo"
set libs = "${libs} -lgm2em"
 
set ncdf_incs = `nc-config --fflags`
set ncdf_libs = `nc-config --flibs`
 
# ----- Create a new SVN tag ------------------
tag:
 
if ( "${mode}" == "tag" ) then
svn info
if ( "${#argv}" != 2 ) then
echo "Usage: install.csh tag id <id=tag number>"
else
set tagnr = $2
endif
svn copy ${svnpath}/trunk ${svnpath}/tags/${tagnr} -m "Release ${tagnr}"
exit 0
endif
 
 
if ( "${mode}" != "clean" ) goto compile
# ----- Make clean ----------------------------
clean:
 
if ( "${mode}" != "clean" ) goto compile
 
cd ${bdir}/lib
foreach lib ( libcdfio libcdfplus libipo libgm2em )
\rm -f ${lib}.o
end
 
cd ${bdir}/diag/
foreach tool ( calc_qgpv check_boundcon difference hydrostatic qvec_analysis )
\rm -f ${tool}.o
\rm -f ${tool}
end
 
cd ${bdir}/post/
foreach tool ( add2p rotate_lalo )
\rm -f ${tool}.o
\rm -f ${tool}
end
 
cd ${bdir}/prep/
foreach tool ( coastline cutnetcdf def_anomaly p2z ref_profile rotate_grid z2s )
\rm -f ${tool}.o
\rm -f ${tool}
end
 
cd ${bdir}/pvin/
foreach tool ( inv_cart prep_iteration pv_to_qgpv z2s )
\rm -f ${tool}.o
\rm -f ${tool}
end
 
cd ${bdir}/spec/
foreach tool ( modify_anomaly )
\rm -f ${tool}.o
\rm -f ${tool}
end
 
# ----- Compile -------------------------------
compile:
 
if ( "${mode}" != "compile" ) goto done
 
cd ${bdir}/lib
 
foreach lib ( libcdfio libcdfplus libipo libgm2em )
 
\rm -f ${lib}.o
 
echo "pgf90 -c ${lib}.f ${ncdf_incs}"
pgf90 -c ${lib}.f ${ncdf_incs}
 
end
 
cd ${bdir}/diag/
 
foreach tool ( calc_qgpv check_boundcon difference hydrostatic qvec_analysis )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
cd ${bdir}/post/
 
foreach tool ( add2p rotate_lalo )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
cd ${bdir}/prep/
 
foreach tool ( coastline cutnetcdf def_anomaly p2z ref_profile rotate_grid z2s )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
cd ${bdir}/pvin/
 
foreach tool ( inv_cart prep_iteration pv_to_qgpv z2s )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
cd ${bdir}/spec/
 
foreach tool ( modify_anomaly )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
# ----- Done ----------------------------------
done:
 
exit 0
Property changes:
Added: svn:executable
/tags/1.0/diag/calc_qgpv.f
0,0 → 1,819
PROGRAM main_calc_qgpv
 
c ********************************************************************************
c * CALCULATE QUASI-GEOSTROPHIC PV ACCORDING TO ITS DEFINITION *
c * Michael Sprenger / Summer, Autumn 2006 *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Declaration of variables, parameters, externals and common blocks
c --------------------------------------------------------------------------------
 
implicit none
 
c Input and output file
character*80 diagfile
character*80 referfile
 
c Grid parameters
integer nx,ny,nz
real xmin,ymin,zmin,xmax,ymax,zmax
real dx,dy,dz
real deltax,deltay,deltaz
real mdv
real, allocatable,dimension (:,:) :: coriol
 
c Reference state
real, allocatable,dimension (:) :: nsqref
real, allocatable,dimension (:) :: thetaref
real, allocatable,dimension (:) :: rhoref
real, allocatable,dimension (:) :: pressref
real, allocatable,dimension (:) :: zref
 
c 3d fields for calculation of qgPV
real,allocatable,dimension (:,:,:) :: qgpv,th,uu,vv
 
c Auxiliary variables
integer i,j,k
integer stat
character*80 varname
 
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
 
print*,'********************************************************'
print*,'* CALC_QGPV *'
print*,'********************************************************'
 
c Read parameter file
open(10,file='fort.10')
read(10,*) diagfile
read(10,*) referfile
close(10)
print*
print*,trim(diagfile)
print*,trim(referfile)
print*
 
c Get lat/lon gid parameters from input file
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> diagfile)
print*,'Read_Dim: nx,ny,nz = ',nx,ny,nz
print*,' dx,dy,dz = ',dx,dy,dz
print*,' xmin,ymin,zmin = ',xmin,ymin,zmin
print*,' mdv = ',mdv
print*
 
c Count from 0, not from 1: consistent with <inv_cart.f>.
nx=nx-1
ny=ny-1
nz=nz-1
 
c Allocate memory for Coriolis parameters
allocate(coriol(0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating coriol'
 
c Allocate memory for reference profile
allocate(rhoref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating rhoref'
allocate(pressref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pressref'
allocate(thetaref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating thetaref'
allocate(nsqref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating nsqref'
allocate(zref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating zref'
c Allocate memory for 3d fields
allocate(qgpv(0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating qgpv'
allocate(uu(0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating uu'
allocate(vv(0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating vv'
allocate(th(0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating th'
 
c --------------------------------------------------------------------------------
c Calculate the qgPV from definition and put it onto file
c --------------------------------------------------------------------------------
 
c Read data from file
varname='U'
call read_inp (uu,varname,diagfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='V'
call read_inp (vv,varname,diagfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='TH'
call read_inp (th,varname,diagfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
 
c Read reference profile and grid parameters
call read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,coriol,
> referfile)
deltax=1000.*deltax
deltay=1000.*deltay
print*,'Deltax,deltay,deltaz =',deltax,deltay,deltaz
 
c Calculate qgPV
print*,'C qgPV'
call calc_qgpv (qgpv,uu,vv,th,
> rhoref,pressref,nsqref,thetaref,coriol,
> nx,ny,nz,deltax,deltay,deltaz,mdv)
 
c Write result to netcdf file
varname='QGPV_DIA'
call write_inp (qgpv,varname,diagfile,nx,ny,nz)
 
end
 
c ********************************************************************************
c * NETCDF OUTPUT *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Write input field to netcdf
c --------------------------------------------------------------------------------
 
SUBROUTINE write_inp (field,fieldname,pvsrcfile,nx,ny,nz)
 
c Read <fieldname> from netcdf file <pvsrcfile> into <field>. The grid is specified
c by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the input
c files are consitent with this grid.
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real field (0:nx,0:ny,0:nz)
character*80 fieldname
character*80 pvsrcfile
 
c Auxiliary variables
integer cdfid,stat
integer vardim(4)
real misdat
real varmin(4),varmax(4),stag(4)
integer ndimin,outid,i,j,k
real max_th
real tmp(0:nx,0:ny,0:nz)
integer ntimes
real time(200)
integer nvars
character*80 vnam(100),varname
integer isok
 
c Get grid parameters from THETA
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 998
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 998
isok=0
varname='TH'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 998
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 998
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
 
c Save variables (write definition, if necessary)
call cdfwopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 998
isok=0
varname=fieldname
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
endif
call putdat(cdfid,varname,time(1),0,field,stat)
print*,'W ',trim(varname),' ',trim(pvsrcfile)
if (stat.ne.0) goto 998
 
c Close input netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
return
 
c Exception handling
998 print*,'Write_Inp: Problem with input netcdf file... Stop'
stop
 
end
 
c --------------------------------------------------------------------------------
c Read input fields
c --------------------------------------------------------------------------------
 
SUBROUTINE read_inp (field,fieldname,pvsrcfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
 
c Read <fieldname> from netcdf file <pvsrcfile> into <field>. The grid is specified
c by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the input
c files are consitent with this grid. The missing data value is set to <mdv>.
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real field(0:nx,0:ny,0:nz)
character*80 fieldname
character*80 pvsrcfile
real dx,dy,dz,xmin,ymin,zmin
real mdv
 
c Numerical and physical parameters
real eps
parameter (eps=0.01)
 
c Auxiliary variables
integer cdfid,stat,cdfid99
integer vardim(4)
real misdat
real varmin(4),varmax(4),stag(4)
integer ndimin,outid,i,j,k
real max_th
real tmp(nx,ny,nz)
integer ntimes
real time(200)
integer nvars
character*80 vnam(100),varname
integer isok
 
c Open the input netcdf file
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 998
 
c Check whether needed variables are on file
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 998
isok=0
varname=trim(fieldname)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 998
 
c Get the grid parameters from theta
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 998
 
c Check whether grid parameters are consistent
if ( (vardim(1).ne.(nx+1)).or.
> (vardim(2).ne.(ny+1)).or.
> (vardim(3).ne.(nz+1)).or.
> (abs(varmin(1)-xmin).gt.eps).or.
> (abs(varmin(2)-ymin).gt.eps).or.
> (abs(varmin(3)-zmin).gt.eps).or.
> (abs((varmax(1)-varmin(1))/real(vardim(1)-1)-dx).gt.eps).or.
> (abs((varmax(2)-varmin(2))/real(vardim(2)-1)-dy).gt.eps).or.
> (abs((varmax(3)-varmin(3))/real(vardim(3)-1)-dz).gt.eps) )
>then
print*,'Input grid inconsitency...'
print*,' Nx = ',vardim(1),nx+1
print*,' Ny = ',vardim(2),ny+1
print*,' Nz = ',vardim(3),nz+1
print*,' Varminx = ',varmin(1),xmin
print*,' Varminy = ',varmin(2),ymin
print*,' Varminz = ',varmin(3),zmin
print*,' Dx = ',(varmax(1)-varmin(1))/real(nx-1),dx
print*,' Dy = ',(varmax(2)-varmin(2))/real(ny-1),dy
print*,' Dz = ',(varmax(3)-varmin(3))/real(nz-1),dz
goto 998
endif
 
c Load variables
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
call getdat(cdfid,varname,time(1),0,field,stat)
print*, 'R ',trim(varname),' ',trim(pvsrcfile)
if (stat.ne.0) goto 998
 
c Close input netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
 
c Set missing data value to <mdv>
do i=1,nx
do j=1,ny
do k=1,nz
if (abs(field(i,j,k)-misdat).lt.eps) then
field(i,j,k)=mdv
endif
enddo
enddo
enddo
 
return
 
c Exception handling
998 print*,'Read_Inp: Problem with input netcdf file... Stop'
stop
 
end
 
c --------------------------------------------------------------------------------
c Read refernece profile from netcdf
c --------------------------------------------------------------------------------
 
SUBROUTINE read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,coriol,
> pvsrcfile)
 
c Read the reference profile from file
c
c thetaref : Reference potential temperature (K)
c pressref : Reference pressure (Pa)
c rhoref : Reference density (kg/m^3)
c nsqref : Stratification (s^-1)
c zref : Reference height (m)
c nx,nny,nz : Grid dimension in x,y,z direction
c deltax,deltay,deltaz : Grid spacings used for calculations (m)
c coriol : Coriolis parameter (s^-1)
c pvsrcfile : Input file
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real nsqref (0:2*nz)
real thetaref(0:2*nz)
real rhoref (0:2*nz)
real pressref(0:2*nz)
real zref (0:2*nz)
real deltax,deltay,deltaz
real coriol (0:nx,0:ny)
character*80 pvsrcfile
 
c Numerical and physical parameters
real eps
parameter (eps=0.01)
 
c Auxiliary variables
integer cdfid,stat
integer vardim(4)
real misdat
integer ndimin
real varmin(4),varmax(4),stag(4)
integer i,j,k,nf1
integer ntimes
real time(200)
character*80 vnam(100),varname
integer nvars
integer isok,ierr
real x(0:nx,0:ny),y(0:nx,0:ny)
real mean,count
 
c Get grid description from topography
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 997
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 997
isok=0
varname='ORO'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 997
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 997
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
 
c Open output netcdf file
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 997
c Create the variable if necessary
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 997
 
c Read data from netcdf file
isok=0
varname='NSQREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,nsqref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='RHOREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,rhoref,stat)
if (stat.ne.0) goto 997
isok=0
varname='THETAREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,thetaref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='PREREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,pressref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='ZREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,zref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='CORIOL'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,coriol,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='X'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,x,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='Y'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,y,stat)
if (stat.ne.0) goto 997
 
c Close netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
 
c Determine the grid spacings <deltax, deltay, deltaz>
mean=0.
count=0.
do i=1,nx
do j=0,ny
mean=mean+abs(x(i,j)-x(i-1,j))
count=count+1.
enddo
enddo
deltax=mean/count
 
mean=0.
count=0.
do j=1,ny
do i=0,nx
mean=mean+abs(y(i,j)-y(i,j-1))
count=count+1.
enddo
enddo
deltay=mean/count
 
mean=0.
count=0.
do k=1,nz-1
mean=mean+abs(zref(k+1)-zref(k-1))
count=count+1.
enddo
deltaz=mean/count
 
return
 
c Exception handling
997 print*,'Read_Ref: Problem with input netcdf file... Stop'
stop
 
end
 
 
c --------------------------------------------------------------------------------
c Check whether variable is found on netcdf file
c --------------------------------------------------------------------------------
 
subroutine check_varok (isok,varname,varlist,nvars)
 
c Check whether the variable <varname> is in the list <varlist(nvars)>. If this is
C the case, <isok> is incremented by 1. Otherwise <isok> keeps its value.
 
implicit none
 
c Declaraion of subroutine parameters
integer isok
integer nvars
character*80 varname
character*80 varlist(nvars)
 
c Auxiliary variables
integer i
 
c Main
do i=1,nvars
if (trim(varname).eq.trim(varlist(i))) isok=isok+1
enddo
 
end
 
c --------------------------------------------------------------------------------
c Get grid parameters
c --------------------------------------------------------------------------------
 
subroutine read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> pvsrcfile)
 
c Get the grid parameters from the variable <THETA> on the input file <pvsrcfile>.
c The grid parameters are
c nx,ny,nz : Number of grid points in x, y and z direction
c xmin,ymin,zmin : Minimum domain coordinates in x, y and z direction
c xmax,ymax,zmax : Maximal domain coordinates in x, y and z direction
c dx,dy,dz : Horizontal and vertical resolution
c Additionally, it is checked whether the vertical grid is equally spaced. If ok,
c the grid paramters are transformed from lon/lat to distance (in meters)
 
implicit none
 
c Declaration of subroutine parameters
character*80 pvsrcfile
integer nx,ny,nz
real dx,dy,dz
real xmin,ymin,zmin,xmax,ymax,zmax
real mdv
 
c Numerical epsilon and other physical/geoemtrical parameters
real eps
parameter (eps=0.01)
 
c Auxiliary variables
integer cdfid,cstid
integer ierr
character*80 vnam(100),varname
integer nvars
integer isok
integer vardim(4)
real misdat
real varmin(4),varmax(4),stag(4)
real aklev(1000),bklev(1000),aklay(1000),bklay(1000)
real dh
character*80 csn
integer ndim
integer i
 
c Get all grid parameters
call cdfopn(pvsrcfile,cdfid,ierr)
if (ierr.ne.0) goto 998
call getvars(cdfid,nvars,vnam,ierr)
if (ierr.ne.0) goto 998
isok=0
varname='TH'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 998
call getcfn(cdfid,csn,ierr)
if (ierr.ne.0) goto 998
call cdfopn(csn,cstid,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname,ndim,misdat,vardim,varmin,varmax,
> stag,ierr)
if (ierr.ne.0) goto 998
nx=vardim(1)
ny=vardim(2)
nz=vardim(3)
xmin=varmin(1)
ymin=varmin(2)
zmin=varmin(3)
call getlevs(cstid,nz,aklev,bklev,aklay,bklay,ierr)
if (ierr.ne.0) goto 998
call getgrid(cstid,dx,dy,ierr)
if (ierr.ne.0) goto 998
xmax=varmax(1)
ymax=varmax(2)
zmax=varmax(3)
dz=(zmax-zmin)/real(nz-1)
call clscdf(cstid,ierr)
if (ierr.ne.0) goto 998
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 998
 
c Check whether the grid is equallay spaced in the vertical
do i=1,nz-1
dh=aklev(i+1)-aklev(i)
if (abs(dh-dz).gt.eps) then
print*,'Aklev: Vertical grid must be equally spaced... Stop'
print*,(aklev(i),i=1,nz)
stop
endif
dh=aklay(i+1)-aklay(i)
if (abs(dh-dz).gt.eps) then
print*,'Aklay: Vertical grid must be equally spaced... Stop'
print*,(aklay(i),i=1,nz)
stop
endif
enddo
 
c Set missing data value
mdv=misdat
 
return
 
c Exception handling
998 print*,'Read_Dim: Problem with input netcdf file... Stop'
stop
 
end
 
 
 
c --------------------------------------------------------------------------------
c Calculate qgPV from wind and theta
c --------------------------------------------------------------------------------
 
subroutine calc_qgpv (qgpv,uu,vv,th,
> rhoref,pressref,nsqref,thetaref,coriol,
> nx,ny,nz,deltax,deltay,deltaz,mdv)
 
c Calculate qgPV from wind and potential temperature according to
c equation 2.9 p 16 Thesis Rene Fehlmann. Note a cartesian grid with
c equidistant grid spacings <deltax,deltay,deltaz> is assumend. No
c 'correction' is made for spherical geoemtry.
 
implicit none
c Declaration of subroutine parameters
integer nx,ny,nz
real qgpv(0:nx,0:ny,0:nz)
real uu(0:nx,0:ny,0:nz)
real vv(0:nx,0:ny,0:nz)
real th(0:nx,0:ny,0:nz)
real rhoref(0:2*nz)
real nsqref(0:2*nz)
real thetaref(0:2*nz)
real pressref(0:2*nz)
real deltax,deltay,deltaz
real mdv
real coriol(0:nx,0:ny)
 
c Numerical epsilon and physical constants
real g
parameter (g=9.81)
real eps
parameter (eps=0.01)
real scale
parameter (scale=1e6)
 
c Auxiliary variables
integer i,j,k
integer kk,jj
real dvdx(0:nx,0:ny,0:nz)
real dudy(0:nx,0:ny,0:nz)
real dtdz(0:nx,0:ny,0:nz)
real t1,t2
c Calculate horizontal derivatives dudy and dvdx of velocity
do k=0,nz
do j=0,ny
do i=0,nx
c Calculate dudy
if (j.eq.0) then
if ( (abs(uu(i,1,k)-mdv).gt.eps).and.
> (abs(uu(i,0,k)-mdv).gt.eps)) then
dudy(i,0,k)=(uu(i,1,k)-uu(i,0,k))/deltay
else
dudy(i,0,k)=mdv
endif
elseif (j.eq.ny) then
if ( (abs(uu(i,ny, k)-mdv).gt.eps).and.
> (abs(uu(i,ny-1,k)-mdv).gt.eps)) then
dudy(i,ny,k)=(uu(i,ny,k)-uu(i,ny-1,k))/deltay
else
dudy(i,ny,k)=mdv
endif
else
if ( (abs(uu(i,j+1,k)-mdv).gt.eps).and.
> (abs(uu(i,j-1,k)-mdv).gt.eps)) then
dudy(i,j,k)=(uu(i,j+1,k)-uu(i,j-1,k))/(2.*deltay)
else
dudy(i,j,k)=mdv
endif
endif
 
c Calculate dvdx
if (i.eq.0) then
if ((abs(vv(1,j,k)-mdv).gt.eps).and.
> (abs(vv(0,j,k)-mdv).gt.eps)) then
dvdx(0,j,k)=(vv(1,j,k)-vv(0,j,k))/deltax
else
dvdx(0,j,k)=mdv
endif
elseif (i.eq.nx) then
if ((abs(vv(nx, j,k)-mdv).gt.eps).and.
> (abs(vv(nx-1,j,k)-mdv).gt.eps)) then
dvdx(nx,j,k)=(vv(nx,j,k)-vv(nx-1,j,k))/deltax
else
dvdx(nx,j,k)=mdv
endif
else
if ((abs(vv(i+1,j,k)-mdv).gt.eps).and.
> (abs(vv(i-1,j,k)-mdv).gt.eps)) then
dvdx(i,j,k)=(vv(i+1,j,k)-vv(i-1,j,k))/(2.*deltax)
else
dvdx(i,j,k)=mdv
endif
endif
 
enddo
enddo
enddo
 
c Calculate vertical derivative of potential temperature
do i=0,nx
do j=0,ny
do k=0,nz
 
if (k.eq.0) then
if ((abs(th(i,j,2)-mdv).gt.eps).and.
> (abs(th(i,j,1)-mdv).gt.eps)) then
t1=rhoref(2)*th(i,j,1)/thetaref(2)/nsqref(2)*g
t2=rhoref(0)*th(i,j,0)/thetaref(0)/nsqref(0)*g
dtdz(i,j,0)=(t1-t2)/deltaz
else
dtdz(i,j,0)=mdv
endif
else if (k.eq.nz) then
if ((abs(th(i,j,nz )-mdv).gt.eps).and.
> (abs(th(i,j,nz-1)-mdv).gt.eps)) then
kk=2*nz
t1=rhoref(kk )*th(i,j,nz )/
> thetaref(kk)/nsqref(kk)*g
t2=rhoref(kk-2)*th(i,j,nz-1)/
> thetaref(kk-2)/nsqref(kk-2)*9.8
dtdz(i,j,nz)=(t1-t2)/deltaz
else
dtdz(i,j,nz)=mdv
endif
else
if ((abs(th(i,j,k+1)-mdv).gt.eps).and.
> (abs(th(i,j,k )-mdv).gt.eps).and.
> (abs(th(i,j,k-1)-mdv).gt.eps)) then
kk=2*k
t1=rhoref(kk+1)*(th(i,j,k)+th(i,j,k+1))/2.
> /thetaref(kk+1)/nsqref(kk+1)*g
t2=rhoref(kk-1)*(th(i,j,k)+th(i,j,k-1))/2.
> /thetaref(kk-1)/nsqref(kk-1)*g
dtdz(i,j,k)=(t1-t2)/deltaz
else
dtdz(i,j,k)=mdv
endif
endif
enddo
enddo
enddo
c Calculate qgPV
do i=0,nx
do j=0,ny
do k=0,nz
kk=2*k
 
if ((abs(dudy(i,j,k)-mdv).gt.eps).and.
> (abs(dvdx(i,j,k)-mdv).gt.eps).and.
> (abs(dtdz(i,j,k)-mdv).gt.eps)) then
qgpv(i,j,k)=-dudy(i,j,k)+dvdx(i,j,k)+
> coriol(i,j)*dtdz(i,j,k)/rhoref(kk)
else
qgpv(i,j,k)=mdv
endif
enddo
enddo
enddo
 
end
 
Property changes:
Added: svn:executable
/tags/1.0/diag/check_boundcon.f
0,0 → 1,871
 
PROGRAM set_boundcon
 
c ************************************************************************
c * Set boundary conditions for inversion; lower and upper boundary *
c * conditions for potential temperature; lateral boundary conditions *
c * for zonal and meridional wind; in particular, missing data values *
c * are removed. *
c * *
c * Michael Sprenger / Summer 2006 *
c ************************************************************************
 
c --------------------------------------------------------------------------------
c Declaration of variables, parameters, externals and common blocks
c --------------------------------------------------------------------------------
 
implicit none
 
c Input and output file
character*80 anomafile
character*80 referfile
 
c Grid parameters
integer nx,ny,nz
real xmin,ymin,zmin,xmax,ymax,zmax
real dx,dy,dz
real mdv
real deltax,deltay,deltaz
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 3d arrays
real,allocatable,dimension (:,:,:) :: th_anom,pv_anom
real,allocatable,dimension (:,:,:) :: uu_anom,vv_anom
 
c Auxiliary variables
integer i,j,k,kk
integer stat
character*80 varname
integer n1,n2
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
 
print*,'********************************************************'
print*,'* CHECK_BOUNDCON *'
print*,'********************************************************'
 
c Read parameter file
open(10,file='fort.10')
read(10,*) anomafile
read(10,*) referfile
close(10)
print*
print*,trim(anomafile)
print*,trim(referfile)
print*
 
c Get lat/lon gid parameters from input file
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> 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(pv_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv_anom'
allocate(th_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating th_anom'
allocate(uu_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating uu_anom'
allocate(vv_anom (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating vv_anom'
 
c Allocate memory for reference profile
allocate(rhoref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating rhoref'
allocate(pressref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pressref'
allocate(thetaref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating thetaref'
allocate(nsqref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating nsqref'
allocate(zref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating zref'
 
c Allocate memory for Coriolis parameter
allocate(coriol(0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating f'
 
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 Read reference profile and ngrid parameters
call read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,coriol,
> referfile)
deltax=1000.*deltax
deltay=1000.*deltay
print*,'Deltax,deltay,deltaz =',deltax,deltay,deltaz
c Read data from MOD file
varname='QGPV'
call read_inp (pv_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='TH'
call read_inp (th_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='U'
call read_inp (uu_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='V'
call read_inp (vv_anom,varname,anomafile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
 
 
c --------------------------------------------------------------------------------
c Consistency check for boundary conditions and adaptions
c --------------------------------------------------------------------------------
 
c Copy 3d to boundary conditions
do i=0,nx
do j=0,ny
thetatop(i,j)=th_anom(i,j,nz)
thetabot(i,j)=th_anom(i,j,0)
enddo
enddo
do i=0,nx
do k=0,nz
ua(i,k)=uu_anom(i, 0,k)
ub(i,k)=uu_anom(i,ny,k)
enddo
enddo
do j=0,ny
do k=0,nz
va(j,k)=vv_anom( 0,j,k)
vb(j,k)=vv_anom(nx,j,k)
enddo
enddo
 
c Check the lower and upper boundary condition for consistency check
print*
call combouncon(pv_anom,nsqref,rhoref,thetatop,
> thetabot,thetaref,coriol,ua,ub,va,vb,
> nx,ny,nz,deltax,deltay,deltaz)
print*
 
 
end
 
 
c ********************************************************************************
c * NETCDF INPUT AND OUTPUT *
c ********************************************************************************
 
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='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 refernece profile from netcdf
c --------------------------------------------------------------------------------
 
SUBROUTINE read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,coriol,
> pvsrcfile)
 
c Read the reference profile from file
c
c thetaref : Reference potential temperature (K)
c pressref : Reference pressure (Pa)
c rhoref : Reference density (kg/m^3)
c nsqref : Stratification (s^-1)
c zref : Reference height (m)
c nx,nny,nz : Grid dimension in x,y,z direction
c deltax,deltay,deltaz : Grid spacings used for calculations (m)
c coriol : Coriolis parameter (s^-1)
c pvsrcfile : Input file
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real nsqref (0:2*nz)
real thetaref(0:2*nz)
real rhoref (0:2*nz)
real pressref(0:2*nz)
real zref (0:2*nz)
real deltax,deltay,deltaz
real coriol (0:nx,0:ny)
character*80 pvsrcfile
 
c Numerical and physical parameters
real eps
parameter (eps=0.01)
 
c Auxiliary variables
integer cdfid,stat
integer vardim(4)
real misdat
integer ndimin
real varmin(4),varmax(4),stag(4)
integer i,j,k,nf1
integer ntimes
real time(200)
character*80 vnam(100),varname
integer nvars
integer isok,ierr
real x(0:nx,0:ny),y(0:nx,0:ny)
real mean,count
 
c Get grid description from topography
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 997
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 997
isok=0
varname='ORO'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 997
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 997
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
 
c Open output netcdf file
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 997
c Create the variable if necessary
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 997
 
c Read data from netcdf file
isok=0
varname='NSQREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,nsqref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='RHOREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,rhoref,stat)
if (stat.ne.0) goto 997
isok=0
varname='THETAREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,thetaref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='PREREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,pressref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='ZREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,zref,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='CORIOL'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,coriol,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='X'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,x,stat)
if (stat.ne.0) goto 997
 
isok=0
varname='Y'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,y,stat)
if (stat.ne.0) goto 997
 
c Close netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
 
c Determine the grid spacings <deltax, deltay, deltaz>
mean=0.
count=0.
do i=1,nx
do j=0,ny
mean=mean+abs(x(i,j)-x(i-1,j))
count=count+1.
enddo
enddo
deltax=mean/count
 
mean=0.
count=0.
do j=1,ny
do i=0,nx
mean=mean+abs(y(i,j)-y(i,j-1))
count=count+1.
enddo
enddo
deltay=mean/count
 
mean=0.
count=0.
do k=1,nz-1
mean=mean+abs(zref(k+1)-zref(k-1))
count=count+1.
enddo
deltaz=mean/count
 
return
 
c Exception handling
997 print*,'Read_Ref: Problem with input netcdf file... Stop'
stop
 
end
 
 
c ********************************************************************************
c * BOUNDARY CONDITIONS - CONSISTENCY CHECK AND ADAPTIONS *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Boundary condition
c --------------------------------------------------------------------------------
 
subroutine combouncon(pv,nsq,rhoref,thetatop,
> thetabot,thetaref,coriol,
> ua,ub,va,vb,nx,ny,nz,dx,dy,dz)
 
c Evaluate the consistency integrals A.7 from Rene's dissertation. This inegral
c is a necessary condition that the von Neumann problem has a unique solution.
c Adjust the upper and lower boundary conditions on <thetabot> and <thetatop>, so
c that the consitency check is ok.
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real dx,dy,dz
real pv(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 coriol(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)
 
c Numerical and physical parameters
real g
parameter (g=9.81)
 
c Auxiliary variables
integer i,j,k
real dxy,dxz,dyz,dxyz
real integr,denombot,denomtop,denom
real shifttop,shiftbot
 
c Set the area and volume infinitesimals for integration
dxy =dx*dy
dxz =dx*dz
dyz =dy*dz
dxyz=dx*dy*dz
 
c Init integration variables
integr=0.
 
c Inner
do k=1,nz-1
do i=1,nx-1
do j=1,ny-1
integr=integr+dxyz*rhoref(2*k)*pv(i,j,k)
enddo
enddo
enddo
 
c ZY plane
do k=1,nz-1
do j=1,ny-1
integr=integr+dyz*
> rhoref(2*k)*(dx*pv(0, j,k)+va(j,k))
c
integr=integr+dyz*
> rhoref(2*k)*(dx*pv(nx,j,k)-vb(j,k))
enddo
enddo
 
c ZX plane
do k=1,nz-1
do i=1,nx-1
integr=integr+dxz*
> rhoref(2*k)*(dy*pv(i,0,k)-ua(i,k))
c
integr=integr+dxz*
> rhoref(2*k)*(dy*pv(i,ny,k)+ub(i,k))
enddo
enddo
 
c XY plane
do i=1,nx-1
do j=1,ny-1
integr=integr+dxy*rhoref(0)*(
> dz*pv(i,j,0)+coriol(i,j)*g*thetabot(i,j)/
> (nsq(0)*thetaref(0)))
c
integr=integr+dxy*rhoref(2*nz)*(
> dz*pv(i,j,nz)-coriol(i,j)*g*thetatop(i,j)/
> (nsq(2*nz)*thetaref(2*nz)))
c
enddo
enddo
 
c X edges
do i=1,nx-1
integr=integr+dx*
> rhoref(0)*(dyz*pv(i,0,0)-
> dz*ua(i,0)+dy*coriol(i,0)*g*thetabot(i,0)/
> (nsq(0)*thetaref(0)))
c
integr=integr+dx*
> rhoref(0)*(dyz*pv(i,ny,0)+
> dz*ub(i,0)+dy*coriol(i,ny)*g*thetabot(i,ny)/
> (nsq(0)*thetaref(0)))
c
integr=integr+dx*
> rhoref(2*nz)*(dyz*pv(i,0,nz)-
> dz*ua(i,nz)-dy*coriol(i,0)*g*thetatop(i,0)/
> (nsq(2*nz)*thetaref(2*nz)))
 
integr=integr+dx*
> rhoref(2*nz)*(dyz*pv(i,ny,nz)+
> dz*ub(i,nz)-dy*coriol(i,ny)*g*thetatop(i,ny)/
> (nsq(2*nz)*thetaref(2*nz)))
c
enddo
 
c Y edges
do j=1,ny-1
integr=integr+dy*
> rhoref(0)*(dxz*pv(0,j,0)+
> dz*va(j,0)+dx*coriol(0,j)*g*thetabot(0,j)/
> (nsq(0)*thetaref(0)))
c
integr=integr+dy*
> rhoref(0)*(dxz*pv(nx,j,0)-
> dz*vb(j,0)+dx*coriol(nx,j)*g*thetabot(nx,j)/
> (nsq(0)*thetaref(0)))
c
integr=integr+dy*
> rhoref(2*nz)*(dxz*pv(0,j,nz)+
> dz*va(j,nz)-dx*coriol(0,j)*g*thetatop(0,j)/
> (nsq(2*nz)*thetaref(2*nz)))
c
integr=integr+dy*
> rhoref(2*nz)*(dxz*pv(nx,j,nz)-
> dz*vb(j,nz)-dx*coriol(nx,j)*g*thetatop(nx,j)/
> (nsq(2*nz)*thetaref(2*nz)))
c
enddo
 
c Z edges
do k=1,nz-1
integr=integr+dz*
> rhoref(2*k)*(dxy*pv(0,0,k)+
> dy*va(0,k)-dx*ua(0,k))
c
integr=integr+dz*
> rhoref(2*k)*(dxy*pv(nx,0,k)-
> dy*vb(0,k)-dx*ua(nx,k))
c
integr=integr+dz*
> rhoref(2*k)*(dxy*pv(0,ny,k)+
> dy*va(ny,k)+dx*ub(0,k))
c
integr=integr+dz*
> rhoref(2*k)*(dxy*pv(nx,ny,k)-
> dy*vb(ny,k)+dx*ub(nx,k))
enddo
 
c Points
integr=integr+rhoref(0)*(dxyz*pv(0,0,0)+
> dyz*va(0,0)-dxz*ua(0,0)+
> dxy*coriol(0,0)*g*thetabot(0,0)/
> (nsq(0)*thetaref(0)))
c
integr=integr+rhoref(0)*(dxyz*pv(nx,0,0)-
> dyz*vb(0,0)-dxz*ua(nx,0)+
> dxy*coriol(nx,0)*g*thetabot(nx,0)/
> (nsq(0)*thetaref(0)))
c
integr=integr+rhoref(0)*(dxyz*pv(0,ny,0)+
> dyz*va(ny,0)+dxz*ub(0,0)+
> dxy*coriol(0,ny)*g*thetabot(0,ny)/
> (nsq(0)*thetaref(0)))
c
integr=integr+rhoref(0)*(dxyz*pv(nx,ny,0)-
> dyz*vb(ny,0)+dxz*ub(nx,0)+
> dxy*coriol(nx,ny)*g*thetabot(nx,ny)/
> (nsq(0)*thetaref(0)))
c
integr=integr+rhoref(2*nz)*(dxyz*pv(0,0,nz)+
> dyz*va(0,nz)-dxz*ua(0,nz)-
> dxy*coriol(0,0)*g*thetatop(0,0)/
> (nsq(2*nz)*thetaref(2*nz)))
c
integr=integr+rhoref(2*nz)*(dxyz*pv(nx,0,nz)-
> dyz*vb(0,nz)-dxz*ua(nx,nz)-
> dxy*coriol(nx,0)*g*thetatop(nx,0)/
> (nsq(2*nz)*thetaref(2*nz)))
c
integr=integr+rhoref(2*nz)*(dxyz*pv(0,ny,nz)+
> dyz*va(ny,nz)+dxz*ub(0,nz)-
> dxy*coriol(0,ny)*g*thetatop(0,ny)/
> (nsq(2*nz)*thetaref(2*nz)))
c
integr=integr+rhoref(2*nz)*(dxyz*pv(nx,ny,nz)-
> dyz*vb(ny,nz)+dxz*ub(nx,nz)-
> dxy*coriol(nx,ny)*g*thetatop(nx,ny)/
> (nsq(2*nz)*thetaref(2*nz)))
c
 
c Get the integrals from the reference state at bottom and top
denombot=0.
denomtop=0.
do i=0,nx
do j=0,ny
denombot=denombot+dxy*
> rhoref(0)*coriol(i,j)*g/
> (nsq(0)*thetaref(0))
c
denomtop=denomtop+dxy*
> rhoref(2*nz)*coriol(i,j)*g/
> (nsq(2*nz)*thetaref(2*nz))
enddo
enddo
denom=denomtop-denombot
c Determine the deviation of potential temperature from reference profile
shiftbot=0.
shifttop=0.
do i=0,nx
do j=0,ny
shifttop=shifttop+thetatop(i,j)
shiftbot=shiftbot+thetabot(i,j)
enddo
enddo
shifttop=shifttop/real((nx+1)*(ny+1))
shiftbot=shiftbot/real((nx+1)*(ny+1))
 
c Write some information about the consitency integrals
print*,'Consistency Check for boundary'
print*,' integ = ', integr
print*,' denombot = ', denombot
print*,' denomtop = ', denomtop
print*,' denom = ', denom
print*,' theta adjustment = ', integr/denom
print*,' theta shift @ top = ', shifttop,
> thetaref(2*nz)
print*,' theta shift @ bot = ', shiftbot,
> thetaref(0)
 
end
Property changes:
Added: svn:executable
/tags/1.0/diag/check_boundcon.m
0,0 → 1,267
% -------------------------------------------------------------------------
% Load files
% -------------------------------------------------------------------------
 
% 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)
z_th = cdf_loadV(folder,filename,'TH');
z_uu = cdf_loadV(folder,filename,'U');
z_vv = cdf_loadV(folder,filename,'V');
 
% -------------------------------------------------------------------------
% Lower boundary condition for potential temperature
% -------------------------------------------------------------------------
 
ilev=1;
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set projection
load coast
h=axesm('MapProjection','eqdcylin');
setm(gca,'FLatLimit',[z_th.latmin z_th.latmax],'FLonLimit',[z_th.lonmin z_th.lonmax]);
h=plotm(lat,long);
gridm;
 
% Scale the plotting field for color map
fld=squeeze(z_th.var(ilev,:,:));
c_map = scale_col(230:5:310,fld);
 
% Plot TH
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]=contourfm(lat,lon,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,2);
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
title([ 'Lower Boundary Condition : Potential Temperature @' num2str(z_th.aklay(ilev)) ' m ASL' ]);
 
% Save figure
figname = [ base '/bound_lower_th_' filename '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% -------------------------------------------------------------------------
% Upper boundary condition for potential temperature
% -------------------------------------------------------------------------
 
ilev=z_th.nz;
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Set projection
load coast
h=axesm('MapProjection','eqdcylin');
setm(gca,'FLatLimit',[z_th.latmin z_th.latmax],'FLonLimit',[z_th.lonmin z_th.lonmax]);
h=plotm(lat,long);
gridm;
 
% Scale the plotting field for color map
fld=squeeze(z_th.var(ilev,:,:));
c_map = scale_col(450:10:550,fld);
 
% Plot TH
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]=contourfm(lat,lon,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,2);
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
title([ 'Upper Boundary Condition : Potential Temperature @ ' num2str(z_th.aklay(ilev)) ' m ASL' ]);
 
% Save figure
figname = [ base '/bound_upper_th_' filename '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
 
% -------------------------------------------------------------------------
% Southern lateral boundary condition for zonal wind
% -------------------------------------------------------------------------
 
ilev=1;
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Scale the plotting field for color map
fld=squeeze(z_uu.var(:,ilev,:));
c_map = scale_col(-50:10:50,fld);
 
% Plot
lev=z_uu.aklev/10000;
lon=z_uu.xmin + (0:z_uu.nx-1) * z_uu.dx;
[C,h]=contourf(lon,lev,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,2);
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
title([ 'Southern lateral Boundary Condition : Zonal Wind @ ' num2str(z_uu.ymin) '^\circ N' ]);
xlabel('Longitude');
ylabel('Height [km]');
 
% Save figure
figname = [ base '/bound_south_uu_' filename '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
 
% -------------------------------------------------------------------------
% Northern lateral boundary condition for zonal wind
% -------------------------------------------------------------------------
 
ilev=z_uu.ny;
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Scale the plotting field for color map
fld=squeeze(z_uu.var(:,ilev,:));
c_map = scale_col(-50:10:50,fld);
 
% Plot
lev=z_uu.aklev/10000;
lon=z_uu.xmin + (0:z_uu.nx-1) * z_uu.dx;
[C,h]=contourf(lon,lev,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,2);
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
title([ 'Northern lateral Boundary Condition : Zonal Wind @ ' num2str(z_uu.ymax) '^\circ N' ]);
xlabel('Longitude');
ylabel('Height [km]');
 
% Save figure
figname = [ base '/bound_north_uu_' filename '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% -------------------------------------------------------------------------
% Western lateral boundary condition for meridional wind
% -------------------------------------------------------------------------
 
ilev=1;
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Scale the plotting field for color map
fld=squeeze(z_vv.var(:,:,ilev));
c_map = scale_col(-50:10:50,fld);
 
% Plot
lev=z_vv.aklev/10000;
lat=z_vv.ymin + (0:z_vv.ny-1) * z_vv.dy;
[C,h]=contourf(lat,lev,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,2);
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
title([ 'Western lateral Boundary Condition : Meridional Wind @ ' num2str(z_vv.xmin) '^\circ E' ]);
xlabel('Latitude');
ylabel('Height [km]');
 
% Save figure
figname = [ base '/bound_west_vv_' filename '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
 
% -------------------------------------------------------------------------
% Eastern lateral boundary condition for meridional wind
% -------------------------------------------------------------------------
 
ilev=z_vv.nx;
 
% Create a new figure
close;
fh=figure('Units','pixels','Position',[100 100 900 900])
 
% Scale the plotting field for color map
fld=squeeze(z_vv.var(:,:,ilev));
c_map = scale_col(-50:10:50,fld);
 
% Plot
lev=z_vv.aklev/10000;
lat=z_vv.ymin + (0:z_vv.ny-1) * z_vv.dy;
[C,h]=contourf(lat,lev,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,2);
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
title([ 'Eastern lateral Boundary Condition : Meridional Wind @ ' num2str(z_vv.xmax) '^\circ E' ]);
xlabel('Latitude');
ylabel('Height [km]');
 
% Save figure
figname = [ base '/bound_east_vv_' filename '.eps' ];
set(gcf, 'PaperPosition', [2 1 15 10]);
print('-depsc2','-r0',figname);
Property changes:
Added: svn:executable
/tags/1.0/diag/difference.f
0,0 → 1,241
PROGRAM difference
 
c **************************************************************************
c * Get the difference between two runs *
c * Michael Sprenger / Autumn 2006 *
c **************************************************************************
 
implicit none
 
c --------------------------------------------------------------------------
c Declaration of subroutine parameters
c --------------------------------------------------------------------------
 
c Physical and numerical parameters
real eps
parameter (eps=0.01)
integer nmax
parameter (nmax=300*300*200)
 
c Variables for input file 1
character*80 i1_filename
real i1_varmin(4),i1_varmax(4),i1_stag(4)
integer i1_vardim(4)
real i1_mdv
integer i1_ndim
integer i1_nx,i1_ny,i1_nz
real i1_time
integer i1_nvars
character*80 i1_vnam(100)
real i1_field(nmax)
 
c Variables for input file 2
character*80 i2_filename
real i2_varmin(4),i2_varmax(4),i2_stag(4)
integer i2_vardim(4)
real i2_mdv
integer i2_ndim
integer i2_nx,i2_ny,i2_nz
real i2_time
integer i2_nvars
character*80 i2_vnam(100)
real i2_field(nmax)
 
c Variables for output file
character*80 o_filename
real o_varmin(4),o_varmax(4),o_stag(4)
integer o_vardim(4)
real o_mdv
integer o_ndim
integer o_nx,o_ny,o_nz
real o_time
real o_field(nmax)
 
c Auxiliary variables
integer i,j,k
integer cdfid,ierr
integer isok
character*80 cfn,varname
 
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
 
print*,'********************************************************'
print*,'* DIFFERENCE *'
print*,'********************************************************'
 
c Read parameter file
open(10,file='fort.10')
read(10,*) i1_filename
read(10,*) i2_filename
read(10,*) o_filename
close(10)
print*
print*,trim(i1_filename)
print*,trim(i2_filename)
print*,trim(o_filename)
print*
 
c Get a list of all variables on the two input files
call cdfopn(i1_filename,cdfid,ierr)
if (ierr.ne.0) goto 998
call getvars(cdfid,i1_nvars,i1_vnam,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,i1_vnam(i1_nvars),i1_ndim,i1_mdv,i1_vardim,
> i1_varmin,i1_varmax,i1_stag,ierr)
call clscdf(cdfid,ierr)
print*,(trim(i1_vnam(i))//' ',i=1,i1_nvars)
 
call cdfopn(i2_filename,cdfid,ierr)
if (ierr.ne.0) goto 997
call getvars(cdfid,i2_nvars,i2_vnam,ierr)
if (ierr.ne.0) goto 997
call clscdf(cdfid,ierr)
print*,(trim(i2_vnam(i))//' ',i=1,i2_nvars)
print*
 
c Create the output file
o_ndim=i1_ndim
do i=1,i1_ndim
o_varmin(i)=i1_varmin(i)
o_varmax(i)=i1_varmax(i)
enddo
cfn=trim(o_filename)//'_cst'
call crecdf(trim(o_filename),cdfid,o_varmin,o_varmax,
> o_ndim,trim(cfn),ierr)
if (ierr.ne.0) goto 996
call clscdf(cdfid,ierr)
 
c --------------------------------------------------------------------------------
c Loop through all variables
c --------------------------------------------------------------------------------
 
do i=1,i1_nvars
 
c Check wether the variable is available on both files
varname=i1_vnam(i)
if (varname.eq.'time') goto 100
isok=0
call check_varok (isok,varname,i2_vnam,i2_nvars)
if (isok.eq.0) goto 100
 
c Read first input file
call cdfopn(i1_filename,cdfid,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname,i1_ndim,i1_mdv,i1_vardim,
> i1_varmin,i1_varmax,i1_stag,ierr)
if (ierr.ne.0) goto 998
call getdat(cdfid,varname,0.,0,i1_field,ierr)
if (ierr.ne.0) goto 998
call clscdf(cdfid,ierr)
c Read second input file
call cdfopn(i2_filename,cdfid,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname,i2_ndim,i2_mdv,i2_vardim,
> i2_varmin,i2_varmax,i2_stag,ierr)
if (ierr.ne.0) goto 998
call getdat(cdfid,varname,0.,0,i2_field,ierr)
if (ierr.ne.0) goto 998
call clscdf(cdfid,ierr)
 
c Consistency check
if (i1_ndim.ne.i2_ndim) then
print*,'Inconsistent input files... Stop',i1_ndim,i2_ndim
stop
endif
do j=1,3
if ( (i1_vardim(j).ne.i2_vardim(j)).or.
> (abs(i1_varmin(j)-i2_varmin(j)).gt.eps).or.
> (abs(i1_varmax(j)-i2_varmax(j)).gt.eps).or.
> (abs(i1_stag(j)-i2_stag(j)).gt.eps)) then
print*,'Inconsistent input files... Stop'
print*,j,i1_varmin(j),i2_varmin(j)
print*,j,i1_varmax(j),i2_varmax(j)
print*,j,i1_vardim(j),i2_vardim(j)
print*,j,i1_stag(j), i2_stag(j)
stop
endif
enddo
c Get the difference
do j=1,i1_vardim(1)*i1_vardim(2)*i1_vardim(3)
if ( (abs(i1_field(j)-i1_mdv).gt.eps).and.
> (abs(i2_field(j)-i2_mdv).gt.eps) ) then
o_field(j)=i1_field(j)-i2_field(j)
else
o_field(j)=i1_mdv
endif
enddo
 
c Write to output file
o_ndim=i1_ndim
o_mdv =i1_mdv
do j=1,i1_ndim
o_vardim(j)=i1_vardim(j)
o_varmin(j)=i1_varmin(j)
o_varmax(j)=i1_varmax(j)
o_stag(j) =i1_stag(j)
enddo
call cdfwopn(o_filename,cdfid,ierr)
if (ierr.ne.0) goto 996
call putdef(cdfid,varname,o_ndim,o_mdv,o_vardim,
> o_varmin,o_varmax,o_stag,ierr)
if (ierr.ne.0) goto 996
call putdat(cdfid,varname,0.,0,o_field,ierr)
if (ierr.ne.0) goto 996
print*,'W ',trim(varname),' ',trim(o_filename)
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 996
 
c Next
100 continue
 
enddo
 
c -----------------------------------------------------------------
c Exception handling and format specs
c -----------------------------------------------------------------
 
stop
 
998 print*,'Problems with input file 1 ',trim(i1_filename)
stop
 
997 print*,'Problems with input file 2 ',trim(i2_filename)
stop
 
996 print*,'Problems with output file ',trim(o_filename)
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
 
Property changes:
Added: svn:executable
/tags/1.0/diag/hydrostatic.f
0,0 → 1,542
PROGRAM hydrostatic
 
c Calculate the geopotential and add it to the P file
c Michael Sprenger / Spring 2006
 
implicit none
 
c ---------------------------------------------------------------
c Declaration of variables
c ---------------------------------------------------------------
 
c Variables for input P file : model level
character*80 ml_pfn
real ml_varmin(4),ml_varmax(4),ml_stag(4)
integer ml_vardim(4)
real ml_mdv
integer ml_ndim
integer ml_nx,ml_ny,ml_nz
real ml_xmin,ml_xmax,ml_ymin,ml_ymax,ml_dx,ml_dy
integer ml_ntimes
real ml_aklev(500),ml_bklev(500)
real ml_aklay(500),ml_bklay(500)
real ml_time
real ml_pollon,ml_pollat
integer ml_nvars
character*80 ml_vnam(100)
integer ml_idate(5)
real,allocatable, dimension (:,:) :: ml_ps,ml_zb
real,allocatable, dimension (:,:,:) :: ml_t3,ml_q3,ml_p3,ml_tv3
real,allocatable, dimension (:,:,:) :: ml_zlay3
 
c Variables for input Z file : pressure level
character*80 pl_zfn
real pl_varmin(4),pl_varmax(4),pl_stag(4)
integer pl_vardim(4)
real pl_mdv
integer pl_ndim
integer pl_nx,pl_ny,pl_nz
real pl_xmin,pl_xmax,pl_ymin,pl_ymax,pl_dx,pl_dy
integer pl_ntimes
real pl_aklev(500),pl_bklev(500)
real pl_aklay(500),pl_bklay(500)
real pl_time
real pl_pollon,pl_pollat
integer pl_nvars
character*80 pl_vnam(100)
integer pl_idate(5)
real,allocatable, dimension (:,:,:) :: pl_z3,pl_p3
 
c Physical and numerical parameters
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 zerodiv
parameter (zerodiv=0.0000000001)
real dpmin
parameter (dpmin=10.)
real rdg
parameter (rdg=29.271)
 
c Auxiliary variables
integer ierr
integer cdfid,cstid
character*80 cfn
integer stat
real time
real tv1(1000),z1(1000),p1(1000),f1(1000)
real spline_tv1(1000),spline_f1(1000),spline_z1(1000)
real pu,po,zu,zo,p,z,dp,p0,tvu,tvo,ff
integer i,j,k,l
integer lmin,n
character*80 varname,cdfname
integer isok
integer mode
 
c -----------------------------------------------------------------
c Read input fields
c -----------------------------------------------------------------
 
print*,'*********************************************************'
print*,'* hydrostatic *'
print*,'*********************************************************'
 
c Read in the parameter file
open(10,file='fort.10')
read(10,*) ml_pfn
read(10,*) pl_zfn
close(10)
 
c Decide which mode is used (1: reference from Z, 2: reference from ORO/PS)
if ( trim(ml_pfn).ne.trim(pl_zfn) ) then
mode=1
print*,'Taking reference from Z ',trim(pl_zfn)
else
mode=2
print*,'Taking reference from ORO/PS ',trim(pl_zfn)
endif
 
print*,trim(ml_pfn)
print*,trim(pl_zfn)
c Get grid description for P file : model level
call cdfopn(ml_pfn,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 getvars(cdfid,ml_nvars,ml_vnam,ierr)
varname='T'
isok=0
call check_varok (isok,varname,ml_vnam,ml_nvars)
if (isok.ne.1) goto 998
call getdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 998
ml_nx =ml_vardim(1)
ml_ny =ml_vardim(2)
ml_nz =ml_vardim(3)
ml_xmin=ml_varmin(1)
ml_ymin=ml_varmin(2)
call getlevs(cstid,ml_nz,ml_aklev,ml_bklev,ml_aklay,ml_bklay,ierr)
call getgrid(cstid,ml_dx,ml_dy,ierr)
ml_xmax=ml_xmin+real(ml_nx-1)*ml_dx
ml_ymax=ml_ymin+real(ml_ny-1)*ml_dy
call gettimes(cdfid,ml_time,ml_ntimes,ierr)
call getstart(cstid,ml_idate,ierr)
call getpole(cstid,ml_pollon,ml_pollat,ierr)
call clscdf(cstid,ierr)
call clscdf(cdfid,ierr)
 
c Get grid description reference: either ORO(P) or Z(Z)
call cdfopn(pl_zfn,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 getvars(cdfid,pl_nvars,pl_vnam,ierr)
if (mode.eq.1) then
varname='Z'
isok=0
call check_varok (isok,varname,pl_vnam,pl_nvars)
if (isok.ne.1) goto 998
call getdef(cdfid,varname,pl_ndim,pl_mdv,pl_vardim,
> pl_varmin,pl_varmax,pl_stag,ierr)
if (ierr.ne.0) goto 998
call getlevs(cstid,pl_nz,pl_aklev,pl_bklev,
> pl_aklay,pl_bklay,ierr)
call getgrid(cstid,pl_dx,pl_dy,ierr)
call gettimes(cdfid,pl_time,pl_ntimes,ierr)
call getstart(cstid,pl_idate,ierr)
call getpole(cstid,pl_pollon,pl_pollat,ierr)
 
else if (mode.eq.2) then
varname='ORO'
isok=0
call check_varok (isok,varname,pl_vnam,pl_nvars)
if (isok.ne.1) goto 998
call getdef(cdfid,varname,pl_ndim,pl_mdv,pl_vardim,
> pl_varmin,pl_varmax,pl_stag,ierr)
if (ierr.ne.0) goto 998
call getgrid(cstid,pl_dx,pl_dy,ierr)
call gettimes(cdfid,pl_time,pl_ntimes,ierr)
call getstart(cstid,pl_idate,ierr)
call getpole(cstid,pl_pollon,pl_pollat,ierr)
endif
pl_nx =pl_vardim(1)
pl_ny =pl_vardim(2)
pl_nz =pl_vardim(3)
pl_xmin=pl_varmin(1)
pl_ymin=pl_varmin(2)
pl_xmax=pl_xmin+real(pl_nx-1)*pl_dx
pl_ymax=pl_ymin+real(pl_ny-1)*pl_dy
call clscdf(cstid,ierr)
call clscdf(cdfid,ierr)
 
c Consitency check for the grids
if ( (ml_nx.ne.pl_nx).or.
> (ml_ny.ne.pl_ny).or.
> (abs(ml_xmin-pl_xmin ).gt.eps).or.
> (abs(ml_ymin-pl_ymin ).gt.eps).or.
> (abs(ml_xmax-pl_xmax ).gt.eps).or.
> (abs(ml_ymax-pl_ymax ).gt.eps).or.
> (abs(ml_dx -pl_dx ).gt.eps).or.
> (abs(ml_dy -pl_dy ).gt.eps).or.
> (abs(ml_time-pl_time ).gt.eps).or.
> (abs(ml_pollon-pl_pollon).gt.eps).or.
> (abs(ml_pollat-pl_pollat).gt.eps)) then
print*,'Input P and Z grids are not consistent... Stop'
print*,'Xmin ',ml_xmin ,pl_xmin
print*,'Ymin ',ml_ymin ,pl_ymin
print*,'Xmax ',ml_xmax ,pl_xmax
print*,'Ymax ',ml_ymax ,pl_ymax
print*,'Dx ',ml_dx ,pl_dx
print*,'Dy ',ml_dy ,pl_dy
print*,'Pollon ',ml_pollon ,pl_pollon
print*,'Pollat ',ml_pollat ,pl_pollat
print*,'Time ',ml_time ,pl_time
stop
endif
 
c Allocate memory for all fields
allocate(ml_ps(ml_nx,ml_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_ps ***'
allocate(ml_zb(ml_nx,ml_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_zb ***'
allocate(ml_p3(ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_p3 ***'
allocate(ml_t3(ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_t3 ***'
allocate(ml_q3(ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_q3 ***'
allocate(ml_tv3(ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_tv3 ***'
allocate(ml_zlay3(ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array ml_zlay3 ***'
 
allocate(pl_z3(pl_nx,pl_ny,pl_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array pl_z3 ***'
allocate(pl_p3(pl_nx,pl_ny,pl_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array pl_p3 ***'
 
c Read T, Q, PS from P file
call cdfopn(ml_pfn,cdfid,ierr)
if (ierr.ne.0) goto 998
isok=0
varname='T'
call check_varok (isok,varname, ml_vnam,ml_nvars)
varname='Q'
call check_varok (isok,varname, ml_vnam,ml_nvars)
varname='PS'
call check_varok (isok,varname,ml_vnam,ml_nvars)
if (isok.ne.3) goto 998
print*,'R T ',trim(ml_pfn)
call getdat(cdfid,'T',ml_time,0,ml_t3,ierr)
print*,'R Q ',trim(ml_pfn)
call getdat(cdfid,'Q',ml_time,0,ml_q3,ierr)
print*,'R PS ',trim(ml_pfn)
call getdat(cdfid,'PS',ml_time,1,ml_ps,ierr)
call clscdf(cdfid,ierr)
 
c Read ORO from P or Z from Z file
call cdfopn(pl_zfn,cdfid,ierr)
if (ierr.ne.0) goto 998
if (mode.eq.1) then
isok=0
varname='Z'
call check_varok (isok,varname,pl_vnam,pl_nvars)
if (isok.ne.1) goto 998
print*,'R Z ',trim(pl_zfn)
call getdat(cdfid,varname,pl_time,0,pl_z3,ierr)
else if (mode.eq.2) then
isok=0
varname='ORO'
call check_varok (isok,varname,pl_vnam,pl_nvars)
if (isok.ne.1) goto 998
print*,'R ORO ',trim(pl_zfn)
call getdat(cdfid,varname,pl_time,1,pl_z3,ierr)
endif
call clscdf(cdfid,ierr)
 
c Set the values for the pressure on the pressure levels
do i=1,pl_nx
do j=1,pl_ny
do k=1,pl_nz
if (mode.eq.1) then
pl_p3(i,j,k)=pl_aklay(k)
else if (mode.eq.2) then
pl_p3(i,j,k)=ml_ps(i,j)
endif
enddo
enddo
enddo
 
c Calculate 3d pressure field
print*,'C P'
do k=1,ml_nz
do i=1,ml_nx
do j=1,ml_ny
ml_p3(i,j,k)=ml_aklay(k)+ml_bklay(k)*ml_ps(i,j)
enddo
enddo
enddo
 
c Calculate 3d virtual temperature
print*,'C TV'
do k=1,ml_nz
do i=1,ml_nx
do j=1,ml_ny
ml_tv3(i,j,k) = (ml_t3(i,j,k)+tzero)*
> (1.+kappa*ml_q3(i,j,k))
enddo
enddo
enddo
 
c -----------------------------------------------------------------
c Calculate geopotential
c -----------------------------------------------------------------
 
c Integrate hydrostatic equation towards layers
print*,'C HYDROSTATIC EQUATION (LAYERS)'
do i=1,ml_nx
do j=1,ml_ny
 
c Make the virtual temperature profile available
do k=1,ml_nz
p1 (ml_nz-k+1)=ml_p3 (i,j,k)
tv1(ml_nz-k+1)=ml_tv3(i,j,k)
enddo
call spline (p1,tv1,ml_nz,1.e30,1.e30,spline_tv1)
 
c Loop over all model levels
do k=1,ml_nz
 
c Get pressure at the grid point
p = ml_aklay(k)+ml_bklay(k)*ml_ps(i,j)
 
c Find nearest pressure level which is above topography
if (mode.eq.1) then
lmin=pl_nz
do l=1,pl_nz
if ((abs(p-pl_p3(i,j,l))).lt.
> (abs(p-pl_p3(i,j,lmin)))
> .and.
> (pl_p3(i,j,l).lt.ml_ps(i,j)) ) then
lmin=l
endif
enddo
else if (mode.eq.2) then
lmin=1
endif
 
c Integrate hydrostatic equation from this level to the grid point
p0 = pl_p3(i,j,lmin)
n = nint(abs(p-p0)/dpmin)
if (n.lt.1) n=1
dp = (p-p0)/real(n)
 
pu = p0
z = pl_z3(i,j,lmin)
call splint(p1,tv1,spline_tv1,ml_nz,pu,tvu)
do l=1,n
po = pu+dp
call splint(p1,tv1,spline_tv1,ml_nz,po,tvo)
z = z + rdg*0.5*(tvu+tvo)*alog(pu/po)
tvu = tvo
pu = po
enddo
c Set the geopotential at the grid point
ml_zlay3(i,j,k) = z
enddo
 
enddo
 
enddo
 
c -----------------------------------------------------------------
c Calculate height of topography
c -----------------------------------------------------------------
 
if (mode.eq.1) then
print*,'C TOPOGRAPHY'
do i=1,ml_nx
do j=1,ml_ny
c Make the z/p profile available
do k=1,ml_nz
p1(ml_nz-k+1)=ml_p3(i,j,k)
z1(ml_nz-k+1)=ml_zlay3(i,j,k)
enddo
 
c Cubic spline interpolation
call spline (p1,z1,ml_nz,1.e30,1.e30,spline_z1)
call splint (p1,z1,spline_z1,ml_nz,ml_ps(i,j),ml_zb(i,j))
enddo
enddo
endif
 
c -----------------------------------------------------------------
c Write the topography and geopotential to P file
c -----------------------------------------------------------------
 
c Open P file
call cdfwopn(trim(ml_pfn),cdfid,ierr)
 
c Write orography (levels)
if (mode.eq.1) then
varname='ORO'
print*,'W ',trim(varname),' ',trim(ml_pfn)
isok=0
call check_varok (isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
ml_vardim(3)=1
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
ml_vardim(3)=ml_nz
if (ierr.ne.0) goto 997
endif
call putdat(cdfid,varname,ml_time,1,ml_zb,ierr)
if (ierr.ne.0) goto 997
endif
 
c Write geopotential on layers
varname='Z_DIA'
print*,'W ',trim(varname),' ',trim(ml_pfn)
isok=0
call check_varok (isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
ml_stag(3)=-0.5
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 997
endif
call putdat(cdfid,varname,ml_time,0,ml_zlay3,ierr)
if (ierr.ne.0) goto 997
 
c Close P file
call clscdf(cdfid,ierr)
 
c -----------------------------------------------------------------
c Exception handling and format specs
c -----------------------------------------------------------------
 
stop
 
998 print*,'Z: Problems with input from m level'
stop
 
997 print*,'Z: Problems with output on m level'
stop
 
996 print*,'F: Problems with input from m level'
stop
 
995 print*,'F: Problems with output on z level'
stop
 
 
end
 
c -------------------------------------------------------------
c Natural cubic spline
c -------------------------------------------------------------
 
SUBROUTINE spline(x,y,n,yp1,ypn,y2)
INTEGER n,NMAX
REAL yp1,ypn,x(n),y(n),y2(n)
PARAMETER (NMAX=500)
INTEGER i,k
REAL p,qn,sig,un,u(NMAX)
if (yp1.gt..99e30) then
y2(1)=0.
u(1)=0.
else
y2(1)=-0.5
u(1)=(3./(x(2)-x(1)))*((y(2)-y(1))/(x(2)-x(1))-yp1)
endif
do 11 i=2,n-1
sig=(x(i)-x(i-1))/(x(i+1)-x(i-1))
p=sig*y2(i-1)+2.
y2(i)=(sig-1.)/p
u(i)=(6.*((y(i+1)-y(i))/(x(i+
*1)-x(i))-(y(i)-y(i-1))/(x(i)-x(i-1)))/(x(i+1)-x(i-1))-sig*
*u(i-1))/p
11 continue
if (ypn.gt..99e30) then
qn=0.
un=0.
else
qn=0.5
un=(3./(x(n)-x(n-1)))*(ypn-(y(n)-y(n-1))/(x(n)-x(n-1)))
endif
y2(n)=(un-qn*u(n-1))/(qn*y2(n-1)+1.)
do 12 k=n-1,1,-1
y2(k)=y2(k)*y2(k+1)+u(k)
12 continue
return
END
 
 
SUBROUTINE splint(xa,ya,y2a,n,x,y)
INTEGER n
REAL x,y,xa(n),y2a(n),ya(n)
INTEGER k,khi,klo
REAL a,b,h
klo=1
khi=n
1 if (khi-klo.gt.1) then
k=(khi+klo)/2
if(xa(k).gt.x)then
khi=k
else
klo=k
endif
goto 1
endif
h=xa(khi)-xa(klo)
if (h.eq.0.) pause 'bad xa input in splint'
a=(xa(khi)-x)/h
b=(x-xa(klo))/h
y=a*ya(klo)+b*ya(khi)+((a**3-a)*y2a(klo)+(b**3-b)*y2a(khi))*(h**
*2)/6.
return
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)>.
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
Property changes:
Added: svn:executable
/tags/1.0/diag/qvec_analysis.f
0,0 → 1,1468
PROGRAM z2s
 
c Calculate secondary fields on z levels
c Michael Sprenger / Summer 2006
 
implicit none
 
c ---------------------------------------------------------------
c Declaration of parameters
c ---------------------------------------------------------------
 
real tzero
parameter (tzero=273.15)
real kappa
parameter (kappa=0.6078)
real rd
parameter (rd=287.)
 
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,oro
real,allocatable, dimension (:,:,:) :: out1,out2
real,allocatable, dimension (:,:,:) :: inp
real,allocatable,dimension (:) :: nsqref
real,allocatable,dimension (:) :: thetaref
real,allocatable,dimension (:) :: tref
real,allocatable,dimension (:) :: rhoref
real,allocatable,dimension (:) :: pressref
real,allocatable,dimension (:) :: zref
real deltax,deltay,deltaz
integer nvars
character*80 vnam(100),varname
integer isok
integer cdfid,cstid
character*3 mode
 
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 (:,:) :: tmp
character*80 vnam2(100)
integer nvars2
 
c ---------------------------------------------------------------
c Preparations
c ---------------------------------------------------------------
 
print*,'*********************************************************'
print*,'* qvec_analysis *'
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 Decide whether to enter ANO or MOD/ORG mode
mode = ofn(1:3)
if ( (mode.ne.'ANO').and.
> (mode.ne.'MOD').and.
> (mode.ne.'ORG') )
>then
print*,'Unsupported mode ',trim(mode)
stop
endif
 
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.'GEO' ).and.
> (fieldname.ne.'AGEO' ).and.
> (fieldname.ne.'DIV_UV' ).and.
> (fieldname.ne.'QVEC' ).and.
> (fieldname.ne.'DIV_Q' ) ) then
print*,'Variable not supported ',trim(fieldname)
stop
endif
c Set dependencies
if (fieldname.eq.'GEO') then
nfields=2
field_nam(1)='T'
field_nam(2)='P'
elseif (fieldname.eq.'AGEO') then
nfields=4
field_nam(1)='U'
field_nam(2)='UG'
field_nam(3)='V'
field_nam(4)='VG'
else if (fieldname.eq.'DIV_UV') then
nfields=2
field_nam(1)='U'
field_nam(2)='V'
else if (fieldname.eq.'QVEC') then
nfields=3
field_nam(1)='UG'
field_nam(2)='VG'
field_nam(3)='TH'
else if (fieldname.eq.'DIV_Q') then
nfields=2
field_nam(1)='QX'
field_nam(2)='QY'
endif
 
c Allocate memory
allocate(field_dat(nfields,nx,ny,nz),stat=stat)
if (stat.ne.0) print*,'error allocating field_dat'
allocate(out1(nx,ny,nz),stat=stat)
if (stat.ne.0) print*,'error allocating out1'
allocate(out2(nx,ny,nz),stat=stat)
if (stat.ne.0) print*,'error allocating out2'
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'
allocate(oro(nx,ny),stat=stat)
if (stat.ne.0) print*,'error allocating oro'
 
C Allocate memory for reference profile
allocate(rhoref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating rhoref'
allocate(pressref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pressref'
allocate(thetaref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating thetaref'
allocate(nsqref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating nsqref'
allocate(zref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating zref'
allocate(tref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating tref'
 
c Allocate auxiliary fields
allocate(tmp(nx,ny),stat=stat)
if (stat.ne.0) print*,'error allocating tmp'
c Read reference profile and grid parameters
call read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,f2,oro,gri)
 
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 Calculate reference profile of temperature
print*,'C T_ref = TH_ref * ( P_ref/1000)^kappa'
do i=0,2*nz
tref(i) = thetaref(i) * ( pressref(i)/1000. ) ** kappa
enddo
 
c Init height levels
do i=1,nx
do j=1,ny
do k=1,nz
z3(i,j,k)=zref(2*k-1)
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 Add reference profile if ANO file is provided
if ( mode.eq.'ANO' ) then
 
print*,'C T -> T_ano + T_ref'
n=0
do i=1,nfields
if (field_nam(i).eq.'T') 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) = field_dat(n,i,j,k) + tref(2*k-1)
enddo
enddo
enddo
endif
 
print*,'C TH -> TH_ano + TH_ref'
n=0
do i=1,nfields
if (field_nam(i).eq.'TH') 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) = field_dat(n,i,j,k)+thetaref(2*k-1)
enddo
enddo
enddo
endif
 
print*,'C P -> P_ano + P_ref'
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) = field_dat(n,i,j,k)+pressref(2*k-1)
enddo
enddo
enddo
endif
 
endif
 
c Change units: P (hPa -> Pa), T(K -> degC)
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
 
n=0
do i=1,nfields
if (field_nam(i).eq.'T') n=i
enddo
if (n.ne.0) then
do i=1,nx
do j=1,ny
do k=1,nz
if ( field_dat(n,i,j,1).gt.100. ) then
field_dat(n,i,j,k)=field_dat(n,i,j,k) - tzero
endif
enddo
enddo
enddo
endif
 
c ----------------------------------------------------------------
c Calculations
c ----------------------------------------------------------------
 
c Geostrophic wind (GEO)
if (fieldname.eq.'GEO') then
 
print*,'C ',trim(fieldname)
field_nam(1)='RHO'
do i=1,nx
do j=1,ny
do k=1,nz
if ( mode.eq.'ANO' ) then
field_dat(1,i,j,k)=rhoref(2*k-1)
else
field_dat(1,i,j,k)=
> 1./rd*field_dat(2,i,j,k)/(field_dat(1,i,j,k)+tzero)
endif
enddo
enddo
enddo
call calc_geo (out1,out2, ! (Ug,Vg)
> field_dat(1,:,:,:), ! RHO
> field_dat(2,:,:,:), ! P
> z3,x2,y2,f2, ! Z,X,Y,CORIOL
> nx,ny,nz,mdv)
 
c Ageostrophic wind (AGEO)
elseif (fieldname.eq.'AGEO') then
 
print*,'C ',trim(fieldname)
call calc_ageo (out1,out2, ! (Ua,Va)
> field_dat(1,:,:,:), ! U
> field_dat(2,:,:,:), ! UG
> field_dat(3,:,:,:), ! V
> field_dat(4,:,:,:), ! VG
> nx,ny,nz,mdv)
 
c Divergence of wind (DIV_UV)
else if (fieldname.eq.'DIV_UV') then
 
print*,'C ',trim(fieldname)
call calc_div_uv (out1, ! Div(U,V))
> field_dat(1,:,:,:), ! U
> field_dat(2,:,:,:), ! V
> z3,x2,y2,f2, ! Z,X,Y,CORIOL
> nx,ny,nz,mdv)
 
c Q vector (QVEC)
else if (fieldname.eq.'QVEC') then
 
print*,'C ',trim(fieldname)
call calc_qvec (out1,out2, ! (Qx,Qy)
> field_dat(1,:,:,:), ! UG
> field_dat(2,:,:,:), ! VG
> field_dat(3,:,:,:), ! TH
> z3,x2,y2,f2, ! Z,X,Y,CORIOL
> nx,ny,nz,mdv)
 
c Divergence of Q vector (DIV_Q)
else if (fieldname.eq.'DIV_Q') then
print*,'C ',trim(fieldname)
call calc_div_q (out1, ! Div(U,V))
> field_dat(1,:,:,:), ! QX
> field_dat(2,:,:,:), ! QY
> 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
tmp(i,j)=out1(i,j,k)
enddo
enddo
do n=1,nfilt
call filt2d (tmp,tmp,nx,ny,1.,mdv,0,0,0,0)
enddo
do i=1,nx
do j=1,ny
out1(i,j,k)=tmp(i,j)
enddo
enddo
 
do i=1,nx
do j=1,ny
tmp(i,j)=out2(i,j,k)
enddo
enddo
do n=1,nfilt
call filt2d (tmp,tmp,nx,ny,1.,mdv,0,0,0,0)
enddo
do i=1,nx
do j=1,ny
out2(i,j,k)=tmp(i,j)
enddo
enddo
enddo
 
c ----------------------------------------------------------------
c Save result onto netcdf file
c ----------------------------------------------------------------
 
c Open output file
call cdfwopn(ofn,cdfid,ierr)
if (ierr.ne.0) goto 998
 
c Save geostrophic wind
if (fieldname.eq.'GEO') then
isok=0
varname='UG'
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,out1,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
isok=0
varname='VG'
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,out2,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
 
c Save ageostrophic wind
elseif (fieldname.eq.'AGEO') then
isok=0
varname='UA'
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,out1,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
isok=0
varname='VA'
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,out2,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
 
c Save divergence of wind field
else if (fieldname.eq.'DIV_UV') then
isok=0
varname='DIV_UV'
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,out1,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
 
c Save components of Q vector
else if (fieldname.eq.'QVEC') then
isok=0
varname='QX'
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,out1,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
isok=0
varname='QY'
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,out2,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
 
c Save divergence of wind field
else if (fieldname.eq.'DIV_Q') then
isok=0
varname='DIV_Q'
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,out1,ierr)
if (ierr.ne.0) goto 998
print*,'W ',trim(varname),' ',trim(ofn)
 
endif
 
c Close output file
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 geostrophic wind components
c ----------------------------------------------------------------
 
subroutine calc_geo (ug,vg,rho,p,
> z3,x2,y2,f2,nx,ny,nz,mdv)
 
c Calculate the geostrophic wind components (ug,vg) if the temperature
c (t) and the pressure (p) are given. The grid and the missing data
c value are specified by (z3,x2,y2,f2,nx,ny,nz,mdv)
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real ug (nx,ny,nz)
real vg (nx,ny,nz)
real rho(nx,ny,nz)
real p (nx,ny,nz)
real z3 (nx,ny,nz)
real x2 (nx,ny)
real y2 (nx,ny)
real f2 (nx,ny)
real mdv
 
c Physical parameters and numerical constants
real eps
parameter (eps=0.01)
real g
parameter (g=9.80616)
 
 
c Auxiliray variables
integer i,j,k
real dpdx(nx,ny,nz)
real dpdy(nx,ny,nz)
 
c Calculate horizontal derivatives of pressure
call deriv(dpdx,p,'x',z3,x2,y2,nx,ny,nz,mdv)
call deriv(dpdy,p,'y',z3,x2,y2,nx,ny,nz,mdv)
 
c Calculation
do i=1,nx
do j=1,ny
do k=1,nz
 
if ((abs(rho (i,j,k)-mdv).gt.eps).and.
> (abs(dpdx(i,j,k)-mdv).gt.eps).and.
> (abs(dpdy(i,j,k)-mdv).gt.eps)) then
 
ug(i,j,k)=-1./(rho(i,j,k)*f2(i,j))*dpdy(i,j,k)
vg(i,j,k)= 1./(rho(i,j,k)*f2(i,j))*dpdx(i,j,k)
endif
 
enddo
enddo
enddo
 
end
 
c ----------------------------------------------------------------
c Calculate ageostrophic wind components
c ----------------------------------------------------------------
 
subroutine calc_ageo (ua,va,u,ug,v,vg,nx,ny,nz,mdv)
 
c Calculate the geostrophic wind components (ug,vg) if the temperature
c (t) and the pressure (p) are given. The grid and the missing data
c value are specified by (z3,x2,y2,f2,nx,ny,nz,mdv)
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real ua (nx,ny,nz)
real va (nx,ny,nz)
real u (nx,ny,nz)
real ug (nx,ny,nz)
real v (nx,ny,nz)
real vg (nx,ny,nz)
real mdv
 
c Parameters
real eps
parameter (eps=0.01)
 
c Auxiliray variables
integer i,j,k
 
c Calculation
do i=1,nx
do j=1,ny
do k=1,nz
 
if ((abs(u (i,j,k)-mdv).gt.eps).and.
> (abs(ug(i,j,k)-mdv).gt.eps).and.
> (abs(v (i,j,k)-mdv).gt.eps).and.
> (abs(vg(i,j,k)-mdv).gt.eps)) then
 
ua(i,j,k)=u(i,j,k) - ug(i,j,k)
va(i,j,k)=v(i,j,k) - vg(i,j,k)
 
endif
 
enddo
enddo
enddo
 
end
 
c ----------------------------------------------------------------
c Calculate divergence of wind field
c ----------------------------------------------------------------
 
subroutine calc_div_uv (div_uv,u,v,
> z3,x2,y2,f2,nx,ny,nz,mdv)
 
c Calculate the divergence (div_uv) of the horizontal wind field if+
c the wind components (u,v) are given. The grid and the missing data
c value are specified by (z3,x2,y2,f2,nx,ny,nz,mdv)
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real div_uv(nx,ny,nz)
real u (nx,ny,nz)
real v (nx,ny,nz)
real z3 (nx,ny,nz)
real x2 (nx,ny)
real y2 (nx,ny)
real f2 (nx,ny)
real mdv
 
c Physical parameters and numerical constants
real eps
parameter (eps=0.01)
 
c Auxiliray variables
integer i,j,k
real rho
real dudx(nx,ny,nz)
real dvdy(nx,ny,nz)
 
c Calculate horizontal derivatives of pressure
call deriv(dudx,u,'x',z3,x2,y2,nx,ny,nz,mdv)
call deriv(dvdy,v,'y',z3,x2,y2,nx,ny,nz,mdv)
 
c Calculation
do i=1,nx
do j=1,ny
do k=1,nz
 
if ((abs(dudx(i,j,k)-mdv).gt.eps).and.
> (abs(dvdy(i,j,k)-mdv).gt.eps)) then
 
div_uv(i,j,k)=dudx(i,j,k)+dvdy(i,j,k)
endif
 
enddo
enddo
enddo
 
end
 
c ----------------------------------------------------------------
c Calculate Q vector
c ----------------------------------------------------------------
 
subroutine calc_qvec (qx3,qy3,
> th3,u3,v3,
> z3,x2,y2,f2,nx,ny,nz,mdv)
 
c Calculate teh Q vector components <qx3> and <qy3>, as well as the divergence
c of the Q vector <divq3> on the model grid. The grid is specified in the horizontal
c by <xmin,ymin,dx,dy,nx,ny>. The number of vertical levels is <nz>. The input field
c are: potential temperature <th3>, horizontal wind <u3> and <v3>, pressure <p3>.
c The calculation follows the one described in "Weather Analysis, Dusan Djuric"
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real qx3(nx,ny,nz)
real qy3(nx,ny,nz)
real th3(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 scale1,scale2
parameter (scale1=1.E10,scale2=1.E14)
real eps
parameter (eps=0.01)
real g
parameter (g=9.80616)
real tzero
parameter (tzero=273.16)
 
c Auxiliary variables
real dudx(nx,ny,nz)
real dudy(nx,ny,nz)
real dvdx(nx,ny,nz)
real dvdy(nx,ny,nz)
real dtdx(nx,ny,nz)
real dtdy(nx,ny,nz)
integer i,j,k
 
c Needed derivatives
call deriv (dudx, u3,'x',z3,x2,y2,nx,ny,nz,mdv)
call deriv (dudy, u3,'y',z3,x2,y2,nx,ny,nz,mdv)
call deriv (dvdx, v3,'x',z3,x2,y2,nx,ny,nz,mdv)
call deriv (dvdy, v3,'y',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)
 
c Calculate vector components of the Q vector
do i=1,nx
do j=1,ny
do k=1,nz
 
c Evaluate Q vector formula with missing data check
if ((abs(dudx(i,j,k)-mdv).gt.eps).and.
> (abs(dudy(i,j,k)-mdv).gt.eps).and.
> (abs(dvdx(i,j,k)-mdv).gt.eps).and.
> (abs(dvdy(i,j,k)-mdv).gt.eps).and.
> (abs(dtdx(i,j,k)-mdv).gt.eps).and.
> (abs(dtdy(i,j,k)-mdv).gt.eps)) then
 
qx3(i,j,k) = -g/tzero * (dudx(i,j,k)*dtdx(i,j,k)
> +dvdx(i,j,k)*dtdy(i,j,k))
qy3(i,j,k) = -g/tzero * (dudy(i,j,k)*dtdx(i,j,k)
> +dvdy(i,j,k)*dtdy(i,j,k))
 
else
qx3(i,j,k)=mdv
qy3(i,j,k)=mdv
endif
 
enddo
enddo
enddo
 
c Scale the output
do i=1,nx
do j=1,ny
do k=1,nz
if (abs(qx3(i,j,k)-mdv).gt.eps) then
qx3(i,j,k)=scale1*qx3(i,j,k)
endif
if (abs(qy3(i,j,k)-mdv).gt.eps) then
qy3(i,j,k)=scale1*qy3(i,j,k)
endif
enddo
enddo
enddo
 
end
 
c ----------------------------------------------------------------
c Calculate divergence of wind field
c ----------------------------------------------------------------
 
subroutine calc_div_q (div_q,qx,qy,
> z3,x2,y2,f2,nx,ny,nz,mdv)
 
c Calculate the divergence (div_q) of the Q vector field if
c the components (qx,qy) are given. The grid and the missing data
c value are specified by (z3,x2,y2,f2,nx,ny,nz,mdv)
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real div_q(nx,ny,nz)
real qx (nx,ny,nz)
real qy (nx,ny,nz)
real z3 (nx,ny,nz)
real x2 (nx,ny)
real y2 (nx,ny)
real f2 (nx,ny)
real mdv
 
c Physical parameters and numerical constants
real eps
parameter (eps=0.01)
 
c Auxiliray variables
integer i,j,k
real rho
real dqxdx(nx,ny,nz)
real dqydy(nx,ny,nz)
 
c Calculate horizontal derivatives of pressure
call deriv(dqxdx,qx,'x',z3,x2,y2,nx,ny,nz,mdv)
call deriv(dqydy,qy,'y',z3,x2,y2,nx,ny,nz,mdv)
 
c Calculation
do i=1,nx
do j=1,ny
do k=1,nz
 
if ((abs(dqxdx(i,j,k)-mdv).gt.eps).and.
> (abs(dqydy(i,j,k)-mdv).gt.eps)) then
 
div_q(i,j,k)=dqxdx(i,j,k)+dqydy(i,j,k)
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 deltay
parameter (deltay=111.1775E3)
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
 
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
Property changes:
Added: svn:executable
/tags/1.0/docu/BoxedEPS.tex
0,0 → 1,803
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%%%% BoxedEPS.tex FOR FIGURE INSERTS OF EPSF NORM %%%%%
%%%%% (EPSF = Encapsulated PostScript File)
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%% AUTHOR: Laurent Siebenmann
%% lcs@matups.matups.fr
%%
%%% VERSIONS: Feb 1991 -- October, 1992
%%
%%% SOMMAIRE: BoxedEPS.tex d\'efinit des macro-commandes
%% qui permettent d'int\'egrer dans un document TeX des
%% objets graphiques d\'ecrits par fichier de norme EPSF,
%% tout en accordant a chacun le statut d'une bo\^ite TeX ayant
%% les bonnes dimensions. La (seule!) contribution unique
%% de ce fichier est de faire cela d'une fa{\c}con universelle.
%% C'est a dire de fa{\c}con \`a pouvoir commod\'ement
%% servir avec tout pilote d'imprimante de norme
%% PostScript --- malgr\'e l'absence d'une norme
%% pour \special.
%%
%%% POSTINGS: anonymous ftp
%% --- ftp 130.84.128.100 (alias rsovax.circe.fr);
%% login: anonymous; password: <anything>; directory
%% [anonymous.siebenmann]. This is the master copy in 1992.
%%
%% --- ftp 129.69.1.12 (alias rusinfo.rus.uni-stuttgart.de);
%% login: anonymous; password: <anything>;
%% directory hints .../tex/graphics/...
%%
%%%% DOCUMENTATION:
%% --- see BoxedEPS.doc
%%
%%%% ACTIVATION:
%% by a driver-by-driver protocol
%% see \SetTexturesEPSFSpecial
%% and its companions below.
%%
 
\ifx\MYUNDEFINED\BoxedEPSF
\let\temp\relax
\else
\message{}
\message{ !!! BoxedEPS %
or BoxedArt macros already defined !!!}
\let\temp\endinput
\fi
\temp
\chardef\EPSFCatAt\the\catcode`\@
\catcode`\@=11
 
\chardef\C@tColon\the\catcode`\:
\chardef\C@tSemicolon\the\catcode`\;
\chardef\C@tQmark\the\catcode`\?
\chardef\C@tEmark\the\catcode`\!
\chardef\C@tDqt\the\catcode`\"
 
\def\PunctOther@{\catcode`\:=12
\catcode`\;=12 \catcode`\?=12 \catcode`\!=12 \catcode`\"=12}
\PunctOther@
 
%%temporarily suppress Plain's logging of allocations
\let\wlog@ld\wlog
\def\wlog#1{\relax}
 
%% New for TOOLS
\newif\ifIN@
\newdimen\XShift@ \newdimen\YShift@
\newtoks\Realtoks
%%% New for Boxed EPSF
%
\newdimen\Wd@ \newdimen\Ht@
\newdimen\Wd@@ \newdimen\Ht@@
%
\newdimen\TT@
\newdimen\LT@
\newdimen\BT@
\newdimen\RT@
%
\newdimen\XSlide@ \newdimen\YSlide@
%
\newdimen\TheScale %% secretly scale in mils: 1pt= 1mil
\newdimen\FigScale %% secretly scale in mils: 1pt= 1mil
%
\newdimen\ForcedDim@@
 
\newtoks\EPSFDirectorytoks@
\newtoks\EPSFNametoks@
\newtoks\BdBoxtoks@
\newtoks\LLXtoks@ %% useful info for Oz
\newtoks\LLYtoks@
 
\newif\ifNotIn@
\newif\ifForcedDim@
\newif\ifForceOn@
\newif\ifForcedHeight@
\newif\ifPSOrigin
 
\newread\EPSFile@
%%%% MESSAGES (separate macro needed for Europe)
%%
\def\ms@g{\immediate\write16}
 
%%%% WORD-PROCESSING MACROS
%%
%%% \IN@0#1@#2@ : Is 1st exp of #1 in 1st exp of #2 ??
%% Answer in \ifIN@
\newif\ifIN@\def\IN@{\expandafter\INN@\expandafter}
\long\def\INN@0#1@#2@{\long\def\NI@##1#1##2##3\ENDNI@
{\ifx\m@rker##2\IN@false\else\IN@true\fi}%
\expandafter\NI@#2@@#1\m@rker\ENDNI@}
\def\m@rker{\m@@rker}
 
%%% \SPLIT@0#1@#2@ : Split 1st exp of #2 at 1st exp of #1
%% \Initialtoks@ , \Terminaltoks@ will contain pieces
\newtoks\Initialtoks@ \newtoks\Terminaltoks@
\def\SPLIT@{\expandafter\SPLITT@\expandafter}
\def\SPLITT@0#1@#2@{\def\TTILPS@##1#1##2@{%
\Initialtoks@{##1}\Terminaltoks@{##2}}\expandafter\TTILPS@#2@}
 
%%%% MACROS TO TRIM \ForeTrim@0#1@ and \Trim@0#1@
%% result appears in \Trimtoks@
%% LIMITATION: assume no multiple spaces to trim
 
\newtoks\Trimtoks@
 
%%% \ForeTrim@0#1@ trims initial space of first erpansion of #1
%% #1 of form \the\toks0 or \mymacro
\def\ForeTrim@{\expandafter\ForeTrim@@\expandafter}
\def\ForePrim@0 #1@{\Trimtoks@{#1}}
\def\ForeTrim@@0#1@{\IN@0\m@rker. @\m@rker.#1@%
\ifIN@\ForePrim@0#1@%
\else\Trimtoks@\expandafter{#1}\fi}
%%\m@rker expands here to \m@@rker since spot initial,
%% so no confusuion with \m@rker
 
%%% \Trim@0#1@ trims init and terminal spaces
%% Same syntax.
%% Warns if internal spaces found.
%%
\def\Trim@0#1@{%
\ForeTrim@0#1@%
\IN@0 @\the\Trimtoks@ @%
\ifIN@
\SPLIT@0 @\the\Trimtoks@ @\Trimtoks@\Initialtoks@
\IN@0\the\Terminaltoks@ @ @%
\ifIN@
\else \Trimtoks@ {FigNameWithSpace}%
\fi
\fi
}
 
 
%%%% MATH MACROS (provisional)
%% use dimen registers for reals; unit 1pt
%% (numerical dimension arguments OK unless contrary noted)
 
%%%% One needs the point token seq (pt with cat 12) USES dimen 0
\newtoks\pt@ks
\def \getpt@ks 0.0#1@{\pt@ks{#1}}
\dimen0=0pt\relax\expandafter\getpt@ks\the\dimen0@
 
%%% Convert dimen to "decimal multiplier"% USES dimens 0,2
\newtoks\Realtoks% the output!
\def\Real#1{%
\dimen2=#1%
\SPLIT@0\the\pt@ks @\the\dimen2@%% lop off the points
\Realtoks=\Initialtoks@%\showthe\Realtoks
}
 
%%% Multiplication
% USES dimens 0,2,4,6; preserves args; output \Product
\newdimen\Product
\def\Mult#1#2{%
\dimen4=#1\relax
\dimen6=#2%
\Real{\dimen4}%
\Product=\the\Realtoks\dimen6%
}
 
%%% Inverse
% USES dimens 0; preserves arg; output \Inverse
\newdimen\Inverse
\newdimen\hmxdim@ \hmxdim@=8192pt%halfmaxdimen
\def\Invert#1{%
\Inverse=\hmxdim@
\dimen0=#1%
\divide\Inverse \dimen0%
\multiply\Inverse 8}
 
%%% \Rescale#1#2#3 % USES dimens 0,2,4,6
%% alters dimen register #1 by ratio #2/#3
%% where #2,#3 can be raw dimensions OR dimen registers
\def\Rescale#1#2#3{% Adequate accuracy. Can improve.
\divide #1 by 100\relax
\dimen2=#3\divide\dimen2 by 100 \Invert{\dimen2}%
\Mult{#1}{#2}%
\Mult\Product\Inverse
#1=\Product}
 
%%% \Scale#1 scales dimen register #1
% by dimen register real \TheScale; USES dimens 0
\def\Scale#1{\dimen0=\TheScale %
\divide #1 by 1280 %% 1280*5120*10=1000*2^16
\divide \dimen0 by 5120 %
\multiply#1 by \dimen0
\divide#1 by 10 %% max size of #1 about 32000/10 pt
}
%%% SCRUNCHING BOXES AND SHIFTING CONTENTS
%% TeX has to do this in general
%% since some drivers do not let
%% one do it readily using Postscript
 
\newbox\scrunchbox
 
%%% \Scrunched#1 puts #1 in an hbox
%% then in effect zeros the dimensions of this box
\def\Scrunched#1{{\setbox\scrunchbox\hbox{#1}%
\wd\scrunchbox=0pt
\ht\scrunchbox=0pt
\dp\scrunchbox=0pt
\box\scrunchbox}}
 
%%% \Shifted@#1 puts #1 in \hbox
%% then locates basepoint to bottom left corner
%% then translates ink only by \XShift@,\YShift@
%% with Postscript convention
%% For simplicity use only on scrunched boxes
%\newdimen\XShift@
%\newdimen\YShift@
\def\Shifted@#1{%
\vbox {\kern-\YShift@
\hbox {\kern\XShift@\hbox{#1}\kern-\XShift@}%
\kern\YShift@}}
 
%%% \cBoxedEPSF#1 the main macro
%% component macros are explained in order below
 
\def\cBoxedEPSF#1{{\leavevmode
%% double brace for amstex \allign, \alligned, ...
\ReadNameAndScale@{#1}%
\SetEPSFSpec@
\ReadEPSFile@ \ReadBdB@x
%% Calculations
\TrimFigDims@
\CalculateFigScale@
\ScaleFigDims@
\SetInkShift@
\hbox{$\mathsurround=0pt\relax
\vcenter{\hbox{%
\FrameSpider{\hskip-.4pt\vrule}%
\vbox to \Ht@{\offinterlineskip\parindent=\z@%
\FrameSpider{\vskip-.4pt\hrule}\vfil
\hbox to \Wd@{\hfil}%
\vfil
\InkShift@{\EPSFSpecial{\EPSFSpec@}{\FigSc@leReal}}%
\FrameSpider{\hrule\vskip-.4pt}}%
\FrameSpider{\vrule\hskip-.4pt}}}%
$}%
\CleanRegisters@
\ms@g{ *** Box composed for the %
EPSF file \the\EPSFNametoks@}%
}}
\def\tBoxedEPSF#1{\setbox4\hbox{\cBoxedEPSF{#1}}%
\setbox4\hbox{\raise -\ht4 \hbox{\box4}}%
\box4
}
 
\def\bBoxedEPSF#1{\setbox4\hbox{\cBoxedEPSF{#1}}%
\setbox4\hbox{\raise \dp4 \hbox{\box4}}%
\box4
}
 
\let\BoxedEPSF\cBoxedEPSF% default setting
 
%% Some compatibility with BoxedArt.tex
%
\let\BoxedArt\BoxedEPSF
 
%% Some compatibility with Sweet-teX
%
\def\gLinefigure[#1scaled#2]_#3{%
\BoxedEPSF{#3 scaled #2}}
%% Some compatibility with Rokicki's dvips
%
\let\EPSFbox\bBoxedEPSF \let\EPSFfile\bBoxedEPSF
\def\EPSFxsize{\afterassignment\ForceW@\ForcedDim@@}
\def\ForceW@{\ForcedDim@true\ForcedHeight@false}
\def\EPSFysize{\afterassignment\ForceH@\ForcedDim@@}
\def\ForceH@{\ForcedDim@true\ForcedHeight@true}
 
\def\EmulateRokicki{%
\let\epsfbox\bBoxedEPSF \let\epsffile\bBoxedEPSF
\let\epsfxsize\EPSFxsize \let\epsfysize\EPSFysize}
%%% \ReadNameAndScale@#1
%
\def\ReadNameAndScale@#1{\IN@0 scaled@#1@% DOUBLE BARRELED
\ifIN@\ReadNameAndScale@@0#1@%
\else \ReadNameAndScale@@0#1 scaled\DefaultMilScale @%
\fi}
\def\ReadNameAndScale@@0#1scaled#2@{% HELPER MACRO
\let\OldBackslash@\\%
\def\\{\OtherB@ckslash}%
\edef\temp@{#1}%
\Trim@0\temp@ @%
\EPSFNametoks@\expandafter{\the\Trimtoks@ }%
\FigScale=#2 pt%
\let\\\OldBackslash@
}
\def\SetDefaultEPSFScale#1{%
\global\def\DefaultMilScale{#1}}
 
\SetDefaultEPSFScale{1000}
 
 
%%% \ReadEPSFile@
%
\def \SetBogusBbox@{%
\global\BdBoxtoks@{ BoundingBox:0 0 100 100 }%
\global\def\BdBoxLine@{ BoundingBox:0 0 100 100 }%
\ms@g{ !!! Will use placeholder !!!}%
}
 
{\catcode`\%=12\gdef\P@S@{%!}} %% %! min sign of PS file
 
\def\ReadEPSFile@{%\show\EPSFSpec@%
\openin\EPSFile@\EPSFSpec@
\relax %necessary to prevent precocious expansion of \ifeof
\ifeof\EPSFile@
\ms@g{}%
\ms@g{ !!! EPS FILE \the\EPSFDirectorytoks@
\the\EPSFNametoks@\space WAS NOT FOUND !!!}%
\SetBogusBbox@
\else%\fi
\begingroup%%
\catcode`\%=12\catcode`\:=12\catcode`\!=12
\catcode`\G=14\catcode`\\=14\relax% 14 is comment
\global\read\EPSFile@ to \BdBoxLine@%\show\BdBoxLine@
\IN@0\P@S@ @\BdBoxLine@ @%
\ifIN@ %% %! accepted as %!PS so do BdBox search!!
\NotIn@true
\loop
\ifeof\EPSFile@\NotIn@false
\ms@g{}%
\ms@g{ !!! BoundingBox NOT FOUND IN %
\the\EPSFDirectorytoks@\the\EPSFNametoks@\space!!! }%
\SetBogusBbox@
\else\global\read\EPSFile@ to \BdBoxLine@
%\show\BdBoxLine@
\fi
\global\BdBoxtoks@\expandafter{\BdBoxLine@}%
\IN@0BoundingBox:@\the\BdBoxtoks@ @%
\ifIN@\NotIn@false\fi%
\ifNotIn@\repeat
\else
\ms@g{}%
\ms@g{ !!! \the\EPSFNametoks@\space not PS!\space !!!}%
\SetBogusBbox@
\fi
\endgroup\relax
\fi
\closein\EPSFile@
}
 
 
%%% \ReadBdB@x
% Rmk For simplicity 0 not used in syntax
% of \ReadBdB@x@, \ReadBdB@x@@
\def\ReadBdB@x{% PART 0
\expandafter\ReadBdB@x@\the\BdBoxtoks@ @}
\def\ReadBdB@x@#1BoundingBox:#2@{% PART 1
\ForeTrim@0#2@%
\IN@0atend@\the\Trimtoks@ @%
\ifIN@\Trimtoks@={0 0 100 100 }%
\ms@g{}%
\ms@g{ !!! BoundingBox not found in %
\the\EPSFDirectorytoks@\the\EPSFNametoks@\space !!!}%
\ms@g{ !!! It must not be at end of EPSF !!!}%
\ms@g{ !!! Will use placeholder !!!}%
\fi%% cf \SetBogusBbox@
\expandafter\ReadBdB@x@@\the\Trimtoks@ @%
}
\def\ReadBdB@x@@#1 #2 #3 #4@{% PART 2
\Wd@=#3bp\advance\Wd@ by -#1bp%
\Ht@=#4bp\advance\Ht@ by-#2bp%
\Wd@@=\Wd@ \Ht@@=\Ht@ %% useful info for Clark
\LLXtoks@={#1}\LLYtoks@={#2}%% useful info for Oz
\ifPSOrigin\XShift@=-#1bp\YShift@=-#2bp\fi
}
 
%%% \SetEPSFDirectory
%
\def\G@bbl@#1{}
\bgroup
\global\edef\OtherB@ckslash{\expandafter\G@bbl@\string\\}
\egroup
 
\def\SetEPSFDirectory{% Part 1
\bgroup\PunctOther@\relax
\let\\\OtherB@ckslash
\SetEPSFDirectory@}
 
\def\SetEPSFDirectory@#1{% Part 2
\edef\temp@{#1}%
\Trim@0\temp@ @% result in \Trimtoks@
\global\toks1\expandafter{\the\Trimtoks@ }\relax
\egroup
\EPSFDirectorytoks@=\toks1
}
 
%%% \SetEPSFSpec@
\def\SetEPSFSpec@{%
\bgroup
\let\\=\OtherB@ckslash
\global\edef\EPSFSpec@{%
\the\EPSFDirectorytoks@\the\EPSFNametoks@}%
\global\edef\EPSFSpec@{\EPSFSpec@}%
\egroup}
 
%%% \TrimFigDims@
%
\def\TrimTop#1{\advance\TT@ by #1}
\def\TrimLeft#1{\advance\LT@ by #1}
\def\TrimBottom#1{\advance\BT@ by #1}
\def\TrimRight#1{\advance\RT@ by #1}
 
\def\TrimBoundingBox#1{%
\TrimTop{#1}%
\TrimLeft{#1}%
\TrimBottom{#1}%
\TrimRight{#1}%
}
 
\def\TrimFigDims@{%
\advance\Wd@ by -\LT@
\advance\Wd@ by -\RT@ \RT@=\z@
\advance\Ht@ by -\TT@ \TT@=\z@
\advance\Ht@ by -\BT@
}
 
 
%%% \CalculateFigScale@
%
\def\ForceWidth#1{\ForcedDim@true
\ForcedDim@@#1\ForcedHeight@false}
\def\ForceHeight#1{\ForcedDim@true
\ForcedDim@@=#1\ForcedHeight@true}
 
\def\ForceOn{\ForceOn@true}
\def\ForceOff{\ForceOn@false\ForcedDim@false}
\def\CalculateFigScale@{%
%Have default \FigScale or read \FigScale
\ifForcedDim@\FigScale=1000pt% %% start afresh
\ifForcedHeight@
\Rescale\FigScale\ForcedDim@@\Ht@
\else
\Rescale\FigScale\ForcedDim@@\Wd@
\fi
\fi
\Real{\FigScale}%
\edef\FigSc@leReal{\the\Realtoks}%
}
\def\ScaleFigDims@{\TheScale=\FigScale
\ifForcedDim@
\ifForcedHeight@ \Ht@=\ForcedDim@@ \Scale\Wd@
\else \Wd@=\ForcedDim@@ \Scale\Ht@
\fi
\else \Scale\Wd@\Scale\Ht@
\fi
\ifForceOn@\relax\else\global\ForcedDim@false\fi
\Scale\LT@\Scale\BT@ %%%\Scale\Wd@\Scale\Ht@
\Scale\XShift@\Scale\YShift@
}
%%% \ShowReservedBoxes
%% shows (prints) corrected scaled and positioned
%% bounding boxes; for diagnostics
%%% \HideReservedBoxes makes them invisible again
%%
\def\HideReservedBoxes{\global\def\FrameSpider##1{\null}}
\def\ShowReservedBoxes{\global\def\FrameSpider##1{##1}}
\let\HideDisplacementBoxes\HideReservedBoxes %% some synonyms
\let\ShowDisplacementBoxes\ShowReservedBoxes
\let\HideFigureFrames\HideReservedBoxes
\let\ShowFigureFrames\ShowReservedBoxes
\ShowDisplacementBoxes
%%% \hSlide#1, \vSlide#1
%%
\def\hSlide#1{\advance\XSlide@ by #1}
\def\vSlide#1{\advance\YSlide@ by #1}
%%% \SetInkShift@, \InkShift@#1
%%
\def\SetInkShift@{%
\advance\XShift@ by -\LT@
\advance\XShift@ by \XSlide@
\advance\YShift@ by -\BT@
\advance\YShift@ by -\YSlide@
}
%
\def\InkShift@#1{\Shifted@{\Scrunched{#1}}}
%%% \CleanRegisters@
%
\def\CleanRegisters@{%
\globaldefs=1\relax
\XShift@=\z@\YShift@=\z@\XSlide@=\z@\YSlide@=\z@
\TT@=\z@\LT@=\z@\BT@=\z@\RT@=\z@
\globaldefs=0\relax}
 
%%% Special syntax for several drivers. The macros
%% \SetTexturesEPSFSpecial %% Textures
%% \SetUnixCoopEPSFSpecial %% dvi2ps early unix
%% \SetBechtolsheimDVI2PSEPSFSpecial and
%% \SetBechtolsheimDVITPSEPSFSpecial %% by S.P.Bechtolsheim
%% \SetLisEPSFSpecial %% dvi2ps by Tony Lis
%% \SetRokickiEPSFSpecial %% dvips by Tom Rokicki
%% --- also for DVIReader, in DirectTeX by W. Ricken
%% \SetOzTeXEPSFSpecial %% OzTeX (>=1.42) by Andrew Trevorrow
%% \SetPSprintEPSFSpecial %% PSprint by Andrew Trevorrow
%% --- also for OzTeX versions <= 1.41 !!
%% \SetArborEPSFSpecial %% ArborTeX DVILASER/PS
%% \SetClarkEPSFSpecial %% dvitops by James Clark
%% \SetDVIPSoneEPSFSpecial %% DVIPSONE of Y&Y
%% \SetBeebeEPSFSpecial %% DVIALW by N. Beebe
%% \SetNorthlakeEPSFSpecial %% Northlake Software
%% \SetStandardEPSFSpecial %% Nonexistant: Placebo below
%% Many drivers supported roughly
%% by (re-)defining the macro \EPSFSpecial#1#2, where
%% #1 = EPS file pathname (use \\ for the letter backslash)
%% #2 = scale in mils
%% Be wary of using strange characters in pathnames!
%% Textures, Blue Sky Research, Barry Smith
\def\SetTexturesEPSFSpecial{\PSOriginfalse%\PSOrigintrue
\gdef\EPSFSpecial##1##2{\relax
\edef\specialthis{##2}%
\SPLIT@0.@\specialthis.@\relax
\special{illustration ##1 scaled
\the\Initialtoks@}}}
%% Unix : dvi2ps by: Mark Senn, Stephan Bechtolsheim,
% Bob Brown, Richard, Furuta, James Schaad, Robert Wells,
% Norm Hutchinson, Neal Holt, Scott Jones, Howard Trickey.
% Introduced by B. Horn <bkph@ai.mit.edu>
\def\SetUnixCoopEPSFSpecial{\PSOrigintrue % Please test!
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt% convert real to dimen
\divide\dimen4 by 1000\relax
\Real{\dimen4}%dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%
%%convert dimen to real
\special{psfile=##1\space
hscale=\Aux@\space
vscale=\Aux@}}}
 
%% dvi2ps and dvitps by S.P. Bechtolsheim,
% Introduced by B. Horn <bkph@ai.mit.edu> and Carl.M.Jones,
% testing by R. Evans <Robert@cm.cardiff.ac.uk>
% Note that a prolog file psfig.pro
% specific to the driver should be available.
\def\SetBechtolsheimEPSFSpecial@{%% tool macro only
\PSOrigintrue
\special{\DriverTag@ Include0 "psfig.pro"}%
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt %% convert real to dimen
\divide\dimen4 by 1000\relax
\Real{\dimen4} %% dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%% convert dimen to real
\special{\DriverTag@ Literal "10 10 0 0 10 10 startTexFig
\the\mag\space 1000 div 3.25 neg mul
\the\mag\space 1000 div .25 neg mul translate %% correction
\the\mag\space 1000 div \Aux@\space mul
\the\mag\space 1000 div \Aux@\space mul scale "}%
\special{\DriverTag@ Include1 "##1"}%
\special{\DriverTag@ Literal "endTexFig "}%
}}
 
%% dvi2ps and dvitps by S.P. Bechtolsheim,
% Introduced by B. Horn <bkph@ai.mit.edu> and Carl.M.Jones,
% testing by R. Evans <Robert@cm.cardiff.ac.uk>
% Note that a prolog file psfig.pro
% specific to the driver should be available.
\def\SetBechtolsheimEPSFSpecial@{%% tool macro only
\PSOrigintrue
\special{\DriverTag@ Include0 "psfig.pro"}%
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt %% convert real to dimen
\divide\dimen4 by 1000\relax
\Real{\dimen4} %% dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%% convert dimen to real
\special{\DriverTag@ Literal "10 10 0 0 10 10 startTexFig
\the\mag\space 1000 div
dup 3.25 neg mul 2 index .25 neg mul translate %% correction line
\Aux@\space mul dup scale "}%
\special{\DriverTag@ Include1 "##1"}%
\special{\DriverTag@ Literal "endTexFig "}%
}}
 
\def\SetBechtolsheimDVITPSEPSFSpecial{\def\DriverTag@{dvitps: }%
\SetBechtolsheimEPSFSpecial@}
 
\def\SetBechtolsheimDVI2PSEPSFSSpecial{\def\DriverTag@{DVI2PS: }%
\SetBechtolsheimEPSFSpecial@}
 
%% dvi2ps by Tony Lis,
% implantations? ; dates?; availability?
% Introduced by B. Horn <bkph@ai.mit.edu>
\def\SetLisEPSFSpecial{\PSOrigintrue
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt% convert real to dimen
\divide\dimen4 by 1000\relax
\Real{\dimen4}% dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%
%%convert dimen to real
\special{pstext="10 10 0 0 10 10 startTexFig\space
\the\mag\space 1000 div \Aux@\space mul
\the\mag\space 1000 div \Aux@\space mul scale"}%
\special{psfile=##1}%
\special{pstext=endTexFig}%
}}
 
%% dvips by Tom Rokicki; free driver in portable C
% Introduced by W.D. Neumann <neumann@mps.ohio-state.edu>
\def\SetRokickiEPSFSpecial{\PSOrigintrue
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt% convert real to dimen
\divide\dimen4 by 10\relax
\Real{\dimen4}% dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%
%%convert dimen to real
\special{psfile="##1"\space
hscale=\Aux@\space
vscale=\Aux@}}}
 
\def\SetInlineRokickiEPSFSpecial{\PSOrigintrue
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt% convert real to dimen
\divide\dimen4 by 1000\relax
\Real{\dimen4}% dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%
%%convert dimen to real
\special{ps::[begin] 10 10 0 0 10 10 startTexFig\space
\the\mag\space 1000 div \Aux@\space mul
\the\mag\space 1000 div \Aux@\space mul scale}%
\special{ps: plotfile ##1}%
\special{ps::[end] endTexFig}%
}}
 
%%% OzTeX (versions 1.42 and later), by Andrew Trevorrow
%%% (for earlier versions see PSprint below!!)
%% complete public domain TeX for Macintosh
%% Send 10 UNFORMATTED 800K disks
%% with return postage to
%% Peter Abbott, Computing Service,
%% Aston University, Aston Triangle, Birmingham B4 7ET
%% Posting: ftp midway.uchicago.edu
%% Nota: Version 1.42 may give
%% spurious "offpage" error notices on printing.
%% Nota: Support for MacPaint files not here yet.
\def\SetOzTeXEPSFSpecial{\PSOrigintrue
\gdef\EPSFSpecial##1##2{%
\dimen4=##2pt%% convert real to dimen
\divide\dimen4 by 1000\relax
\Real{\dimen4}%% dimens 0,2 used here
\edef\Aux@{\the\Realtoks}%% convert dimen to real
\special{epsf=\string"##1\string"\space scale=\Aux@}%
}}
 
%% PSprint, by AndrewTrevorrow for VaX VMS
%% and OzTeX versions <= 1.41
% tested 2-91 by Max Calviani <ISICA@ASTRPD.infn.it>
\def\SetPSprintEPSFSpecial{\PSOriginFALSE % artifice; see below
\gdef\EPSFSpecial##1##2{%note order
\special{##1\space
##2 1000 div \the\mag\space 1000 div mul
##2 1000 div \the\mag\space 1000 div mul scale
\the\LLXtoks@\space neg \the\LLYtoks@\space neg translate
}}}
 
%% DVILASER/PS driver originally written by David Fuchs
% marketed and supported by ArborTeXt 535 W. William St.
% Suite 300, Ann Arbor, MI 48103, U.S.A
% (313) 996-3566 (313) 996-3573
% help@arbortext.com, Andrew Dobrowolski
\def\SetArborEPSFSpecial{\PSOriginfalse % check!
\gdef\EPSFSpecial##1##2{%
\edef\specialthis{##2}%
\SPLIT@0.@\specialthis.@\relax % suppress decimals (nec!)
\special{ps: epsfile ##1\space \the\Initialtoks@}}}
 
%% dvitops, (c) James Clark <jjc@jclark.uucp>
% public domain; distributed by UK TeX Archive
% computers: unix, msdos, vms, primos and vm/cms,
% introduced by S. Ratz <spqr@uk.ac.southampton.ecs>
\def\SetClarkEPSFSpecial{\PSOriginfalse % please test!
\gdef\EPSFSpecial##1##2{%
\Rescale {\Wd@@}{##2pt}{1000pt}%
\Rescale {\Ht@@}{##2pt}{1000pt}%
\special{dvitops: import
##1\space\the\Wd@@\space\the\Ht@@}}}
 
%% DVIPSONE, for PC compatibles
% Y&Y, 106 Indian Hill, Carlisle MA 01741, USA
% (508) 371-3286
% (introduced by B. Horn <bkph@ai.mit.edu>)
\let\SetDVIPSONEEPSFSpecial\SetUnixCoopEPSFSpecial
\let\SetDVIPSoneEPSFSpecial\SetUnixCoopEPSFSpecial
 
%% DVIALW by N. Beebe, public domain
% DVI Driver Distribution, Center for Scientific Computing,
% Department of Mathematics, 220 South Physics Building,
% University of Utah, Salt Lake City, UT 84112, USA
% (introduced by B. Horn <bkph@ai.mit.edu>)
% Proposed standard; see TUGboat article 1993.
\def\SetBeebeEPSFSpecial{%please test!
\PSOriginfalse%
\gdef\EPSFSpecial##1##2{\relax
\special{language "PS",
literal "##2 1000 div ##2 1000 div scale",
position = "bottom left",
include "##1"}}}
\let\SetDVIALWEPSFSpecial\SetBeebeEPSFSpecial
 
%% Northlake software
\def\SetNorthlakeEPSFSpecial{\PSOrigintrue
\gdef\EPSFSpecial##1##2{%
\edef\specialthis{##2}%
\SPLIT@0.@\specialthis.@\relax % suppress decimals (nec!)
\special{insert ##1,magnification=\the\Initialtoks@}}}
 
\def\SetStandardEPSFSpecial{%
\gdef\EPSFSpecial##1##2{%
\ms@g{}
\ms@g{%
!!! Sorry! There is still no standard for \string%
\special\space EPSF integration !!!}%
\ms@g{%
--- So you will have to identify your driver using a command}%
\ms@g{%
--- of the form \string\Set...EPSFSpecial, in order to get}%
\ms@g{%
--- your graphics to print. See BoxedEPS.doc.}%
\ms@g{}
\gdef\EPSFSpecial####1####2{}
}}
 
\SetStandardEPSFSpecial %% currently gives warning
\let\wlog\wlog@ld %%restore logging
 
\catcode`\:=\C@tColon
\catcode`\;=\C@tSemicolon
\catcode`\?=\C@tQmark
\catcode`\!=\C@tEmark
\catcode`\"=\C@tDqt
 
\catcode`\@=\EPSFCatAt
 
\endinput
 
%%%%%%%%%%%% ASCII Character test
%
% Upper case letters: ABCDEFGHIJKLMNOPQRSTUVWXYZ
% Lower case letters: abcdefghijklmnopqrstuvwxyz
% Digits: 0123456789
% Square, curly, angle braces, parentheses: [] {} <> ()
% Backslash, slash, vertical bar: \ / |
% Punctuation: . ? ! , : ;
% Underscore, hyphen, equals sign: _ - =
% Quotes--right left double: ' ` "
%"at", "number" "dollar", "percent", "and": @ # $ % &
% "hat", "star", "plus", "tilde": ^ * + ~
%
%%%%%%%%%%%%%%%%%%%%%%%%
%
% Une seule erreur de transmission peut empoisoner un programme!
%
% A single transmission error can poison a whole program.
%
%%%%%%%%%%%%%%%%%%%%%%%%
Property changes:
Added: svn:executable
/tags/1.0/docu/fig/20021116_12wv.ps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/500_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/Fig05_pv_320K.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/Fig11_PVInv_tropo1.PS.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/an_2d_Z0_20060115_18_08000.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/an_ew_Z0_20060115_18_n35.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/an_ew_Z0_20060115_18_n51.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/ano_00_k35_pr.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/ano_00_k35_psi.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/ano_00_k35_tt.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/ano_00_k35_uv.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/bound_lower_th_Z1_20060115_18.ai.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/bound_lower_th_Z1_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/bound_lower_th_Z1_20060115_18.ps.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/bound_upper_th_Z1_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/box.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/coast1.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/coast2.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/con_00_k35_psi.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/con_01_k35_psi.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/con_02_k35_psi.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/con_03_k35_psi.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/con_table.txt.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/coriol_grid.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/coriolis.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/diag_test.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/difference.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/fl_2d_Z0_20060115_18_08000.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/fl_ew_Z0_20060115_18_n35.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/flussdiag.sdr.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/handle_mdv2.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/inp_pv.th_45n.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/inp_pv_350hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/inp_t_500_k30.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/inp_th_350hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/inp_tt_k38.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/inp_uv_k38.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/iterations.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/latlon_grid.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/latlon_nh.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/local_cart_grid.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/numericalgrid.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/numericalgrid.jpg.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_pv.th_45n.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_pv_350hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_t_500_k30.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_th_350hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_tt_k38.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_uv_500_k30.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/out_uv_k38.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/postproc.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/prep_k35_mod.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/prep_k35_org_ano.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/preparation.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/prepiter.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pro_q_70w40n_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pro_t_70w40n_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/ps_20060116_18_500hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/psi_ano_k01.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/psi_ano_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/psi_ano_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_20060114_18_315K.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_20060115_18_315K.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_20060116_18_315K.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_20060117_18_315K.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_20060118_18_315K.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_2d_Z0_20060115_18_08000.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_2d_Z0_20060115_18_10000.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ano_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ano_k30.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ano_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ano_k50.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_color.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_colorbar.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_colorbar.jpg.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ew_Z0_20060115_18_n35.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ew_Z0_20060115_18_n40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ew_Z0_20060115_18_n45.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_ew_Z0_20060115_18_n51.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_mod_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_mod_k30.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_mod_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_mod_k50.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_org_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_org_k30.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_org_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_org_k50.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/pv_to_qgpv.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/q_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/q_20060116_18_500hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qg_2d_Z1_20060115_18_08000.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qg_2d_Z1_20060115_18_10000.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qgpv_ano_ew.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qgpv_ano_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qgpv_ano_ns.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qgpv_k35_calc.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qgpv_k35_diff.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/qgpv_k35_spec.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/reference.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/rot_k35_geo_t.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/rot_k35_rot_t.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/run_text.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/sat_wv.ps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/sigma_level.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/sigma_level.jpg.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/splitting.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/streamer.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/t_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/t_20060116_18_500hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/test.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/threesteps.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/uv_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/uv_20060116_18_500hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/weight1.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/weight2.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/xy_grid.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/z_20060115_18.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/z_20060116_18_250hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/z_20060116_18_500hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/z_20060116_18_850hPa.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_nsq_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_nsq_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_pv_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_pv_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_rho_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_rho_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_th_k20.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/fig/zus_th_k40.eps.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/x-gzip
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/x-gzip
\ No newline at end of property
/tags/1.0/docu/userguide.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/pdf
Property changes:
Added: svn:executable
Added: svn:mime-type
+application/pdf
\ No newline at end of property
/tags/1.0/docu/userguide.tex
0,0 → 1,4320
\documentclass[12pt]{article}
 
\renewcommand{\topfraction}{0.93}
\renewcommand{\bottomfraction}{0.93}
\renewcommand{\textfraction}{.07}
 
\input BoxedEPS
\SetRokickiEPSFSpecial
\ForceOn
\SetEPSFDirectory{M:/Weiterbildung/Allgemeine_Informatik/Diplomarbeit/fig/}
\HideDisplacementBoxes
 
\textwidth16.0cm
\textheight26.0cm
\oddsidemargin0.5cm
\topmargin-1.5cm
\headsep0cm
\topskip0cm
 
\renewcommand{\baselinestretch}{1.2}
 
\begin{document}
 
\pagenumbering{Roman}
 
% ----------------------------------------------------------------------------------------------
% Title page
% ----------------------------------------------------------------------------------------------
 
\thispagestyle{empty}
 
\vspace{0.7cm}
 
\begin{center}
 
{\Large\bf Numerical Piecewise Potential Vorticity Inversion \\[2mm]
A user guide for real-case experiments}
 
\vspace{1cm}
\begin{center}
\begin{minipage}[t]{10cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{Fig05_pv_320K.eps}
\end{minipage}
\end{center}
 
 
\vspace{1cm}
Michael Sprenger, Ph.\,D.$^{1}$ \\
\vspace{0.3cm}
{\sl Institute for Atmospheric and Climate Science, ETH Z\"urich, Switzerland}\\
\vspace{1.8cm}
\today \\
{Diploma Thesis for the Postgraduate Course in Computer Science, FHSS Schweiz,\\
under the supervision of Lars Kruse, Ph.\,D.}
\end{center}
\vspace{2cm}
 
\noindent
{\sl $^1$Corresponding author and his address:}\\[1mm]
Michael Sprenger\\
Institute for Climate and Atmospheric Science, {\it IAC}ETH \\
ETH Zurich \\
CH-8092 Zurich, Switzerland \\
e-mail: michael.sprenger@env.ethz.ch
 
 
\newpage
\vspace{20cm}
\noindent
{\bf Title figure:} Ertel's potential vorticity at 320\,K.
 
% ----------------------------------------------------------------------------------------------
% Abstract
% ----------------------------------------------------------------------------------------------
 
\newpage
 
\begin{center}
{\large \bf Abstract}
\end{center}
 
\noindent
Potential vorticity (PV) is a key quantity in atmospheric dynamics. Its value is based upon several
points: (a) PV is conserved in purely adiabatic flows, i.e. if radiative and condensational heating and other
diabatic processes can be neglected; (b) under suitable balance conditions the specification of PV
in the interior of a domain and with boundary values for potential temperature completely determines
the flow field, in particular horizontal wind and temperature can be derived; (c) in many respects
the atmosphere can be partitioned into several distinct PV features, which then interact and allow
the dynamics to be interpreted as the interaction of these PV elements. Points (b) and (c) are known
as the invertibility and partitioning principle, respectively.\\
 
\noindent
In this thesis, a program package is presented which allows to isolate PV elements and then to
study their impact on the atmospheric flow field and on the temperature distribution. Technically,
this is done with a so-called PV inversion, which in turn comprises several different steps, as for
example transformation into suitable co-ordinate systems and numerical solution of a poisson equation. With PV inversion, two major problems arise: Firstly, a suitable balance condition must
be formulated, secondly the inversion problem for Ertel's PV is nonlinear, and therefore poses a significant challenge. The program presented in this thesis is based upon the so-called
quasi-geostrophic balance condition. More specifically, the linear quasi-geostrophic PV equation is
solved. Since quasi-geostrophic and Ertel's PV do not exactly coincide, an iterative technique
is adopted to approach the nonlinear Ertel-PV inversion by means of successively quasi-geostrophic
inversions.\\
 
\noindent
The aim of this work is to present an in-depth discussion of all steps which are needed for a PV inversion.
Special focus was given to a clear and user-friendly program package, where all steps are
well documented and hence are attractive for further development. In this respect, the complete
inversion is controlled by one single Linux Shell script.
The new user needs only to adjust some few paths in this script. The
main parameters for the inversion itself are specified in a separate parameter file.
 
\newpage
 
\begin{center}
{\large \bf Zusammenfassung}
\end{center}
 
\noindent
Die potentielle Vortizit\"at (PV) ist eine Kerngr\"osse der dynamischen Meteorologie. Ihre Bedeutung basiert auf mehreren Eigenschaften: (a) In einer adiabatischen Str\"omung, dh. wenn Strahlung,
die Freisetzung von latenter W\"arme und andere diabatische Prozesse vernachl\"assigt werden
k\"onnen, ist PV eine lagrange'sche Erhaltungsgr\"osse; (b) unter geeigneten Balancebedingungen bestimmt die Verteilung der PV im Innern und der potentiellen Temperatur am Rand eines Gebietes
vollst\"andig den Zustand der Atmosph\"are, insbesondere die horizontalen Windfelder und das
Temperaturfeld; (c) h\"aufig l\"asst sich die Atmosph\"are in mehrere, klar voneinander getrennte PV-Elemente unterteilen, die dann die Dynamik der Atmosph\"are durch ihre Wechselwirkung bestimmen.
Die Eigenschaften (b) und (c) sind in der Literatur bekannt als das Invertibilit\"atsprinzip und
Partitionierungsprinzip.\\
 
\noindent
In dieser Arbeit wird ein Programmpaket vorgestellt, mit dessen Hilfe sich einzelne PV-Elemente
isolieren und ihr Einfluss auf die atmosph\"arischen Windfelder und Temperaturen studieren
lassen. Programmtechnisch besteht diese sogenannte PV-Inversion aus mehreren Schritten. So muss
zum Beispiel eine Koordinatentransformation durchgef\"uhrt werden und eine Poisson-Gleichung
numerisch gel\"ost werden. Damit die PV-Inversion sinnvoll ist, m\"ussen zwei Probleme gel\"ost
werden. Zun\"achst muss eine geeignete Balancebedingung vorgegegeben sein. Ausserdem handelt es
sich bei der Inversion um einen nichtlinearen Prozess, der numerisch einige Herausforderungen
stellt. In dem Programmpaket dieser Arbeit wird die sogenannte quasi-geostrophische Balance
verwendet, dh. der mathematische/numerische Inversionsprozess besteht in der L\"osung der
linearen quasi-geostrophischen PV-Gleichung. Das Problem der Nichtlinearit\"at wird dadurch gel\"ost, dass
die Berechnung des genannten linearen Inversionsproblems mehrmals wiederholt wird. Iterativ
ergibt sich somit eine L\"osung des nichtlinearen Problems.\\
 
\noindent
Ziel dieser Arbeit ist eine detailierte Darstellung aller Schritte, die bei einer PV-Inversion
n\"otig sind. Besonderes Augenmerk wurde bei der Entwicklung des Programmpakets auf die klare
Strukturierung und Anwenderfreundlichkeit gelegt. Dadurch kann das Paket einerseits als Black-Box
verwendet werden, zugleich erlaubt es erfahrenen Benutzern eine leichte Einarbeitung in die
Programme und damit die M\"oglichkeit zu deren Erweiterung. Die ganze Inversion wird von einem einzigen
Linux Shell Skript kontrolliert, in dem lediglich einige wenige Pfade angepasst werden m\"ussen. Die
meisten Parameter, welche das gestellte Problem der PV-Inversion beschreiben, sind in einer
separaten Parameterdatei eingetragen.
 
 
 
 
% ----------------------------------------------------------------------------------------------
% Inhalt
% ----------------------------------------------------------------------------------------------
 
\newpage
\section*{Contents}
 
\vspace{0.5cm}
\renewcommand{\contentsname}{}
\contentsline{section}{\hspace{0.5cm} Abstract}{III}
\contentsline{section}{\hspace{0.5cm} Zusammenfassung}{IV}
\contentsline{section}{\hspace{0.5cm} Abbreviations}{VII}
\contentsline{section}{\hspace{0.5cm} List of Figures}{VIII}
\vspace{-1.5cm}
\tableofcontents
 
 
 
% ----------------------------------------------------------------------------------------------
% Abkürzungen
% ----------------------------------------------------------------------------------------------
 
\newpage
\section*{Abbreviations}
 
\vspace{0.5cm}
\begin{tabular}{rll}
{\bf [1]} & {\bf DWD} & Deutscher Wetterdienst (German weather service)\\[2mm]
{\bf [2]} & {\bf ECMWF} & European Centre for Medium Range Weather Forecasts\\[2mm]
{\bf [3]} & {\bf ERA-40} & Re-analysis of the ECMWF for the periods 1958-2001\\[2mm]
{\bf [4]} & {\bf ERA-15} & Re-analysis of the ECMWF for the periods 1979-1993\\[2mm]
{\bf [5]} & {\bf ETH} & Eidgen\"ossische Technische Hochschule\\[2mm]
{\bf [6]} & {\bf f} & Coriolis parameter (in $s^{-1}$)\\[2mm]
{\bf [7]} & {\bf IACETH} & Institute for Atmospheric and Climate Science at ETH Zurich\\[2mm]
{\bf [8]} & {\bf METEOSAT} & European geostationary weather satellite\\[2mm]
{\bf [9]} & {\bf MeteoSwiss} & Swiss weather service\\[2mm]
{\bf [10]} & {\bf NaN } & Not a Number (missing data flag)\\[2mm]
{\bf [11]} & {\bf netcdf } & Compact and random-access file format\\[2mm]
{\bf [12]} & {\bf NWP } & Numerical weather prediction\\[2mm]
{\bf [13]} & {\bf $N^2$ } & Squared Brunt-Vais\"al\"a frequency (in $s^-2$)\\[2mm]
{\bf [14]} & {\bf PV} & Potential vorticity (if not otherwise stated Ertel's potential vorticity)\\[2mm]
{\bf [15]} & {\bf pvu} & Potential vorticity unit\\[2mm]
{\bf [16]} & {\bf PDE} & Partial differential equation\\[2mm]
{\bf [17]} & {\bf SOR} & Successive over-relaxation\\[2mm]
{\bf [18]} & {\bf T} & Temperature (in $^\circ$C)\\[2mm]
{\bf [19]} & {\bf $T_v$} & Virtual temperature (in $^\circ$C)\\[2mm]
{\bf [20]} & {\bf U} & Zonal velocity component (in west/east direction)\\[2mm]
{\bf [21]} & {\bf V} & Meridional velocity component (in south/north direction)\\[2mm]
{\bf [22]} & {\bf $\omega$} & Vertical velocity component (in Pa/s)\\[2mm]
{\bf [23]} & {\bf q} & Specific humidity (in kg/kg)\\[2mm]
{\bf [24]} & {\bf $\theta$} & Potential temperature (in K)\\[2mm]
{\bf [25]} & {\bf $\rho$} & Air density (in kg/m$^3$)\\[2mm]
{\bf [26]} & {\bf R$_d$} & Gas constant for dry air (in kg/m$^3$)\\[2mm]
{\bf [27]} & {\bf $\epsilon$} & Ratio of gas constants for dry air and water vapour\\[2mm]
{\bf [28]} & {\bf g} & Earth's gravity (in kg m/s$^2)$\\
\end{tabular}
 
\newpage
\listoffigures
 
% ----------------------------------------------------------------------------------------------
% Introduction and Motivation
% ----------------------------------------------------------------------------------------------
 
\newpage
\clearpage
\pagenumbering{arabic}
 
\section{Introduction and Motivation}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{16cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{sat_wv.ps}
\end{minipage}
\\
\caption{\it Water vapour satellite imagery (in gray shading) and isolines of Ertel's potential vorticity (PV)
at 350\,hPa and for 3 May 1998, 12\,UTC. Dark regions indicate a dry upper troposphere, whereas bright and white regions are
indicative for a lot of moisture in the upper troposphere. Note that high-PV regions are coincident with
dry regions. }
\label{satwv}
\end{center}
\end{figure}
 
There are different ways how the state of the atmosphere can be described. Traditionally this is done by specification of temperature, horizontal and vertical wind components and of either pressure, if geometrical height is used as the vertical co-ordinate, or geopotential height, if pressure is used as the vertical co-ordinate. This traditional approach has its main advantage in its simplicity. On the other hand, theoretical physics has often experienced the case that new insight can be gained if abstract, but physically more fundamental quantities were introduced. Consider for example the introduction of action and its primary physical parameter, the Planck constant. Similarly, geophysical fluid dynamics and hence atmospheric dynamics made some transitions away from the simple traditional meteorological fields toward more abstract ones.\\
 
\noindent
A long existing concept of engineering fluid dynamics is the concept of vorticity, which mathematically is defined as the curl of the wind vector field. Vorticity is treated in nearly every text book on fluid dynamics, for instance in Acheson (1990). Vorticity is a scalar quantity, but nevertheless, in a divergent-free and two-dimensional flow its specification is sufficient to deduce the complete velocity field. We could call this the invertibility principle for vorticity in such a non-divergent and two-dimensional flow. Moreover, an interesting conservation law hold for vorticity under these assumptions: Following the fluid motion, vorticity is conserved, i.e. its lagrangian derivative with respect to time is zero. Probably, in its most elegant way this conservation principle is expressed in Kelvin's circulation theorem (Acheson, 1990). These concepts of barotropic flow and of conservation of vorticity were indeed the basis for the first numerical weather predictions by Charney in 1950 (for an interesting history of numerical weather prediction, consult either Lynch, 2006, or Nebeker, 1995).\\
 
\noindent
Of course, the atmosphere cannot be treated in an exact way as a barotropic fluid. It constitutes a
stratified fluid where density and pressure decreases with increasing height. Therefore, a suitable
generalisation of the barotropic-vorticity equation for the real atmosphere is by far not trivial, but would be highly desirable.
Potential vorticity goes into this direction. The fundamental work by Rossby (1940) and Ertel (1942)
showed that potential vorticity is conserved in adiabatic (no latent heat release, no radiative heating
or cooling) and frictionless flow. The generalisation of the "invertibility principle for vorticity"
in two-dimensional flow was first stated in a rough way by Kleinschmidt (1950). He was able to attribute
some low-level flow features to an upper-level PV anomaly, in his words to a "Zyklonenk\"orper". Figure\,1
is a nice illustration of an upper-level PV anomaly. It shows some isolines of Ertel's PV on 350\,hPa,
which form an elongated and narrow filament of high PV extending from Scandinavia south to the north-western
edge of Spain. Remarkably, this anomaly of high PV is also discernible as a dark band in the water vapour
imagery of the geostationary METEOSAT weather satellite. Hence, the high PV band is associated with a very dry upper troposphere. \\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{16cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{Fig11_PVInv_tropo1.ps}
\end{minipage}
\\
\caption{\it Section across the circularly symmetric structure induced by an isolated, circularly symmetric, cyclonic potential vorticity anomaly near the model tropopause across which the Rossby-Ertel potential vorticity has a strong discontinuity, by a factor of 6. The bold line is the tropopause, the horizontal
thin lines are potential temperature, plotted at 5\,K intervals, and the circular/elliptical lines denote tangential velocity, at 3\,m/s intervals. The structure is typical for middle latitudes; the Coriolis parameter is $10^{-4}s^{-1}$ (as at geographical latitude $43.3^\circ$N). The domain shown has a radius of 2500\,km (taken from McIntyre,
1997).}
\label{inversion}
\end{center}
\end{figure}
 
\noindent
A very influential set of equations was introduced by Charney by means of a scale analysis of the dynamical equations (1948). These so called quasi-geostrophic equations are well suitable to describe synoptic and planetary-scale
processes, whilst neglecting smaller-scale features. Although these equations nowadays are considered no
longer of sufficient accuracy for numerical weather prediction, they nevertheless still are of great importance in
theoretical dynamic meteorology due to their simplicity and elegance (Holton, 1992).
Along with this set of equations came a new version of potential vorticity. This quasi-geostrophic
potential vorticity is linearly "linked" to the flow and temperature field, and -particularly interesting for
this study- an invertibility principle can be formulated. Indeed, the linear relationship between quasi-geostrophic potential vorticity and the flow field makes it very interesting since sophisticated
numerical techniques exist for the solution of this kind of problem. An example of such an inversion is shown in Fig.\,\ref{inversion} where
a cyclonic potential-vorticity anomaly near a model tropopause is shown. The potential vorticity is high
in the stratosphere and low in the troposphere. Therefore, the downward excursion of the tropopause is
associated locally with anomalously high potential vorticity. This anomaly is marked in the figure with
stippling. The "horizontal" lines correspond to the potential temperature, the "circular/elliptical" contours to the tangential velocity. Note that the isolines of potential temperature (the so-called isentropes) are
pulled upwards below the PV anomaly, and pulled downward within the PV anomaly. An interesting aspect of
the upward pulling of the isentropes is the associated reduction in atmospheric stability. Due to the reduced
vertical gradient of potential temperature, the atmosphere is more prone to convective instability. In fact,
in a recent study Martius et al. (2006) showed that many heavy precipitation events in the south of the Alps are
associated with such upper-level distortions of the tropopause, and hence with a PV anomaly. Moreover, note
that the upper-level PV anomaly is not only associated with a deformation of the isentropes, but is
also linked with a wind field. The induced wind field in this idealised setting reaches 21\,m/s at its maximum and
is cyclonically (anti-clockwise) oriented. The wind field is strongest at the tropopause level, but is even discernible at
the surface far below the anomaly. In this respect, the PV field exhibits a far-field effect, and this in turn
is the basic idea behind the invertibility principle. If this principle is taken together with the partitioning
principle, its explaining power becomes particularly attractive. This latter principles states that the atmospheric state can
be expressed as the interaction of isolated PV elements. This immediately invokes a research strategy, which is: to
enter, modify or remove some of these PV elements, and to see how the flow evolves in the thus
changed state. A very influential review article on PV and PV thinking was presented by Hoskins et al. (1985).
Here the key elements of PV thinking are discussed and applied to many atmospheric dynamical problems. \\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{16cm}
\vspace{-2cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{streamer.eps}
\end{minipage}
\\[-2cm]
\caption{\it Stratospheric PV streamer and positions with stratosphere-troposphere mass exchange. The section is
for 1 January 1986, 06\,UTC and on the 320\,K isentrope. It is taken from the ERA-15 data set of the ECMWF. In color Ertel's potential vorticity is shown in pvu. Mass exchange from the stratosphere to the troposphere is
marked with stars, transport in the opposite direction by open circles (taken from Sprenger et al., 2007)}
\label{streamer}
\end{center}
\end{figure}
 
 
\noindent
Many studies relate to this PV thinking perspective. For instance, Davis and Emanuel (1991) looked at the
potential vorticity diagnostics of cyclogenesis; Fehlmann and Davies (1997) investigated the impact of PV
structures on precipitation events over Europe. In addition to this methodology, PV has gained a lot of
interest in recent years as a diagnostic tool. Indeed, from a dynamicist's point of view it is highly
attractive to use potential vorticity as the defining component of the extra-tropical tropopause (Stohl et al. 2003). Typically,
this value is set to 2\,pvu, and every air parcel with larger PV is treated as stratospheric and
every air parcel with lower PV as tropospheric. This definition allows to discuss the dynamics of the extra-tropical tropopause, as it would not be feasible with the more common thermal (or lapse-rate) definition of the tropopause. In Fig.\,\ref{streamer} a prominent feature of the extra-tropical tropopause is shown: a stratospheric
PV streamer. It corresponds to a pronounced excursion of stratospheric (high-PV) air towards the south. These
features are quite common in the extra-tropics and are important for the mass exchange between the stratosphere
and the troposphere, amongst other impacts (for example they are often related to cyclogenesis). The positions where stratospheric mass (and chemical constituents, as for example ozone) crosses the tropopause are marked in the figure by stars. They are predominantly found on the upstream
(western) side of the streamer. Crossing in the opposite direction, i.e. from the troposphere to the stratosphere,
on the other hand occurs on the downstream (eastern) side of the streamer. Interesting questions emerge from the
inspection of a such a figure: If the intensity, or the southward excursion of the PV streamer was reduced, would there still be a significant mass flux across the tropopause? These, and similar questions are at the heart of
the PV inversion, which is introduced in this study.\\
 
 
\noindent
The study is organised in the following way: In chapter 2 the mathematical problem of PV inversion is
formulated and some essential aspects of the numerical algorithm are discussed. Chapter~3 introduces some
key aspects for the re-structuring of the program package.
Then, in chapter 4 a detailed
example of PV inversion is discussed. This part is intended to be a practical user guide for PV inversion,
and therefore rather detailed technical aspects are presented. Chapter 5 follows with some helpful
diagnostic tools which allow to quality and impact of the PV inversion. Finally, chapter 6 concludes
with some general remarks and wishes regarding the PV inversion tool.
 
 
 
 
\newpage
 
\section{Mathematical Framework and Numerical Aspects}
 
In this study we use the quasi-geostrophic approximation for the real-case
inversion problem. In this limit the relative (quasi-geostrophic) potential vorticity
$q$ is given by:\\[-2mm]
 
\[
q = \frac{\partial^2\psi}{\partial x^2} + \frac{\partial^2\psi}{\partial y^2} +
\frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z} ( \frac{\rho_0}{N_0^2}
\cdot \frac{\partial \psi}{\partial z})
\]
 
\vspace{0.3cm}
\noindent
with the boundary values of potential temperature at the upper and lower lid and
of zonal and meridional wind components at the lateral boundaries:\\[-2mm]
 
\[
g \cdot \frac{\theta^*}{\theta_0} = f \cdot \frac{\partial \psi}{\partial z}
\quad \quad
u = -\frac{\partial \psi}{\partial y}
\quad \quad
v = -\frac{\partial \psi}{\partial x}
\]
 
\vspace{0.3cm}
\noindent
Here $N_0^2$, $\rho_0$ and $\theta_0$ denote the squared Brunt-V\"as\"ala frequency, the density and the
potential temperature of a reference state depending only on the vertical co-ordinate $z$. $\psi$ is the
streamfunction from which the horizontal wind components can be derived. Finally, $f$ is the Coriolis parameter
which measures the Earth's rotation rate (typically $10^{-4}s^{-1}$ in the mid-latitudes and 0 at the equator),
and $g$ is the Earth's gravity.\\
 
 
 
\noindent
The above equations constitute a so-called von Neumann boundary problem for the elliptic
differential equation relating the potential vorticity $q$ to the streamfunction $\psi$. Hence,
the elliptic partial differential equation (PDE) can be transformed into the general form:\\[-2mm]
 
\[
\frac{\partial}{\partial x}(\alpha \cdot \frac{\partial \psi}{\partial x}) +
\frac{\partial}{\partial y}(\beta \cdot \frac{\partial \psi}{\partial y}) +
\frac{\partial}{\partial z}(\gamma \cdot \frac{\partial \psi}{\partial z}) +
\sigma = 0
\]
 
\vspace{0.3cm}
\noindent
where the coefficients $\alpha$, $\beta$, $\gamma$ and $\sigma$ are easily expressed in terms of
the density $\rho_0$, the Coriolis parameter $f$ and the squared Brunt-Vais\"al\"a frequency $N^2$:\\[-2mm]
 
\[
\alpha = \rho_0(z) \quad \quad
\beta = \rho_0(z) \quad \quad
\gamma = \frac{f^2(y) \cdot \rho_0(z)}{N_0^2(z)} \quad \quad
\sigma = - \rho_0(z) \cdot q(x,y,z)
\]
 
\vspace{0.3cm}
\noindent
The next step is to discretise the above PDE by means of finite differences. We assume that all
fields (quasi-geostrophic PV $q$, streamfunction $\psi$,...) are defined on a three-dimensional grid, whose
grid points can be addressed by the three indices $i$, $j$, and $k$ in the x-, y- and z-direction (see Fig.\,ref{grid}). With this
convention, the discretised PDE can be written as:\\[-2mm]
 
\[
\Delta_x(A \cdot \Delta_x \psi) +
\Delta_y(B \cdot \Delta_y \psi) +
\Delta_z(C \cdot \Delta_z \psi) +
S = 0
\]
 
\vspace{0.3cm}
\noindent
Here the operators $\Delta_x(A \cdot \Delta_x\psi)$, $\Delta_y(B \cdot \Delta_y\psi)$ and
$\Delta_z(C \cdot \Delta_z\psi)$ at the grid position $i,j,k$ are defined by:
 
\begin{eqnarray*}
\Delta_x(A \cdot \Delta_x\psi)_{i,j,k} & = &
A_{i+1/2,j,k} \cdot (\psi_{i+1,j,k}-\psi_{i,j,k}) -
A_{i-1/2,j,k} \cdot (\psi_{i,j,k}-\psi_{i-1,j,k}) \\[0.2cm]
\Delta_y(B \cdot \Delta_y\psi)_{i,j,k} & = &
B_{i,j+1/2,k} \cdot (\psi_{i,j+1,k}-\psi_{i,j,k}) -
B_{i,j-1/2,k} \cdot (\psi_{i,j,k}-\psi_{i,j-1,k}) \\[0.2cm]
\Delta_z(C \cdot \Delta_z\psi)_{i,j,k} & = &
C_{i,j,k+1/2} \cdot (\psi_{i,j,k+1}-\psi_{i,j,k}) -
C_{i,j,k-1/2} \cdot (\psi_{i,j,k}-\psi_{i,j,k-1})
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
Some simple algebra yields the following expressions for $A$, $B$ and $C$:
 
\begin{eqnarray*}
A_{i,j,k} & = & \frac{\Delta y \cdot \Delta z}{\Delta x} \cdot \alpha_{i,j,k}\\[0.2cm]
B_{i,j,k} & = & \frac{\Delta y \cdot \Delta z}{\Delta x} \cdot \beta_{i,j,k}\\[0.2cm]
C_{i,j,k} & = & \frac{\Delta y \cdot \Delta z}{\Delta x} \cdot \gamma_{i,j,k}
\end{eqnarray*}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{16cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{numericalgrid.eps}
\end{minipage}
\\
\caption{\it The numerical grid for the PV inversion in an xz cross-section. The horizontal grid spacing is $\Delta x$
in the x-direction (and correspondingly $\Delta y$ in the y-direction), the vertical grid spacing $\Delta z$. Note that in the vertical, a staggered grid at half-levels is also needed (taken from Fehlmann, 1997).}
\label{grid}
\end{center}
\end{figure}
 
\vspace{0.3cm}
\noindent
Finally, the additive operator $S$ is expressed as:
 
\[
S_{i,j,k} = \Delta x \cdot \Delta y \cdot \Delta z \cdot \sigma_{i,j,k}
\]
 
\vspace{0.3cm}
\noindent
It turns out to be advantageous to have the coefficients $\alpha$, $\beta$, $\gamma$ and $\sigma$
not only on the 3d grid where the quasi-geostrophic PV and the streamfunction are defined, but to
have them also on intermediate points. These leads to the grid structure which is shown in Fig.\,\ref{grid}.
On the left side the indices for the $\psi$-grid is shown, i.e. for the grid where the
quasi-geostrophic PV and the streamfunction is defined. The right side gives the indices for the
coefficients $\alpha$, $\beta$, $\gamma$ and $\sigma$, i.e. for the intermediate layers.\\
 
\noindent
Let $\rho(k) = \rho_{k/2}$ and $N^2(k)=N^2_{k/2}$, hence expressing the vertical grid with intermediate layers. With these definitions the coefficients $A$, $B$ and $C$ for the inversion problem are readily obtained (note that these coefficients are dependent only on the vertical index z):
 
\begin{eqnarray*}
A_k & = & \frac{\Delta y \cdot \Delta z}{\Delta x} \cdot \rho(2k) \quad (k=0,...,nz)\\[0.2cm]
B_k & = & \frac{\Delta y \cdot \Delta z}{\Delta x} \cdot \rho(2k) \quad (k=0,...,nz)\\[0.2cm]
C_k & = & \frac{\Delta y \cdot \Delta z}{\Delta x} \cdot \frac{\rho(k) \cdot f^2}{N^2(k)} \quad (k=0,...2\cdot nz)
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
The additive operator $S$ depends on all three grid indices. In its discretised form it is:
 
\[
S_{i,j,k} = - \Delta x \cdot \Delta y \cdot \Delta z \cdot \rho(2k) \cdot q_{i,j,k}
\quad (i=0,...,nx, j=0,...,ny, k=0,...,nz)
\]
 
\vspace{0.3cm}
\noindent
It is convenient to additionally define the coefficients $C_{-1}=C_0$ and $C_{2nz+1}=C_{2nz}$. With
all these definitions the fully discretised quasi-geostrophic PV equation can be written as:
 
\begin{eqnarray*}
S_{i,j,k} & = &
\quad \quad (\psi_{i-1,j,k}-2\psi_{i,j,k}+\psi_{i+1,j,k}) \cdot A_k \\[0.2cm]
& & + \quad (\psi_{i,j-1,k}-2\psi_{i,j,k}+\psi_{i,j+1,k}) \cdot B_k \\[0.2cm]
& & + \quad (\psi_{i,j,k-1} - \psi_{i,j,k}) \cdot C_{2k-1} \\[0.2cm]
& & + \quad (\psi_{i,j,k+1} - \psi_{i,j,k}) \cdot C_{2k+1}
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
with the indices ranges as follows: $i=0, ... nx$ and $k=0, ... nz$. In addition to this discretised
PV equation, additional equations must be specified for terms like $\psi_{-1,j,k}$. These discretised
von Neumann boundary conditions are:
 
\begin{eqnarray*}
A_k \cdot (\psi_{0,j,k} - \psi_{-1,j,k}) & = & {\Delta y} \cdot {\Delta z} \cdot \rho(2k) \cdot v_a(j,k)\\[0.2cm]
A_k \cdot (\psi_{nx+1,j,k} - \psi_{nx,j,k}) & = & {\Delta y} \cdot {\Delta z} \cdot \rho(2k) \cdot v_b(j,k)\\[0.2cm]
B_k \cdot (\psi_{i,0,k} - \psi_{i,-1,k}) & = & -{\Delta x} \cdot {\Delta z} \cdot \rho(2k) \cdot u_a(i,k)\\[0.2cm]
B_k \cdot (\psi_{i,ny+1,k} - \psi_{i,ny,k}) & = & -{\Delta x} \cdot {\Delta z} \cdot \rho(2k) \cdot u_b(i,k)
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
where $u_a,u_b$ denote the velocity components in x direction at the left (western) and right (eastern) lateral boundary, and
correspondingly $v_a,v_b$ denote the velocity components in y direction at the front (southern) and back (northern) lateral boundary. Additional boundary values are specified at the lower and upper lid of the domain:
 
\begin{eqnarray*}
C_{-1} \cdot (\psi_{i,j,0} - \psi_{i,j,-1}) & = & {\Delta x} \cdot {\Delta z} \cdot
\frac{f \cdot g \cdot \rho(0) \cdot \theta_{bot}(i,j)}{N^2(0) \cdot \theta_0(0)}\\[0.2cm]
C_{2 nz + 1} \cdot (\psi_{i,j,nz+1} - \psi_{i,j,nz}) & = & {\Delta x} \cdot {\Delta z} \cdot
\frac{f \cdot g \cdot \rho(2 nz) \cdot \theta_{top}(i,j)}{N^2(2 nz) \cdot \theta_0(2 nz)}
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
Here, $\theta_{bot}$ and $\theta_{top}$ denote the boundary conditions for potential temperature at the
lower and upper lid of the domain.\\
 
\noindent
This is a system of linear equations which can be expressed as\\[-2mm]
 
\[
B\psi = b
\]
 
\vspace{0.3cm}
\noindent
where $B$ is a $m \times m$ matrix with in total $m=(nx+1) \cdot (ny+1) \cdot (nz+1)$ elements (not to be
confused with the above coefficients $B_k$). This linear
system has a solution if the following condition is fulfilled:
 
\[
\sum_{i,j,k} b_{i,j,k} = 0
\]
 
\vspace{0.3cm}
\noindent
This is exactly the discrete version of the compatibility condition in section~5.1. The derivation of the
condition starts with the observation that the null space, i.e. the kernel of the system is at least
one-dimensional because the non-trivial vector $\psi_{i,j,k}=1 \forall i,j,k$ is element of this kernel. Physically, this expresses the fact that the streamfunction is determined only up to an additive constant. Since the kernel of the linear system is at least one-dimensional, the image of the operator $B$ is
at most (m-1) dimensional. Moreover, the operator $B$ is normal, and therefore the image is orthogonal to the
kernel. Because $b$ is in the image of the operator $B$ and $\psi_{i,j,k}=1$ is in the kernel, the two vectors
are orthogonal. This leads immediately to the necessary consistency condition $\sum_{i,j,k} b_{i,j,k} = 0$.
Note that this expresses a complicated relationship which must be fulfilled by the interior PV distribution and the boundary values of potential temperature and horizontal wind components, because $b$ includes all these
forcing terms.\\
 
\noindent
The consistency condition is not met if vanishing boundary values are specified. This automatically
leads to an inconsistency in the numerical solution of the equation. In practice, the fulfillment
of the consistency condition can be enforced if a potential temperature "correction" is added at the
lower and upper lid, this correction being uniform and of opposite sign on the two boundaries. For
reasonable PV and temperature distributions this additive temperature shift remains smaller than about 2\,K.\\
 
\noindent
There exist several techniques how to solve linear systems of equations. Here we adopt the successive
over-relaxation (SOR) method: Let $A$ be a linear operator which is represented by an $m \times m$ matrix, and
let $\omega$ be a real number (the relaxation parameter) such that $|1-\omega (1+A)|< 1$. Then a solution
of the equation can be obtained iteratively, starting with an arbitrary first guess $\psi_i^{(0)}$. The iterations
 
\[
\psi_i^{(n+1)} = \omega \cdot (b_i - \sum_{j=1}^{i-1} A_{i,j} \cdot \psi_j^{(n+1)}
- \sum_{j=i}^{m} A_{i,j} \cdot \psi_j^{(n)})
+ (1-\omega) \cdot \psi_i^{(n)}
\]
 
\vspace{0.3cm}
\noindent
converge toward the solution of the system $A\psi + \psi =b$. If we choose $A=B-1$, the iterations converge toward a solution of the quasi-geostrophic PV equation. \\
 
\noindent
Note that the above outlined algorithm allows to overwrite the variable $\psi_i^{(n)}$ with the updated
variable $\psi_i^{(n+1)}$, and therefore needs a minimum of computational memory. In the Fortran program
{\em inv\-cart.f} the number of iterations and the SOR parameter $\omega$ are specified. The are set to 500 iterations and 1.81, respectively.
 
% ----------------------------------------------------------------------------------------------
% Program philosophy
% ----------------------------------------------------------------------------------------------
 
\newpage
\section{Re-Structuring of the Code}
 
In this section some key concepts of the program package are described. In fact, an earlier version of the package already existed (developed originally by Rene Fehlmann and later modified by Sebastien Dirren) and the present work is based upon this pre-existing package. So, the question arises what added value this re-development and re-structuring of the code is associated with. The basic
idea is to provide a code which fulfills the following three requirements:
 
\begin{center}
\begin{minipage}[t]{10cm}
\begin{itemize}
\item[a)] {\bf Transparency and Modularity}\\[-3mm]
\item[b)] {\bf Universality and Model Independence}\\[-3mm]
\item[c)] {\bf User friendliness}
\end{itemize}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
In the following parts, a detailed discussion is intended to illustrate how this requirements were missing in the existing code
and how they could be incorporated into the new version. Before doing so, it is worthwhile to consider why the original code was lacking these requirements. A short review of the relevant literature
illustrates that the situation is actually quite common. Any software which is really used has to be adapted to the changing demands. It must be maintained. Unfortunately this maintenance often leads
to a degeneration of the code. The changes introduced into the code then make necessary some further
adaptions, and so on. Finally, in the end the code becomes so "distorted" and "chaotic" that often
a complete re-coding is easier to be done than a re-structuring of the existing version. The
remedy against this code degeneration is a continuous re-structuring. Hence, if changes in the code
are obligatory due to new user demands, it is important not only to introduce the needed changes
short-sightedly. The overall structure of the program should be kept in mind, and if possible
long-term perspectives in code maintenance should be allowed, although such a long-term perspective
momentarily leads to an additional effort. \\
 
\noindent
Computer science, in particular software engineering, has defined the term "re-structuring" (or
"re-factoring" for object-oriented programming languages) for the process how code should be
maintained in order to avoid severe degeneration. Fowler defines the term re-factoring in the
following way (taken from URL {\em www.refactoring.com}):\\
 
\begin{center}
\parbox{14cm}{"Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a series of small behavior preserving transformations. Each transformation (called a 'refactoring') does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it's less likely to go wrong. The system is also kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring."}
\end{center}
 
\vspace{0.6cm}
\noindent
Hence, the key aspect of re-structuring is to continuously maintain the code, not only in
its performance, but also in its readability, documentation and adaptabilty to needed
changes.\\
 
\vspace{0.3cm}
\noindent
Scientific programming in particular is very prone to code degeneration. This is certainly due
to the fact that cutting-edge science is, by "definition", investigating what is not known.
Therefore, if for instance a computer program is written to numerically simulate a physical
process, it might well turn out during the development of the code that complete new aspects
must be included. This naturally leads to chaotically structured code. In the present case, i.e.
for the PV inversion program, this certainly explains to a large part why the code became
so un-organised. Several works have been done with the program, several researchers included
into the code what they needed for their specific task, without considering that other users might have no use of their changes. The results was a program package which, in principle, was still
working, but the knowledge of how to apply it went lost.\\
\noindent
A first rough inspection immediately made
clear that major changes were necessary to make the code available to a broader community again.
Would it have been possible to only re-organise the code and write a new user guide? In a first
try, this was in fact considered. But then the advantages of a more or less complete
re-coding turned out to be more suitable. Hence, the original software package joined the
sad fate of so many degenerated codes: a complete re-coding. On the other hand, such a re-coding
must be seen as a great chance. It allows to improve the code in such a way, as it would never be
possible if only "slight" changes at the existing code were made.\\
\noindent
In the following three
subsections, some key aspects of this re-coding will be presented. They are by no means
exhausting, but should give an impression of the new "philosophy". Hopefully, they also motivate
future users of the program package to "successfully" maintain it.
 
\subsection{Transparency and Modularity}
 
What makes a computer program readable? Probably one of the most important points is "modularity".
The problem to be solved numerically can and should be split into several distinct steps. For instance,
for the PV inversion a classic three step splitting is appropriate: pre-processing, PV inversion, and post-processing. Moreover, each of these three primary steps can further be split into several secondary sub-steps.
In the existing code, the splitting of the problem into distinct sub-problems was not clearly discernible. Indeed, the main Fortran program included not only the numerical inversion of the quasi-geostrophic PV equation, but also some of the
preparatory steps and some of the post-processing steps. \\
 
\noindent
A major improvement was gained by a very strict separation of the distinct primary steps. So, pre-processing, inversion and post-processing are done by three completely separated program packages. This strict
separation is supported by the fact that three separated directories are used: There is one directory where pre-processing is done, on directory where inversion is done, and finally one directory where post-processing is done. A flow of data between the three directories is allowed only at well-defined
steps within the whole process. At the end of pre-processing the relevant files, and only those, are moved to the inversion (or run) directory. Similarly, at the end of the inversion, the relevant files
are moved from the run directory to the post-processing directory.\\
 
\noindent
Additional improvement resulted from a very clear separation of the sub-processes in the three main-processes (pre-processing, inversion, post-processing). In fact, it was not tried to incorporate
all preparatory steps into one large Fortran program, but instead each well-defined task (as for example transformation into a new co-ordinate system) constitutes a separate Fortran program. This
modularity is very similar to the "philosophy" of the Linux operating system: Keep flexibility and
clarity by offering not one program which handles everything (and thereby becomes a "monstrosity"), but offer many flexible and simple tools which the user only has to combine in order to perform complex tasks.\\
 
\noindent
What else except for modularity can be done to improve the readability of computer programs? It is obvious, and probably the most neglected aspect of good computer code generation: in-code documentation. Every
small sub-section of a computer program should be documented. It should be possible to gain
insight into an algorithm only by looking at the in-code documentation. It is definitely not
sufficient only to document for every subroutine what its aim is and what its interface is, although
quite often even this most basic principle is not fulfilled. Hence, in the re-coding of the
PV inversion focus was led to good documentation: Where are files opened, where variables initialised, what is a subroutine call meaning? \\
 
\noindent
Finally a remark concerning the used programming language. A complete re-coding of a software package might also be
a chance to switch to a "better" programming language. In the present case, the original code was written in
Fortran 77, and this language was also used for the re-coding. Fortran, and in particular its older version
Fortran 77, is by far not a modern language. Comparing its vocabulary and its structural elements to languages like C++ or Java, its power is very limited. Moreover, Fortran includes jump statements like {\em Goto} which could easily make
any code un-readable. So why do so many research codes still rely on Fortran? In fact, most numerical
weather prediction models are written in Fortran. There are two reasons why the PV inversion was written in Fortran: Firstly, the small vocabulary and the intuitive naming of the inherent Fortran commands
makes it quite easy to read a code. Many researches never had a profound introduction into programming. Nevertheless they should be able to implement algorithms for their daily work. This is easily done with Fortran, and certainly much easier done than using object-oriented concepts offered by C++ and other modern languages. The PV inversion should be available
to a research community which has excellent algorithmic thinking, but only a "weak" background in computer languages. Fortran is an optimal choice in this respect. The second reason why the re-coding was done in Fortran is its high performance. In fact, PV inversion is very resource demanding, and compilers must create fast-running codes in order
the PV inversion tool to be helpful.\\
 
\noindent
Regarding the "unholy" {\em Goto} statements, it can be immediately said that good programming style is not restricted to languages which do not offer a {\em Goto} statement. A well-structured and carefully developed Fortran program is
certainly preferable to a "bad" algorithm in a "good" computer language, "good" meaning that this language offers many
controlling structures. Probably, a key concept of well-written computer code is a good balance between the "power" of a (Fortran)
subroutine and its length (expressed in the number of code lines). Two extreme examples might illustrate this point: If no subroutines at all are used, i.e. if the program consists only in one single main program, the algorithm might get
"lost" in two many "technical" details. On the other hand, if every single and minor step is a separate subroutine, the
code lacks clarity due to the large number of subroutines. In the present re-coding of the PV inversion, focus was given
to a good balance of functionality (power) of a subroutine and its length.
 
 
\subsection{Universality and Model Independence}
 
Universality was another aspect which was important in re-coding the PV inversion. In the present
example universality might be better named "model independence". Model in this respect refers either to different numerical weather prediction (NWP) models or to idealised experiments. In the former case,
the variety of NWP models is very large. The PV inversion tool was originally written for the Europa
model (EM) of the German weather service (DWD). Later it was applied to the higher-resolution
model (HRM and CHRM) which was run by the DWD and the Swiss weather service (MeteoSwiss). In recent years, the
non-hydrostatic local model (LM) developed by the DWD replaced the HRM in regional
weather forecasting. So, an adaption of the existing PV inversion code would have been necessary.
Moreover, PV inversion is particularly attractive for global-scale data sets. So, the method and the
programs were adapted to conform with the global model of the European Centre for Medium Range Forecasts (ECMWF). To make things worse, idealised experiments should also be performed. What actually
makes the situation so difficult is that each model has its own horizontal grid structure and its own vertical grid structure. For instance, ECMWF uses a terrain-following co-ordinate system which in higher levels becomes a pressure-level co-ordinate system, quite in contrast what is used by the regional LM model (a variant of geometrical height). \\
 
\noindent
Model independence cannot completely avoided. It is a fact which has to be adopted and cleverly
dealt with. In the re-coding, model aspects were removed in the first two preparatory steps (out of
eight different steps, see section~4.4) and the way back to the model is done in the last post-processing steps.
Essentially the preparatory steps interpolate the needed meteorological fields onto a stack of height levels and
transforms the fields into a local quasi-cartesian co-ordinate system. After completing these steps, the other preparatory steps and the PV inversion itself is completely independent of the model from which the input data is retrieved. As a particular example consider the PV inversion of a structure over the North Pole. In the existing code such an inversion would not have been feasible due to the convergence of the
longitude circles at the North Pole. The new code, on the other hand, elegantly circumvents this
problem by introducing a new quasi-cartesian co-ordinate system centered over the North Pole. In this
respect the North Pole is not different from any other region on the globe.\\
\noindent
With respect to idealised experiments, the following strategy was adopted. This kind of experiments
is generally so different from what is needed for real-case studies that a complete separation
is preferable. So, in contrast to the existing code, this type of experiments is now handled by
a completely separated program package. Of course, many programs "overlap" or are even identical, but it nevertheless makes sense to treat the two kind of experiments (real-case versus idealised) separately.
 
 
 
 
 
\subsection{User Friendliness}
 
Computer programs are not written for a computer's joy, but because they should solve a problem
which cannot be solved analytically by any person. So, computer programs are tools which should
make "life" easier for their users, or at least they should make some problems tractable. If the
user-interface of a computer program is chaotic and badly structured, the computer does not complain.
The user, on the other hand, might give up using the tool simply because it needs too much effort to understand how the program must be handled. Scientific programs are especially in danger of
having bad user-interfaces because these kind of programs are always "in the flow". This in turn
means that often it is not worthwhile to develop a graphical user-interface, as it is an absolute
must for commercial software. \\
 
\noindent
In the existing code for the PV inversion the user-interface was highly "chaotic". It consisted of
several hundred lines of Linux Shell scripts which were difficult to read -partly due to lack of documentation, partly due to the unnecessarily complex structure. The behaviour of the inversion
was controlled by many variables set in the beginning of the Linux Shell script, set without
knowing exactly where and when these variables are used. This gave the user a "bad feeling" about
his experiments, simply because it was not always clear what changing parameters really meant.\\
 
\noindent
Although a graphical user-interface is not provided for the new version, an attractive command-based
interface is now available. This interface essentially consists of two parts. Firstly, a Linux Shell script
is provided which handles all calls to the computing Fortran programs. For instance, {\em inversion.sh prep} runs through all preparatory steps. User friendliness is reached by the fact the the user needs to make no changes to this Linux Shell script, although its limited size and documentation would make it quite simple.
Probably the best user-interface is provided by a parameter file. Such a file is provided in the new
version, and all parameters describing the inversion problem can be entered into this file. In fact,
this kind of user-interface was motivated by sophisticated numerical weather prediction (NWP) models. There too,
the specifications characterising a model run are passed to the NWP model by means of a parameter
file.\\
 
 
\noindent
What else made the existing user-interface chaotic? A close inspection revealed that the flow of data and information was absolutely non-transparent. Meteorological fields were moved from one file to
another, only to be renamed there and subsequently being moved again to another file. For a part-time user it would have been impossible to keep track of the flow of information. In the new code the flow of information is very strictly controlled (see also the above subsection~3.1). In fact, there are many different files involved in the PV inversion:
input files, several intermediate files and finally the output files. It is not the number of files which makes a
process difficult to understand. If the flow of information is well controlled, it remains tractable. For the case of
the PV inversion, this information flow can be kept clear, and this was indeed an important aspect of the re-coding.
 
 
% ----------------------------------------------------------------------------------------------
% PV Inversion for Real Cases
% ----------------------------------------------------------------------------------------------
 
\newpage
 
\section{Inversion of an Extra-tropical PV Streamer}
 
\subsection{Scientific question}
 
The PV inversion starts with the selection of a distinct PV anomaly which should be
removed or added to the original PV distribution. It is then the aim to analyse
and compare the meteorological fields of horizontal wind and potential temperature
associated with the modified PV distribution with the corresponding fields associated with
the original PV distribution.\\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_20060114_18_315K.eps}
\end{minipage}
\hspace{0.5cm}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_20060115_18_315K.eps}
\end{minipage}
\\
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_20060116_18_315K.eps}
\end{minipage}
\hspace{0.5cm}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_20060117_18_315K.eps}
\end{minipage}
\\
\begin{minipage}[t]{11cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_colorbar.eps}
\end{minipage}
\\
\caption{\it Time evolution of Ertel's potential vorticity (PV) on the 315\,K isentropic surface. The four
plots are for 14, 15, 16 and 17 January 2006, 18\,UTC. The PV inversion will be exemplified in this user guide for 16 January 2006, 18\,UTC.}
\label{question}
\end{center}
\end{figure}
 
\noindent
The time evolution of potential vorticity (PV) on the 315\,K isentropic surface shows a distinct feature over the Eastern United States (Fig.\,\ref{question}). This so-called stratospheric PV streamer is indicative for
a deep intrusion of stratospheric air towards the equator. In the course of the four days shown, the
PV streamer moves towards the east, and in the later stages exhibits an cyclonic rolling-up. An eminent
question is how this stratospheric PV streamer influences the atmospheric flow in its neighbourhood. From theoretical
considerations, it can be expected that the impact on the horizontal velocity and on the static stability
is quite large (see introduction, Fig.\,2). By means of the so-called quasi-geostrophic omega equation (Holton, 1992), it is also expected that pronounced
vertical motions are directly associated with the passage of the PV streamer. It is the aim of this study -and of PV inversion in general- to surmount the qualitative argumentation, and to
quantitatively assess the impact of such a structure on the atmospheric flow. \\
 
\noindent
In the following chapters, all steps are discussed which are needed to quantify this impact. Here, we
exemplarily consider the date of 16 January 2006, 18\,UTC, and determine explicitly for this date
the atmospheric response the upper-level (near tropopause level) PV structure.
 
 
 
\subsection{Necessary input files}
 
\begin{figure}[t]
\vspace{-2cm}
\begin{center}
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{q_20060116_18_500hPa.eps}
\end{minipage}
\hspace{-0.6cm}
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{t_20060116_18_500hPa.eps}
\end{minipage}
\\[-3cm]
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{uv_20060116_18_500hPa.eps}
\end{minipage}
\hspace{-0.6cm}
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{ps_20060116_18_500hPa.eps}
\end{minipage}
\\[-2cm]
\caption{\it Specific humidity (g/kg), temperature (in $^\circ$C), wind vectors
at 500\,hPa and surface pressure for 16 January 2006, 18\,UTC. These field are needed
as input for the PV inversion, and are available on the so-called P file.}
\label{inpp}
\end{center}
\end{figure}
Several preparatory steps are necessary before the PV inversion itself can be
performed. Here each of these steps is described in detail and -where possible-
illustrated with suitable figures. Starting point of the analysis is the P and
Z file of the ECMWF (re-)analysis:
 
\begin{itemize}
\item {\bf P20060116\_18} with temperature T (in $^\circ$C), horizontal wind components U,V (in m/s) in
zonal and meridional direction, respectively,
specific humidity Q (in kg/kg) and surface pressure PS (in hPa).
\item {\bf Z20060116\_18} with geopotential height Z (in m) on a stack of pressure
levels (for instance on 850, 500 and 250\,hPa).
\end{itemize}
 
\begin{figure}[t]
\vspace{-2cm}
\begin{center}
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{z_20060116_18_250hPa.eps}
\end{minipage}
\hspace{-0.6cm}
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{z_20060116_18_500hPa.eps}
\end{minipage}
\\[-3.5cm]
\begin{minipage}[t]{8.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{z_20060116_18_850hPa.eps}
\end{minipage}
\\[-1.5cm]
\caption{\it Geopotential height (in m) on 250, 500 and 850\,hPa for 16 January 2006, 18\,UTC. These field are needed
as input for the PV inversion, and are available on the Z file.}
\label{inpz}
\end{center}
\end{figure}
 
\noindent
Figure\,\ref{inpp} shows temperature T, specific humidity Q and wind vectors (U,V) at 500\,hPa and the surface pressure for 16 January 2006, 18\,UTC. A narrow band of high specific humidity is discernible on the downstream
side (to the east) of the PV streamer (upper-left panel). Most probably, this extended band is directly associated with
the southerly winds which prevail to the east of the PV streamer, and which are able to transport moist
air from the warm subtropics to the north. In the temperature field (upper-right panel), the PV streamer's impact is also discernible. It is associated -at this level- by a local warm anomaly. On theoretical grounds, we would expect a local cold anomaly below the streamer and a local warm anomaly within and above the streamer (see introduction, Fig.\,2). The present signal indicates that the streamer reaches far down into the troposphere, and enforces a local warm anomaly at the low level of 500\,hPa. As already mentioned before, and explicitly shown by the wind vectors (lower-left panel), the PV streamer is also associated with a cyclonic flow. Besides the impact on the temperature field, this PV induced flow field is the most eminent impact of a PV streamer. Indeed, it is the wind field where the far-field effect of a PV streamer becomes most evident, because the streamer's impact on temperature and stratification is essentially confined to the
regions just below or above.
Finally, the P file contains the surface pressure PS (lower-right panel), which of course to the largest extent simply reflects the surface topography. So for instance,
the high topography of the Rocky Mountains or of the Greenland ice shield, is associated with low
surface pressure, 700\,hPa corresponding to about 3\,km height above sea level.\\
 
\noindent
In addition to the P file, a so-called Z file must be provided as input for the PV inversion. This file contains the geopotential height on a distinct set of pressure levels. Typically, these levels are
850, 500 and 250\,hPa. A plot of these levels is shown in Fig.\,\ref{inpz}. The need for this reference levels
will become evident in a subsequent section. In short: They are needed to integrate the hydrostatic equation and thereby to transform from pressure to geometrical height as vertical co-ordinate.
Note how the PV streamer over the west Atlantic is discernible in the geopotential as a deep trough.
 
 
 
\subsection{An overview of the inversion}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{6cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{threesteps.eps}
\end{minipage}
\\
\caption{\it Data flow diagram for the three steps of the PV inversion. The preparatory steps are
essentially performed in the input directory, the inversion in the run directory and the output is
finally written to the output directory.}
\label{threesteps}
\end{center}
\end{figure}
 
The PV inversion can be split into three well-separated steps. The first step is associated with
preparations, in particular with the definition of the modified Ertel-PV field. In addition, some
preparatory steps have to be performed in order to adapt the ECMWF grid to the cartesian grid which is
assumed in the inversion algorithm. In the second step the atmospheric state is iteratively adjusted to
the modified PV field, as it was specified in the previous preparatory step. This second part comprises the "core" of the algorithm, i.e. the numerical inversion of the quasi-geostrophic potential
vorticity equation by means of a successive over-relaxation (SOR) technique. Finally, in the third step
the modified atmospheric state is brought back from the cartesian grid of the inversion to the
original latitude/longitude grid of the ECMWF, including its hybrid vertical co-ordinate. After this
step a direct comparison between input and output fields is feasible due to the equivalent
grid structure of input and output fields. The basic three steps are shown in Fig.\,\ref{threesteps}, and will subsequently be described in greater detail in the following sections. Before doing so, a note has to be made on the user-interface for the PV inversion.\\
 
 
\noindent
The inversion is controlled by one master Linux Shell script (inversion.sh), which calls the performing Fortran programs
(for a complete listing of the Linux Shell script consider Appendix~9.2).
A major aim of this work was to make the
application of the inversion as easy as possible. Therefore, the typical user is not forced to study
the master script itself, but can provide all needed parameters by means of a so-called "parameter file"
(inversion.param).
The contents of this file is parsed by a Perl script, which extracts all needed information. In the
description of the subsequent steps, the relevant parts of this parameter file will be reproduced and
described. A complete listing of the parameter file can be found in Appendix~9.3.\\
 
 
\noindent
Nevertheless, it will be necessary for an advanced usage of the inversion package to go into
some greater details. For instance, if particular PV structures should be removed or added, the
implemented simple filtering approach (to be discussed in section~4.4.4) might not be sufficient.
In this case, the advanced user is encouraged to modify the Fortran code in order to fulfill his particular
tasks.\\
 
 
\noindent
In a first step some directories must be specified. This is done in the parameter file {\em inversion.param} in the section DATA. For the example of this study this section looks like:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\ForceWidth{1.0\textwidth}
\begin{verbatim}
BEGIN DATA
DATE = 20060116_18;
INP_DIR = /lhome/sprenger/PV_Inversion_Tool/real/inp;
RUN_DIR = /lhome/sprenger/PV_Inversion_Tool/real/run;
OUT_DIR = /lhome/sprenger/PV_Inversion_Tool/real/out;
END DATA
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The first argument (DATE) gives the date of the case. Then the following three entries specify the input (INP\_DIR), the run (RUN\_DIR) and the output (OUT\_DIR) directory, respectively. These directories can be created by the call
\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\ForceWidth{1.0\textwidth}
\begin{verbatim}
inversion.sh inst
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
For test reasons a set of sample files is provided. These sample P20060115\_18 and Z20060115\_18 files can be copied to the input directory with the call
\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\ForceWidth{1.0\textwidth}
\begin{verbatim}
inversion.sh sample
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The fields available on the two files are:
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
Q & Specific humidity ($kg/kg$) & P20060116\_18 \\
U & Zonal velocity ($m/s$) & P20060116\_18 \\
V & Meridional velocity ($m/s$) & P20060116\_18 \\
T & Temperature ($^\circ C$) & P20060116\_18 \\
OMEGA & Vertical velocity ($Pa/s$) & P20060116\_18 \\
PS & Surface pressure ($hPa$) & P20060116\_18 \\
\hline
Z & Geopotential height ($m$) on 850, 500 and 250\,hPa & Z20060115\_18 \\
\hline
\end{tabular}
\end{center}
 
 
\vspace{0.5cm}
\noindent
With these preparatory steps, the inversion can be performed. The following sections discuss the three basic step, i.e. the preparation of the input files for the inversion, the inversion itself and the post processing of the output files.
 
 
 
\subsection{Pre-processing: Defining the inversion problem [prep]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{12cm}
\vspace{2.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{preparation.eps}
\end{minipage}
\\
\caption{\it Flowchart of preparatory steps. Additionally, to the left of the single steps the
essential flow of information is shown. For instance, H $\rightarrow$ R means that the input is taken from
the file with prefix H and the output is then written to the file with prefix R.}
\label{preparation}
\end{center}
\end{figure}
 
Firstly, the vertical co-ordinate
has to be changed from pressure to geometrical height (section~4.4.1) and the fields have to be
transformed from the geographical latitude/longitude grid to a cartesian grid (section~4.4.2). Then additional meteorological
fields have to be computed on this new cartesian grid (section~4.4.3). With these two preparations the
Ertel-PV anomaly can be defined (section~4.4.4), and the input files for the quasi-geostrophic PV inversion be written
(section~4.4.5). Some additional steps are then: definition of a reference profile (in section~4.4.6) and
the transformation of the coastlines into the cartesian grid (section~4.4.6).\\
 
\noindent
These single steps have to be done once for every inversion problem. A complete flowchart of
the preparatory steps is shown in Fig.\,\ref{preparation}. In the following description every single step will
be launched and discussed individually. If desired, the call
\\[0.0cm]
\begin{center}
\begin{minipage}[t]{13cm}
\ForceWidth{1.0\textwidth}
\begin{verbatim}
inversion.sh prep
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.6cm}
\noindent
will run through all steps without waiting for intermediate check. This is particularly practical if all
settings remain essentially unchanged, and therefore a detailed check after each step is not necessary.
 
 
\subsubsection{Transformation to height levels [prep1]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{10cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{sigma_level.eps}
\end{minipage}
\\
\caption{\it Illustration of the terrain-following hybrid co-ordinate system of the ECMWF grid.
Here it is shown with 15 levels, recent versions of the ECMWF model contain 60 hybrid levels for the ERA-40 re-analysis and 91 levels for the operational analysis and deterministic 10\,day forecast [illustration taken
from "An Introduction to dynamic meteorology" by Holton, 1992].}
\label{sigma}
\end{center}
\end{figure}
 
The input data are available on a latitude/longitude grid
in the horizontal and on a so-called hybrid $\sigma$-grid on the vertical. Whereas the former is
well known, the latter needs some explanation. The basic idea is illustrated in Fig.\,\ref{sigma}. The
model levels are terrain-following, and the pressure p(i,j,k) at a specific grid point (with grid indices i,j,k) is given by the expression:
\[
p(i,j,k) = ak(k) + bk(k)*ps(i,j)
\]
 
\vspace{0.3cm}
\noindent
where $ps(i,j)$ is the pressure at the surface at the specified grid position. The two one-dimensional
arrays $ak$ and $bk$ are part of the P file, more specifically of the constants file associated with the P file. The main advantage of this hybrid grid is its non-intersection with the ground, which
facilitates many numerical calculations.\\
 
\noindent
The ECMWF fields are easily plotted on pressure surfaces since the vertical co-ordinate of the
underlying data set is essentially based upon pressure. On the other hand, the inversion program
assumes a cartesian grid with geometrical height (in m) as vertical co-ordinate. Therefore, all needed fields from the
original P file must be interpolated onto a stack of height levels. This transformation is easily
done by means of the hydrostatic equation:
\[
\frac{\partial p}{\partial z} = - \rho \cdot g
\]
 
\vspace{0.3cm}
\noindent
where $\rho$ denotes the density of moist air and $g$ is the Earth's gravity. Note that this
equation can be re-formulated to one including temperature if the ideal gas equation
\[
p = \rho \cdot R_d \cdot T_v
\]
is used and $\rho$ replaced. Here $R_d$ is the ideal gas constant of dry air and $T_v$ is the virtual temperature,
i.e. the temperature corrected for the water vapour contents of the air. The definition of
virtual temperature takes into account the specific humidity of an air parcel and its (sensible)
temperature (see for instance Wallace and Hobbs, 1977):\\
\[
T_v = T \cdot \{ 1 - \frac{q}{\epsilon} \cdot (1 - \epsilon) \}^{-1} \approx
T \cdot ( 1 + \epsilon \cdot q )
\]
 
\vspace{0.3cm}
\noindent
where $T$ is the temperature (in K), $q$ the specific humidity (in kg/kg), $\epsilon=R_d/R_v$ is the ratio of the gas constant for dry ($R_d$) air and water vapour ($R_v$). \\
 
\noindent
With the previous definitions, the hydrostatic equation can be integrated vertically to get
the height as a function of the pressure p:
 
\[
z(p) = z_{ref} - \frac{R_d}{g} \cdot \int_{\log(p_{ref})}^{\log(p)} T_v \cdot d\log(p)
\]
 
\vspace{0.3cm}
\noindent
where $z_{ref}$ and $p_{ref}$ denote the reference level. If several reference levels are given
(for example at 850, 500 and 250\,hPa, see Fig.\,7) the integration can be performed from the nearest
reference level to the specified pressure level. Note that at least one reference level
must be given, i.e. at one pressure level the geometrical height must be known.
Typically, this correspondence is known for the 500\,hPa level (see Fig.\,\ref{hydro}). As a result
of the integration, the geometrical height is given as a function of the pressure at all points
of the model grid.\\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pro_t_70w40n_20060115_18.eps}
\end{minipage}
\hspace{0.5cm}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pro_q_70w40n_20060115_18.eps}
\end{minipage}
\\
\caption{\it Left: Vertical profile of temperature (in $^\circ$C) in dependence of pressure at 70$^\circ$W
and 40$^\circ$ for 15 January 2006, 18\,UTC. Additionally the reference pressure levels are included with
the corresponding geopotential height (in m). Right: Vertical profile of specific humidity (in g/kg).}
\label{hydro}
\end{center}
\end{figure}
 
\noindent
In addition to the geometrical height at each grid point, the hydrostatic equation can be integrated
downward to obtain a consistent estimate of topography height. In fact, if the surface pressure
$p_s$ is given, the height of the topography is readily determined by\\
 
\[
z(p_s) = z_{ref} - \frac{R_d}{g} \cdot \int_{\log(p_{ref})}^{\log(p_s)} T_v \cdot d\log(p)
\]
 
\vspace{0.3cm}
\noindent
The advantage of the thus determined topography (instead of using the ECMWF topography) is its
consistency.\\
 
\noindent
Having determined the geometrical height $z(i,j,k)$ at each grid point $i,j,k$ in addition to the already known
pressure $p(i,j,k)$, it is straightforward to interpolate a field (temperature, velocity,...) onto an arbitrary height level.
The method adopted here is to lie a natural cubic spline through the grid points along a vertical
profile and then to evaluate the spline at the pre-specified height levels. In detail: The cubic spline at a horizontal grid position $i,j$ is based upon the values $[x_k=z(i,j,k),y_k=T(i,j,k)]$ if temperature $T$ is to be interpolated onto
a stack of height levels. Having determined the associated cubic spline $T_{sp}$, temperature at an arbitrary height $z$
can be calculated by evaluating the cubic spline at this level: $T_{sp}(z)$. The algorithm for the cubic spline is taken from Press et al. (1992).
\\
 
 
\noindent
The interpolation onto height levels is done with the call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep1
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
which numerically
integrates the hydrostatic equation and therefore attributes to each grid point not only its
pressure (in hPa) but also its geometrical height (in m). The relevant numerical parameters are taken from the
parameter file {\em inversion.param}, where the following section is essential:\\
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
BEGIN GRID
GEO_ZMIN = 0.;
GEO_NZ = 125 ;
GEO_DZ = 200.;
END GRID
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The three parameters describe the new vertical co-ordinate. The lowest levels is assumed to be at ground
(GEO\_ZMIN), the number of vertical levels is 125 (GEO\_NZ) and the vertical resolution is equidistantly
200\,m (GEO\_DZ). Hence, the new vertical grid spans the range from ground up to 25\,km.\\
 
\noindent
The output file H20060115\_18 is a new netcdf file which has now geometrical height as vertical co-ordinate
and the variables ({U,V,T,Q}) interpolated onto the height levels from surface up to 25\,km. Note that the height of the topography ({ORO}) is also
determined. If a model level is below the topography, all field values are set to missing data. The following table gives all the variables which are available on the new H file:\\
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
Q & Specific humidity ($kg/kg$) & H20060116\_18 \\
U & Zonal velocity ($m/s$) & H20060116\_18 \\
V & Meridional velocity ($m/s$) & H20060116\_18 \\
T & Temperature ($^\circ C$) & H20060116\_18 \\
P & Pressure ($hPa$) & H20060116\_18 \\
ORO & Height of topography ($m$) & H20060116\_18 \\
\hline
\end{tabular}
\end{center}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{14cm}
\vspace{-1cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{latlon_nh.eps}
\end{minipage}
\\[-0.5cm]
\caption{\it Latitude/longitude grid of the ECMWF P and Z files. For clarity, the grid spacing was reduced to 5 degrees, instead of the 1 degree in the files. Meteorological fields -as for instance
temperature, wind vectors, pressure and geopotential- are given at the intersection of the latitude and
longitude circles. Note how this grid becomes singular toward the north pole.}
\label{latlon}
\end{center}
\end{figure}
 
 
\subsubsection{Rotating to a quasi-cartesian co-ordinate system [prep2]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{13cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{local_cart_grid.eps}
\end{minipage}
\\
\caption{\it Local cartesian grid which is centered at the PV streamer's position and which
shows much less distortion due to the sphericity of the Earth. The center of the new grid
corresponds to the rotated latitude and longitude (0,0). The boundaries are at $-31^\circ$ and
$+31^\circ$ rotated longitude, and at $-31^\circ$ and $+31^\circ$ rotated latitude.}
\label{localcart}
\end{center}
\end{figure}
 
The input fields are given on a latitude/longitude grid, with -after the previous step- the fields
on an equi-distant grid of height levels. The inversion itself assumes a cartesian grid, hence a
uniform grid spacing is also assumed in the horizontal directions. This is clearly not the case for the
latitude/longitude grid, as illustrated in Fig.\,\ref{latlon}.
Due to the sphericity of the Earth, the zonal
grid spacing decreases with increasing geographical latitude. As a remedy to this singularity, all
input fields are transformed to a "quasi-cartesian" grid with its center on the PV structure of
interest. The transformation between the two grids is illustrated in Fig.\,\ref{localcart}. It becomes evident
that the grid distortion is significantly reduced by this step. The formula which relates the two
grids is based upon the co-ordinate transformation given in the Appendix~A (Fortran subroutines {\em lmstolm} and
{\em phstoph}). The geographical latitude/longitude corresponding to a grid point in the rotated (quasi-cartesian) co-ordinate system is obtained in the following way. Firstly, the rotated latitude/longitude $\phi_{rot},\lambda_{rot}$ is transformed into
 
\begin{eqnarray*}
\lambda'_{rot} & = & 90+lmstolm(\phi_{rot},\lambda_{rot}-90,90+\alpha,-180) \\[0.2cm]
\phi'_{rot} & = & phstoph(\phi_{rot},\lambda_{rot}-90,90+\alpha,-180)
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
where $\alpha$ is the rotation angle given in the parameter file (CROT, see below). These two
values are then, in a second rotation, transformed into geographical latitude and longitude:
 
\begin{eqnarray*}
\lambda_{geo} & = & lmstolm(\phi'_{rot},\lambda'_{rot},90-\phi_{cen},\lambda_{cen}-180) \\[0.2cm]
\phi_{geo} & = & phstoph(\phi'_{rot},\lambda'_{rot},90-\phi_{cen},\lambda_{cen}-180))
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
where the centre of the PV anomaly (the centre of the quasi-cartesian co-ordinate system in geogrpahical
latitude/longitude co-ordinates) is given by $\phi_{cen}$ and $\lambda_{cen}$ (CLAT and CLON in the
parameter file, see below).\\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{latlon_grid.eps}
\end{minipage}
\hspace{-0.5cm}
\begin{minipage}[t]{8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{xy_grid.eps}
\end{minipage}
\\
\caption{\it Quasi-cartesian grid which is centered at the PV streamer's position and which
shows much less distortion due to the sphericity of the Earth. On the left panel the latitude and
longitude on the Earth surface is shown, on the right panel the x and y co-ordinates in the new
co-ordinate system. Note how the distortion is considerably reduced with the new x,y co-ordinates (right), as compared with the original latitude/longitude co-ordinates (left). Additionally, the topography (in m above sea level) is shown
in color: Clearly discernible is Greenland and the east coast of North America.}
\label{xylatlon}
\end{center}
\end{figure}
\noindent
The transformation looks quite complicated, but has an easy geometrical interpretation. In fact, we create a new
latitude/longitude grid, but now longitude and latitude are defined not relative to the Earth's north
pole, but relative to a rotated imaginary "north pole". Therefore, we call the new latitudes/longitudes rotated co-ordinates. The link between the geographical latitude/longitude and
the rotated ones is shown in Fig.\,\ref{xylatlon} for the case study. Here, the left panel gives the latitude and longitude at the grid positions of the quasi-cartesian grid. The right panel gives the quasi-cartesian co-ordinates x and y, which correspond to the grand-circle distance on the Earth surface.
While the transformation of a scalar quantity (like for instance temperature, pressure, wind speed) is straightforward with the above formulas, the transformation of a vector field is much more
complicated. This is easily illustrated with the following example: Consider a perfectly zonal flow
in the geographical grid, i.e. there is only a wind component along the geographical latitude circles, but none along the geographical longitude circles (hence, in the left panel of Fig.\,14 the velocity vector is parallel to the latitude
circles). In the rotated grid -the quasi-cartesian grid- this
pure zonal velocity is transformed into a wind vector which has components both along the rotated
longitude and latitude circles (i.e. in Fig.\,14 the vector has a component along the horizontal and the
vertical axis).
In principle, a complicated formula could be derived which gives an explicit expression how the
individual velocity components transform. Here, we adopt a more pragmatic approach: We numerically
determine the local rotation angle between the two orthogonal co-ordinate systems, and subsequently
use these angles to get the transformed velocity components. \\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{10cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{coriol_grid.eps}
\end{minipage}
\\
\caption{\it Coriolis parameter (in $10^{-4}s^{-1}$) in the quasi-cartesian co-ordinate frame.
The Coriolis parameter is a local measure for the Earth's rotation. It is constant along
latitude circles. Note that $f$ becomes maximal at the pole and vanishes at the equator. No
PV inversion can be performed if the cartesian grid crosses the equator and hence crosses the
zero isoline of the Coriolis parameter.}
\label{coriol}
\end{center}
\end{figure}
 
\noindent
Of course, the Coriolis parameter must be kept in the transformation to the quasi-cartesian
co-ordinate frame. Tis parameter is given by:
 
\[
f = 2 \cdot \Omega \cdot sin(\phi)
\]
 
\vspace{0.3cm}
\noindent
where $\Omega$ is the angular velocity of the Earth rotation and $\phi$ is the geographical latitude.
From the definition it is clear that the Coriolis parameter is constant along latitude circles. Furthermore,
it takes its maximum value at the pole and vanishes at the equator. A typical value for the mid-latitudes
is $f=10^{-4}s^{-1}$. For the case study the Coriolis parameter is shown in Fig.\,\ref{coriol}.\\
 
 
 
\noindent
Numerically, the rotation of the fields to the quasi-cartesian co-ordinate frame is done with the
call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep2
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The program needs some information from the parameter file. The relevant section is:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
BEGIN GRID
ROT_NX = 250 ;
ROT_NY = 250 ;
ROT_DX = 0.25;
ROT_DY = 0.25;
CLON = -65.;
CLAT = 45.;
CROT = 0.;
END GRID
\end{verbatim}
\end{minipage}
\end{center}
\vspace{0.3cm}
\noindent
The first two parameters (ROT\_NX and ROT\_NY) give the number of grid points in the horizontal directions for
the rotated co-ordinate system. Here it is assumed that the grid has 250 grid points in x and in y direction. Note
that the number of grid points in the z direction needs not to be specified because this information is
already available on the file H20060115\_18. The new horizontal resolution of the rotated grid is given by the
next two values. They give the resolution in x (ROT\_DX) and in y (ROT\_DY) direction. In the present case these
resolutions are 0.25 degrees, which corresponds to approximately 28\,km, according to the formula\\
 
\[
0.25 \cdot \frac{2\pi}{360} \cdot R_E \quad \quad \mbox{with the Earth's radius} \quad R_E=6370\,km
\]
 
\vspace{0.3cm}
\noindent
Note that the resolution of the rotated grid is higher than the resolution of the input grid, where a value of
1\,degree is given. Finally, the last three parameters specify where the new co-ordinate system is centered on the
globe. Here, this position is at 65\,W (CLON) and 45\,N (CLAT), i.e. approximately in the centre of the PV streamer
shown in Fig.\,\ref{question}. The last parameter (CROT) allows the new grid to be rotated. At the end of this step, the following fields are available on the R20060115\_18 file:\\[0.2cm]
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
Q & Specific humidity ($kg/kg$) & R20060116\_18 \\
U & (Rotated) Zonal velocity ($m/s$) & R20060116\_18 \\
V & (Rotated) Meridional velocity ($m/s$) & R20060116\_18 \\
T & Temperature ($^\circ C$) & R20060116\_18 \\
P & Pressure ($hPa$) & R20060116\_18 \\
ORO & Height of topography ($m$) & R20060116\_18 \\
LAT & Geographical latitude & R20060116\_18 \\
LON & Geographical longitude & R20060116\_18 \\
CORIOL & Coriolis parameter ($1/s$) & R20060116\_18 \\
X & Cartesian distance from centre along x axis ($km$) & R20060116\_18 \\
Y & Cartesian distance from centre along x axis ($km$) & R20060116\_18 \\
\hline
\end{tabular}
\end{center}
 
 
 
\subsubsection{Calculating secondary fields [prep3]}
 
 
Several additional fields are needed for the PV inversion, the most prominent of course being Ertel's PV itself.
This field can easily derived from the horizontal wind components, the potential temperature and
the density. Firstly, the potential temperature $\theta$ is calculated from pressure $p$ (in hPa) and
temperature $T$ (in K) according to its definition:
 
\[
\theta = T \cdot (\frac{p_0}{p})^\kappa
\]
where the reference pressure is fixed as 1000\,hPa and $\kappa=R/C_p$ is the ratio of the gas constant
for dry air ($R$) and the specific heat at constant pressure ($c_p$). Numerically, this value
is in good approximation: $\kappa=0.286$.
Note that an inherent property of the atmosphere is its stability. This is expressed physically by
a potential temperature which increases with height. Regions where potential temperature decreases
with height are hydrostatically unstable and the pre-requisites for a PV inversion are not fulfilled
there. \\
 
 
\noindent
The density $\rho$ (in kg/m$^3$) of the air is determined by the ideal gas equation for air.\\[-0.3cm]
 
\[
\rho = \frac{p}{R_D \cdot T}
\]
 
\vspace{0.3cm}
\noindent
where $R_d$ is the gas constant for dry air and p and T are the pressure (in Pa) and temperature
(in K), respectively.\\
 
\noindent
With this definition of potential temperature and density, Ertel's PV is readily calculated according to:
 
\[
PV = -\frac{1}{\rho} \cdot ( \vec{\xi} + f \cdot \hat{k} ) \cdot \vec{\nabla}{\theta}
\]
 
\vspace{0.3cm}
\noindent
Here, $\hat{k}$ is a unit vector pointing in the vertical direction, $f$ is the planetary vorticity
(typically $10^{-4} s^{-1}$ in the extra-tropics),
i.e. the vorticity due to the Earth's rotation, and $\vec{\xi}$ is the curl $\vec{\nabla} \times \vec{u}$
of the wind vector $\vec{u}$. In large-scale dynamics vertical wind components can be neglected in the
above formula. The final expression for Ertel's PV then reduces to:
 
\[
PV = -\frac{1}{\rho} \cdot [ ( \frac{\partial v}{\partial x} - \frac{\partial u}{\partial y} + f )
\cdot \frac{\partial \theta}{\partial z}
+ \frac{\partial u}{\partial z} \cdot \frac{\partial \theta}{\partial y}
- \frac{\partial v}{\partial z} \cdot \frac{\partial \theta}{\partial x}]
\]
 
\vspace{0.3cm}
\noindent
In many cases the latter two terms (involving vertical derivatives of horizontal velocity) can
also be neglected. Here, we keep these terms in order to have a higher-order approximation to Ertel's
PV. Note that the first term on the right side includes the aforementioned vertical
derivative of potential temperature. The stability criterion forces this derivative to be positive.
The theory of atmospheric turbulence leads to a still stronger constraint. Indeed, the whole PV
must be positive (on the northern hemisphere), since otherwise symmetric instability will set in and
turbulently adjust the atmosphere to a state where PV is non-negative.\\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{zus_pv_k40.eps}
\end{minipage}
\hspace{0cm}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{zus_th_k40.eps}
\end{minipage}
\\[0cm]
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{zus_nsq_k40.eps}
\end{minipage}
\hspace{0cm}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{zus_rho_k40.eps}
\end{minipage}
\\[0cm]
\caption{\it Secondary fields:
Ertel's potential vorticity (upper-left, in $pvu$), potential temperature (upper-right, in K),
squared Brunt-V\"ais\"al\"a frequency (lower-left, in $10^{-4} s^{-2}$) and density (lower-right,
in $kg m^{-3}$). The stratification is a measure of the vertical stratification of the atmosphere.
High values correspond
to strong stratification and suppression of vertical motions. Note how the stratospheric PV streamer is
associated with enhanced stratification. The density, on the other hand, is slightly decreased within the
streamer's region. All
fields are plotted on model level 40, corresponding to a geometrical height of approximately 8\,km.
}
\label{secfield}
\end{center}
\end{figure}
 
\noindent
The last field which is needed for the PV inversion is strongly related to the vertical derivative
of potential temperature. It is the so-called squared Brunt-V\"as\"ala frequency (or stratification),
defined by
 
\[
N^2 = \frac{g}{\theta} \cdot \frac{\partial \theta}{\partial z}
\]
 
\vspace{0.3cm}
\noindent
where $g$ is the Earth's gravity. Following the above discussion, a necessary condition for
atmospheric stability is that $N^2$ is non-negative. Note that strong stratifications counteract
vertical motions. Particularly strong stratifications are typically found in the stratosphere,
($N^2 \approx 10^{-4} s^{-2}$) whereas the troposphere is considerably weaker stratified
($N^2 \approx 10^{-4} s^{-2}$).\\
 
\noindent
All these secondary fields are calculated with the call to \\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep3
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
After this step, four additional variables are available on the file R20060116\_18. They are listed in the following table and are shown in Fig.\,\ref{secfield}:\\
 
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
TH & Potential temperature ($K$) & R20060116\_18 \\
PV & Ertel's potential vorticity ($pvu$) & R20060116\_18 \\
NSQ & Squared Brunt-Vai\"al\"a frequency ($1/s^2$) & R20060116\_18 \\
RHO & Air density ($kg/m^3$) & R20060116\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.5cm}
 
\subsubsection{Identification of a PV anomaly [prep4]}
 
 
Having calculated Ertel's PV on height levels, it is now time to specify the modified PV distribution
which should be obtained by the PV inversion. In short, a PV anomaly has to be identified from the original
PV field and then the effect of this anomaly on the potential temperature and velocity has to be determined.\\
 
\noindent
There is no unique and fool-proof method how to specify an anomaly. Indeed, this step strongly depends on
the features which should be studied. In the present example, we look at a so-called stratospheric PV streamer and the aim
is to remove this streamer from the PV field and thereby to quantify its influence on the stability and wind
fields in the middle and lower troposphere. Figure\,ref{box} shows the PV in a horizontal cross-section at 8\,km
height. The PV streamer is clearly discernible as a
southward intrusion of high-PV, i.e. stratospheric air toward the south. In the vertical the streamer reaches
down to levels of 6\,km (not shown).\\
 
\noindent
The extraction of the streamer is performed by filtering the original PV field. This filtering is done
by the call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep4
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
Essentially, the program performs
the following two steps: Choose a grid point within the filtering box (see Fig\,ref{box}), and
replace the PV value at this grid point by the zonal mean of all PV values. Formally this might be
written as:
 
\[
PV \quad \rightarrow \quad <PV>
\]
 
\vspace{0.3cm}
\noindent
where $<>$ denotes the filtering operator which applies only within the filtering box.
The anomaly could now be determined as the difference of the original and filtered PV:
It turns out that this simple difference $AN=PV-<PV>$ would produce not only the desired positive anomaly associated
with the streamer, but also surrounding negative PV anomalies. We neglect all these negative anomalies
by simply setting them to zero. \\[-0.2cm]
 
\[
AN = PV - <PV> \quad \mbox{and} \quad AN \rightarrow AN^+.
\]
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{13cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{box.eps}
\end{minipage}
\\
\caption{\it Ertel's PV on level $k=40$ (corresponding to a height of 8\,km). Additionally the horizontal
grid is shown, and the filtering box is marked with the bold black lines.}
\label{box}
\end{center}
\end{figure}
 
\vspace{0.3cm}
\noindent
The outcome $AN^+$ is a "well-behaved" PV anomaly, which in turn is used to finally define the modified $PV^M$, i.e.
the PV field which should be obtained by the inversion:\\
 
\[
PV^M = PV - AN^+
\]
 
\vspace{0.3cm}
\noindent
The original $PV$, modified $PV^M$ and the anomaly $AN^+$ is shown in Fig.\,\ref{ano} at several model levels. Note how the PV streamer of Fig.\,\ref{question} is well captured by the PV anomaly
 
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_org_k20.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_mod_k20.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_ano_k20.eps}
\end{minipage}
\\
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_org_k30.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_mod_k30.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_ano_k30.eps}
\end{minipage}
\\
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_org_k40.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_mod_k40.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_ano_k40.eps}
\end{minipage}
\\
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_org_k50.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_mod_k50.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_ano_k50.eps}
\end{minipage}
\\
\caption{\it Original (left), modified (middle) and anomaly (right) Ertel's PV for 16 January 2006, 18\,UTC. The different rows correspond to the levels (from top to bottom) 20, 30 40 50 corresponding to the heights 4, 6, 8 and 10\,km.}
\label{ano}
\end{center}
\end{figure}
 
\noindent
The filtering
is characterised by the values in six lines of the parameter file. \\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
BEGIN ANOMALY
BOX_XMIN = -1200.;
BOX_XMAX = 1200.;
BOX_YMIN = -1200.;
BOX_YMAX = 1200.;
BOX_ZMIN = 2000.;
BOX_ZMAX = 10000.;
NFILTER = 5 ;
BOUND_XY = 500.;
BOUND_Z = 500.;
END ANOMALY
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.6cm}
\noindent
The lines specify the filtering box in the west-east direction (from -1200\,km to
1200\,km, from BOX\_XMIN to BOX\_XMAX), in the south-north direction (from -1200\,km to 1200\,km, from BOX\_YMIN to BOX\_YMAX), and in the vertical
(from 2000\,m to 10000\,m, from BOX\_ZMIN to BOX\_ZMAX). The filtering is not only applied once, but
(as given by NFILTER) $n=5$ times.
Finally the last two parameters describe the handling at the boundaries of the filtering box. In fact,
it is advantageous to force the anomaly PV to zero at the boundaries of the box. This is accomplished
by multiplying the PV anomaly with a function f$_{\partial F}$ which is 0 without the box, then monotonically increases
to 1 within a boundary zone, and then is constant 1 in the interior of the box. The width of the boundary
zone is given as 500\,km in the horizontal direction (BOUND\_XY) and 500\,m in the vertical direction (BOUND\_Z).\\
 
\noindent
The modified PV field and the anomaly are written to the R20060116\_18 file.
Additionally the boundary values are written. The velocity fields must be specified on the lateral
boundaries, whereas the potential temperature anomaly must be specified on the lower and upper boundary. In
the present settings, all boundary values are zero. The following table lists all fields which are additionally
written to the R file.
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
PV\_FILT & Modified Ertel's PV ($pvu$) & R20060116\_18 \\
PV\_ANOM & Anomaly in Ertel' PV ($pvu$) & R20060116\_18 \\
UU\_ANOM & Lateral boundary condition of zonal wind($m/s$) & R20060116\_18 \\
VV\_ANOM & Lateral boundary condition of meridional wind ($m/s$) & R20060116\_18 \\
TH\_ANOM & Upper and lower boundary of potential temperature ($K$) & R20060116\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.5cm}
 
 
\subsubsection{Splitting into different files [prep5]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{11.5cm}
\hspace{-2.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{splitting.eps}
\end{minipage}
\\
\caption{\it Splitting of the initial R20060116\_18 file into four different files with
prefix ORG, MOD, ANO and REF. }
\label{split}
\end{center}
\end{figure}
 
\noindent
So far, all new fields are written to the R20060116\_18 file. In the further steps it is
advantageous to split this file into several files. One file should get all original
fields, one only the modified fields and one only anomaly fields. Additionally, some
"static" fields, such as orography and Coriolis parameter, should be written to a special
file, from here on called the reference file.\\
 
\noindent
The splitting is done with the call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{15cm}
\begin{verbatim}
inversion.sh prep4
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The result of this step is a set of new netcdf files with prefix ORG, MOD, ANO and REF. The following table
(and Fig.\,\ref{split}) illustrates which variables are written to which file. Note that some variables are renamed in this process.
\\
 
\begin{center}
\begin{tabular}{|r|r|r|r|}
\hline
Old variable name & New variable name & Source file & Destination file \\
\hline
PV & PV & R20060115\_18 & ORG\_20060116\_18 \\
U & U & R20060115\_18 & ORG\_20060116\_18 \\
V & V & R20060115\_18 & ORG\_20060116\_18 \\
TH & TH & R20060115\_18 & ORG\_20060116\_18 \\
Q & Q & R20060115\_18 & ORG\_20060116\_18 \\
P & P & R20060115\_18 & ORG\_20060116\_18 \\
T & T & R20060115\_18 & ORG\_20060116\_18 \\
\hline
PV\_FILT & PV\_AIM & R20060115\_18 & MOD\_20060116\_18 \\
U & U & R20060115\_18 & MOD\_20060116\_18 \\
V & V & R20060115\_18 & MOD\_20060116\_18 \\
Q & Q & R20060115\_18 & MOD\_20060116\_18 \\
P & P & R20060115\_18 & MOD\_20060116\_18 \\
T & T & R20060115\_18 & MOD\_20060116\_18 \\
NSQ & NSQ & R20060115\_18 & MOD\_20060116\_18 \\
RHO & RHO & R20060115\_18 & MOD\_20060116\_18 \\
TH & TH & R20060115\_18 & MOD\_20060116\_18 \\
\hline
\end{tabular}
\begin{tabular}{|r|r|r|r|}
\hline
Old variable name & New variable name & Source file & Destination file \\
\hline
PV\_ANOM & PV & R20060115\_18 & ANO\_20060115\_18 \\
TH\_ANOM & TH & R20060115\_18 & ANO\_20060115\_18 \\
UU\_ANOM & U & R20060115\_18 & ANO\_20060115\_18 \\
VV\_ANOM & V & R20060115\_18 & ANO\_20060115\_18 \\
\hline
ORO & ORO & R20060115\_18 & REF\_20060115\_18 \\
X & X & R20060115\_18 & REF\_20060115\_18 \\
Y & Y & R20060115\_18 & REF\_20060115\_18 \\
LAT & LAT & R20060115\_18 & REF\_20060115\_18 \\
LON & LON & R20060115\_18 & REF\_20060115\_18 \\
CORIOL & CORIOL & R20060115\_18 & REF\_20060115\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.5cm}
 
 
 
\subsubsection{Specifying the reference profile [prep6]}
 
 
A reference vertical profile must be
defined for the PV inversion. The profile should be as near as possible to the real profile. Any quantity is defined in
the inversion as a deviation from this profile. Hence if the profile is well chosen only small
deviations can be expected and the assumed linearisation (see later) is better. Physically we determine
a good reference profile by taking the area mean over the subdomain, i.e at every model level the
mean over potential temperature $\theta$, squared Brunt Vais\"al\"a frequency $N^2$ and density $\rho$
is calculated. The resulting profiles are shown in Fig.\,\ref{reference} as a function of height, and additionally
as a function of pressure.\\
 
\noindent
Note how the density of the reference profile exponentially decreases
decreases with increasing height. If pressure is used as vertical co-ordinate, the decrease in density
is essentially linear with decreasing pressure. The profile of potential temperature increases with
increasing height: This is a necessary condition for the convective stability of the air column. In fact,
any region where potential temperature decreases with increasing height is unstable and characterised by high levels
of turbulence. The stability expressed by this potential temperature increase with height is numerically
determined by the so-called (squared) Brunt-Vais\"al\"a frequency, shown in the left panels. Since this
field directly goes into the solution of the quasi-geostrophic PV equation (see section~3.5), it must
be guaranteed that it always remains positive.\\
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{16cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{reference.eps}
\end{minipage}
\\
\caption{\it Reference profiles of potential temperature $\theta$, squared Brunt Vais\"al\"a frequency $N^2$ and density $\rho$ as a function of height (upper panels) and pressure (lower panels). The
reference profiles correspond to the area-averaged values over the inversion subdomain. }
\label{reference}
\end{center}
\end{figure}
 
\noindent
The reference profile is calculated with the call to \\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep5
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
After his step some additional variables are available on the REF file. These are:\\
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
NSQREF & Reference squared Brunt-Vais\"al\"a frequency ($1/s^2$) & MOD\_20060116\_18 \\
RHOREF & Reference air density ($kg/m^3$) & MOD\_20060116\_18 \\
PREREF & Reference pressure ($hPa$) & MOD\_20060115\_18 \\
THETAREF & Reference potential temperature ($K$) & MOD\_20060116\_18 \\
ZREF & Reference geopotential height ($m$) & MOD\_20060116\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.5cm}
 
\subsubsection{Adding the coastlines [prep7]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{coast1.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{coast2.eps}
\end{minipage}
\\
\caption{\it Coastlines transformed into the quasi-cartesian co-ordinate system. In the left panel, the
coastlines are shown in a system with rotated longitude and latitude as axes, in the right panel they
are shown in a x/y co-ordinate system.}
\label{coastline}
\end{center}
\end{figure}
 
At this stage it is not possible to plot the continental coastlines in the quasi-cartesian co-ordinate frame.
In fact, this becomes only feasible if the geographical coastlines (as given in latitude/longitude co-ordinates) are transformed into the new quasi-cartesian co-ordinate system. This is done
with the call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep7
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
In Fig.\,\ref{coastline} the transformed co-ordinates are shown. On the left panel, the co-ordinate axis are the rotated longitude and latitude and on the left panel they are given by the distance (in km) from the co-ordinate's center (see Fig.\,14).
In this step the following additional fields are written to the REF\_20060116\_18 file:
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
COAST\_LON & Longitude of coastline & REF\_20060115\_18 \\
COAST\_LAT & Latitude of coastline & REF\_20060115\_18 \\
COAST\_RLON & Rotated longitude of coastline & REF\_20060115\_18 \\
COAST\_RLAT & Rotated latitude of coastline & REF\_20060115\_18 \\
COAST\_X & X co-ordinate of coastline & REF\_20060115\_18 \\
COAST\_Y & Y co-ordinate of coastline & REF\_20060115\_18 \\
\hline
\end{tabular}
\end{center}
 
\vspace{0.3cm}
\noindent
The coastline in geographical co-ordinates is taken from a global data set which can be retrieved from
the National Geophysical Data Center
(rimmer.ngdc.noaa.gov/coast/). Only, the part of the coastlines inside the rotated co-ordinate system are specified. This allows
an efficient plotting of the coastlines. If Matlab is used as a visualisation tool, the plotting can be
done with the following few lines, depending whether rotated longitude/latitude or X/Y is used as co-ordinate
axes.\\[0.0cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
%Read input file
inp = ncget('REF_20060116_18');
 
% Plot continental boundaries (rotated latitude/longitude)
figure;
plot(inp.COAST_RLON.data,inp.COAST_RLAT.data,'k');
 
% Plot continental boundaries (x/y)
figure;
plot(inp.COAST_X.data,inp.COAST_Y.data,'k');
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.6cm}
\noindent
The first command reads the reference file. All variables and parameters are then available in the Matlab structure inp. The COAST subfields of this structure can then immediately be plotted. Sometimes it turns
out to be better to set all co-ordinates outside the plotting domain to NaN.
 
 
\subsubsection{Moving the files to the run directory [prep8]}
 
At this stage, all essential preparatory steps for the PV inversion are done: The modified PV field is defined, the
boundary conditions are written and the reference profile is available. In this last step, the files are moved from the
input directory to the run directory, where all iterations of the PV inversions are performed. The moving of the
files is done with\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh prep8
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The ORG, MOD, ANO and REF files are now available in the run directory (see Fig.\,8). No further processes are
run in the input directory.
 
 
 
\subsection{Inversion - Iterative steps toward modified PV field [pvin]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{14cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{iterations.eps}
\end{minipage}
\\
\caption{\it Flowchart of the different inversion steps. Additionally, to the right of the different blocks, the
"flow" of information is illustrated. For instance, MOD $\rightarrow$ ANO means that the input information
is taken from the MOD file and then written to the ANO file. }
\label{iterations}
\end{center}
\end{figure}
 
The following steps build the core of the PV inversion. An interior anomaly of Ertel's PV
and the boundary values for the inversion were specified in the previous preparatory steps.
Now the flow anomalies (wind vectors, temperature, pressure and potential temperature) associated
with this PV anomaly has to be determined. This is the aim of the inversion. More specifically
the process must be split again into several distinct steps. These different steps are shown as a flowchart in
Fig.\,\ref{iterations}.
 
 
 
 
\subsubsection{Calculation of secondary fields [pvin1]}
 
Secondary fields have to be calculated. These fields are potential temperature, potential vorticity
density and squared Brunt-Vais\"al\"a frequency. The details of these calculations were already presented
in section~4.4.3, and are not repeated here. All the secondary fields are calculated with the call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh pvin1
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The call subsequently calculates potential temperature, squared Brunt-V\"as\"ala frequency, density and Ertel's PV. Where the height levels are below topography,
missing data values are written. The following table lists the new fields which are written to the MOD file:
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
TH & Potential temperature ($K$) & MOD\_20060116\_18 \\
PV & Ertel's potential vorticity ($pvu$) & MOD\_20060116\_18 \\
NSQ & Squared Brunt-Vai\"al\"a frequency ($1/s^2$) & MOD\_20060116\_18 \\
RHO & Air density ($kg/m^3$) & MOD\_20060116\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.5cm}
 
\subsubsection{Transforming Ertel's PV to quasi-geostrophic PV [pvin2]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{14.0cm}
\hspace{-1.0cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{pv_to_qgpv.eps}
\end{minipage}
\\
\caption{\it Determination of Ertel's PV anomaly and its transformation into
an anomaly of quasi-geostrophic PV. The calculated Ertel's PV is subtracted from
Ertel's PV which should be reached, and then this difference is transformed into
an approximate quasi-geostrophic PV. The input is taken from the MOD file, and the
output is written to the ANO file.}
\label{pvtoqg}
\end{center}
\end{figure}
 
So far only Ertel's PV was used. On the other hand, the inverson problem is formulated for the
quasi-geostrophic PV. Therefore a conversion between the two has to be done. In a first approximation
Ertels's PV is given by (for clarity it is denoted as EPV in this section):\\[-0.2cm]
 
\[
EPV = \frac{1}{\rho} \cdot ( \xi + f ) \cdot \frac{\partial \theta}{\partial z}
\]
 
\vspace{0.3cm}
\noindent
where $\rho$ is the density, $\xi$ the relative vorticity, $f$ the Coriolis parameter and $\theta$ the potential temperature.
Ertel's PV can be expressed in terms of the reference profile and deviation thereof. If we set
$\theta=\theta_0 + \theta^*$ and $\rho=\rho_0 + \rho^*$, consider the definition
of the reference stratification $N^2_0=g/\theta_0 \cdot \partial {\theta_0}/{\partial z}$ and furthermore
apply the quasi-geostrophic assumption $\xi \ll f$, the following approximate
expression hold in first order (we have neglected the density perturbation $\rho^*$ in the denominator):\\[-2mm]
 
\[
EPV = \frac{\theta_0 N_0^2}{g \rho_0} \cdot (\xi + \frac{f g}{\theta_0 N_0^2} \cdot \frac{\partial \theta^*}{\partial z})
\]
 
\vspace{0.3cm}
\noindent
On the other hand, the quasi-geostrophic PV (denoted by qgPV in this section) is defined by the streamfunction $\psi$\\[-0.2cm]
 
\[
qgPV = \frac{\partial^2\psi}{\partial x^2} + \frac{\partial^2\psi}{\partial y^2} +
\frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z} (\frac{\rho_0}{N_0^2}
\cdot \frac{\partial \psi}{\partial z} )
\]
 
\vspace{0.3cm}
\noindent
where $\rho_0$ and $N_0^2$ denotes a reference profile of density and stratification (as defined in the
preparatory steps and written to the REF file). The following relationship between the streamfunction and the meteorological fields persists:\\[-2mm]
 
\[
g \cdot \frac{\theta^*}{\theta_0} = f \cdot \frac{\partial \psi}{\partial z}
\quad \quad
u = -\frac{\partial \psi}{\partial y}
\quad \quad
v = -\frac{\partial \psi}{\partial x}
\]
 
\vspace{0.3cm}
\noindent
If these expressions are inserted into the above equation for $q$, one gets:\\[-2mm]
 
\[
qgPV = \xi + \frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z}
(\frac{\rho_0 g}{N_0^2 f \theta_0} \cdot \theta^* )
\]
 
\vspace{0.3cm}
\noindent
In a first approximation, we treat the reference profile and the Coriolis parameter as constant. Then,
this last expression is further simplified to:\\[-2mm]
 
\[
qgPV = \xi + \frac{f g}{N_0^2 \theta_0} \cdot \frac{\partial \theta^*}{\partial z}
\]
 
 
\vspace{0.3cm}
\noindent
With this form, it is easy to see that the following approximate relationship between Ertel's and the
quasi-geostrophic PV holds. \\[-2mm]
 
\[
qgPV \approx \frac{\rho_0 g}{\theta_0 N_0^2} \cdot EPV - f
\]
 
\vspace{0.3cm}
\noindent
Note that according to the previous derivation, this equation does not hold exactly. It is based upon
an assumption of linearisation and on approximate forms of Ertel's PV. Nevertheless, we can expect it
to be a good first-order approximation. In the PV inversion tool, use is made of this relationship,
but since it is only approximate, an iterative technique has to be applied. Finally note that this
formula can be easily applied to PV anomalies. Indeed, if $\Delta PV$ refers to a anomaly in Ertel's
PV, the corresponding anomaly in quasi-geostrophic PV is given by:\\[-2mm]
 
\[
\Delta(qgPV) \approx \frac{\rho_0 g}{\theta_0 N_0^2} \cdot \Delta(EPV)
\]
 
 
\vspace{0.3cm}
\noindent
It is in this latter form that the program call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh pvin2
\end{verbatim}
\end{minipage}
\end{center}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{8.1cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{qgpv_ano_ew.eps}
\end{minipage}
\hspace{-0.5cm}
\begin{minipage}[t]{8.1cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{qgpv_ano_ns.eps}
\end{minipage}
\\
\caption{\it Quasi-geostrophic PV anomaly in an east/west (left) and an north/south (right)
vertical cross-section for 16 January 2006, 18\,UTC. }
\label{qgano}
\end{center}
\end{figure}
 
\vspace{0.3cm}
\noindent
makes the conversion. It takes the Ertel-PV from the MOD file, and subtracts it from the PV\_AIM which is also
available on the MOD file. The difference between the two PV is the new anomaly in Ertel's PV which has to
be inverted in this iterative step. The approximate relationship between quasi-geostrophic PV and Ertel's
PV is then used to get a corresponding anomaly of the former one (see Fig.\,ref{pvtoqg}).
Note that this program handles also missing data values. If at some grid point Ertel's PV is not defined,
i.e. the missing data flag is set, the corresponding value of quasi-geostrophic PV is set to zero. It is not
set to the missing data value since no check will be done by the PV inversion program. Therefore, it is
best to treat every missing value as a vanishing anomaly of quasi-geostrophic PV. A vertical cross-section
of the anomaly in quasi-geostrophic PV is shown in Fig.\,\ref{qgano}.
The additional or changed fields on the file ANO\_20060116\_18 are given in the following table:\\
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
PV & Ertel's PV anomaly ($pvu$) & ANO\_20060116\_18 \\
QGPV & Anomaly in quasi-geostrophic PV ($s^{-1}$) & ANO\_20060116\_18 \\
\hline
\end{tabular}
\end{center}
 
 
 
 
 
\subsubsection{Inversion of the quasi-geostrophic PV [pvin3]}
 
At this stage the interior distribution of quasi-geostrophic PV and the boundary values
are given, and therefore the inversion can be performed in order to get the streamfunction.
Numerical aspects of the inversion were already presented in section~2. Here, we focus on the
practical aspects. The numerical problem solved in this step is expressed in the following
boundary value problem: \\[-0.3cm]
 
\[
q = \frac{\partial^2\psi}{\partial x^2} + \frac{\partial^2\psi}{\partial y^2} +
\frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z} ( \frac{\rho_0}{N_0^2}
\cdot \frac{\partial \psi}{\partial z})
\]
 
\vspace{0.3cm}
\noindent
with the pre-described values\\[-0.3cm]
 
\[
g \cdot \frac{\theta^*}{\theta_0} = f \cdot \frac{\partial \psi}{\partial z}
\quad \quad
u = -\frac{\partial \psi}{\partial y}
\quad \quad
v = -\frac{\partial \psi}{\partial x}
\]
 
\vspace{0.3cm}
\noindent
on the upper and lower boundaries (for $\theta^*$) and on the lateral boundaries (for $u$ and $v$). The inversion program is called by\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh pvin3
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
Note that the inversion affects only the file ANO\_20060116\_18 because the inversion is
performed for an anomaly of quasi-geostrophic PV.
The final aim of this step is to calculate the wind, temperature, pressure and potential temperature
perturbations which are associated with the specified anomaly of quasi-geostrophic PV.
The call to the program yields some information about the ongoing iterative steps. First of all,
the spectral width in the x-, y- and z-direction is written to screen. In the present example this
is:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{small}
\begin{verbatim}
Spectrum of the matrix in each direction
Spectrum = 1.028528 0.9136161 1.231250
\end{verbatim}
\end{small}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The spectral widths $\lambda_x,\lambda_y, \lambda_z$ (in the same order as in the above program output) are important to decide whether the inversion can be reasonably be performed. The
criterion is based upon the matrix elements defining the inversion problem. For a reasonable setting
the following inequalities should be fulfilled:
 
\[
\lambda_x > 1/2 \cdot \lambda_y \quad \quad \mbox{and} \quad \quad \lambda_x > 1/2 \cdot \lambda_z
\]
\[
\lambda_y > 1/2 \cdot \lambda_x \quad \quad \mbox{and} \quad \quad \lambda_y > 1/2 \cdot \lambda_z
\]
\[
\lambda_z > 1/2 \cdot \lambda_x \quad \quad \mbox{and} \quad \quad \lambda_z > 1/2 \cdot \lambda_y
\]
 
\vspace{0.3cm}
\noindent
which is evidently fulfilled in our case study (otherwise the program would abort with the error
message that the grid dimensions are not large enough). Then some run-time statistics is provided for the
iterative solution of the elliptical partial differential equation. As described in section~2 the
solution of the quasi-geostrophic PV equation is found by means of an successive over-relaxation (SOR)
technique. Starting from an initial estimate of the streamfunction $\psi$ several hundred iterations of
 
 
\[
\psi_i^{(n+1)} = \omega \cdot (b_i - \sum_{j=1}^{i-1} A_{i,j} \cdot \psi_j^{(n+1)}
- \sum_{j=i}^{m} A_{i,j} \cdot \psi_j^{(n)})
+ (1-\omega) \cdot \psi_i^{(n)}
\]
 
\vspace{0.3cm}
\noindent
are performed (see section~2 for details). Essentially two statistical measures are provided: The first one $\psi_{gauge}$
measures the amplitude of the streamfunction which is produced in the course of the iteration,
the second one is a direct check whether the iteration solution converges. In fact, after several iterations the so-far
reached streamfunction is used to calculate the quasi-geostrophic $PV^{c}$ according to the formula:\\[-0.3cm]
 
\[
PV^c = \frac{\partial^2\psi}{\partial x^2} + \frac{\partial^2\psi}{\partial y^2} +
\frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z} ( \frac{\rho_0}{N_0^2}
\cdot \frac{\partial \psi}{\partial z})
\]
 
\vspace{0.3cm}
\noindent
This value can then be compared to the quasi-geostrophic
$PV^{i}$ distribution which was given as input to the inversion algorithm. The following norm $\Delta^2$ is then
calculated as a measure of the convergence:\\[-0.3cm]
\[
\Delta^2 = \sum_{i,j,k} (\psi^{i}_{i,j,k}-\psi^{c}_{i,j,k})^2
\]
 
\vspace{0.3cm}
\noindent
Some sample output is reproduced below for the case study, the first column corresponding to $\psi_{gauge}$ and the
second one to $\Delta^2$:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
psigauge = 0.000E+00 deltasq = 0.850E-09
psigauge = 0.000E+00 deltasq = 0.112E-09
psigauge = -0.681E+03 deltasq = 0.643E-10
psigauge = -0.681E+03 deltasq = 0.466E-10
psigauge = -0.806E+03 deltasq = 0.367E-10
psigauge = -0.806E+03 deltasq = 0.303E-10
psigauge = -0.547E+03 deltasq = 0.259E-10
psigauge = -0.547E+03 deltasq = 0.228E-10
psigauge = -0.398E+03 deltasq = 0.206E-10
psigauge = -0.398E+03 deltasq = 0.191E-10
psigauge = -0.309E+03 deltasq = 0.180E-10
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.6cm}
\noindent
Note that the gauge streamfunction reaches a value of order -3000 (corresponding to a substantial anomaly of wind
and temperature), and that the convergence measure $\Delta^2$ decreases
by an order of magnitude from the beginning to the end. At the end of this step, the streamfunction associated with the quasi-geostrophic PV anomaly is determined. It is shown in Fig.\,\ref{stream} at three horizontal cross-sections. The
minimum of the streamfunction is found in the interior of the domain, in agreement with the cyclonic flow around the
positive anomaly of quasi-geostrophic PV. \\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{psi_ano_k01.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{psi_ano_k20.eps}
\end{minipage}
\hspace{0.0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{psi_ano_k40.eps}
\end{minipage}
\\
\caption{\it Streamfunction associated with the quasi-geostrophic PV anomaly shown in Fig.\,ref{qgano}. The three panels show horizontal cross-sections at 0, 4\,km and 8\,km above ground.}
\label{stream}
\end{center}
\end{figure}
 
\noindent
Now, additional perturbation fields can be computed from this streamfunction: Potential temperature,
wind components in x and y direction, pressure, and temperature. The corresponding formula are:\\[-0.5cm]
 
\begin{eqnarray*}
\theta^* & = & \frac{f}{g} \cdot \theta_0 \cdot \frac{\partial \psi}{\partial z}\\[0.2cm]
u & = & - \frac{\partial \psi}{\partial y}\\
\end{eqnarray*}
\begin{eqnarray*}
v & = & \frac{\partial \psi}{\partial x}\\
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
The anomaly of potential temperature $\theta^*$ and the two horizontal wind components $u$ and $v$ can directly determined from the
streamfunction. Moreover, the pressure anomaly is directly proportional to the streamfunction, which is only
determined up to an additive constant. In order to obtain a vanishing pressure at the boundary of the
inversion domain, we firstly calculate such a constant $\psi_0$ (essentially the average over the domain boundary) and then set the pressure to:\\[-0.2cm]
 
\[
p^* = \rho_0 \cdot f \cdot (\psi - \psi_0)
\]
 
\vspace{0.3cm}
\noindent
The temperature anomaly is now easily calculated from pressure and potential temperature according the relationship
$\theta = T \cdot (p_ref/p)^\kappa$, where $T$ is the temperature in Kelvin, $p_ref$ is the reference pressure level (1000\,hPa) and $\kappa$ is the ratio between the gas constant for dry air ($R_d$) and the specific heat at constant pressure ($c_p$). Consistent with previous approximations we set:\\[-0.2cm]
 
\[
T^* = (\frac{p_0}{p_ref})^\kappa \cdot (\theta^* + \kappa \cdot \theta_0 \cdot \frac{p^*}{p_0} )
\]
 
\vspace{0.3cm}
\noindent
Figure\,\ref{anofield} shows some of these perturbation fields. The positive anomaly of quasi-geostrophic PV is
associated with a cyclonic (anti-clockwise) flow field, which reaches down to surface levels. Furthermore, we know from theoretical studies that a positive PV anomaly goes along with an increase of potential temperature above the anomaly, and correspondingly a decrease of
potential temperature below. This is nicely confirmed in the perturbation field of the calculation.
Finally, the cyclonic flow must be associated with a local pressure minimum, according to the
geostrophic wind equation. This is also fulfilled in our calculation. The following table gives all anomaly fields on the ANO\_10060116\_18 file which are calculated:
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{ano_00_k35_pr.eps}
\end{minipage}
\hspace{-0.6cm}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{ano_00_k35_tt.eps}
\end{minipage}
\\[-0.3cm]
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{ano_00_k35_uv.eps}
\end{minipage}
\hspace{-0.6cm}
\begin{minipage}[t]{7.5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{ano_00_k35_psi.eps}
\end{minipage}
\\
\caption{\it Pressure, temperature, wind vectors and streamfunction (from upper-left to lower-right)
associated with the quasi-geostrophic PV anomaly. The horizontal cross-section is at level 7\,km. For clarity,
some isolines of quasi-geostrophic PV are also shown.}
\label{anofield}
\end{center}
\end{figure}
 
\vspace{0.3cm}
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
STREAM & Streamfunction ($m^2/s$) & ANO\_20060116\_18 \\
THETA & Potential temperature ($K$) & ANO\_20060116\_18 \\
U & Velocity component in X direction ($m/s$) & ANO\_20060116\_18 \\
V & Velocity in Y direction ($m/s$) & ANO\_20060116\_18 \\
T & Temperature ($^\circ C$) & ANO\_20060116\_18 \\
P & Pressure ($hPa$) & ANO\_20060116\_18 \\
\hline
\end{tabular}
\end{center}
 
\vspace{0.3cm}
\noindent
Finally, the question emerges whether the convergence of the algorithm was sufficient. In order to assess the
quality of convergence a diagnostic tool is presented in section~5.2, which allows to calculate the
quasi-geostrophic PV according to its definition and then to compare it with the anomaly given at
the beginning of the PV inversion.
 
 
\subsubsection{Preparing the next step for iteration [pvin4]}
 
 
\noindent
At this point, the quasi-geostrophic PV anomaly is inverted and the associated streamfunction and
other flow fields have been determined. But the inversion problem is not yet solved. In fact,
we specified an anomaly of Ertel's PV, but in the previous step a anomaly of quasi-geostrophic PV
was inverted. By the above reasoning, we expect the two anomalies to be closely linked. However,
inversion of the quasi-geostrophic PV equation is a linear problem, whereas the inversion of Ertel's
PV is inherently non-linear. That is why some further iteration must be performed.\\
 
\noindent
In a first step, we take the basic flow fields (temperature, velocity, pressure) from the anomaly (ANO)
file and subtract it from the MOD file (Fig.\,\ref{prepiter}). This is done by call to\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh pvin3
\end{verbatim}
\end{minipage}
\end{center}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{10cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{prepiter.eps}
\end{minipage}
\\
\caption{\it Preparation for the next iteration: The fields (pressure, temperature, velocity, potential
temperature) from iteration n and the anomalies of iteration n are combined to give the fields at iteration
n+1.}
\label{prepiter}
\end{center}
\end{figure}
 
\vspace{0.3cm}
\noindent
There is one external parameter involved in this step. It is found in the NUMERICS section of the
parameter file and is called ALPHA. This value determines which fraction of the perturbation has to
be subtracted from the MOD fields. Formally, we do the following transformation (see also Fig.\,\ref{prepiter}):
 
\begin{eqnarray*}
u^{n+1}_{MOD} & \leftarrow & u^n_{MOD} - \alpha \cdot u^n_{ANO}\\[0.2cm]
v^{n+1}_{MOD} & \leftarrow & v^n_{MOD} - \alpha \cdot v^n_{ANO}\\[0.2cm]
T^{n+1}_{MOD} & \leftarrow & T^n_{MOD} - \alpha \cdot T^n_{ANO}\\[0.2cm]
p^{n+1}_{MOD} & \leftarrow & p^n_{MOD} - \alpha \cdot p^n_{ANO}
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
A value $\alpha < 1$ slows down the convergence because only part of the inversion result is used. On the other hand, it was found that the stability of the algorithm is enhanced by values $\alpha < 1$. In
the case study a value of 0.5 was used, and good convergence reached, whereas a value of 1 resulted in unrealistic small-scale perturbations which diverge with continuing iterative steps.\\
 
\noindent
The variables which are adjusted in the MOD\_20060116\_18 file are given in the following table and an example
for the adjustment is shown in Fig.\,\ref{prepsub}:
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
THETA & Potential temperature & MOD\_20060115\_18 \\
U & Velocity component in X direction ($m/s$) & MOD\_20060115\_18 \\
V & Velocity in Y direction ($m/s$) & MOD\_20060115\_18 \\
T & Temperature ($^\circ C$) & MOD\_20060115\_18 \\
P & Pressure ($hPa$) & MOD\_20060115\_18 \\
\hline
\end{tabular}
\end{center}
 
\vspace{0.5cm}
\noindent
It might be valuable to study the convergence of the inversion in greater detail. To this aim, the
master script allows the call:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh pvin5
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
which makes a copy of the momentarily reached MOD and ANO file. For this save option to work, the
SAVEITER flag in the NUMERICS section of the parameter file must be set to "yes".
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
BEGIN NUMERICS
SAVEITER = yes;
END NUMERICS
\end{verbatim}
\end{minipage}
\end{center}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{8.3cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{prep_k35_org_ano.eps}
\end{minipage}
\hspace{-1cm}
\begin{minipage}[t]{8.3cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{prep_k35_mod.eps}
\end{minipage}
\\
\caption{\it Left: Temperature in the modified MOD file (in color) and in the anomaly ANO file (with contour lines)
at the end of the quasi-geostrophic PV inversion. The temperature anomaly in ANO is subtracted from the initial temperature in MOD. Right: New modified temperature in the MOD file after the subtraction.
This new modified field gives the next entry for the PV inversion. }
\label{prepsub}
\end{center}
\end{figure}
 
 
\subsubsection{Convergence after several iterations [pvin5]}
 
At this stage, the next iterative steps can be performed. The MOD file has been adjusted according to
the outcome of the quasi-geostrophic PV inversion. The modified wind and temperature fields can be used to calculate a new Ertel-PV field, which in turn can be compared with the pre-specified aim-PV field.
Hopefully, after several iterative steps, the re-currently calculated PV of the MOD file converges
toward the aim-PV. If so, the non-linear inversion problem for Ertel's PV is solved. Figure\,\ref{convergence}
illustrates the convergence for the case study. Note that the iterative steps need not be
launched by hand, but can be run automatically with call to\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh pvin
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The script will run through all inversion steps and will loop through the number of iterations specified in NOFITER in the NUMERICS section of the parameter file.
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
BEGIN NUMERICS
NOFITER = 6;
END NUMERICS
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The panels of Fig.\,\ref{convergence} show the streamfunction at three consecutive iterative steps.
Note that the amplitiude of the streamfunction clearly decreases, indicating that the iteration
process converges.
Generally, after six steps good convergence is reached. This is further supported by
the standard output during the quasi-geostrophic inversion (see listing on page~38). The final line of this output
is shown below for several consecutive iterations (the first one corresponding to the line on page~38):
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{con_01_k35_psi.eps}
\end{minipage}
\hspace{0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{con_02_k35_psi.eps}
\end{minipage}
\hspace{0cm}
\begin{minipage}[t]{5cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{con_03_k35_psi.eps}
\end{minipage}
\\
\caption{\it streamfunction for three iterative steps. Note the different contour intervals
for the three sub panels. The decrease of the amplitude clearly indicates a convergence of the
PV inversion.}
\label{convergence}
\end{center}
\end{figure}
 
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
psigauge = -0.309E+03 deltasq = 0.180E-10
psigauge = -0.128E+03 deltasq = 0.548E-11
psigauge = -0.570E+02 deltasq = 0.233E-11
psigauge = -0.265E+02 deltasq = 0.117E-11
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
Note that with each iterative step "less" streamfunction is produced. Since the basic perturbation
fields (temperature, pressure, horizontal wind, potential temperature) are directly proportional
to the streamfunction, the corrections to the flow fields also
become smaller and smaller.
 
\subsection{Post processing - Changing the P file [post]}
 
The PV inversion was completed in the previous step and the modified temperature, pressure and wind field is available in the run files. It is the aim of the post processing steps to bring these modified
fields back to the format of the input fields. The steps are summarised in Fig.\,\ref{postproc}.\\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{12cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{postproc.eps}
\end{minipage}
\\
\caption{\it Different steps of post processing. Additionally, to the left of the different
blocks the main flow of information is indicated. For instance, MOD $\rightarrow$ GEO means
that the input is taken from the MOD file and the output written to the GEO file. }
\label{postproc}
\end{center}
\end{figure}
 
\noindent
But at first the input field and the link to the modified output field must be made available with a call to:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh post1
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The P file is copied from the input directory to the output directory and a symbolic link is set to the
MOD file in the run directory.
 
 
 
 
\subsubsection{Rotating to the geographical latitude/longitude grid [post2]}
 
Figure~\ref{backrot} illustrates the step which is necessary to transform the meteorological fields to a geographical co-ordinate system. The left panel shows the temperature at 2000\,m above sea level in the local-cartesian co-ordinate system, the right panel is the same field, but projected back to a geographical grid. Note that in this latter frame only a small section is filled by temperature values, whereas most are
undefined.\\
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{8.3cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{rot_k35_rot_t.eps}
\end{minipage}
\hspace{-1.2cm}
\begin{minipage}[t]{8.3cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{rot_k35_geo_t.eps}
\end{minipage}
\\
\caption{\it Modified temperature field at 7\,km above ground in the rotated co-ordinate system (left) and transformed back into the geographical latitude/longitude grid (right). Additionally
the wind vectors are shown in both co-ordinate systems. Note that the transformation of the vectorial
wind is much more complicated than the transformation of the scalar temperature.}
\label{backrot}
\end{center}
\end{figure}
 
\noindent
The rotation itself is the reverse transformation performed in the preparatory steps (section~4.4.2). It is called by (and its effect shown in Fig.\,\ref{backrot})\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh post2
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
and its behaviour is controlled by the following entries in the parameter file:
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
BEGIN GRID
GEO_XMIN = -180.;
GEO_NX = 361 ;
GEO_DX = 1.;
GEO_YMIN = 0.;
GEO_NY = 91 ;
GEO_DY = 1.;
CLON = -65.;
CLAT = 45.;
CROT = 0.;
END GRID
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The first six parameters define the geographical grid of the input files. More specifically the left grid boundary is at $180^\circ$\,W (GEO\_XMIN), the number of grid points in the zonal (west-to-east) direction is 361 (GEO\_NX) and
the grid resolution in zonal direction is $1^\circ$\,longitude (GEO\_DX). Analogously, the parameters of the
grid in meridional (south-to-north) direction are given: Lowest latitude $0^\circ$\,N (GEO\_YMIN), number of grid
points 91 (GEO\_NY) and grid resolution $1^\circ$\,latitude (GEO\_DY). The rotation itself is described by
the last three entries (CLON, CLAT and CROT), which have the exactly same meaning as given in section~4.4.2\\
 
\noindent
Note again, that the transformation of a scalar quantity is considerably easier than the transformation of a vectorial quantity. In the latter case, the specific transformation
of the vectorial components must be correctly handled. The transformation algorithm for a scalar quantity is based
upon the transformation rules given in Appendix~9.1 (Fortran subroutines {\em lmtolms} and {\em phtophs}). Essentially, the
steps are the reverse of the ones presented in section~4.4.2.
The rotated (quasi-cartesian) latitude/longitude corresponding to a grid point in the geographical co-ordinate system is obtained in the following way. Firstly, the geographical latitude/longitude $\phi_{geo},\lambda_{geo}$ is transformed into
 
\begin{eqnarray*}
\lambda'_{rot} & = & lmtolms(\phi_{geo},\lambda_{geo},90-\phi_{cen},\lambda_{cen}-180) \\[0.2cm]
\phi'_{rot} & = & phtophs(\phi_{geo},\lambda_{geo},90-\phi_{cen},\lambda_{cen}-180))
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
where the centre of the PV anomaly (the centre of the quasi-cartesian co-ordinate system in geographical
latitude/longitude co-ordinates) is given by $\phi_{cen}$ and $\lambda_{cen}$ (CLAT and CLON in the
parameter file, see above).
These two
values are then, in a second rotation, transformed into rotated latitude and longitude:
 
\begin{eqnarray*}
\lambda_{rot} & = & 90+lmtolms(\phi'_{rot},\lambda'_{rot}-90,90+\alpha,-180) \\[0.2cm]
\phi_{rot} & = & phtophs(\phi'_{rot},\lambda'_{rot}-90,90+\alpha,-180)
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
where $\alpha$ is the rotation angle given in the parameter file (CROT, see below). With the correspondence
$(\lambda_{geo},\phi_{geo}) \leftrightarrow (\lambda_{rot},\phi_{rot})$ it is straightforward to perform
the transformation of a scalar field. In the program package this is done by means of linear interpolation.\\
\noindent
The fields which are written to GEO\_20060116\_18 are given in the following table:\\
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
U & Zonal velocity ($m/s$) & GEO\_20060116\_18 \\
V & Meridional velocity ($m/s$) & GEO\_20060116\_18 \\
T & Temperature ($^\circ C$) & GEO\_20060116\_18 \\
P & Pressure ($hPa$) & GEO\_20060116\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.5cm}
 
\begin{figure}[t]
\vspace{-3cm}
\begin{center}
\begin{minipage}[t]{16cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{weight1.eps}
\end{minipage}
\\[-4.2cm]
\caption{\it Weighting function (in color) for the insertion of the modified fields into the original
P file. Additionally, the distance from the boundary of insertion region is plotted as contour lines (positive
inside the region, negative outside region). The zero contour line of the distance corresponds to the
boundary of the insertion domain.}
\label{comparep}
\end{center}
\end{figure}
 
 
\subsubsection{Transformation from height to hybrid ECMWF co-ordinates [post3]}
 
\begin{figure}[t]
\vspace{-1cm}
\begin{center}
\begin{minipage}[t]{8.2cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{inp_tt_k38.eps}
\end{minipage}
\hspace{-0.7cm}
\begin{minipage}[t]{8.2cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{out_tt_k38.eps}
\end{minipage}
\\[-2.8cm]
\begin{minipage}[t]{8.2cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{inp_uv_k38.eps}
\end{minipage}
\hspace{-0.7cm}
\begin{minipage}[t]{8.2cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{out_uv_k38.eps}
\end{minipage}
\\[-1.5cm]
\caption{\it Comparison of original (with PV streamer, left) and modified (without PV streamer, right)
temperature (top panels) and velocity/wind vectors bottom panels) at model level 38 of the ECMWF grid.}
\label{comparep2}
\end{center}
\end{figure}
 
\noindent
The vertical co-ordinate in the back-rotated field is still geometrical height, whereas the input
fields are given on the hybrid ECMWF grid. In this step the transformation to the hybrid vertical co-ordinate is performed. The call is:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh post3
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The transformation is based upon a cubic spline interpolation. The fields which are overwritten
in the P20060116\_18 file are:\\
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
U & Velocity component in zonal direction ($m/s$) & P20060115\_18 \\
V & Velocity in meridional direction ($m/s$) & P20060115\_18 \\
T & Temperature ($^\circ C$) & P20060115\_18 \\
PS & Surface pressure ($hPa$) & P20060115\_18 \\
\hline
\end{tabular}
\end{center}
 
\vspace{0.3cm}
\noindent
An impression of the modified flow field is given in Fig.\,\ref{comparep2}.
 
 
\subsubsection{Calculating secondary fields [post4]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{inp_pv.th_45n.eps}
\end{minipage}
\hspace{0cm}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{out_pv.th_45n.eps}
\end{minipage}
\\[-1.5cm]
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{inp_pv_350hPa.eps}
\end{minipage}
\hspace{0cm}
\begin{minipage}[t]{7.8cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{out_pv_350hPa.eps}
\end{minipage}
\\[-1.5cm]
\caption{\it Comparison of original (with PV streamer, left) and modified (without PV streamer, right)
potential temperature and PV in a west/east cross section along the $45^\circ$\,N latitude circle (top panels)
and PV at 350\,hPa (bottom panels)}
\label{compares}
\end{center}
\end{figure}
 
In this last step, Ertel's PV and potential temperature are calculated on the ECMWF grid. This allows
to directly check whether the PV anomaly was removed and to investigate how the corresponding potential temperature is
changed in the absence of the PV anomaly. The call to this step is:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh post4
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The program creates the S file and writes the following two fields onto it:\\[-0.3cm]
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
TH & Potential temperature ($K$) & S20060116\_18 \\
PV & Ertel's PV ($pvu$) & S20060116\_18 \\
\hline
\end{tabular}
\end{center}
 
\vspace{0.3cm}
\noindent
Figure~\ref{compares} shows a direct comparison of the input and of the output Ertel-PV and potential temperature.
It can clearly be seen that the stratospheric PV streamer is essentially removed from the output
file. Moreover, the potential temperature is considerably changed. Whereas in the presence of the
PV streamer the isolines of potential temperature are pulled upwards, they are much more horizontally
aligned in its absence. This "vacuum cleaner" effect of upper-level PV structures is well documented
and predicted by theoretical considerations (see also Fig.\,2 in section~1).
 
 
% ----------------------------------------------------------------------------------------------
% PV Inversion for Idealised Cases
% ----------------------------------------------------------------------------------------------
 
\newpage
 
 
\section{Diagnostic Tools}
 
\subsection{A consistency check for the boundary condition [diag1]}
 
The problem posed by the inversion equations constitutes a von Neumann boundary value problem.
It has only a solution if some additional conditions are fulfilled between the interior PV distribution and the values of potential temperature on the upper and lower boundaries and the values of horizontal wind components on the lateral sides of the inversion domain. What follows is a
detailed description of these additional requirements. The discussion very closely follows the one given
in Fehlmann (1997).\\
 
\noindent
To facilitate the derivation, let's define a new vertical co-ordinate such theta the quasi-geostrophic PV q can be expressed as the divergence of a vector field $\vec{E}$. Let\\[-0.2cm]
 
\[
\eta(z) = - \frac{p_0(z)}{g f^2} \quad \quad \mbox{and} \quad \quad
\Delta_h = \frac{\partial^2}{\partial x^2} + \frac{\partial^2}{\partial y^2}
\]
 
\vspace{0.3cm}
\noindent
where $p_o(z)$ is the reference profile of pressure, $f$ is the Coriolis parameter and $g$ is the Earth's gravity. Note that $\eta$ is a scaled pressure co-ordinate. If we use the hydrostatic assumption $\partial{\eta}/{\partial z} = \rho_0/f^2$, the following expression for the quasi-geostrophic PV q results:
 
\[
q = \Delta_h\psi + \frac{\partial}{\partial \eta} ( \frac{\rho_0^2}{f^2 N_0^2}
\cdot \frac{\partial \psi}{\partial \eta} )
\]
 
\vspace{0.3cm}
\noindent
Here, $\rho_o(z)$ and $N_o^2(z)$ are the reference profiles of density and squared Brunt-Vais\"al\"a frequency,
respectively, and $\psi$ is the streamfunction. Hence, q is now expressed as the divergence of a vector field ${\vec E}$, and Gauss' theorem can be
applied:
 
\[
\int_G q(x,y,\eta) dx dy d\eta = \int_{\partial G} \vec{E}(x,y,\eta) \vec{d\sigma} \quad \quad
\mbox{with} \quad \quad
\vec{E} = ( \frac{\partial \psi}{\partial x}, \frac{\partial \psi}{\partial y},
\frac{\rho_0^2}{f^2 N_0^2} \cdot \frac{\partial \psi}{\partial \eta} )
\]
 
\vspace{0.3cm}
\noindent
Note that this integration has to be carried out in the co-ordinate system (x,y,$\eta$). If we now specify
the inversion domain B as a two-dimensional domain in the (x,y)-plane and $[z_a,z_b]$ be the vertical domain, then $G=B \times [z_a,z_b]$ in the Cartesian space. This compatibility condition can be
transformed back into the Cartesian co-ordinate system and the integration be split over the boundary of
the domain G into an integration over the surface, the lid and the lateral boundaries of the domain. It then
follows that
 
\begin{eqnarray*}
\int_G \rho_0(z) q(x,y,z) dx dy dz & = &
\int _{z_a}^{z_b} (\int_{\partial B} \vec{v}(x,y,z) \cdot \vec{dr} ) \rho_0(z) dz\\[4mm]
& - & \int_B \frac{\rho_0(z_a) g f \theta^*(x,y,z_a)}{\theta_0(z_a) N_0^2(z_a)} dx dy \\[4mm]
& + & \int_B \frac{\rho_0(z_b) g f \theta^*(x,y,z_b)}{\theta_0(z_b) N_0^2(z_b)} dx dy \\
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
Only if this condition is fulfilled, does there exist a unique solution (up to a constant). This means
that not every formulation of the inversion problem needs to have a solution.\\
 
\noindent
The inversion program has to check whether the just discussed integral constraint is fulfilled to
satisfactory accuracy. In order to estimate, how big these inconsistencies really are, we ask for a constant perturbation potential temperature $\theta^*$ which is needed in order to fulfill the integral
constraint. If readily follows from the above discussion that this value is:
 
\begin{eqnarray*}
\theta^* & = &
( \int_G \rho_0(z) q(x,y,z) dx dy dz -
\int _{z_a}^{z_b} (\int_{\partial B} \vec{v}(x,y,z) \cdot \vec{dr} ) \rho_0(z) dz )\\[4mm]
& &
(
- \int_B \frac{\rho_0(z_a) g f}{\theta_0(z_a) N_0^2(z_a)} dx dy
+ \int_B \frac{\rho_0(z_b) g f}{\theta_0(z_b) N_0^2(z_b)} dx dy )^{-1}\\
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
If this quantity is calculated for the present example, $\theta^*=$-2.8\,K results. This value seems
sufficiently small that problem can be solved despite the inconsistency. But note that the problems due
to the ill-posedness of the problem are not well understood (see references in Fehlmann, 1997).\\
 
\noindent
The program handling the consistency check related to the boundary values is:\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh diag1
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The output from this program is given in the following table (the labels A,B,C and D are entered for easier
reference in the text):\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
A integ = 1.7558686E+12
B denombot = 5.6644076E+11
C denomtop = 5.9614413E+09
D denom = -5.6047934E+11
theta adjustment = -3.132798
theta shift @ top = 0.000000 613.2715
theta shift @ bot = 0.000000 271.9355
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
The first line is the integral which includes the quasi-geostrophic PV in the interior, the
velocity integrals on the laterals boundaries and the potential temperature integrals at the
lower and upper boundary:
 
\begin{eqnarray*}
A & = & \int_G \rho_0(z) q(x,y,z) dx dy dz -
\int _{z_a}^{z_b} (\int_{\partial B} \vec{v}(x,y,z) \cdot \vec{dr} ) \rho_0(z) dz\\[6mm]
& & + \int_B \frac{\rho_0(z_a) g f \theta^*(x,y,z_a)}{\theta_0(z_a) N_0^2(z_a)} dx dy
- \int_B \frac{\rho_0(z_b) g f \theta^*(x,y,z_b)}{\theta_0(z_b) N_0^2(z_b)} dx dy \\
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
In exact fulfillment of the integral constraint, this term A would vanish, i.e. $A=0$.
The second and third line give the integrals over the upper and lower boundary only:
 
\begin{eqnarray*}
B & = & \int_B \frac{\rho_0(z_a) g f \theta^*(x,y,z_a)}{\theta_0(z_a) N_0^2(z_a)} dx dy\\[6mm]
C & = & \int_B \frac{\rho_0(z_b) g f \theta^*(x,y,z_b)}{\theta_0(z_b) N_0^2(z_b)} dx dy\\
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
The difference between these two lines is the contents of the next line:
 
\begin{eqnarray*}
D & = & \int_B \frac{\rho_0(z_a) g f \theta^*(x,y,z_a)}{\theta_0(z_a) N_0^2(z_a)} dx dy
- \int_B \frac{\rho_0(z_b) g f \theta^*(x,y,z_b)}{\theta_0(z_b) N_0^2(z_b)} dx dy\\
\end{eqnarray*}
 
\noindent
Note that this term D corresponds to the last two terms in expression~A.
With these expressions an estimate can be made for the correction which would eliminate the inconsistency
of the boundary conditions with respect to the interior distribution of quasi-geostrophic PV. This adjustment
of potential temperature is the next line
 
\begin{eqnarray*}
\theta^* & = & A / D
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
and corresponds with the aforementioned expression for $\theta^*$.
Finally, in the last two lines the shift in potential temperature at the upper and at the
lower boundary is given, together with the mean potential temperatures at these two boundaries.
At the moment, no shift (value 0 in the output lines) is performed, i.e. the inconsistency in the boundary conditions
is not "solved".
 
 
\subsection{Convergence of the quasi-geostrophic inversion [diag2]}
 
The key numerical algorithm is the inversion of the quasi-geostrophic PV equation (see section~4.5.3).
It relates the PV to the streamfunction by\\[-0.3cm]
 
\[
q_a = \frac{\partial^2\psi}{\partial x^2} + \frac{\partial^2\psi}{\partial y^2} +
\frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z} ( \frac{\rho_0}{N_0^2}
\cdot \frac{\partial \psi}{\partial z}
\]
 
\vspace{0.3cm}
\noindent
with the boundary conditions of potential temperature at the lower and upper lid, and of horizontal wind
components at the lateral sides of the inversion domain:\\[-0.3cm]
 
\[
g \cdot \frac{\theta^*}{\theta_0} = f \cdot \frac{\partial \psi}{\partial z}
\quad \quad
u = -\frac{\partial \psi}{\partial y}
\quad \quad
v = \frac{\partial \psi}{\partial x}
\]
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{8.3cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{qgpv_k35_calc.eps}
\end{minipage}
\hspace{-1cm}
\begin{minipage}[t]{8.3cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{qgpv_k35_spec.eps}
\end{minipage}
\\
\caption{\it Comparison of calculated (left) and pre-described (right) quasi-geostrophic PV. }
\label{compqg}
\end{center}
\end{figure}
 
\vspace{0.3cm}
\noindent
The numerical solution by means of the successive over-relaxation (SOR) technique
then completely determines the perturbations of potential temperature and of horizontal wind. These meteorological fields can be expressed
in the following way by the streamfunction (see also section~2):
 
\begin{eqnarray*}
\theta^* & = & \frac{f}{g} \cdot \theta_0 \cdot \frac{\partial \psi}{\partial z}\\
u & = & - \frac{\partial \psi}{\partial y}\\
v & = & \frac{\partial \psi}{\partial x}\\
\end{eqnarray*}
 
\vspace{0.3cm}
\noindent
This allows a simple test whether the inversion of the quasi-geostrophic equation was successful. Indeed, the
quasi-geostrophic PV can be calculated from the perturbation fields:
 
\[
q_c = \frac{\partial^2\psi}{\partial x^2} + \frac{\partial^2\psi}{\partial y^2} +
\frac{f^2}{\rho_0} \cdot \frac{\partial}{\partial z} ( \frac{\rho_0}{N_0^2}
\cdot \frac{\partial \psi}{\partial z})
\]
 
\vspace{0.3cm}
\noindent
If the inversion was successful, this calculated quasi-geostrophic PV ($q_c$) must coincide with the
pre-described PV ($q_a$). For the present case study, the validation is shown in Fig.\,\ref{compqg} for the first step
of the iteration. The two panels show the calculated and the pre-described PV, respectively, and it becomes
immediately clear that a reasonable degree of convergence was reached.\\
 
 
\noindent
The calculation of the quasi-geostrophic PV is accomplished with the call\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
inversion.sh diag2 ANO
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
where the second argument (ANO) specifies that the ANO\_20060116\_18 file is taken for the
calculation. It is implictely assumed that the reference file is available on the corresponding REF file. The output of the calculation is then written to the same ANO\_20060116\_18 file,
with the name QGPV\_DIAG. Hence the table of modified fields and files is:
 
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
QGPV\_DIAG & Calculated quasi-geostrophic PV ($1/s$) & ANO\_20060116\_18 \\
\hline
\end{tabular}
\end{center}
\vspace{0.3cm}
 
\subsection{Difference between two files [diag3]}
 
\begin{figure}[t]
\begin{center}
\begin{minipage}[t]{16cm}
\vspace{-1cm}
\ForceWidth{1.0\textwidth}
\BoxedEPSF{difference.eps}
\end{minipage}
\\[-0.5cm]
\caption{\it Difference between the ORG and the MOD file in a vertical cross section. In color, the difference of the meridional
wind velocity is shown. The difference of potential temperature is given by the thin lines (black:positive,
blue:negative). The bold black line is the 2.5 isoline of the difference of Ertel's PV. }
\label{diff}
\end{center}
\end{figure}
 
The impact of a PV anomaly is most easily determined if the meteorological fields (temperature, velocity,
pressure,...) in the presence of the anomaly is subtracted from the corresponding fields in the absence
of the anomaly. The change in the meteorological fields can then be attributed to the PV anomaly. In order
to facilitate this with/without comparison, a diagnostic tool is provide which calculates the difference.
For instance, the call to
\begin{center}
\begin{minipage}[t]{11cm}
\begin{verbatim}
inversion.sh diag3 ORG MOD
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
takes the ORG and MOD file in the run directory and calculates the difference of all fields which
are available on both input files. The difference fields are then written to a new file with prefix DIA.
An example is shown in Fig.\,\ref{diff}.
 
% ---------------------------------------------------------------------------------------------
% Final Remarks
% ---------------------------------------------------------------------------------------------
 
\newpage
 
\section{Final Remarks and Outlook}
 
Several additional extensions are possible for the PV inversion tool introduced in this study. Most of them will attract a lot of interest in the research and education community. Some extensions which are and will be undertaken recently in our institute are:
 
\begin{itemize}
\item [a] The PV inversion is not only of interest in real-case studies, as was described in this work. Considerable insight can also be gained by looking at highly idealised experiments. Such experiments enforce the existence of a tool which allows to set set up them. In the course of this diploma thesis, such a tool was developed. However, it was considered to be preferable to limit
the thesis's documentation itself to the real-case experiments.\\
\item [b] Removing and adding, or more generally modifying the initial PV distribution, is particularly interesting if the modified state of the atmosphere is used as the input -initial
and boundary values- for a regional weather prediction model. This kind of experiments allows to
assess in a quantitative way how the PV field influences the future weather development. In parallel to this thesis a program package has been developed at the Institute for Atmospheric and Climate Science at ETH Zurich (IACETH) which allows to transform
the (modified) P files of the PV inversion directly into the input and boundary files for the
Climate HRM model. It is the aim that some case studies will be undertaken in this way by a
diploma student at our institute.\\
\item [c] From the quasi-geostrophic omega equation it is well known that PV structures are able to
enforce vertical motions. These are particularly interesting because vertical motion leads to
condensation or convective instability, if the vertical temperature and humidity profile are suitable. Therefore,
it would be of great interest to see how the modified PV distribution is associated with different
vertical motions. Technically this means that an additional equation, the aforementioned
quasi-geostrophic omega equation, has to be solved. In the coming summer semester, a student with focus on scientific
programming will attack this problem.\\
\item [d] Teaching atmospheric dynamics at the graduate level involves several challenges. One
particular challenge is associated with the abstract concept of potential vorticity. An easy-to-use
PV inversion tool might be of great relieve to the teacher since he can easily illustrate and
apply the concepts to real and idealised cases. It is quite certain that such a visualisation help
would be much appreciated by graduate students in atmospheric dynamics. It is one aim of the
dynamic's group at {\it IAC}ETHto improve teaching in this respect, while keeping the mathematical and physical
level of the taught contents.
\end{itemize}
 
 
\newpage
\section{Acknowledgment}
 
 
There are many persons which need to be mentioned in this acknowledgment. Perhaps, most crucially is
a heartily thanks to Rene Fehlmann who initially developed the inversion tool. I had the joy to start my atmospheric research under Rene's supervision, and his enthusiasm for mathematics, numerics and atmosphere
always was and still is very inspiring for me. \\
 
\noindent
Recently I read that success in science cannot be attributed solely to one's own intelligence an
"superiority". And with my long experience in science, I fully agree with that statement. Success needs
luck, and last but not least it needs excellent teachers, supervisors and colleagues. I had the great pleasure
to work together and get help from excellent scientists and teachers: Christoph Sch\"ar, Heini Wernli and Huw Davies. I appreciated very much their scientific qualities, but probably still more their warmth and
friendliness as colleagues.\\
 
\noindent
Many research colleagues were indirectly important in the development of this PV inversion tool. Conny Schwierz, Olivia Martius, Mischa Croci-Maspoli, Sarah Kew. Certainly, thanks should also go to Linda Schlemmer who
accepted a diploma thesis based on this tool, and is now testing all aspects of it.\\
 
\noindent
Finally, this work was done in the frame of the postgraduate course in Computer Science at the Fernfachhochschule Schweiz. Thanks goes to all teachers, and in particular to Lars Kruse who accepted to supervise this diploma thesis and discussed with me the different steps. Although we had some
different views what should be included into this thesis ("Why do you want to send this part to the appendix? This is a diploma thesis,...") I enjoyed working with him, particularly because of his interest in the atmospheric sciences.
 
 
\newpage
\section{References}
 
\noindent
{\bf [1]} Acheson, D.\,J., 1990:
Elementary Fluid Dynamics.
{\sl Oxford Applied Mathematics and Computing Science Series,}, Oxford UP, 395pp.\\
 
\noindent
{\bf [2]} Appenzeller, C., H.~C.~Davies, and W.~A.~Norton, 1996:
Fragmentation of stratospheric intrusions.
{\sl J.~Geophys.~Res.,} {\bf 101,} 1435-1456.\\
 
\noindent
{\bf [3]} Hoskins, B.\,J., M.\,E.\,McIntyre, and A.\,W.\,Robertson, 1985:
On the use and significance of isentropic potential vorticity maps. Quart.\,J.\,Roy.\,Meteor.\,Soc.,{\bf 111}, 877-946.\\
 
\noindent
{\bf [4]} Bluestein,\,H.\,B., 1993:
Synoptic-Dynamic Meteorology in Midlatitudes. Volume II: Observations and Theory of Weather Systems, Oxford University Press, {594 pp}.\\
 
\noindent
{\bf [5]} Charney, J.\,B., 1993:
On the scale of atmospheric motions. Geofysisk.\,Publ.,{\bf 17}, No.\,2.\\
 
\noindent
{\bf [6]} Davis, C.\,A., 1992:
Piecewise potential vorticity inversion. J.\,Atmos.\,Sci., {\bf 49}, 1397-1411.\\
 
\noindent
{\bf [7]} Davis, C.\,A., and K.\,A.\,Emanuel, 1992:
Potential vorticity diagnostic of cyclogenesis. Mon.\,Wea.\,Rev., {\bf 119}, 1929-1953.\\
 
\noindent
{\bf [8]} Ertel, H., 1942:
Ein neuer hydrodynamischer Wirbelsatz. Meteor.\,Z., {\bf 59}, 277-281.\\
 
\noindent
{\bf [9]} Fehlmann, R., 1997:
Dynamics of seminal PV elements.
PhD thesis No. 12229, ETH Z\"urich, 143 pp.\\
 
\noindent
{\bf [10]} Fehlmann, R. and H.\,C.\,Davies, 1997:
Misforecasts of synoptic systems: Diagnosis via PV retrodiction. Mon.\,Wea.\,Rev., {\bf 125}, 2247-2264.\\
 
 
\noindent
{\bf [11]} Holton, J.\,R., 1992:
An Introduction to Dynamic Meteorology. Third Edition.
Academic Press, San Diego, California, 511pp.\\
 
\noindent
{\bf [12]} Kleinschmidt, E., 1950:
\"Uber Aufbau und Entstehung von Zyklonen. Teil 1. Meteor.\,Rundsch., {\bf 3}, 1-6.\\
 
\noindent
{\bf [13]} Martius, O., E.\,Zenklusen, C. Schwierz, and H.\,C.\,Davies 2006:
Episodes of alpine heavy precipitation with an overlying elongated stratospheric intrusion: a climatology. Intl.\,J.\,Climatology., {\bf Vol. 96, Issue 9}, 1149-1164.\\
 
\noindent
{\bf [14]} McIntyre, M., 1997:
GEFD (Geophysical and Environmental Fluid Dynamics) Summer School, DAMPTP University of Cambridge.\\
 
\noindent
{\bf [15]} Lynch, P., 2006:
The Emergence of Numerical Weather Prediction. Richardson's Dream.
Cambridge UP, Cambridge, UK. 279pp.\\
 
\noindent
{\bf [16]} Nebeker, F., 1995:
Calculating the Weather. Meteorology in the 20th Century..
Academic Press, San Diego, California, 255pp.\\
 
\noindent
{\bf [17]} Press, W.\,H., Flannery, B.\,P., Teukolsky, S.\,A., and Vetterling, W.\,T., 1992:
Numerical Recipes in FORTRAN: The Art of Scientific Computing.
Cambridge University Press, Cambridge, UK, 1447pp.\\
 
 
\noindent
{\bf [18]} Sprenger, M.~and H.~Wernli, 2003:
A northern hemispheric climatology of cross-tropopause exchange for the ERA15
time period (1979-1993).
{\sl J.~Geophys.~Res.,} {\bf 108}(D12), 8521, doi:10.1029/2002JD002636.\\
 
\noindent
{\bf [19]} Stohl, A., P. Bonasoni, P. Cristofanelli, W. Collins, J. Feichter,
A. Frank, C. Forster, E. Gerasopoulos, H. G\"uggeler, P. James,
T. Kentarchos, H. Kromp-Kolb, B. Kr\"uger, C. Land, J. Meloen,
A. Papayannis, A. Priller, P. Seibert, M. Sprenger, G. J. Roelofs,
H. E. Scheel, C. Schnabel, P. Siegmund, L. Tobler, T. Trickl,
H. Wernli, V. Wirth, P. Zanis, and C. Zerefos: 2003.
Stratosphere-troposphere exchange: A review, and what we have learned from STACCATO.
J.\,Geophys.\,Res.,{\bf Vol. 108}, No. D12, 8516, doi:10.1029/2002JD002490.\\
 
 
\noindent
{\bf [20]} Wallace, J.\,M. and P.\,V.\,Hobbs, R., 1977:
Atmospheric Science. An Introductory Survey.
Academic Press, San Diego, California, 467pp.\\
 
 
 
\newpage
\section{Appendix}
 
\subsection{Scalar co-ordinate transformation}
 
Four real function are needed for the transformation between the geographical latitude/-longitude grid
used by ECMWF and the quasi-cartesian grid used by the PV inversion. Physically the new quasi-cartesian
co-ordinate system is obtained by introducing a new latitude/longitude grid, but now the two co-ordinates
being defined relative to a rotated north pole. Therefore, the new longitude and latitude are referred to as rotated co-ordinates. The position (in geographical latitude and longitude) of the new north pole is given as parameters POLPHI and POLLAM. Then, the functions\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
LAM = REAL FUNCTION LMSTOLM (PHIS, LAMS, POLPHI, POLLAM)
PHI = REAL FUNCTION PHSTOPH (PHIS, LAMS, POLPHI, POLLAM)
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
relate the rotated latitude (PHIS) and longitude (LAMS) to corresponding latitude (PHI) and
longitude (LAM) in the geographical system. Correspondingly, the following two functions give
the reverse transformation, i.e. to every position in geographical latitude/longitude a rotated
pair of co-ordinates is attributed. Again, the pole position (in the geographical grid) must be
passed as parameters (POLPHI and POLLAT).\\[-0.3cm]
\begin{center}
\begin{minipage}[t]{13cm}
\begin{verbatim}
LAMS = REAL FUNCTION LMTOLMS (PHI, LAM, POLPHI, POLLAM)
PHIS = REAL FUNCTION PHTOPHS (PHI, LAM, POLPHI, POLLAM)
\end{verbatim}
\end{minipage}
\end{center}
 
\vspace{0.3cm}
\noindent
Here, the geographical co-ordinates (PHI, LAM) are transformed into rotated co-ordinates (PHIS, LAMS).
If the corresponding pair of coordinates are given, any scalar field can easily be transformed. The following
Fortran functions are taken from the source code from the numerical weather prediction model of the German/Swiss weather service.
 
 
\begin{small}
\begin{verbatim}
C -------------------------------------------------------------------------
REAL FUNCTION LMSTOLM (PHIS, LAMS, POLPHI, POLLAM)
C -------------------------------------------------------------------------
C
C**** LMSTOLM - FC:BERECHNUNG DER WAHREN GEOGRAPHISCHEN LAENGE FUER
C**** EINEN PUNKT MIT DEN KOORDINATEN (PHIS, LAMS)
C**** IM ROTIERTEN SYSTEM. DER NORDPOL DES SYSTEMS HAT
C**** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** AUFRUF : LAM = LMSTOLM (PHIS, LAMS, POLPHI, POLLAM)
C** ENTRIES : KEINE
C** ZWECK : BERECHNUNG DER WAHREN GEOGRAPHISCHEN LAENGE FUER
C** EINEN PUNKT MIT DEN KOORDINATEN (PHIS, LAMS)
C** IM ROTIERTEN SYSTEM. DER NORDPOL DIESES SYSTEMS HAT
C** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** VERSIONS-
C** DATUM : 03.05.90
C**
C** EXTERNALS: KEINE
C** EINGABE-
C** PARAMETER: PHIS REAL GEOGR. BREITE DES PUNKTES IM ROT.SYS.
C** LAMS REAL GEOGR. LAENGE DES PUNKTES IM ROT.SYS.
C** POLPHI REAL WAHRE GEOGR. BREITE DES NORDPOLS
C** POLLAM REAL WAHRE GEOGR. LAENGE DES NORDPOLS
C** AUSGABE-
C** PARAMETER: WAHRE GEOGRAPHISCHE LAENGE ALS WERT DER FUNKTION
C** ALLE WINKEL IN GRAD (NORDEN>0, OSTEN>0)
C**
C** COMMON-
C** BLOECKE : KEINE
C**
C** FEHLERBE-
C** HANDLUNG : KEINE
C** VERFASSER: D.MAJEWSKI
REAL LAMS,PHIS,POLPHI,POLLAM
DATA ZRPI18 , ZPIR18 / 57.2957795 , 0.0174532925 /
ZSINPOL = SIN(ZPIR18*POLPHI)
ZCOSPOL = COS(ZPIR18*POLPHI)
ZLAMPOL = ZPIR18*POLLAM
ZPHIS = ZPIR18*PHIS
ZLAMS = LAMS
IF(ZLAMS.GT.180.0) ZLAMS = ZLAMS - 360.0
ZLAMS = ZPIR18*ZLAMS
ZARG1 = SIN(ZLAMPOL)*(- ZSINPOL*COS(ZLAMS)*COS(ZPHIS) +
1 ZCOSPOL* SIN(ZPHIS)) -
2 COS(ZLAMPOL)* SIN(ZLAMS)*COS(ZPHIS)
ZARG2 = COS(ZLAMPOL)*(- ZSINPOL*COS(ZLAMS)*COS(ZPHIS) +
1 ZCOSPOL* SIN(ZPHIS)) +
2 SIN(ZLAMPOL)* SIN(ZLAMS)*COS(ZPHIS)
IF (ABS(ZARG2).LT.1.E-30) THEN
IF (ABS(ZARG1).LT.1.E-30) THEN
LMSTOLM = 0.0
ELSEIF (ZARG1.GT.0.) THEN
LMSTOLAM = 90.0
ELSE
LMSTOLAM = -90.0
ENDIF
ELSE
LMSTOLM = ZRPI18*ATAN2(ZARG1,ZARG2)
ENDIF
RETURN
END
C -------------------------------------------------------------------------
REAL FUNCTION PHSTOPH (PHIS, LAMS, POLPHI, POLLAM)
C -------------------------------------------------------------------------
C
C**** PHSTOPH - FC:BERECHNUNG DER WAHREN GEOGRAPHISCHEN BREITE FUER
C**** EINEN PUNKT MIT DEN KOORDINATEN (PHIS, LAMS) IM
C**** ROTIERTEN SYSTEM. DER NORDPOL DIESES SYSTEMS HAT
C**** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** AUFRUF : PHI = PHSTOPH (PHIS, LAMS, POLPHI, POLLAM)
C** ENTRIES : KEINE
C** ZWECK : BERECHNUNG DER WAHREN GEOGRAPHISCHEN BREITE FUER
C** EINEN PUNKT MIT DEN KOORDINATEN (PHIS, LAMS) IM
C** ROTIERTEN SYSTEM. DER NORDPOL DIESES SYSTEMS HAT
C** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** VERSIONS-
C** DATUM : 03.05.90
C**
C** EXTERNALS: KEINE
C** EINGABE-
C** PARAMETER: PHIS REAL GEOGR. BREITE DES PUNKTES IM ROT.SYS.
C** LAMS REAL GEOGR. LAENGE DES PUNKTES IM ROT.SYS.
C** POLPHI REAL WAHRE GEOGR. BREITE DES NORDPOLS
C** POLLAM REAL WAHRE GEOGR. LAENGE DES NORDPOLS
C** AUSGABE-
C** PARAMETER: WAHRE GEOGRAPHISCHE BREITE ALS WERT DER FUNKTION
C** ALLE WINKEL IN GRAD (NORDEN>0, OSTEN>0)
C**
C** COMMON-
C** BLOECKE : KEINE
C**
C** FEHLERBE-
C** HANDLUNG : KEINE
C** VERFASSER: D.MAJEWSKI
REAL LAMS,PHIS,POLPHI,POLLAM
DATA ZRPI18 , ZPIR18 / 57.2957795 , 0.0174532925 /
SINPOL = SIN(ZPIR18*POLPHI)
COSPOL = COS(ZPIR18*POLPHI)
ZPHIS = ZPIR18*PHIS
ZLAMS = LAMS
IF(ZLAMS.GT.180.0) ZLAMS = ZLAMS - 360.0
ZLAMS = ZPIR18*ZLAMS
ARG = COSPOL*COS(ZPHIS)*COS(ZLAMS) + SINPOL*SIN(ZPHIS)
PHSTOPH = ZRPI18*ASIN(ARG)
RETURN
END
C -------------------------------------------------------------------------
REAL FUNCTION LMTOLMS (PHI, LAM, POLPHI, POLLAM)
C -------------------------------------------------------------------------
C
C%Z% Modul %M%, V%I% vom %G%, extrahiert am %H%
C
C**** LMTOLMS - FC:UMRECHNUNG DER WAHREN GEOGRAPHISCHEN LAENGE LAM
C**** AUF EINEM PUNKT MIT DEN KOORDINATEN (PHIS, LAMS)
C**** IM ROTIERTEN SYSTEM. DER NORDPOL DES SYSTEMS HAT
C**** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** AUFRUF : LAM = LMTOLMS (PHI, LAM, POLPHI, POLLAM)
C** ENTRIES : KEINE
C** ZWECK : UMRECHNUNG DER WAHREN GEOGRAPHISCHEN LAENGE LAM AUF
C** EINEM PUNKT MIT DEN KOORDINATEN (PHIS, LAMS) IM
C** ROTIERTEN SYSTEM. DER NORDPOL DIESES SYSTEMS HAT
C** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** VERSIONS-
C** DATUM : 03.05.90
C**
C** EXTERNALS: KEINE
C** EINGABE-
C** PARAMETER: PHI REAL BREITE DES PUNKTES IM GEOGR. SYSTEM
C** LAM REAL LAENGE DES PUNKTES IM GEOGR. SYSTEM
C** POLPHI REAL GEOGR.BREITE DES N-POLS DES ROT. SYSTEMS
C** POLLAM REAL GEOGR.LAENGE DES N-POLS DES ROT. SYSTEMS
C** AUSGABE-
C** PARAMETER: WAHRE GEOGRAPHISCHE LAENGE ALS WERT DER FUNKTION
C** ALLE WINKEL IN GRAD (NORDEN>0, OSTEN>0)
C**
C** COMMON-
C** BLOECKE : KEINE
C**
C** FEHLERBE-
C** HANDLUNG : KEINE
C** VERFASSER: G. DE MORSIER
REAL LAM,PHI,POLPHI,POLLAM
DATA ZRPI18 , ZPIR18 / 57.2957795 , 0.0174532925 /
ZSINPOL = SIN(ZPIR18*POLPHI)
ZCOSPOL = COS(ZPIR18*POLPHI)
ZLAMPOL = ZPIR18*POLLAM
ZPHI = ZPIR18*PHI
ZLAM = LAM
IF(ZLAM.GT.180.0) ZLAM = ZLAM - 360.0
ZLAM = ZPIR18*ZLAM
ZARG1 = - SIN(ZLAM-ZLAMPOL)*COS(ZPHI)
ZARG2 = - ZSINPOL*COS(ZPHI)*COS(ZLAM-ZLAMPOL)+ZCOSPOL*SIN(ZPHI)
IF (ABS(ZARG2).LT.1.E-30) THEN
IF (ABS(ZARG1).LT.1.E-30) THEN
LMTOLMS = 0.0
ELSEIF (ZARG1.GT.0.) THEN
LMTOLMS = 90.0
ELSE
LMTOLMS = -90.0
ENDIF
ELSE
LMTOLMS = ZRPI18*ATAN2(ZARG1,ZARG2)
ENDIF
RETURN
END
 
C -------------------------------------------------------------------------
REAL FUNCTION PHTOPHS (PHI, LAM, POLPHI, POLLAM)
C -------------------------------------------------------------------------
C
C%Z% Modul %M%, V%I% vom %G%, extrahiert am %H%
C
C**** PHTOPHS - FC:UMRECHNUNG DER WAHREN GEOGRAPHISCHEN BREITE PHI
C**** AUF EINEM PUNKT MIT DEN KOORDINATEN (PHIS, LAMS)
C**** IM ROTIERTEN SYSTEM. DER NORDPOL DES SYSTEMS HAT
C**** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** AUFRUF : PHI = PHTOPHS (PHI, LAM, POLPHI, POLLAM)
C** ENTRIES : KEINE
C** ZWECK : UMRECHNUNG DER WAHREN GEOGRAPHISCHEN BREITE PHI AUF
C** EINEM PUNKT MIT DEN KOORDINATEN (PHIS, LAMS) IM
C** ROTIERTEN SYSTEM. DER NORDPOL DIESES SYSTEMS HAT
C** DIE WAHREN KOORDINATEN (POLPHI, POLLAM)
C** VERSIONS-
C** DATUM : 03.05.90
C**
C** EXTERNALS: KEINE
C** EINGABE-
C** PARAMETER: PHI REAL BREITE DES PUNKTES IM GEOGR. SYSTEM
C** LAM REAL LAENGE DES PUNKTES IM GEOGR. SYSTEM
C** POLPHI REAL GEOGR.BREITE DES N-POLS DES ROT. SYSTEMS
C** POLLAM REAL GEOGR.LAENGE DES N-POLS DES ROT. SYSTEMS
C** AUSGABE-
C** PARAMETER: ROTIERTE BREITE PHIS ALS WERT DER FUNKTION
C** ALLE WINKEL IN GRAD (NORDEN>0, OSTEN>0)
C**
C** COMMON-
C** BLOECKE : KEINE
C**
C** FEHLERBE-
C** HANDLUNG : KEINE
C** VERFASSER: G. DE MORSIER
REAL LAM,PHI,POLPHI,POLLAM
DATA ZRPI18 , ZPIR18 / 57.2957795 , 0.0174532925 /
ZSINPOL = SIN(ZPIR18*POLPHI)
ZCOSPOL = COS(ZPIR18*POLPHI)
ZLAMPOL = ZPIR18*POLLAM
ZPHI = ZPIR18*PHI
ZLAM = LAM
IF(ZLAM.GT.180.0) ZLAM = ZLAM - 360.0
ZLAM = ZPIR18*ZLAM
ZARG = ZCOSPOL*COS(ZPHI)*COS(ZLAM-ZLAMPOL) + ZSINPOL*SIN(ZPHI)
PHTOPHS = ZRPI18*ASIN(ZARG)
RETURN
END
\end{verbatim}
\end{small}
 
\newpage
\subsection{Controlling Linux Shell Script}
 
In this appendix the controlling Linux Shell script of the PV inversion is reproduced. This script
offers a user-friendly interface to the inversion. It is essentially split into five
different section: (1) installation and parameter settings, (2) preparatory steps, (3)
iterative solution of the PV inversion problem, (4) post-processing, and (5) diagnostic
tools.\\
\begin{small}
\begin{verbatim}
#!/bin/csh
 
# Master Linux script for PV inversion
# Michael Sprenger / Winter 2006,2007
 
# -------------------------------------------------------------------
# Set some variables and paths
# -------------------------------------------------------------------
 
# Handling of input parameters
set step="help"
if ( $#argv == 1 ) then
set step=$1
endif
if ( $#argv == 2 ) then
set step=$1
set file1=$2
endif
if ( $#argv == 3 ) then
set step=$1
set file1=$2
set file2=$3
endif
 
# Set base directory for programmes
set bdir=/home/sprenger/PV_Inversion_Tool/real/
 
# Set name of the parameter file, the coastline file and the sample files
set parafile="${PWD}/inversion.param"
set coastfile="${bdir}/prep/coastline.dat"
set sampledir="/net/rossby/lhome/sprenger/PV_Inversion_Tool/real/inp/"
 
# Extract parameters from parameter file
set progex=${bdir}/inversion.perl
set date=`${progex} ${parafile} date | awk '{ print $2}'`
set nofiter=`${progex} ${parafile} n_of_iteration | awk '{ print $2}'`
set save=`${progex} ${parafile} save_iteration | awk '{ print $2}'`
set idir=`${progex} ${parafile} inp_dir | awk '{ print $2}'`
set rdir=`${progex} ${parafile} run_dir | awk '{ print $2}'`
set odir=`${progex} ${parafile} out_dir | awk '{ print $2}'`
 
# ---------------------------------------------------------------------------
# Installation, help and sample
# ---------------------------------------------------------------------------
 
# Create the needed directories
if ( ${step} == "inst" ) then
if ( ! -d ${idir} ) mkdir ${idir}
if ( ! -d ${rdir} ) mkdir ${rdir}
if ( ! -d ${odir} ) mkdir ${odir}
endif
 
# Create the needed directories
if ( ${step} == "help" ) then
echo
echo "Installation"
echo " inst: Creates the input, run and output directory"
echo
echo "Sample case study"
echo " sample: Copy all files for a sample case study"
echo
echo "Preparing input files [prep]"
echo " prep0: Calculate S file with PV and TH"
echo " prep1: Interpolate onto height levels"
echo " prep2: Rotate into local cartesian co-ordinate system"
echo " prep3: Add TH,PV,NSQ and RHO to the data file"
echo " prep4: Define modified and anomaly PV field and boundary values"
echo " prep5: Reduce the domain size and split the input files"
echo " prep6: Add the reference profile"
echo " prep7: Add coastlines to REF file"
echo " prep8: Move the files to the run directory"
echo
echo "Perform the PV inversion [pvin]"
echo " pvin1: Add NSQ, TH, RHO, and PV"
echo " pvin2: Change Ertel's PV anomaly into one of quasi-geostrophic PV"
echo " pvin3: Inversion of quasi-geostrophic PV anomaly"
echo " pvin4: Subtract anomaly from MOD file"
echo " pvin5: Keep iterative steps if save flag is set"
echo
echo "Postprocessing [post]"
echo " post1: Copy needed files from input and run directory"
echo " post2: Rotate from quasi-cartesian co-ordinate frame to lat/lon system"
echo " post3: Bring modified fields back to P file"
echo " post4: Calculate S file with PV and TH"
echo " post5: Make clean"
echo
echo "Diagnostic Tools"
echo " diag1: Check the consistency of the boundary conditions"
echo " diag2: Calculate the quasi-geostrophic PV"
echo " diag3: Get the difference between two files"'
echo
endif
 
 
# Copy sample files (if specified)
if ( ${step} == "sample" ) then
\cp ${sampledir}/P20060116_18 ${idir}
\cp ${sampledir}/ml_cst ${idir}
\cp ${sampledir}/Z20060116_18 ${idir}
\cp ${sampledir}/pl_cst ${idir}
endif
 
# ---------------------------------------------------------------------------
# Preparatory steps
# ---------------------------------------------------------------------------
 
# Change to data directory
cd ${idir}
 
# Step 0: Calculate S file with PV and TH (not in prep mode)
if ( ${step} == "prep0" ) then
\rm -f S${date}
p2s P${date} TH PV
endif
 
# Step 1: Interpolate onto height levels
if ( ${step} == "prep1" | ${step} == "prep" ) then
echo "P${date}" >! fort.10
echo "Z${date}" >> fort.10
echo "H${date}" >> fort.10
${bdir}/inversion.perl ${parafile} p2z >> fort.10
echo "U U P${date}" >> fort.10
echo "V V P${date}" >> fort.10
echo "T T P${date}" >> fort.10
echo "Q Q P${date}" >> fort.10
${bdir}/prep/p2z
\mv H${date}_cst zl_cst
changecst H${date} zl_cst
#\rm -f fort.10
endif
 
# Step 2: Rotate into local cartesian co-ordinate system
if ( ${step} == "prep2" | ${step} == "prep" ) then
echo "H${date}" >! fort.10
echo "R${date}" >> fort.10
${bdir}/inversion.perl ${parafile} rotate_grid >> fort.10
echo "5" >> fort.10
echo "ORO" >> fort.10
echo "U.V" >> fort.10
echo "P" >> fort.10
echo "T" >> fort.10
echo "Q" >> fort.10
${bdir}/prep/rotate_grid
\mv R${date}_cst ro_cst
changecst R${date} ro_cst
\rm -f fort.10
endif
 
# Step 3: Add TH,PV,NSQ and RHO to the data file
if ( ${step} == "prep3" | ${step} == "prep" ) then
echo "TH" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
echo "PV" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
echo "NSQ" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
echo "RHO" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
\rm -f fort.10
endif
 
# Step 4: Set the modified PV field and boundary values
if ( ${step} == "prep4" | ${step} == "prep" ) then
echo "R${date}" >! fort.10
${bdir}/inversion.perl ${parafile} def_anomaly >> fort.10
${bdir}/prep/def_anomaly
\rm -f fort.10
endif
 
# Step 5: Reduce the domain size and split the input files
if ( ${step} == "prep5" | ${step} == "prep" ) then
echo "PV PV R${date} ORG_${date}" >! fort.10
echo "U U R${date} ORG_${date}" >> fort.10
echo "V V R${date} ORG_${date}" >> fort.10
echo "TH TH R${date} ORG_${date}" >> fort.10
echo "Q Q R${date} ORG_${date}" >> fort.10
echo "P P R${date} ORG_${date}" >> fort.10
echo "T T R${date} ORG_${date}" >> fort.10
echo "PV_FILT PV_AIM R${date} MOD_${date}" >> fort.10
echo "U U R${date} MOD_${date}" >> fort.10
echo "V V R${date} MOD_${date}" >> fort.10
echo "Q Q R${date} MOD_${date}" >> fort.10
echo "P P R${date} MOD_${date}" >> fort.10
echo "T T R${date} MOD_${date}" >> fort.10
echo "NSQ NSQ R${date} MOD_${date}" >> fort.10
echo "RHO RHO R${date} MOD_${date}" >> fort.10
echo "TH TH R${date} MOD_${date}" >> fort.10
echo "PV_ANOM PV R${date} ANO_${date}" >> fort.10
echo "TH_ANOM TH R${date} ANO_${date}" >> fort.10
echo "UU_ANOM U R${date} ANO_${date}" >> fort.10
echo "VV_ANOM V R${date} ANO_${date}" >> fort.10
echo "ORO ORO R${date} REF_${date}" >> fort.10
echo "X X R${date} REF_${date}" >> fort.10
echo "Y Y R${date} REF_${date}" >> fort.10
echo "LAT LAT R${date} REF_${date}" >> fort.10
echo "LON LON R${date} REF_${date}" >> fort.10
echo "CORIOL CORIOL R${date} REF_${date}" >> fort.10
${bdir}/prep/cutnetcdf
\rm -f fort.10
endif
 
# Step 6: Add the reference profile
if ( ${step} == "prep6" | ${step} == "prep" ) then
\rm -f fort.10
echo "MOD_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/prep/ref_profile
\rm -f fort.10
endif
 
# Step 7: Add coastlines to REF file
if ( ${step} == "prep7" | ${step} == "prep" ) then
\rm -f fort.10
echo \"REF_${date}\" >! fort.10
echo \"${coastfile}\" >> fort.10
${bdir}/inversion.perl ${parafile} coastline >> fort.10
${bdir}/prep/coastline
\rm -f fort.10
endif
 
# Step 8: Move the files to the run directory
if ( ${step} == "prep8" | ${step} == "prep" ) then
\mv MOD_${date} MOD_${date}_cst ${rdir}
\mv ORG_${date} ORG_${date}_cst ${rdir}
\mv ANO_${date} ANO_${date}_cst ${rdir}
\mv REF_${date} REF_${date}_cst ${rdir}
\rm -f fort.10
endif
 
# ---------------------------------------------------------------------------
# Inversion
# ---------------------------------------------------------------------------
 
# Change to data directory
cd ${rdir}
 
# Start loop
set count=0
loop:
 
# Step 1: Add NSQ, TH, RHO, and PV to MOD file, take grid from REF file
if ( ${step} == "pvin1" | ${step} == "pvin" ) then
echo "NSQ" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
echo "RHO" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
echo "TH" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
echo "PV" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
\rm -f fort.10
endif
 
# Step 2: Change Ertel's PV anomaly into an anomaly of quasi-geostrophic PV
if ( ${step} == "pvin2" | ${step} == "pvin" ) then
echo "MOD_${date}" >! fort.10
echo "REF_${date}" >> fort.10
echo "ANO_${date}" >> fort.10
${bdir}/pvin/pv_to_qgpv
\rm -f fort.10
endif
 
# Step 3: Inversion of quasi-geostrophic PV anomaly with Neumann boundary
if ( ${step} == "pvin3" | ${step} == "pvin" ) then
echo "ANO_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/pvin/inv_cart
\rm -f fort.10
endif
 
# Step 4: Prepare the output of the inversion for next iteration step
if ( ${step} == "pvin4" | ${step} == "pvin" ) then
\rm -f fort.10
echo "MOD_${date}" >! fort.10
echo "ANO_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} prep_iteration >> fort.10
${bdir}/pvin/prep_iteration
\rm -f fort.10
endif
 
# Step 5: Keep iterative steps if save flag is set
if ( ${step} == "pvin5" | ${step} == "pvin" ) then
if ( "${save}" == "yes" ) then
set pre=''
if ( ${count} < 10 ) then
set pre='0'
endif
\cp MOD_${date} MOD_${date}_${pre}${count}
\cp ANO_${date} ANO_${date}_${pre}${count}
endif
endif
 
# End loop for iterations
if ( ${step} == "pvin" ) then
@ count = ${count} + 1
if ( ${count} < ${nofiter} ) goto loop
endif
 
# ---------------------------------------------------------------------------
# Postprocessing
# ---------------------------------------------------------------------------
 
# Change to data directory
cd ${odir}
 
# Step 1: Copy needed files from input and run directory
if ( ${step} == "post1" | ${step} == "post" ) then
ln -sf ${rdir}/MOD_${date} ${rdir}/MOD_${date}_cst .
\cp ${idir}/P${date} ${idir}/ml_cst .
endif
 
# Step 2: Rotate from quasi-cartesian co-ordinate frame to lat/lon system
if ( ${step} == "post2" | ${step} == "post" ) then
echo "MOD_${date}" >! fort.10
echo "GEO_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} rotate_lalo >> fort.10
echo "3" >> fort.10
echo "T" >> fort.10
echo "U.V" >> fort.10
echo "P" >> fort.10
${bdir}/post/rotate_lalo
\rm -f fort.10
endif
 
# Step 3: Bring modified fields back to P file
if ( ${step} == "post3" | ${step} == "post" ) then
\rm -f fort.10
echo "P${date}" >! fort.10
echo "GEO_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} add2p >> fort.10
${bdir}/post/add2p
\rm -f fort.10
endif
 
# Step 4: Calculate S file with PV and TH
if ( ${step} == "post4" | ${step} == "post" ) then
\rm -f S${date}
p2s P${date} TH PV
endif
 
# Step 5: Make clean
if ( ${step} == "post5" | ${step} == "post" ) then
\rm -f MOD_${date} MOD_${date}_cst
\rm -f GEO_${date} GEO_${date}_cst
endif
 
# ---------------------------------------------------------------------------
# Diagnostic Tools
# ---------------------------------------------------------------------------
 
# Change to run directory
cd ${rdir}
 
# Step 1: Check the consistency of the boundary conditions (diag1)
if ( ${step} == "diag1" ) then
\rm -f fort.10
echo "ANO_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/diag/check_boundcon
\rm -f fort.10
endif
 
# Step 2: Calculate the quasi-geostrophic PV (diag2 [ORG|MOD|ANO]
if ( ${step} == "diag2" ) then
\rm -f fort.10
echo "${file1}_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/diag/calc_qgpv
\rm -f fort.10
endif
 
# Step 3: Get difference between two files (diag3 [ORG|MOD|ANO] - [ORG|MOD|ANO])
if ( ${step} == "diag3" ) then
\rm -f fort.10
echo "${file1}_${date}" >! fort.10
echo "${file2}_${date}" >> fort.10
echo "DIA_${date}" >> fort.10
${bdir}/diag/difference
\rm -f fort.10
endif
\end{verbatim}
\end{small}
 
\newpage
\subsection{Controlling Parameter File}
 
The inversion problem is specified in a parameter file. This file is set as a parameter in the
controlling Linux Shell script (see Appendix~9.2) and is often the only file which has to be adapted.
 
\begin{small}
\begin{verbatim}
BEGIN DATA
DATE = 20060116_18; ! Date for case study
INP_DIR = /lhome/sprenger/PV_Inversion_Tool/real/inp; ! Input directory
RUN_DIR = /lhome/sprenger/PV_Inversion_Tool/real/run; ! Run directory
OUT_DIR = /lhome/sprenger/PV_Inversion_Tool/real/out; ! Output directory
END DATA
 
BEGIN GRID
GEO_XMIN = -180.; ! Geographical grid in zonal direction
GEO_NX = 361 ;
GEO_DX = 1.;
GEO_YMIN = 0.; ! Geographical grid in meridional direction
GEO_NY = 91 ;
GEO_DY = 1.;
GEO_ZMIN = 0.; ! Vertical levels ( ZMIN and DZ in [m] )
GEO_NZ = 125 ;
GEO_DZ = 200.;
ROT_NX = 250 ; ! Rotated grid ( DX and DY in [deg] )
ROT_NY = 250 ;
ROT_DX = 0.25;
ROT_DY = 0.25;
CLON = -65.; ! Longitude, latitude [deg] and angle of rotated grid
CLAT = 45.;
CROT = 0.;
END GRID
 
BEGIN ANOMALY
BOX_XMIN = -1200.; ! Box where to apply the digital filter
BOX_XMAX = 1200.;
BOX_YMIN = -1200.;
BOX_YMAX = 1200.;
BOX_ZMIN = 2000.;
BOX_ZMAX = 10000.;
NFILTER = 5 ; ! Number of filter iterations;
BOUND_XY = 500.; ! Transition zone for horizontal boundaries ( in [km] )
BOUND_Z = 500.; ! Transition zone for vertical boundaries ( in [m] )
END ANOMALY
 
BEGIN NUMERICS
ALPHA = 0.5; ! Adjustment factor after one iteration step
NOFITER = 6; ! Number of "external" iterations
SAVEITER = no; ! Flag whether to save iteration steps
END NUMERICS
\end{verbatim}
\end{small}
 
\newpage
\subsection{List of Fortran, Perl and Linux programs}
 
The main tasks of the PV inversion are handled by Fortran programs. The following table contains a complete list
of these programs with some details. The first column gives the name of the program, the second column the section
(pre-processing, inversion, post-processing, diagnostics) where this program is needed, the third column the authors (in
order of their contribution), and the fourth column is a short description of the code. In the table, Fortran programs
are marked with the appendix ".f", Perl programs with the appendix ".perl", and Linux Shell scripts with the appendix ".sh".
 
\begin{center}
\begin{tabular}{|l|l|l|l|}
\hline
{\bf Name of program} & {\bf Section} & {\bf Author} & {\bf Short description} \\[2mm]
\hline
{\bf p2z.f} & prep & Michael Sprenger & Interpolation onto height levels\\[2mm]
\hline
{\bf rotate\_grid.f} & prep & Michael Sprenger & Rotation to quâsi-cartesian system\\[2mm]
\hline
{\bf z2s.f} & prep, pvin & Michael Sprenger & Calculation of secondary fields\\[2mm]
\hline
{\bf def\_anomaly.f} & prep & Michael Sprenger & Definition of modified Ertel's PV\\[2mm]
\hline
{\bf cutnetcdf.f } & prep & Michael Sprenger & Splitting of netcdf files\\
& & Heini Wernli & \\[2mm]
\hline
{\bf ref\_profile.f} & prep & Michael Sprenger & Definition of reference profile\\
& & Olivia Martius & \\[2mm]
\hline
{\bf coastline.f} & prep & Michael Sprenger & Add coastlines to reference file\\[2mm]
\hline
{\bf pv\_to\_qgpv.f} & pvin & Michael Sprenger & Calculate quasi-geostrophic PV\\[2mm]
\hline
{\bf inv\_cart.f} & pvin & Rene Fehlmann & Inversion of quasi-geostrophic PV\\
& & Michael Sprenger & \\[2mm]
\hline
{\bf prep\_iteration.f} & pvin & Michael Sprenger & Prepare next iteration step\\
& & Rene Fehlmann & \\[2mm]
\hline
{\bf rotate\_lalo.f} & post & Michael Sprenger & Rotate to geographical grid\\[2mm]
\hline
{\bf add2p.f} & post & Michael Sprenger & Interpolation to hybrid grid\\[2mm]
\hline
{\bf p2s.f} & prep, post & Heini Wernli & Secondary fields on hybrid grid\\[2mm]
\hline
{\bf check\_boundcon.f} & diag & Rene Fehlmann & Consistency check for boundaries\\
& & Michael Sprenger & \\[2mm]
\hline
{\bf calc\_qgpv.f} & diag & Sebastien Dirren & Convergence check for inversion\\
& & Michael Sprenger & \\[2mm]
\hline
{\bf difference.f} & diag & Michael Sprenger & Difference of two netcdf files\\[2mm]
\hline
{\bf inversion.sh} & & Michael Sprenger & Master Linux Shell script\\[2mm]
\hline
{\bf inversion.perl} & & Michael Sprenger & Extraction of parameters\\[2mm]
\hline
\end{tabular}
\end{center}
 
 
\end{document}
Property changes:
Added: svn:executable
/tags/1.0/inversion.docu
0,0 → 1,0
okular ${DYN_TOOLS}/inversion/docu/userguide.pdf
Property changes:
Added: svn:executable
/tags/1.0/inversion.install
0,0 → 1,123
# ----- Load modules --------------------------
 
module load netcdf/4.2.1-pgf90
module list
 
# ----- Set libraries and includes ------------
 
set libs = "-L ${DYN_TOOLS}/lib"
set libs = "${libs} -lcdfio"
set libs = "${libs} -lcdfplus"
set libs = "${libs} -lipo"
set libs = "${libs} -lgm2em"
 
set ncdf_incs = `nc-config --fflags`
set ncdf_libs = `nc-config --flibs`
 
# ----- Compile --------------------- ----------
 
cd ${DYN_TOOLS}/inversion/diag/
 
foreach tool ( calc_qgpv check_boundcon difference hydrostatic qvec_analysis )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
cd ${DYN_TOOLS}/inversion/post/
 
foreach tool ( add2p rotate_lalo )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
cd ${DYN_TOOLS}/inversion/prep/
 
foreach tool ( coastline cutnetcdf def_anomaly p2z ref_profile rotate_grid z2s )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
 
cd ${DYN_TOOLS}/inversion/pvin/
 
foreach tool ( inv_cart prep_iteration pv_to_qgpv z2s )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
 
cd ${DYN_TOOLS}/inversion/spec/
 
foreach tool ( modify_anomaly )
 
\rm -f ${tool}.o
\rm -f ${tool}
 
echo "pgf90 -c ${tool}.f ${ncdf_incs}"
pgf90 -c ${tool}.f ${ncdf_incs}
echo "pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}"
pgf90 -o ${tool} ${tool}.o ${libs} ${ncdf_libs}
 
if ( ! -f ${tool} ) then
echo "ERROR: compilation of <tool> failed... exit"
exit 1
endif
 
end
 
 
# ----- Set <bin> --------------------------------
 
ln -svf ${DYN_TOOLS}/inversion/inversion.sh ${DYN_TOOLS}/bin/inversion
 
chmod og+rx ${DYN_TOOLS}/bin/inversion
 
exit 0
Property changes:
Added: svn:executable
/tags/1.0/inversion.param
0,0 → 1,46
BEGIN DATA
DATE = 20060116_18; ! Date for case study
INP_DIR = /lhome/sprenger/PV_Inversion_Tool/real/inp; ! Input directory
RUN_DIR = /lhome/sprenger/PV_Inversion_Tool/real/run; ! Run directory
OUT_DIR = /lhome/sprenger/PV_Inversion_Tool/real/out; ! Output directory
END DATA
 
BEGIN GRID
GEO_XMIN = -180.; ! Geographical grid in zonal direction
GEO_NX = 361 ;
GEO_DX = 1.;
GEO_YMIN = 0.; ! Geographical grid in meridional direction
GEO_NY = 91 ;
GEO_DY = 1.;
GEO_ZMIN = 0.; ! Vertical levels ( ZMIN and DZ in [m] )
GEO_NZ = 125 ;
GEO_DZ = 200.;
ROT_NX = 250 ; ! Rotated grid ( DX and DY in [deg] )
ROT_NY = 250 ;
ROT_DX = 0.25;
ROT_DY = 0.25;
CLON = -65.; ! Longitude, latitude [deg] and angle of rotated grid
CLAT = 45.;
CROT = 0.;
REF_R = 500.; ! Radius for reference radius; -1 if whole domain)
END GRID
 
BEGIN ANOMALY
BOX_XMIN = -1200.; ! Box where to apply the digital filter
BOX_XMAX = 1200.;
BOX_YMIN = -1200.;
BOX_YMAX = 1200.;
BOX_ZMIN = 2000.;
BOX_ZMAX = 10000.;
NFILTER = 5 ; ! Number of filter iterations;
BOUND_XY = 500.; ! Transition zone for horizontal boundaries ( in [km] )
BOUND_Z = 500.; ! Transition zone for vertical boundaries ( in [m] )
END ANOMALY
 
BEGIN NUMERICS
ALPHA = 0.5; ! Adjustment factor after one iteration step
NOFITER = 6; ! Number of "external" iterations
SAVEITER = no; ! Flag whether to save iteration steps
TRANS_XY = 500.; ! Smooth transition zone (in km) for back-insertion into P file
PS_CHANGE = 0.0; ! Allow (1.0), do not allow (0.0), or fractionally allow (0<x<1) changes in surface pressure
END NUMERICS
Property changes:
Added: svn:executable
/tags/1.0/inversion.perl
0,0 → 1,129
#!/usr/bin/perl
 
# Get input arguments
$paramfile=$ARGV[0];
$parammode=$ARGV[1];
 
# Define the extraction tables for the inversion programmes
if ( "$parammode" eq "p2z" )
{ @list = ('GRID.GEO_ZMIN',
'GRID.GEO_NZ',
'GRID.GEO_DZ'); }
if ( "$parammode" eq "ref" )
{ @list = ('GRID.REF_R'); }
 
if ( "$parammode" eq "def_anomaly" )
{ @list = ('ANOMALY.BOX_XMIN',
'ANOMALY.BOX_XMAX',
'ANOMALY.BOX_YMIN',
'ANOMALY.BOX_YMAX',
'ANOMALY.BOX_ZMIN',
'ANOMALY.BOX_ZMAX',
'ANOMALY.NFILTER',
'ANOMALY.BOUND_XY',
'ANOMALY.BOUND_Z'); }
 
if ( "$parammode" eq "rotate_grid" )
{ @list = ('GRID.ROT_NX',
'GRID.ROT_NY',
'GRID.ROT_DX',
'GRID.ROT_DY',
'GRID.CLON',
'GRID.CLAT',
'GRID.CROT'); }
 
if ( "$parammode" eq "rotate_lalo" )
{ @list = ('GRID.GEO_NX',
'GRID.GEO_NY',
'GRID.GEO_DX',
'GRID.GEO_DY',
'GRID.GEO_XMIN',
'GRID.GEO_YMIN',
'GRID.CLON',
'GRID.CLAT',
'GRID.CROT'); }
 
if ( "$parammode" eq "add2p" )
{ @list = ('NUMERICS.TRANS_XY',
'NUMERICS.PS_CHANGE' ); }
 
if ( "$parammode" eq "coastline" )
{ @list = ('GRID.CLON',
'GRID.CLAT',
'GRID.CROT'); }
 
if ( "$parammode" eq "prep_iteration" )
{ @list = ('NUMERICS.ALPHA'); }
 
if ( "$parammode" eq "inp_dir" )
{ @list = ('DATA.INP_DIR'); };
 
if ( "$parammode" eq "run_dir" )
{ @list = ('DATA.RUN_DIR'); };
 
if ( "$parammode" eq "out_dir" )
{ @list = ('DATA.OUT_DIR'); };
 
if ( "$parammode" eq "n_of_iteration" )
{ @list = ('NUMERICS.NOFITER'); };
 
if ( "$parammode" eq "save_iteration" )
{ @list = ('NUMERICS.SAVEITER'); };
 
if ( "$parammode" eq "date" )
{ @list = ('DATA.DATE'); };
 
# Read the parameter file
@zeilen = `more $paramfile`;
 
# Set the first parameter which should be retrieved
foreach $listentry (@list)
{
# Get section and name of the parameter
@param = split /\./, "$listentry";
$found=0;
 
# Loop over all variables
foreach $zeile ( @zeilen )
{
# -------------- BEGIN ------------------------------------
if ( $zeile =~ 'BEGIN' )
{
@field = split / /, "$zeile";
$_=$field[1];s/\s+//g;$bmode=$_;
}
 
# -------------- ASSIGNMENT -------------------------------
if ( ($zeile =~ '=') && ($zeile =~ ';') )
{
@field1 = split /=/, "$zeile";
@field2 = split /;/, "$field1[1]";
$_=$field1[0];s/\s+//g;$field1[0]=$_;
$_=$field2[0];s/\s+//g;$field2[0]=$_;
@field = ( $field1[0], $field2[0] );
if ( ("$bmode" eq "$param[0]") && ("$field[0]" eq "$param[1]" ) )
{
$found=1;
print "$field[0] $field[1] \n";
}
}
 
# -------------- END --------------------------------------
if ( $zeile =~ 'END' )
{
@field = split / /, "$zeile";
$_=$field[1];s/\s+//g;$emode=$_;
if ( "$bmode" ne "$emode" )
{
die "Invalid structure of parameter file... $bmode\n";
}
}
}
if ( $found == 0 )
{
die("Parameter $listentry not found... Stop");
}
}
Property changes:
Added: svn:executable
/tags/1.0/inversion.sh
0,0 → 1,550
#!/bin/csh
 
# -------------------------------------------------------------------
# Set some variables and paths
# -------------------------------------------------------------------
 
# Jump to specified step
set step="help"
set param1=
set param2=
set param3=
 
if ( $#argv == 1 ) then
set step=$1
endif
if ( $#argv == 2 ) then
set step=$1
set param1=$2
endif
if ( $#argv == 3 ) then
set step=$1
set param1=$2
set param2=$3
endif
if ( $#argv == 4 ) then
set step=$1
set param1=$2
set param2=$3
set param3=$4
endif
 
set file1=${param1}
set file2=${param2}
 
# Set base directory for programmes
set bdir=${DYN_TOOLS}/inversion/
 
# Set name of the parameter file, coastline file and sample directory
set parafile="${PWD}/inversion.param"
set coastfile="${bdir}/prep/coastline.dat"
set sampledir="/net/bio/atmosdyn/erainterim/cdf/2006/01/"
 
# ---------------------------------------------------------------------------
# Installation, help and sample
# ---------------------------------------------------------------------------
 
# Get parameter file, if not yet available
if ( ! -f ${parafile} ) then
cp ${bdir}/inversion.param .
endif
 
# Extract parameters from parameter file
set progex=${bdir}/inversion.perl
set date=`${progex} ${parafile} date | awk '{ print $2}'`
set nofiter=`${progex} ${parafile} n_of_iteration | awk '{ print $2}'`
set save=`${progex} ${parafile} save_iteration | awk '{ print $2}'`
set idir=`${progex} ${parafile} inp_dir | awk '{ print $2}'`
set rdir=`${progex} ${parafile} run_dir | awk '{ print $2}'`
set odir=`${progex} ${parafile} out_dir | awk '{ print $2}'`
 
# Create the needed directories
if ( ${step} == "inst" ) then
if ( ! -d ${idir} ) mkdir ${idir}
if ( ! -d ${rdir} ) mkdir ${rdir}
if ( ! -d ${odir} ) mkdir ${odir}
endif
 
# Create the needed directories
if ( ${step} == "help" ) then
echo
echo "Installation"
echo " inst: Creates the input, run and output directory; copy template parameter file"
echo
echo "Sample case study"
echo " sample: Copy all files for a sample case study"
echo
echo "Preparing input files [prep]"
echo " prep0: Calculate S file with PV and TH [ P -> S ]"
echo " prep1: Interpolate onto height levels [ P,Z -> H ]"
echo " prep2: Rotate into local cartesian coordinate system [ H -> R ]"
echo " prep3: Add TH,PV,NSQ and RHO to the data file [ -> R ]"
echo " prep4: Define modified and anomaly PV field and boundary values [ -> R ]"
echo " prep5: Reduce the domain size and split the input files [ R -> ORG,MOD,ANO,REF]"
echo " prep6: Add the reference profile [MOD -> REF]"
echo " prep7: Add coastlines to REF file [-> REF]"
echo " prep8: Move the files to the run directory [ORG,MOD,ANO,REF -> ]"
echo
echo "Perform the PV inversion [pvin]"
echo " pvin1: Add NSQ, TH, RHO, and PV [ -> MOD]"
echo " pvin2: Change Ertel's PV anomaly into one of quasi-geostrophic PV [MOD -> ANO]"
echo " pvin3: Inversion of quasi-geostrophic PV anomaly [ANO -> ANO]"
echo " pvin4: Subtract anomaly from MOD file [MOD-ANO -> MOD]"
echo " pvin5: Keep iterative steps if save flag is set"
echo
echo "Postprocessing [post]"
echo " post1: Copy needed files from input and run directory [P,MOD -> ]"
echo " post2: Rotate from quasi-cartesian coordinate frame to lat/lon system [ MOD -> GEO ]"
echo " post3: Bring modified fields back to P file [ P+GEO -> P ]"
echo " post4: Calculate S file with PV and TH [ P -> S ]"
echo " post5: Make clean"
echo " post6: Calculate difference to original P and S file"
echo
echo "Diagnostic Tools"
echo " diag1: Check the consitency of the boundary conditions"
echo " diag2: Calculate the quasi-geostrophic PV (diag2 [ORG|MOD|ANO])"
echo " diag3: Get the difference between two files (diag3 [ORG|MOD|ANO] [ORG|MOD|ANO])"
echo " diag4: Calculate geopotential with hydrostatic equation (diag4 [P|ORG|MOD|ANO])"
echo " diag5: Q vector analysis; geostrophic wind balance [ORG|MOD|ANO] [GEO|DIV_UV|QVEC|DIV_Q]"
echo
echo "Modifying Pv anomalies"
echo " mod1: Stretching and amplitude changes for anomalies [MOD]"
endif
 
 
# Copy sample files (if specified)
if ( ${step} == "sample" ) then
\cp ${sampledir}/P20060116_18 ${idir}
\cp ${sampledir}/eraint_cst ${idir}
\cp ${sampledir}/Z20060116_18 ${idir}
\cp ${sampledir}/pressure_cst ${idir}
endif
 
# ---------------------------------------------------------------------------
# Preparatory steps
# ---------------------------------------------------------------------------
 
# Change to data directory
cd ${idir}
 
# Step 0: Calculate S file with PV and TH (not in prep mode)
if ( ${step} == "prep0" ) then
\rm -f S${date}
p2s P${date} TH PV
endif
 
# Step 1: Interpolate onto height levels
if ( ${step} == "prep1" | ${step} == "prep" ) then
echo "P${date}" >! fort.10
echo "Z${date}" >> fort.10
echo "H${date}" >> fort.10
${bdir}/inversion.perl ${parafile} p2z >> fort.10
echo "U U P${date}" >> fort.10
echo "V V P${date}" >> fort.10
echo "T T P${date}" >> fort.10
echo "Q Q P${date}" >> fort.10
${bdir}/prep/p2z
\rm -f fort.10
endif
 
# Step 2: Rotate into local cartesian coordinate system
if ( ${step} == "prep2" | ${step} == "prep" ) then
echo "H${date}" >! fort.10
echo "R${date}" >> fort.10
${bdir}/inversion.perl ${parafile} rotate_grid >> fort.10
echo "5" >> fort.10
echo "ORO" >> fort.10
echo "U.V" >> fort.10
echo "P" >> fort.10
echo "T" >> fort.10
echo "Q" >> fort.10
${bdir}/prep/rotate_grid
\rm -f fort.10
endif
 
# Step 3: Add TH,PV,NSQ and RHO to the data file
if ( ${step} == "prep3" | ${step} == "prep" ) then
echo "TH" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
echo "PV" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
echo "NSQ" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
echo "RHO" >! fort.10
echo "R${date}" >> fort.10
echo "R${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/prep/z2s
\rm -f fort.10
endif
 
# Step 4: Set the modified PV field and boundary values
if ( ${step} == "prep4" | ${step} == "prep" ) then
echo "R${date}" >! fort.10
${bdir}/inversion.perl ${parafile} def_anomaly >> fort.10
${bdir}/prep/def_anomaly
\rm -f fort.10
endif
 
# Step 5: Reduce the domain size and split the input files
if ( ${step} == "prep5" | ${step} == "prep" ) then
echo "PV PV R${date} ORG_${date}" >! fort.10
echo "U U R${date} ORG_${date}" >> fort.10
echo "V V R${date} ORG_${date}" >> fort.10
echo "TH TH R${date} ORG_${date}" >> fort.10
echo "Q Q R${date} ORG_${date}" >> fort.10
echo "P P R${date} ORG_${date}" >> fort.10
echo "T T R${date} ORG_${date}" >> fort.10
echo "PV_FILT PV_AIM R${date} MOD_${date}" >> fort.10
echo "U U R${date} MOD_${date}" >> fort.10
echo "V V R${date} MOD_${date}" >> fort.10
echo "Q Q R${date} MOD_${date}" >> fort.10
echo "P P R${date} MOD_${date}" >> fort.10
echo "T T R${date} MOD_${date}" >> fort.10
echo "NSQ NSQ R${date} MOD_${date}" >> fort.10
echo "RHO RHO R${date} MOD_${date}" >> fort.10
echo "TH TH R${date} MOD_${date}" >> fort.10
echo "PV_ANOM PV R${date} ANO_${date}" >> fort.10
echo "TH_ANOM TH R${date} ANO_${date}" >> fort.10
echo "UU_ANOM U R${date} ANO_${date}" >> fort.10
echo "VV_ANOM V R${date} ANO_${date}" >> fort.10
echo "ORO ORO R${date} REF_${date}" >> fort.10
echo "X X R${date} REF_${date}" >> fort.10
echo "Y Y R${date} REF_${date}" >> fort.10
echo "LAT LAT R${date} REF_${date}" >> fort.10
echo "LON LON R${date} REF_${date}" >> fort.10
echo "CORIOL CORIOL R${date} REF_${date}" >> fort.10
${bdir}/prep/cutnetcdf
\rm -f fort.10
endif
 
# Step 6: Add the reference profile
if ( ${step} == "prep6" | ${step} == "prep" ) then
\rm -f fort.10
echo "MOD_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} ref >> fort.10
${bdir}/prep/ref_profile
\rm -f fort.10
endif
 
# Step 7: Add coastlines to REF file
if ( ${step} == "prep7" | ${step} == "prep" ) then
\rm -f fort.10
echo \"REF_${date}\" >! fort.10
echo \"${coastfile}\" >> fort.10
${bdir}/inversion.perl ${parafile} coastline >> fort.10
${bdir}/prep/coastline
\rm -f fort.10
endif
 
# Step 8: Move the files to the run directory
if ( ${step} == "prep8" | ${step} == "prep" ) then
\mv MOD_${date} MOD_${date}_cst ${rdir}
\mv ORG_${date} ORG_${date}_cst ${rdir}
\mv ANO_${date} ANO_${date}_cst ${rdir}
\mv REF_${date} REF_${date}_cst ${rdir}
\rm -f fort.10
endif
 
# ---------------------------------------------------------------------------
# Inversion
# ---------------------------------------------------------------------------
 
# Change to data directory
cd ${rdir}
 
# Start loop
set count=0
loop:
 
# Step 1: Add NSQ, TH, RHO, and PV to MOD file, take grid from REF file
if ( ${step} == "pvin1" | ${step} == "pvin" ) then
echo "NSQ" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
echo "RHO" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
echo "TH" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
echo "PV" >! fort.10
echo "MOD_${date}" >> fort.10
echo "REF_${date}" >> fort.10
echo "5 " >> fort.10
${bdir}/pvin/z2s
\rm -f fort.10
endif
 
# Step 2: Change Ertel's PV anomaly into an anomaly of quasi-geostrophic PV
if ( ${step} == "pvin2" | ${step} == "pvin" ) then
echo "MOD_${date}" >! fort.10
echo "REF_${date}" >> fort.10
echo "ANO_${date}" >> fort.10
${bdir}/pvin/pv_to_qgpv
\rm -f fort.10
endif
 
# Step 3: Inversion of quasi-geostrophic PV anomaly with Neumann boundary
if ( ${step} == "pvin3" | ${step} == "pvin" ) then
echo "ANO_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/pvin/inv_cart
\rm -f fort.10
endif
 
# Step 4: Prepare the output of the inversion for next iteration step
if ( ${step} == "pvin4" | ${step} == "pvin" ) then
\rm -f fort.10
echo "MOD_${date}" >! fort.10
echo "ANO_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} prep_iteration >> fort.10
${bdir}/pvin/prep_iteration
\rm -f fort.10
endif
 
# Step 5: Keep iterative steps if save flag is set
if ( ${step} == "pvin5" | ${step} == "pvin" ) then
if ( "${save}" == "yes" ) then
set pre=''
if ( ${count} < 10 ) then
set pre='0'
endif
\cp MOD_${date} MOD_${date}_${pre}${count}
\cp ANO_${date} ANO_${date}_${pre}${count}
endif
endif
 
# End loop for iterations
if ( ${step} == "pvin" ) then
@ count = ${count} + 1
if ( ${count} < ${nofiter} ) goto loop
endif
 
# ---------------------------------------------------------------------------
# Postprocessing
# ---------------------------------------------------------------------------
 
# Change to output directory
cd ${odir}
 
# Step 1: Copy needed files from input and run directory
if ( ${step} == "post1" | ${step} == "post" ) then
ln -sf ${rdir}/MOD_${date} .
ln -sf ${rdir}/MOD_${date}_cst .
ln -sf ${rdir}/ORG_${date} .
ln -sf ${rdir}/ORG_${date}_cst .
\cp ${idir}/P${date} .
set cfn = `getcfn P${date}`
\cp ${idir}/${cfn} .
endif
 
# Step 2: Rotate from quasi-cartesian coordinate frame to lat/lon system
if ( ${step} == "post2" | ${step} == "post" ) then
echo "MOD_${date}" >! fort.10
echo "GEO.MOD_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} rotate_lalo >> fort.10
echo "3" >> fort.10
echo "T" >> fort.10
echo "U.V" >> fort.10
echo "P" >> fort.10
${bdir}/post/rotate_lalo
\rm -f fort.10
echo "ORG_${date}" >! fort.10
echo "GEO.ORG_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} rotate_lalo >> fort.10
echo "3" >> fort.10
echo "T" >> fort.10
echo "U.V" >> fort.10
echo "P" >> fort.10
${bdir}/post/rotate_lalo
\rm -f fort.10
endif
 
# Step 3: Bring modified fields back to P file
if ( ${step} == "post3" | ${step} == "post" ) then
\rm -f fort.10
echo "P${date}" >! fort.10
echo "GEO.MOD_${date}" >> fort.10
echo "GEO.ORG_${date}" >> fort.10
${bdir}/inversion.perl ${parafile} add2p >> fort.10
${bdir}/post/add2p
\rm -f fort.10
endif
 
# Step 4: Calculate S file with PV and TH
if ( ${step} == "post4" | ${step} == "post" ) then
\rm -f S${date}
p2s P${date} TH PV
endif
 
# Step 5: Make clean
if ( ${step} == "post5" | ${step} == "post" ) then
\rm -f MOD_${date} MOD_${date}_cst
\rm -f GEO_${date} GEO_${date}_cst
endif
 
# Step 6: Get difference of original and modified P,S files
if ( ${step} == "post6" | ${step} == "post" ) then
\rm -f levs
echo "950." >! levs
echo "925." >> levs
echo "900." >> levs
echo "875." >> levs
echo "850." >> levs
echo "825." >> levs
echo "800." >> levs
echo "775." >> levs
echo "750." >> levs
echo "725." >> levs
echo "700." >> levs
echo "675." >> levs
echo "650." >> levs
echo "625." >> levs
echo "600." >> levs
echo "575." >> levs
echo "550." >> levs
echo "525." >> levs
echo "500." >> levs
echo "475." >> levs
echo "450." >> levs
echo "425." >> levs
echo "400." >> levs
echo "375." >> levs
echo "350." >> levs
echo "325." >> levs
echo "300." >> levs
echo "275." >> levs
echo "250." >> levs
echo "225." >> levs
echo "200." >> levs
echo "175," >> levs
echo "150." >> levs
echo "125." >> levs
echo "100." >> levs
echo " 75." >> levs
echo " 50." >> levs
 
\rm -f vars
echo "U P" >! vars
echo "V P" >> vars
echo "T P" >> vars
echo "Z P" >> vars
echo "TH S" >> vars
echo "PV S" >> vars
 
nput2p ${date} pr_cst levs vars
ncks -A -v PS P${date} L${date}
\mv -f L${date} L${date}.1
 
\cp levs vars ${idir}/
cd ${idir}
nput2p ${date} pr_cst levs vars
ncks -A -v PS P${date} L${date}
\rm levs
\rm vars
\mv L${date} ${odir}/L${date}.0
cd ${odir}
 
ncdiff L${date}.1 L${date}.0 L${date}
\rm -f L${date}.1
\rm -f L${date}.0
 
endif
 
 
# ---------------------------------------------------------------------------
# Diagnotic Tools
# ---------------------------------------------------------------------------
 
# Step 1: Check the consistency of the boundary conditions (diag1)
if ( ${step} == "diag1" ) then
cd ${rdir}
\rm -f fort.10
echo "ANO_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/diag/check_boundcon
\rm -f fort.10
endif
 
# Step 2: Calculate the quasi-geostrophic PV (diag2 [ORG|MOD|ANO]
if ( ${step} == "diag2" ) then
cd ${rdir}
\rm -f fort.10
echo "${file1}_${date}" >! fort.10
echo "REF_${date}" >> fort.10
${bdir}/diag/calc_qgpv
\rm -f fort.10
endif
 
# Step 3: Get difference between two files (diag3 [ORG|MOD|ANO] - [ORG|MOD|ANO])
if ( ${step} == "diag3" ) then
cd ${rdir}
\rm -f fort.10
echo "${file1}_${date}" >! fort.10
echo "${file2}_${date}" >> fort.10
echo "DIA_${date}" >> fort.10
${bdir}/diag/difference
\rm -f fort.10
endif
 
# Step 4: Calculate geopotential with hydrostatic equation (diag4)
if ( ${step} == "diag4" ) then
cd ${odir}
\rm -f fort.10
echo "P${date}" >! fort.10
echo "P${date}" >> fort.10
${bdir}/diag/hydrostatic
\rm -f fort.10
endif
 
# Step 5: Q vector analysis / geostrophic balance check
if ( ${step} == "diag5" ) then
cd ${rdir}
\rm -f fort.10
echo "${param3}" >! fort.10
echo "${file1}" >> fort.10
echo "${file2}" >> fort.10
echo 1 >> fort.10
${bdir}/diag/qvec_analysis
\rm -f fort.10
endif
 
 
# ---------------------------------------------------------------------------
# Modifying tools
# ---------------------------------------------------------------------------
 
if ( ${step} == "mod1" ) then
cd ${idir}
\rm -f fort.10
set commandstr=$2
echo "R${date}" >! fort.10
echo \"${commandstr}\" >> fort.10
${bdir}/spec/modify_anomaly
\rm -f fort.10
endif
 
 
 
 
 
 
 
 
Property changes:
Added: svn:executable
/tags/1.0/inversion.summary
0,0 → 1,0
piecewise potential vorticity inversion for ECMWF data; qg- and Ertel-PV
/tags/1.0/lib/libcdfio.f
0,0 → 1,1648
subroutine clscdf (cdfid, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine closes an open netCDF file.
c Aguments :
c cdfid int input the id of the file to be closed.
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 error detected.
c History:
c Nov. 91 PPM UW Created.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer cdfid, error
 
c Local variable declarations.
integer ncopts
 
c Get current value of error options.
call ncgopt (ncopts)
 
c Make sure netCDF errors do not abort execution.
call ncpopt (NCVERBOS)
 
c Close requested file.
call ncclos (cdfid, error)
 
c Reset error options.
call ncpopt (ncopts)
 
end
 
 
subroutine cdfwopn(filnam,cdfid,ierr)
C------------------------------------------------------------------------
 
C Opens the NetCDF file 'filnam' and returns its identifier cdfid.
 
C filnam char input name of NetCDF file to open
C cdfid int output identifier of NetCDF file
C ierr int output error flag
C------------------------------------------------------------------------
 
include 'netcdf.inc'
 
integer cdfid,ierr
character*(*) filnam
 
integer strend
 
call ncpopt(NCVERBOS)
cdfid=ncopn(filnam(1:strend(filnam)),NCWRITE,ierr)
 
return
end
 
 
subroutine cdfopn(filnam,cdfid,ierr)
C------------------------------------------------------------------------
 
C Opens the NetCDF file 'filnam' and returns its identifier cdfid.
 
C filnam char input name of NetCDF file to open
C cdfid int output identifier of NetCDF file
C ierr int output error flag
C------------------------------------------------------------------------
 
include 'netcdf.inc'
 
integer cdfid,ierr
character*(*) filnam
 
integer strend
 
call ncpopt(NCVERBOS)
cdfid=ncopn(filnam(1:strend(filnam)),NCNOWRIT,ierr)
 
return
end
 
 
subroutine crecdf (filnam, cdfid, phymin, phymax, ndim, cfn,
& error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to create a netCDF file for use with
c the UWGAP plotting package.
c Any netCDF file written to must be closed with the call
c 'call clscdf(cdfid,error)', where cdfid and error are
c as in the argumentlist below.
c Arguments:
c filnam char input the user-supplied netCDF file name.
c cdfid int output the file-identifier
c phymin real input the minimum physical dimension of the
c entire physical domain along each axis.
c phymin is dimensioned (ndim)
c phymax real input the maximum physical dimension of the
c entire physical domain along each axis.
c phymax is dimensioned (ndim)
c ndim int input the number of dimensions in the file
c (i.e. number of elements in phymin,
c phymax)
c cfn char input constants file name
c ('0' = no constants file).
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 error detected.
c History:
c Nov. 91 PPM UW Created cr3df.
c Jan. 92 CS UW Created crecdf.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer MAXDIM
parameter (MAXDIM=4)
integer ndim, error
character *(*) filnam,cfn
real phymin(*), phymax(*)
 
c Local variable declarations.
character *(20) attnam
character *(1) chrid(MAXDIM)
integer cdfid, k, ibeg, iend, lenfil, ncopts
data chrid/'x','y','z','a'/
 
c Get current value of error options, and make sure netCDF-errors do
c not abort execution
call ncgopt (ncopts)
call ncpopt(NCVERBOS)
 
c Initially set error to indicate no errors.
error = 0
 
c create the netCDF file
cdfid = nccre (trim(filnam), NCCLOB, error)
if (error.ne.0) go to 920
 
c define global attributes
do k=1,ndim
attnam(1:3)='dom'
attnam(4:4)=chrid(k)
attnam(5:7)='min'
attnam=attnam(1:7)
call ncapt(cdfid,NCGLOBAL,attnam,NCFLOAT,1,phymin(k),error)
if (error.gt.0) goto 920
 
attnam(1:3)='dom'
attnam(4:4)=chrid(k)
attnam(5:7)='max'
attnam=attnam(1:7)
call ncapt(cdfid,NCGLOBAL,attnam,NCFLOAT,1,phymax(k),error)
if (error.gt.0) goto 920
enddo
 
c define constants file name
if (cfn.ne.'0') then
call ncaptc (cdfid, NCGLOBAL, 'constants_file_name',
c & NCCHAR, len_trim(cfn)+1, cfn // char(0) , error)
& NCCHAR, len_trim(cfn), cfn , error)
if (error.gt.0) goto 920
endif
 
c End variable definitions.
call ncendf (cdfid, error)
if (error.gt.0) goto 920
 
c normal exit
call ncpopt (ncopts)
return
 
c error exit
920 write (6, *) 'ERROR: An error occurred while attempting to ',
& 'create the data file in subroutine crecdf.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
end
 
subroutine opncdf(filnam, cdfid,
& phymin, phymax, ndim, varnam, nvar, cfn, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to open a netCDF file for read and write
c with the UWGAP plotting package.
c Arguments:
c filnam char input the user-supplied netCDF file name.
c cdfid int output the file-identifier
c phymin real output the minimum physical dimension of the
c entire physical domain along each axis.
c phymin is dimensioned (ndim)
c phymax real output the maximum physical dimension of the
c entire physical domain along each axis.
c phymax is dimensioned (ndim)
c ndim int output the number of dimensions in the file
c (i.e. number of elements in phymin,
c phymax)
c varnam char output an array containing the variable names.
c varnam is dimensioned (nvar).
c nvar int output the number of variables in the file
c cfn char output constants file name
c ('0'=no constants file).
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 error detected.
c History:
c Nov. 91 PPM UW Created cr3df.
c Jan. 92 CS UW Created opncdf.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer MAXDIM
parameter (MAXDIM=4)
integer ndim, nvar, error
character *(*) filnam, varnam(*),cfn
real phymin(*), phymax(*)
 
c Local variable declarations.
character *(20) attnam,vnam
character *(1) chrid(MAXDIM)
integer cdfid, i,k
integer ncopts, ndims,ngatts,recdim
integer nvdims,vartyp,nvatts,vardim(MAXDIM)
real attval
integer lenstr
data chrid/'x','y','z','a'/
data lenstr/80/
 
c Get current value of error options and make sure netCDF-errors do
c not abort execution
call ncgopt (ncopts)
call ncpopt(NCVERBOS)
 
c Initially set error to indicate no errors.
error = 0
 
c open the netCDF file for write
cdfid = ncopn (trim(filnam), NCWRITE, error)
if (error.ne.0) then
c try to open the netCDF file for read
cdfid = ncopn (trim(filnam), NCNOWRIT, error)
if (error.ne.0) go to 920
endif
 
c inquire for number of variables
call ncinq(cdfid,ndims,nvar,ngatts,recdim,error)
if (error.eq.1) goto 920
 
c read the variables
do i=1,nvar
call ncvinq(cdfid,i,varnam(i),vartyp,nvdims,vardim,
& nvatts,error)
if (vartyp.ne.NCFLOAT) error=1
if (error.gt.0) goto 920
enddo
 
c get global attributes
k=0
100 continue
k=k+1
attnam(1:3)='dom'
attnam(4:4)=chrid(k)
attnam(5:7)='min'
attnam=attnam(1:7)
 
c switch off error message
call ncpopt(0)
 
c check whether dimension k is present
call ncagt(cdfid,NCGLOBAL,attnam,attval,error)
if (error.gt.0) goto 110
phymin(k)=attval
 
attnam(1:3)='dom'
attnam(4:4)=chrid(k)
attnam(5:7)='max'
attnam=attnam(1:7)
call ncagt(cdfid,NCGLOBAL,attnam,attval,error)
if (error.gt.0) goto 920
phymax(k)=attval
if (k.lt.3) goto 100
k=k+1
 
c define ndim-parameter
110 continue
ndim=k-1
error=0
 
c switch on error messages
call ncpopt(NCVERBOS)
 
c get constants file name
c call ncagt(cdfid,NCGLOBAL,'constants_file_name',cfn,error)
c ! chrigel
call ncagtc(cdfid,NCGLOBAL,'constants_file_name',cfn,lenstr,error)
if (error.gt.0) cfn='0'
 
c normal exit
call ncpopt (ncopts)
return
 
c error exit
920 write (6, *) 'ERROR: An error occurred while attempting to ',
& 'read the data file in subroutine opncdf.'
call ncclos (cdfid, error)
call ncpopt (ncopts)
end
 
 
subroutine readcdf(filnam, cdfid,
& phymin, phymax, ndim, varnam, nvar, cfn, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to open a netCDF file for read
c with the UWGAP plotting package.
c Arguments:
c filnam char input the user-supplied netCDF file name.
c cdfid int output the file-identifier
c phymin real output the minimum physical dimension of the
c entire physical domain along each axis.
c phymin is dimensioned (ndim)
c phymax real output the maximum physical dimension of the
c entire physical domain along each axis.
c phymax is dimensioned (ndim)
c ndim int output the number of dimensions in the file
c (i.e. number of elements in phymin,
c phymax)
c varnam char output an array containing the variable names.
c varnam is dimensioned (nvar).
c nvar int output the number of variables in the file
c cfn char output constants file name
c ('0'=no constants file).
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 error detected.
c History:
c Nov. 91 PPM UW Created cr3df.
c Jan. 92 CS UW Created opncdf.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer MAXDIM
parameter (MAXDIM=4)
integer ndim, nvar, error
character *(*) filnam, varnam(*),cfn
real phymin(*), phymax(*)
 
 
c Local variable declarations.
character *(20) attnam
character *(1) chrid(MAXDIM)
integer cdfid, i,k
integer ncopts, ndims,ngatts,recdim
integer nvdims,vartyp,nvatts,vardim(MAXDIM)
real attval
integer lenstr
data chrid/'x','y','z','a'/
data lenstr/80/
 
c Get current value of error options.
call ncgopt (ncopts)
 
c make sure netCDF-errors do not abort execution
call ncpopt(NCVERBOS)
 
c Initially set error to indicate no errors.
error = 0
 
c open the netCDF file for read
cdfid = ncopn (trim(filnam), NCNOWRIT, error)
if (error.ne.0) go to 920
 
c inquire for number of variables
call ncinq(cdfid,ndims,nvar,ngatts,recdim,error)
if (error.eq.1) goto 920
 
c read the variables
do i=1,nvar
call ncvinq(cdfid,i,varnam(i),vartyp,nvdims,vardim,
& nvatts,error)
if (vartyp.ne.NCFLOAT) error=1
c print *,varnam(i),nvdims,nvatts
if (error.gt.0) goto 920
enddo
 
c get global attributes
k=0
100 continue
k=k+1
attnam(1:3)='dom'
attnam(4:4)=chrid(k)
attnam(5:7)='min'
attnam=attnam(1:7)
 
c switch off error message
call ncpopt(0)
 
c check whether dimension k is present
call ncagt(cdfid,NCGLOBAL,attnam,attval,error)
if (error.gt.0) goto 110
phymin(k)=attval
 
attnam(1:3)='dom'
attnam(4:4)=chrid(k)
attnam(5:7)='max'
attnam=attnam(1:7)
call ncagt(cdfid,NCGLOBAL,attnam,attval,error)
if (error.gt.0) goto 920
phymax(k)=attval
if (k.lt.4) goto 100
k=k+1
 
c define ndim-parameter
110 continue
ndim=k-1
error=0
 
c switch on error messages
call ncpopt(NCVERBOS)
 
c get constants file name
c call ncagt(cdfid,NCGLOBAL,'constants_file_name',cfn,error)
c ! chrigel
call ncagtc(cdfid,NCGLOBAL,'constants_file_name',cfn,lenstr,error)
if (error.gt.0) cfn='0'
c print *,cfn
 
c normal exit
call ncpopt (ncopts)
return
 
c error exit
920 write (6, *) 'ERROR: An error occurred while attempting to ',
& 'read the data file in subroutine opncdf.'
call ncclos (cdfid, error)
call ncpopt (ncopts)
end
 
 
 
subroutine getcdf (cdfid, varnam, ndim, misdat,
& vardim, varmin, varmax, stag, dat, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to get a variable and its attributes
c from a netCDF file for use with the UWGAP plotting package.
c It is assumed that the data is floating-point data. Prior to
c calling this routine, the file must be opened with a call to
c opncdf.
c Arguments:
c cdfid int input file-identifier
c (can be obtained by calling routine
c opncdf)
c varnam char input the user-supplied variable name.
c (can be obtained by calling routine
c opncdf)
c ndim int output the number of dimensions (ndim<=4)
c misdat real output missing data value for the variable.
c vardim int output the dimensions of the variable.
c is dimensioned at least (ndim).
c varmin real output the location in physical space of the
c origin of each variable.
c is dimensioned at least Min(ndim,3).
c varmax real output the extent of each variable in physical
c space.
c is dimensioned at least Min(ndim,3).
c stag real output the grid staggering for each variable.
c is dimensioned at least Min(ndim,3).
c dat real output data-array dimensioned suffiecently
c large, at least
c vardim(1)* ... vardim(ndim)
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 error detected.
c History:
c Nov. 91 PPM UW Created cr3df.
c Jan. 92 CS UW Created getcdf.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer MAXDIM
parameter (MAXDIM=4)
character *(*) varnam
integer vardim(*), ndim, error, cdfid
real misdat, stag(*), varmin(*), varmax(*), dat(*)
 
c Local variable declarations.
character *(20) dimnam(100),attnam
character *(1) chrid(MAXDIM)
integer id,i,k,corner(MAXDIM)
integer ndims,nvars,ngatts,recdim,dimsiz(100)
integer vartyp,nvatts, ncopts
data chrid/'x','y','z','a'/
data corner/1,1,1,1/
 
c Get current value of error options, and make sure netCDF-errors do
c not abort execution
call ncgopt (ncopts)
call ncpopt(NCVERBOS)
 
c Initially set error to indicate no errors.
error = 0
 
c inquire for number of dimensions
call ncinq(cdfid,ndims,nvars,ngatts,recdim,error)
if (error.eq.1) goto 920
 
c read dimension-table
do i=1,ndims
call ncdinq(cdfid,i,dimnam(i),dimsiz(i),error)
if (error.gt.0) goto 920
enddo
 
c get id of the variable
id=ncvid(cdfid,varnam,error)
if (error.eq.1) goto 910
 
c inquire about variable
call ncvinq(cdfid,id,varnam,vartyp,ndim,vardim,nvatts,error)
if (vartyp.ne.NCFLOAT) error=1
if (error.gt.0) goto 920
 
c Make sure ndim <= MAXDIM.
if (ndim.gt.MAXDIM) then
error = 1
go to 900
endif
 
c get dimensions from dimension-table
do k=1,ndim
vardim(k)=dimsiz(vardim(k))
enddo
 
c get attributes
do k=1,min0(ndim,3)
c get staggering
attnam(1:1)=chrid(k)
attnam(2:5)='stag'
attnam=attnam(1:5)
call ncagt(cdfid,id,attnam,stag(k),error)
if (error.gt.0) goto 920
c get min postion
attnam(1:1)=chrid(k)
attnam(2:4)='min'
attnam=attnam(1:4)
call ncagt(cdfid,id,attnam,varmin(k),error)
if (error.gt.0) goto 920
c get max position
attnam(1:1)=chrid(k)
attnam(2:4)='max'
attnam=attnam(1:4)
call ncagt(cdfid,id,attnam,varmax(k),error)
if (error.gt.0) goto 920
enddo
 
c get missing data value
call ncagt(cdfid,id,'missing_data',misdat,error)
if (error.gt.0) goto 920
 
c get data
call ncvgt(cdfid,id,corner,vardim,dat,error)
if (error.gt.0) goto 920
 
c normal exit
call ncpopt (ncopts)
return
 
 
c Error exits.
900 write (6, *) 'ERROR: When calling getcdf, the number of ',
& 'variable dimensions must be less or equal 4.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
 
910 write (6, *) 'ERROR: The selected variable could not be found ',
& 'in the file by getcdf.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
 
920 write (6, *) 'ERROR: An error occurred while attempting to ',
& 'read the data file in subroutine getcdf.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
 
end
 
 
subroutine putcdf (cdfid, varnam, ndim, misdat,
& vardim, varmin, varmax, stag, dat, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to put a variable and its attributes
c onto a netCDF file for use with the UWGAP plotting package.
c It is assumed that the data is floating-point data. Prior to
c calling this routine, the file must be created (crecdf) or
c opened (opncdf).
c Any netCDF file written to must be closed with the call
c call ncclos(cdfid,error), where cdfid and error are
c as in the argumentlist below.
c Arguments:
c cdfid int input file-identifier
c (can be obtained by calling routine
c opncdf)
c varnam char input the user-supplied variable name.
c (can be obtained by calling routine
c opncdf)
c ndim int input the number of dimensions (ndim<=4)
c misdat real input missing data value for the variable.
c vardim int input the dimensions of the variable.
c is dimensioned at least (ndim).
c varmin real input the location in physical space of the
c origin of each variable.
c is dimensioned at least Min(ndim,3).
c varmax real input the extent of each variable in physical
c space.
c is dimensioned at least Min(ndim,3).
c stag real input the grid staggering for each variable.
c is dimensioned at least Min(ndim,3).
c dat real input data-array dimensioned suffiecently
c large, at least
c vardim(1)* ... vardim(ndim)
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 error detected.
c History:
c Nov. 91 PPM UW Created cr3df, wr3df.
c Jan. 92 CS UW Created putcdf.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer MAXDIM
parameter (MAXDIM=4)
character *(*) varnam
integer vardim(*), ndim, error, cdfid
real misdat, stag(*), varmin(*), varmax(*), dat(*)
 
c Local variable declarations.
character *(20) dimnam,attnam,dimchk
character *(1) chrid(MAXDIM)
character *(20) dimnams(MAXNCDIM)
integer dimvals(MAXNCDIM)
integer numdims,numvars,numgats,dimulim
integer id,did(MAXDIM),i,k,corner(MAXDIM)
integer ncopts
integer ibeg,iend
data chrid/'x','y','z','t'/
data corner/1,1,1,1/
 
c Get current value of error options.
call ncgopt (ncopts)
 
c make sure netCDF-errors do not abort execution
call ncpopt(NCVERBOS)
 
c Initially set error to indicate no errors.
error = 0
 
c Make sure ndim <= MAXDIM.
if (ndim.gt.MAXDIM) then
error = 1
go to 900
endif
 
c Read existing dimensions-declarations from the file
call ncinq(cdfid,numdims,numvars,numgats,dimulim,error)
if (error.ne.0) numdims=0
if (numdims.gt.0) then
do i=1,numdims
call ncdinq(cdfid,i,dimnams(i),dimvals(i),error)
c print *,dimnams(i),dimvals(i)
enddo
endif
 
c put file into define mode
call ncredf(cdfid,error)
if (error.ne.0) goto 920
 
c define the dimension
do k=1,ndim
c define the dimension-name
dimnam(1:3)='dim'
dimnam(4:4)=chrid(k)
dimnam(5:5)='_'
dimnam(6:5+len_trim(varnam))=trim(varnam)
dimnam=dimnam(1:5+len_trim(varnam))
did(k)=-1
if (numdims.gt.0) then
c check if an existing dimension-declaration can be used
c instead of defining a nuw dimension
do i=1,numdims
dimchk=dimnams(i)
if ((vardim(k).eq.dimvals(i)).and.
& (dimnam(1:4).eq.dimchk(1:4))) then
did(k)=i
goto 100
endif
enddo
100 continue
endif
if (did(k).lt.0) then
c define the dimension
did(k)=ncddef(cdfid,dimnam,vardim(k),error)
if (error.ne.0) goto 920
endif
enddo
 
c define variable
id=ncvdef(cdfid,varnam,NCFLOAT,ndim,did,error)
if (error.ne.0) goto 920
 
c define attributes
do k=1,min0(ndim,3)
c staggering
attnam(1:1)=chrid(k)
attnam(2:5)='stag'
attnam=attnam(1:5)
call ncapt(cdfid,id,attnam,NCFLOAT,1,stag(k),error)
if (error.gt.0) goto 920
c min postion
attnam(1:1)=chrid(k)
attnam(2:4)='min'
attnam=attnam(1:4)
call ncapt(cdfid,id,attnam,NCFLOAT,1,varmin(k),error)
if (error.gt.0) goto 920
c max position
attnam(1:1)=chrid(k)
attnam(2:4)='max'
attnam=attnam(1:4)
call ncapt(cdfid,id,attnam,NCFLOAT,1,varmax(k),error)
if (error.gt.0) goto 920
enddo
 
c define missing data value
call ncapt(cdfid,id,'missing_data',NCFLOAT,1,misdat,error)
if (error.gt.0) goto 920
 
c leave define mode
call ncendf(cdfid,error)
if (error.gt.0) goto 920
 
c define data
call ncvpt(cdfid,id,corner,vardim,dat,error)
if (error.gt.0) goto 920
 
c synchronyse output to disk and exit
call ncsnc (cdfid,error)
call ncpopt (ncopts)
return
 
c Error exits.
900 write (6, *) 'ERROR: When calling putcdf, the number of ',
& 'variable dimensions must be less or equal 4.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
 
920 write (6, *) 'ERROR: An error occurred while attempting to ',
& 'write the data file in subroutine putcdf.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
end
c
c
subroutine getdef (cdfid, varnam, ndim, misdat,
& vardim, varmin, varmax, stag, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to get the dimensions and attributes of
c a variable from an IVE-NetCDF file for use with the IVE plotting
c package. Prior to calling this routine, the file must be opened
c with a call to opncdf.
c Arguments:
c cdfid int input file-identifier
c (can be obtained by calling routine
c opncdf)
c varnam char input the user-supplied variable name.
c (can be obtained by calling routine
c opncdf)
c ndim int output the number of dimensions (ndim<=4)
c misdat real output missing data value for the variable.
c vardim int output the dimensions of the variable.
c Is dimensioned at least (ndim).
c varmin real output the location in physical space of the
c origin of each variable.
c Is dimensioned at least Min(3,ndim).
c varmax real output the extend of each variable in physical
c space.
c Is dimensioned at least Min(3,ndim).
c stag real output the grid staggering for each variable.
c Is dimensioned at least Min(3,ndim).
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 the variable is not on the file.
c error =10 other errors.
c History:
c Apr. 93 Christoph Schaer (ETHZ) Created.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
c Argument declarations.
integer MAXDIM
parameter (MAXDIM=4)
character *(*) varnam
integer vardim(*), ndim, error, cdfid
real misdat, stag(*), varmin(*), varmax(*)
 
c Local variable declarations.
character *(20) dimnam(MAXNCDIM),attnam,vnam
character *(1) chrid(MAXDIM)
integer id,i,k
integer ndims,nvars,ngatts,recdim,dimsiz(MAXNCDIM)
integer vartyp,nvatts, ncopts
data chrid/'x','y','z','t'/
 
c Get current value of error options.
call ncgopt (ncopts)
 
c make sure NetCDF-errors do not abort execution
call ncpopt(NCVERBOS)
 
c Initially set error to indicate no errors.
error = 0
 
c inquire for number of dimensions
call ncinq(cdfid,ndims,nvars,ngatts,recdim,error)
if (error.eq.1) goto 920
 
c read dimension-table
do i=1,ndims
call ncdinq(cdfid,i,dimnam(i),dimsiz(i),error)
if (error.gt.0) goto 920
enddo
 
c get id of the variable
id=ncvid(cdfid,varnam,error)
if (error.eq.1) goto 910
 
c inquire about variable
call ncvinq(cdfid,id,vnam,vartyp,ndim,vardim,nvatts,error)
if (vartyp.ne.NCFLOAT) error=1
if (error.gt.0) goto 920
 
c Make sure ndim <= MAXDIM.
if (ndim.gt.MAXDIM) then
error = 1
go to 900
endif
 
c get dimensions from dimension-table
do k=1,ndim
vardim(k)=dimsiz(vardim(k))
enddo
 
c get attributes
do k=1,min0(3,ndim)
c get min postion
attnam(1:1)=chrid(k)
attnam(2:4)='min'
attnam=attnam(1:4)
call ncagt(cdfid,id,attnam,varmin(k),error)
if (error.gt.0) goto 920
c get max position
attnam(1:1)=chrid(k)
attnam(2:4)='max'
attnam=attnam(1:4)
call ncagt(cdfid,id,attnam,varmax(k),error)
if (error.gt.0) goto 920
c get staggering
attnam(1:1)=chrid(k)
attnam(2:5)='stag'
attnam=attnam(1:5)
call ncagt(cdfid,id,attnam,stag(k),error)
if (error.gt.0) goto 920
enddo
 
c get missing data value
call ncagt(cdfid,id,'missing_data',misdat,error)
if (error.gt.0) goto 920
 
c normal exit
call ncpopt (ncopts)
return
 
c Error exits.
900 write (6, *) '*ERROR*: When calling getcdf, the number of ',
& 'variable dimensions must be less or equal 4.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
 
910 write (6, *) '*ERROR*: The selected variable could not be found ',
& 'in the file by getcdf.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
return
 
920 write (6, *) '*ERROR*: An error occurred while attempting to ',
& 'read the data file in subroutine getcdf.'
call ncpopt (ncopts)
call ncclos (cdfid, error)
end
 
 
 
subroutine getdat(cdfid, varnam, time, level, dat, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to read the data of a variable
c from an IVE-NetCDF file for use with the IVE plotting package.
c Prior to calling this routine, the file must be opened with
c a call to opncdf (for extension) or crecdf (for creation) or
c readcdf (for readonly).
c Arguments:
c cdfid int input file-identifier
c (must be obtained by calling routine
c opncdf,readcdf or crecdf)
c varnam char input the user-supplied variable name (must
c previously be defined with a call to
c putdef)
c time real input the user-supplied time-level of the
c data to be read from the file (the time-
c levels stored in the file can be obtained
c with a call to gettimes).
c level int input the horizontal level(s) to be read
c to the NetCDF file. Suppose that the
c variable is defined as (nx,ny,nz,nt).
c level>0: the call reads the subdomain
c (1:nx,1:ny,level,itimes)
c level=0: the call reads the subdomain
c (1:nx,1:ny,1:nz,itimes)
c Here itimes is the time-index corresponding
c to the value of 'time'.
c dat real output data-array dimensioned sufficiently
c large. The dimensions (nx,ny,nz)
c of the variable must previously be defined
c with a call to putdef. No previous
c definition of the time-dimension is
c required.
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 the variable is not present on
c the file.
c error = 2 the value of 'time' is not
c known.to the file.
c error = 3 inconsistent value of level
c error =10 another error.
c History:
c March 93 Heini Wernli (ETHZ) Created wr2cdf.
c April 93 Bettina Messmer (ETHZ) Created putdat.
c June 93 Christoph Schaer (ETHZ) Created getdat
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
C Declaration of local variables
character*(*) varnam
character*(20) chars
integer cdfid
 
real dat(*)
real misdat,varmin(4),varmax(4),stag(4)
real time, timeval
 
integer corner(4),edgeln(4),didtim,vardim(4),ndims
integer error, ierr
integer level,ntime
integer idtime,idvar,iflag
integer i
 
call ncpopt(NCVERBOS)
 
c access the variable
call getdef (cdfid, trim(varnam), ndims, misdat,
& vardim, varmin, varmax, stag, ierr)
if (ierr.ne.0) then
print *,'*ERROR* in getdef in getdat'
error=1
return
endif
idvar=ncvid(cdfid,trim(varnam),ierr)
if (ierr.ne.0) then
print *,'*ERROR* in ncvid in getdat'
error=1
return
endif
 
C Get times-array
didtim=ncdid(cdfid,'time',ierr)
if (ierr.ne.0) then
print *,'*ERROR* didtim in getdat'
error=10
return
endif
call ncdinq(cdfid,didtim,chars,ntime,ierr)
if (ierr.ne.0) then
print *,'*ERROR* in ncdinq in getdat'
error=10
return
endif
idtime=ncvid(cdfid,'time',ierr)
if (ierr.ne.0) then
print *,'*ERROR* in ncvid for time in getdat'
error=10
return
endif
c find appropriate time-index
iflag=0
do i=1,ntime
call ncvgt1(cdfid,idtime,i,timeval,ierr)
if (ierr.ne.0) print *,'*ERROR* in ncvgt1 in getdat'
if (time.eq.timeval) iflag=i
enddo
if (iflag.eq.0) then
error=2
print *,'Error: Unknown time in getdat'
return
endif
 
C Define data volume to be written (index space)
corner(1)=1
corner(2)=1
edgeln(1)=vardim(1)
edgeln(2)=vardim(2)
if (level.eq.0) then
corner(3)=1
edgeln(3)=vardim(3)
else if ((level.le.vardim(3)).and.(level.ge.1)) then
corner(3)=level
edgeln(3)=1
else
error=3
return
endif
corner(4)=iflag
edgeln(4)=1
 
C Read data from NetCDF file
c print *,'getdat vor Aufruf ncvgt'
c print *,'cdfid ',cdfid
c print *,'idvar ',idvar
c print *,'corner ',corner
c print *,'edgeln ',edgeln
 
call ncvgt(cdfid,idvar,corner,edgeln,dat,error)
if (error.ne.0) then
print *, '*ERROR* in ncvgt in getdat'
error=10
endif
end
 
 
 
subroutine putdat(cdfid, varnam, time, level, dat, error)
c-----------------------------------------------------------------------
c Purpose:
c This routine is called to write the data of a variable
c to an IVE-NetCDF file for use with the IVE plotting package.
c Prior to calling this routine, the file must be opened with
c a call to opncdf (for extension) or crecdf (for creation), the
c variable must be defined with a call to putdef.
c Arguments:
c cdfid int input file-identifier
c (must be obtained by calling routine
c opncdf or crecdf)
c varnam char input the user-supplied variable name (must
c previously be defined with a call to
c putdef)
c time real input the user-supplied time-level of the
c data to be written to the file (the time-
c levels stored in the file can be obtained
c with a call to gettimes). If 'time' is not
c yet known to the file, a knew time-level is
c allocated and appended to the times-array.
c level int input the horizontal level(s) to be written
c to the NetCDF file. Suppose that the
c variable is defined as (nx,ny,nz,nt).
c level>0: the call writes the subdomain
c (1:nx,1:ny,level,itimes)
c level=0: the call writes the subdomain
c (1:nx,1:ny,1:nz,itimes)
c Here itimes is the time-index corresponding
c to the value of 'time'.
c dat real output data-array dimensioned sufficiently
c large. The dimensions (nx,ny,nz)
c of the variable must previously be defined
c with a call to putdef. No previous
c definition of the time-dimension is
c required.
c error int output indicates possible errors found in this
c routine.
c error = 0 no errors detected.
c error = 1 the variable is not present on
c the file.
c error = 2 the value of 'time' is new, but
c appending it would yield a non
c ascending times-array.
c error = 3 inconsistent value of level
c error =10 another error.
c History:
c March 93 Heini Wernli (ETHZ) Created wr2cdf.
c April 93 Bettina Messmer (ETHZ) Created putdat.
c-----------------------------------------------------------------------
 
include "netcdf.inc"
 
C Declaration of local variables
 
character*(*) varnam
character*(20) chars
integer cdfid
 
 
real dat(*)
real misdat,varmin(4),varmax(4),stag(4)
real time, timeval
data stag/0.,0.,0.,0./
 
integer corner(4),edgeln(4),did(4),vardim(4),ndims
integer error, ierr
integer level,ntime
integer idtime,idvar,iflag
integer i
 
call ncpopt(NCVERBOS)
 
c get definitions of data
call getdef (cdfid, trim(varnam), ndims, misdat,
& vardim, varmin, varmax, stag, ierr)
if (ierr.ne.0) print *,'*ERROR* in getdef in putdat'
 
c get id of variable
idvar=ncvid(cdfid,trim(varnam),ierr)
if (ierr.ne.0) print *,'*ERROR* in ncvid in putdat'
 
c get times-array
did(4)=ncdid(cdfid,'time',ierr)
if (ierr.ne.0) print *,'*ERROR* did(4) in putdat'
call ncdinq(cdfid,did(4),chars,ntime,ierr)
if (ierr.ne.0) print *,'*ERROR* in ncdinq in putdat'
idtime=ncvid(cdfid,'time',ierr)
if (ierr.ne.0) print *,'*ERROR* in ncvid in putdat'
C Check if a new time step is starting
iflag=0
do i=1,ntime
call ncvgt1(cdfid,idtime,i,timeval,ierr)
if (ierr.ne.0) print *,'*ERROR* in ncvgt1 in putdat'
if (time.eq.timeval) iflag=i
enddo
if (iflag.eq.0) then ! new time step
ntime=ntime+1
iflag=ntime
idtime=ncvid(cdfid,'time',ierr)
if (ierr.ne.0) print *, '*ERROR* in ncvid in putdat'
call ncvpt1(cdfid,idtime,ntime,time,ierr)
if (ierr.ne.0) print *, '*ERROR* in ncvpt1 in putdat'
endif
 
C Define data volume to write on the NetCDF file in index space
corner(1)=1 ! starting corner of data volume
corner(2)=1
edgeln(1)=vardim(1) ! edge lengthes of data volume
edgeln(2)=vardim(2)
if (level.eq.0) then
corner(3)=1
edgeln(3)=vardim(3)
else
corner(3)=level
edgeln(3)=1
endif
corner(4)=iflag
edgeln(4)=1
C Put data on NetCDF file
 
c print *,'vor Aufruf ncvpt d.h. Daten schreiben in putdat '
c print *,'cdfid ',cdfid
c print *,'idvar ',idvar
c print *,'corner ',corner
c print *,'edgeln ',edgeln
 
call ncvpt(cdfid,idvar,corner,edgeln,dat,error)
if (error.ne.0) then
print *, '*ERROR* in ncvpt in putdat - Put data on Net