Blame | Last modification | View Log | Download | RSS feed
PROGRAM pv_to_qgpv
c ********************************************************************************
c * TRANSFORM ERTEL'S PV TO QUASI-GEOSTROPHIC PV *
c * Rene Fehlmann 1994 / Code re-organization: Michael Sprenger, 2006 *
c ********************************************************************************
c --------------------------------------------------------------------------------
c Declaration of variables, parameters, externals and common blocks
c --------------------------------------------------------------------------------
implicit none
c Input and output file
character*80 pvsrcfile
character*80 referfile
character*80 anomafile
c Grid parameters
integer nx,ny,nz
real xmin,ymin,zmin,xmax,ymax,zmax
real dx,dy,dz
real mdv
c Numerical and physical parameters
real pi180 ! Pi/180
parameter (pi180=3.141592654/180.)
real rerd ! Earth's radius
parameter (rerd=6.371229e6)
real eps ! Numerical epsilon
parameter (eps=0.01)
real scale ! Scale for PV unit
parameter (scale=1e6)
real minagl ! No PV and qgPV below this height AGL
parameter (minagl=1000.)
c Reference state and grid parameters
real, allocatable,dimension (:) :: nsqref
real, allocatable,dimension (:) :: thetaref
real, allocatable,dimension (:) :: rhoref
real, allocatable,dimension (:) :: pressref
real, allocatable,dimension (:) :: zref
real, allocatable,dimension (:,:) :: coriol
real, allocatable,dimension (:,:) :: oro
real deltax,deltay,deltaz
c 3d fields for calculation of qgPV and Ertel's PV
real,allocatable,dimension (:,:,:) :: qgpv,pv1,pv2,pv
c Auxiliary variables
real zpos
integer i,j,k
integer stat
character*80 varname
integer istep
real mean,rmsq,min,max
integer step
real,allocatable,dimension (:,:) :: tmp
c --------------------------------------------------------------------------------
c Input
c --------------------------------------------------------------------------------
print*,'********************************************************'
print*,'* PV_TO_QGPV *'
print*,'********************************************************'
c Read parameter file
open(10,file='fort.10')
read(10,*) pvsrcfile
read(10,*) referfile
read(10,*) anomafile
close(10)
print*
print*,trim(pvsrcfile)
print*,trim(referfile)
print*,trim(anomafile)
print*
c Get lat/lon gid parameters from input file
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> pvsrcfile)
print*,'Read_Dim: nx,ny,nz = ',nx,ny,nz
print*,' dx,dy,dz = ',dx,dy,dz
print*,' xmin,ymin,zmin = ',xmin,ymin,zmin
print*,' mdv = ',mdv
print*
c Count from 0, not from 1: consistent with <inv_cart.f>.
nx=nx-1
ny=ny-1
nz=nz-1
c Allocate memory for reference profile and grid parameters
allocate(rhoref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating rhoref'
allocate(pressref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pressref'
allocate(thetaref(0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating thetaref'
allocate(nsqref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating nsqref'
allocate(zref (0:2*nz),STAT=stat)
if (stat.ne.0) print*,'error allocating zref'
allocate(coriol (0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating coriol'
allocate(oro (0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating oro'
c Allocate memory for calculation of qgPV and Ertel's PV
allocate(pv1 (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv1'
allocate(pv2 (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv2'
allocate(pv (0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating pv'
allocate(qgpv(0:nx,0:ny,0:nz),STAT=stat)
if (stat.ne.0) print*,'error allocating qgpv'
c Allocate memory for temporary array
allocate(tmp(0:nx,0:ny),STAT=stat)
if (stat.ne.0) print*,'error allocating tmp'
c --------------------------------------------------------------------------------
c Calculate the qgPV from Ertel's PV and put it onto file
c --------------------------------------------------------------------------------
c Read data from file
varname='PV'
call read_inp (pv1,varname,pvsrcfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
varname='PV_AIM'
call read_inp (pv2,varname,pvsrcfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
c Read reference profile and grid parameters
call read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,coriol,oro,
> referfile)
c If the PV is negative, set it to zero
do i=0,nx
do j=0,ny
do k=0,nz
if (pv1(i,j,k).lt.0.) pv1(i,j,k)=0.
if (pv2(i,j,k).lt.0.) pv2(i,j,k)=0.
enddo
enddo
enddo
c Get the difference of Ertel's PV and set all missing values to 0
do i=0,nx
do j=0,ny
do k=0,nz
if ((abs(pv1(i,j,k)-mdv).gt.eps).and.
> (abs(pv2(i,j,k)-mdv).gt.eps)) then
pv(i,j,k)=pv1(i,j,k)-pv2(i,j,k)
else
pv(i,j,k)=0.
endif
enddo
enddo
enddo
c Calculate qgPV
call epv_to_qgpv (qgpv,pv,
> rhoref,pressref,nsqref,thetaref,
> nx,ny,nz,mdv)
c Set values on the boundaries to zero
do i=0,nx
do j=0,ny
qgpv(i,j, 0)=0.
qgpv(i,j,nz)=0.
enddo
enddo
do i=0,nx
do k=0,nz
qgpv(i, 0,k)=0.
qgpv(i,ny,k)=0.
enddo
enddo
do j=0,ny
do k=0,nz
qgpv( 0,j,k)=0.
qgpv(nx,j,k)=0.
enddo
enddo
c Set all values to zero which are too near to the surface
do i=0,nx
do j=0,ny
do k=0,nz
zpos=zmin+real(k)*dz
if (zpos.lt.(oro(i,j)+minagl)) then
pv(i,j,k)=0.
qgpv(i,j,k)=0.
endif
enddo
enddo
enddo
c Write result to netcdf file
varname='QGPV'
call write_inp (qgpv,varname,anomafile,nx,ny,nz)
varname='PV'
call write_inp (pv,varname,anomafile,nx,ny,nz)
c Write some info
print*
print*,'PV -> qgPV: k z min max mean rmsq'
step=nz/10
if (step.lt.1) step=1
do k=0,nz,step
do i=0,nx
do j=0,ny
tmp(i,j)=qgpv(i,j,k)
enddo
enddo
call calc_error(min,max,mean,rmsq,tmp,nx,ny)
write(*,'(8x,i3,f10.1,4f10.2)')
> k,zmin+real(k)*dz,scale*min,scale*max,
> scale*mean,scale*rmsq
enddo
print*
c --------------------------------------------------------------------------------
c Format specifications
c --------------------------------------------------------------------------------
111 format (5f20.9)
106 format (2f20.9)
end
c ********************************************************************************
c * NETCDF INPUT AND OUTPUT *
c ********************************************************************************
c --------------------------------------------------------------------------------
c Write input field to netcdf
c --------------------------------------------------------------------------------
SUBROUTINE write_inp (field,fieldname,pvsrcfile,nx,ny,nz)
c Read <fieldname> from netcdf file <pvsrcfile> into <field>. The grid is specified
c by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the input
c files are consitent with this grid.
implicit none
c Declaration of subroutine parameters
integer nx,ny,nz
real field (0:nx,0:ny,0:nz)
character*80 fieldname
character*80 pvsrcfile
c Auxiliary variables
integer cdfid,stat
integer vardim(4)
real misdat
real varmin(4),varmax(4),stag(4)
integer ndimin,outid,i,j,k
real tmp(0:nx,0:ny,0:nz)
integer ntimes
real time(200)
integer nvars
character*80 vnam(100),varname
integer isok
c Get grid parameters from PV
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 998
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 998
isok=0
varname='PV'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 998
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 998
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
c Save variables (write definition, if necessary)
call cdfwopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 998
isok=0
varname=fieldname
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
endif
call putdat(cdfid,varname,time(1),0,field,stat)
print*,'W ',trim(varname),' ',trim(pvsrcfile)
if (stat.ne.0) goto 998
c Close input netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
return
c Exception handling
998 print*,'Write_Inp: Problem with input netcdf file... Stop'
stop
end
c --------------------------------------------------------------------------------
c Read input fields for reference profile
c --------------------------------------------------------------------------------
SUBROUTINE read_inp (field,fieldname,pvsrcfile,
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)
c Read <fieldname> from netcdf file <pvsrcfile> into <field>. The grid is specified
c by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the input
c files are consitent with this grid. The missing data value is set to <mdv>.
implicit none
c Declaration of subroutine parameters
integer nx,ny,nz
real field(0:nx,0:ny,0:nz)
character*80 fieldname
character*80 pvsrcfile
real dx,dy,dz,xmin,ymin,zmin
real mdv
c Numerical and physical parameters
real eps
parameter (eps=0.01)
c Auxiliary variables
integer cdfid,stat,cdfid99
integer vardim(4)
real misdat
real varmin(4),varmax(4),stag(4)
integer ndimin,outid,i,j,k
real tmp(nx,ny,nz)
integer ntimes
real time(200)
integer nvars
character*80 vnam(100),varname
integer isok
c Open the input netcdf file
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 998
c Check whether needed variables are on file
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 998
isok=0
varname=trim(fieldname)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 998
c Get the grid parameters from theta
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 998
c Check whether grid parameters are consistent
if ( (vardim(1).ne.(nx+1)).or.
> (vardim(2).ne.(ny+1)).or.
> (vardim(3).ne.(nz+1)).or.
> (abs(varmin(1)-xmin).gt.eps).or.
> (abs(varmin(2)-ymin).gt.eps).or.
> (abs(varmin(3)-zmin).gt.eps).or.
> (abs((varmax(1)-varmin(1))/real(vardim(1)-1)-dx).gt.eps).or.
> (abs((varmax(2)-varmin(2))/real(vardim(2)-1)-dy).gt.eps).or.
> (abs((varmax(3)-varmin(3))/real(vardim(3)-1)-dz).gt.eps) )
>then
print*,'Input grid inconsitency...'
print*,' Nx = ',vardim(1),nx+1
print*,' Ny = ',vardim(2),ny+1
print*,' Nz = ',vardim(3),nz+1
print*,' Varminx = ',varmin(1),xmin
print*,' Varminy = ',varmin(2),ymin
print*,' Varminz = ',varmin(3),zmin
print*,' Dx = ',(varmax(1)-varmin(1))/real(nx-1),dx
print*,' Dy = ',(varmax(2)-varmin(2))/real(ny-1),dy
print*,' Dz = ',(varmax(3)-varmin(3))/real(nz-1),dz
goto 998
endif
c Load variables
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 998
call getdat(cdfid,varname,time(1),0,field,stat)
print*, 'R ',trim(varname),' ',trim(pvsrcfile)
if (stat.ne.0) goto 998
c Close input netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 998
c Set missing data value to <mdv>
do i=1,nx
do j=1,ny
do k=1,nz
if (abs(field(i,j,k)-misdat).lt.eps) then
field(i,j,k)=mdv
endif
enddo
enddo
enddo
return
c Exception handling
998 print*,'Read_Inp: Problem with input netcdf file... Stop'
stop
end
c --------------------------------------------------------------------------------
c Read refernece profile from netcdf
c --------------------------------------------------------------------------------
SUBROUTINE read_ref (nsqref,rhoref,thetaref,pressref,zref,
> nx,ny,nz,deltax,deltay,deltaz,coriol,oro,
> pvsrcfile)
c Read the reference profile from file
c
c thetaref : Reference potential temperature (K)
c pressref : Reference pressure (Pa)
c rhoref : Reference density (kg/m^3)
c nsqref : Stratification (s^-1)
c zref : Reference height (m)
c nx,nny,nz : Grid dimension in x,y,z direction
c deltax,deltay,deltaz : Grid spacings used for calculations (m)
c coriol : Coriolis parameter (s^-1)
c oro : Height of orography (m)
c pvsrcfile : Input file
implicit none
c Declaration of subroutine parameters
integer nx,ny,nz
real nsqref (0:2*nz)
real thetaref(0:2*nz)
real rhoref (0:2*nz)
real pressref(0:2*nz)
real zref (0:2*nz)
real deltax,deltay,deltaz
real coriol (0:nx,0:ny)
real oro (0:nx,0:ny)
character*80 pvsrcfile
c Numerical and physical parameters
real eps
parameter (eps=0.01)
c Auxiliary variables
integer cdfid,stat
integer vardim(4)
real misdat
integer ndimin
real varmin(4),varmax(4),stag(4)
integer i,j,k,nf1
integer ntimes
real time(200)
character*80 vnam(100),varname
integer nvars
integer isok,ierr
real x(0:nx,0:ny),y(0:nx,0:ny)
real mean,count
c Get grid description from topography
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 997
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 997
isok=0
varname='ORO'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdef(cdfid,varname,ndimin,misdat,vardim,
> varmin,varmax,stag,stat)
if (stat.ne.0) goto 997
time(1)=0.
call gettimes(cdfid,time,ntimes,stat)
if (stat.ne.0) goto 997
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
c Open output netcdf file
call cdfopn(pvsrcfile,cdfid,stat)
if (stat.ne.0) goto 997
c Create the variable if necessary
call getvars(cdfid,nvars,vnam,stat)
if (stat.ne.0) goto 997
c Read data from netcdf file
isok=0
varname='NSQREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,nsqref,stat)
if (stat.ne.0) goto 997
isok=0
varname='RHOREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,rhoref,stat)
if (stat.ne.0) goto 997
isok=0
varname='THETAREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,thetaref,stat)
if (stat.ne.0) goto 997
isok=0
varname='PREREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,pressref,stat)
if (stat.ne.0) goto 997
isok=0
varname='ZREF'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,zref,stat)
if (stat.ne.0) goto 997
isok=0
varname='CORIOL'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,coriol,stat)
if (stat.ne.0) goto 997
isok=0
varname='ORO'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,oro,stat)
if (stat.ne.0) goto 997
isok=0
varname='X'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,x,stat)
if (stat.ne.0) goto 997
isok=0
varname='Y'
print*,'R ',trim(varname),' ',trim(pvsrcfile)
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 997
call getdat(cdfid,varname,time(1),0,y,stat)
if (stat.ne.0) goto 997
c Close netcdf file
call clscdf(cdfid,stat)
if (stat.ne.0) goto 997
c Determine the grid spacings <deltax, deltay, deltaz>
mean=0.
count=0.
do i=1,nx
do j=0,ny
mean=mean+abs(x(i)-x(i-1))
count=count+1.
enddo
enddo
deltax=mean/count
mean=0.
count=0.
do j=1,ny
do i=0,nx
mean=mean+abs(y(j)-y(j-1))
count=count+1.
enddo
enddo
deltay=mean/count
mean=0.
count=0.
do k=1,nz-1
mean=mean+abs(zref(k+1)-zref(k-1))
count=count+1.
enddo
deltaz=mean/count
return
c Exception handling
997 print*,'Read_Ref: Problem with input netcdf file... Stop'
stop
end
c --------------------------------------------------------------------------------
c Check whether variable is found on netcdf file
c --------------------------------------------------------------------------------
subroutine check_varok (isok,varname,varlist,nvars)
c Check whether the variable <varname> is in the list <varlist(nvars)>. If this is
C the case, <isok> is incremented by 1. Otherwise <isok> keeps its value.
implicit none
c Declaraion of subroutine parameters
integer isok
integer nvars
character*80 varname
character*80 varlist(nvars)
c Auxiliary variables
integer i
c Main
do i=1,nvars
if (trim(varname).eq.trim(varlist(i))) isok=isok+1
enddo
end
c --------------------------------------------------------------------------------
c Get grid parameters
c --------------------------------------------------------------------------------
subroutine read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,
> pvsrcfile)
c Get the grid parameters from the variable <THETA> on the input file <pvsrcfile>.
c The grid parameters are
c nx,ny,nz : Number of grid points in x, y and z direction
c xmin,ymin,zmin : Minimum domain coordinates in x, y and z direction
c xmax,ymax,zmax : Maximal domain coordinates in x, y and z direction
c dx,dy,dz : Horizontal and vertical resolution
c Additionally, it is checked whether the vertical grid is equally spaced. If ok,
c the grid paramters are transformed from lon/lat to distance (in meters)
implicit none
c Declaration of subroutine parameters
character*80 pvsrcfile
integer nx,ny,nz
real dx,dy,dz
real xmin,ymin,zmin,xmax,ymax,zmax
real mdv
c Numerical epsilon and other physical/geoemtrical parameters
real eps
parameter (eps=0.01)
c Auxiliary variables
integer cdfid,cstid
integer ierr
character*80 vnam(100),varname
integer nvars
integer isok
integer vardim(4)
real misdat
real varmin(4),varmax(4),stag(4)
real aklev(1000),bklev(1000),aklay(1000),bklay(1000)
real dh
character*80 csn
integer ndim
integer i
c Get all grid parameters
call cdfopn(pvsrcfile,cdfid,ierr)
if (ierr.ne.0) goto 998
call getvars(cdfid,nvars,vnam,ierr)
if (ierr.ne.0) goto 998
isok=0
varname='PV'
call check_varok(isok,varname,vnam,nvars)
if (isok.eq.0) goto 998
call getcfn(cdfid,csn,ierr)
if (ierr.ne.0) goto 998
call cdfopn(csn,cstid,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname,ndim,misdat,vardim,varmin,varmax,
> stag,ierr)
if (ierr.ne.0) goto 998
nx=vardim(1)
ny=vardim(2)
nz=vardim(3)
xmin=varmin(1)
ymin=varmin(2)
zmin=varmin(3)
call getlevs(cstid,nz,aklev,bklev,aklay,bklay,ierr)
if (ierr.ne.0) goto 998
call getgrid(cstid,dx,dy,ierr)
if (ierr.ne.0) goto 998
xmax=varmax(1)
ymax=varmax(2)
zmax=varmax(3)
dz=(zmax-zmin)/real(nz-1)
call clscdf(cstid,ierr)
if (ierr.ne.0) goto 998
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 998
c Check whether the grid is equallay spaced in the vertical
do i=1,nz-1
dh=aklev(i+1)-aklev(i)
if (abs(dh-dz).gt.eps) then
print*,'Aklev: Vertical grid must be equally spaced... Stop'
print*,(aklev(i),i=1,nz)
stop
endif
dh=aklay(i+1)-aklay(i)
if (abs(dh-dz).gt.eps) then
print*,'Aklay: Vertical grid must be equally spaced... Stop'
print*,(aklay(i),i=1,nz)
stop
endif
enddo
c Set missing data value
mdv=misdat
return
c Exception handling
998 print*,'Read_Dim: Problem with input netcdf file... Stop'
stop
end
c ********************************************************************************
c * CALCULATION *
c ********************************************************************************
c --------------------------------------------------------------------------------
c Calculate qgPV from Ertels's PV
c --------------------------------------------------------------------------------
subroutine epv_to_qgpv (qgpv,pv,
> rhoref,pressref,nsqref,thetaref,
> nx,ny,nz,mdv)
c Calculate the qgPV from Ertel's PV according to equation 2.11 p16, Thesis
c from Rene Fehlmann.
implicit none
c Declaration of subroutine parameters
integer nx,ny,nz
real qgpv(0:nx,0:ny,0:nz),pv(0:nx,0:ny,0:nz)
real rhoref (0:2*nz)
real nsqref (0:2*nz)
real thetaref(0:2*nz)
real pressref(0:2*nz)
real mdv
c Numerical epsilon
real g
parameter (g=9.81)
real eps
parameter (eps=0.01)
real scale
parameter (scale=1e6)
c Auxiliary variables
integer i,j,k
integer kk
c Calculation
do i=0,nx
do j=0,ny
do k=0,nz
kk=2*k
if (( abs(rhoref(kk) -mdv).gt.eps).and.
> ( abs(thetaref(kk)-mdv).gt.eps).and.
> ( abs(nsqref(kk) -mdv).gt.eps).and.
> ( abs(pv(i,j,k) -mdv).gt.eps)) then
qgpv(i,j,k)=rhoref(kk)*g*pv(i,j,k)/thetaref(kk)/
> nsqref(kk)/scale
else
qgpv(i,j,k)=0.
endif
enddo
enddo
enddo
end
c --------------------------------------------------------------------------------
c Calculate error statistics
c --------------------------------------------------------------------------------
subroutine calc_error (min,max,mean,rmsq,tmp,nx,ny)
c Calculate the error statistics for the two-dimensional error field <tmp>. The
c following error measures are calculated: the minimum <min>, the maximum <max>,
c the mean <mean>, the root-mean square <rmsq>
implicit none
c Declaration of subroutine parameters
integer nx,ny
real tmp(0:nx,0:ny)
real mean,rmsq
real min,max
c Auxiliary variables
integer i,j
real sum
integer cnt
c Calculate the minimum and maximum
min=tmp(0,0)
max=tmp(0,0)
do i=0,nx
do j=0,ny
if (tmp(i,j).lt.min) min=tmp(i,j)
if (tmp(i,j).gt.max) max=tmp(i,j)
enddo
enddo
c Calculate the mean
sum=0.
cnt=0
do i=0,nx
do j=0,ny
cnt=cnt+1
sum=sum+tmp(i,j)
enddo
enddo
if (cnt.ge.1) then
mean=sum/real(cnt)
else
mean=0.
endif
c Calculate rmsq
rmsq=0.
cnt=0
do i=0,nx
do j=0,ny
cnt=cnt+1
rmsq=rmsq+(tmp(i,j)-mean)**2
enddo
enddo
if (cnt.ge.1) then
rmsq=1./real(cnt)*sqrt(rmsq)
else
rmsq=0.
endif
end