Blame | Last modification | View Log | Download | RSS feed
PROGRAM inv_prepc ********************************************************************************c * CALCULATE REFERENCE PROFILE, CORIOLIS PARAMETER AND GRID PARAMETERS *c * Rene Fehlmann 1994 / Code re-organization: Michael Sprenger, 2006 *c ********************************************************************************c --------------------------------------------------------------------------------c Declaration of variables, parameters, externals and common blocksc --------------------------------------------------------------------------------implicit nonec Input and output filecharacter*80 pvsrcfile,referfileinteger modereal radiusc Grid parametersinteger nx,ny,nzreal xmin,ymin,zmin,xmax,ymax,zmaxreal dx,dy,dzreal mdvc Reference statereal, allocatable,dimension (:) :: nsqrefreal, allocatable,dimension (:) :: thetarefreal, allocatable,dimension (:) :: rhorefreal, allocatable,dimension (:) :: pressrefreal, allocatable,dimension (:) :: zrefreal pressn,thetanc 3d fields for calculation of reference profilereal,allocatable,dimension (:,:,:) :: th,rho,nsq,p,zc 2d weight for meanreal,allocatable,dimension (:,:) :: weightc Auxiliary variablesinteger i,j,kinteger statinteger jj,kkcharacter*80 varnameinteger istepreal sum,max,mininteger cnt,nmdinteger stepinteger i0,j0real lon0,lat0,lon1,lat1,distinteger vardim(4),ndim,cdfid,ierrreal varmin(4),varmax(4),stag(4)real mdvcharacter*80 namec Externalsreal sdisexternal sdisc --------------------------------------------------------------------------------c Inputc --------------------------------------------------------------------------------print*,'********************************************************'print*,'* ref_grid *'print*,'********************************************************'c Read parameter fileopen(10,file='fort.10')read(10,*) pvsrcfileread(10,*) referfileread(10,*) name,radiusif ( trim(name).ne.'REF_R') stopclose(10)print*print*,trim(pvsrcfile)print*,trim(referfile)print*,radiusprint*c Get lat/lon gid parameters from input filecall read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,> pvsrcfile)print*,'Read_Dim: nx,ny,nz = ',nx,ny,nzprint*,' dx,dy,dz = ',dx,dy,dzprint*,' xmin,ymin,zmin = ',xmin,ymin,zminprint*,' mdv = ',mdvprint*xmax = xmin + real(nx-1) * dxymax = ymin + real(ny-1) * dyc Count from 0, not from 1: consistent with <inv_cart.f>.nx=nx-1ny=ny-1nz=nz-1c Allocate memory for reference profileallocate(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 calculatation of reference profileallocate(th (0:nx,0:ny,0:nz),STAT=stat)if (stat.ne.0) print*,'error allocating th'allocate(rho(0:nx,0:ny,0:nz),STAT=stat)if (stat.ne.0) print*,'error allocating rho'allocate(p (0:nx,0:ny,0:nz),STAT=stat)if (stat.ne.0) print*,'error allocating p'allocate(nsq(0:nx,0:ny,0:nz),STAT=stat)if (stat.ne.0) print*,'error allocating nsq'allocate(z(0:nx,0:ny,0:nz),STAT=stat)if (stat.ne.0) print*,'error allocating z'c Allocate memory for weightallocate(weight(0:nx,0:ny),STAT=stat)if (stat.ne.0) print*,'error allocating weight'c --------------------------------------------------------------------------------c Calculate the reference profile and put it onto netcdf filec --------------------------------------------------------------------------------c Read data from filevarname='TH'call read_inp (th,varname,pvsrcfile,> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)varname='RHO'call read_inp (rho,varname,pvsrcfile,> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)varname='NSQ'call read_inp (nsq,varname,pvsrcfile,> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)varname='P'call read_inp (p,varname,pvsrcfile,> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv)c Init the height field (not really necessary, but code becomes more symmetrical)do i=0,nxdo j=0,nydo k=0,nzz(i,j,k)=zmin+real(k)*dzenddoenddoenddoc Define the weightif ( radius.lt.0 ) thendo i=0,nxdo j=0,nyweight(i,j) = 1.enddoenddoelsei0 = nx/2j0 = ny/2lon0 = xmin + real(i0-1) * dxlat0 = ymin + real(j0-1) * dyweight(i0,j0)=1.do i=0,nxdo j=0,nylon1 = xmin + real(i-1) * dxlat1 = ymin + real(j-1) * dydist = sdis(lon0,lat0,lon1,lat1)if ( dist.lt.radius ) thenweight(i,j) = 1.elseweight(i,j) = 0.endifenddoenddoendifc Determine the reference profile (mean over domain, split levels and layers)call mean(zref, z, nx,ny,nz,mdv,weight)call mean(nsqref, nsq,nx,ny,nz,mdv,weight)call mean(rhoref, rho,nx,ny,nz,mdv,weight)call mean(thetaref,th, nx,ny,nz,mdv,weight)call mean(pressref,p, nx,ny,nz,mdv,weight)c Write reference file to netcdf filecall write_ref (nsqref,rhoref,thetaref,pressref,zref,> nz,referfile)c Write some infoprint*print*,'Ref: z p rho nsq theta'step=2*nz/10if (step.lt.1) step=1do k=0,2*nz,stepwrite(*,'(8x,f10.1,2f10.2,f10.6,f10.2)')> zref(k),pressref(k),rhoref(k),nsqref(k),thetaref(k)enddoprint*c Write weighht to REF filecall cdfwopn(trim(referfile),cdfid,ierr)varname='WEIGHT'vardim(1)=nx+1vardim(2)=ny+1vardim(3)=1vardim(4)=1varmin(1)=xminvarmin(2)=yminvarmin(3)=0.varmax(1)=xmaxvarmax(2)=ymaxvarmax(3)=0.ndim=3mdv=-999.call putdef(cdfid,varname,ndim,mdv,vardim,> varmin,varmax,stag,ierr)call putdat(cdfid,varname,0.,1,weight,ierr)c --------------------------------------------------------------------------------c Format specificationsc --------------------------------------------------------------------------------111 format (5f20.9)106 format (2f20.9)endc --------------------------------------------------------------------------c Spherical distance between lat/lon pointsc --------------------------------------------------------------------------real function sdis(xp,yp,xq,yq)cc calculates spherical distance (in km) between two points givenc by their spherical coordinates (xp,yp) and (xq,yq), respectively.creal reparameter (re=6370.)real pi180parameter (pi180=3.14159/180.)real xp,yp,xq,yq,argarg=sin(pi180*yp)*sin(pi180*yq)+> cos(pi180*yp)*cos(pi180*yq)*cos(pi180*(xp-xq))if (arg.lt.-1.) arg=-1.if (arg.gt.1.) arg=1.sdis=re*acos(arg)endc ********************************************************************************c * NETCDF INPUT AND OUTPUT *c ********************************************************************************c --------------------------------------------------------------------------------c Write reference file to netcdfc --------------------------------------------------------------------------------SUBROUTINE write_ref (nsqref,rhoref,thetaref,pressref,zref,> nz,pvsrcfile)c Write the reference profile to filecc 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 nz : Grid dimension in z directionc pvsrcfile : Output fileimplicit nonec Declaration of subroutine parametersinteger nx,ny,nzreal nsqref (0:2*nz)real thetaref(0:2*nz)real rhoref (0:2*nz)real pressref(0:2*nz)real zref (0:2*nz)character*80 pvsrcfilec Numerical and physical parametersreal epsparameter (eps=0.01)c Auxiliary variablesinteger cdfid,statinteger vardim(4)real misdatinteger ndiminreal varmin(4),varmax(4),stag(4)integer i,j,k,nf1integer ntimesreal time(200)character*80 vnam(100),varnameinteger nvarsinteger isok,ierrc Get grid description from topographycall cdfopn(pvsrcfile,cdfid,stat)if (stat.ne.0) goto 997call getvars(cdfid,nvars,vnam,stat)if (stat.ne.0) goto 997isok=0varname='ORO'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) goto 997call getdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 997time(1)=0.call gettimes(cdfid,time,ntimes,stat)if (stat.ne.0) goto 997call clscdf(cdfid,stat)if (stat.ne.0) goto 997c Open output netcdf filecall cdfwopn(pvsrcfile,cdfid,stat)if (stat.ne.0) goto 997c Create the variable if necessarycall getvars(cdfid,nvars,vnam,stat)if (stat.ne.0) goto 997isok=0varname='NSQREF'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) thenvardim(1)=1vardim(2)=1vardim(3)=2*nz+1call putdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 997endifisok=0varname='RHOREF'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) thenvardim(1)=1vardim(2)=1vardim(3)=2*nz+1call putdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 997endifisok=0varname='PREREF'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) thenvardim(1)=1vardim(2)=1vardim(3)=2*nz+1call putdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 997endifisok=0varname='THETAREF'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) thenvardim(1)=1vardim(2)=1vardim(3)=2*nz+1call putdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 997endifisok=0varname='ZREF'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) thenvardim(1)=1vardim(2)=1vardim(3)=2*nz+1call putdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 997endifc Write datavarname='NSQREF'print*,'W NSQREF ',trim(pvsrcfile)call putdat(cdfid,varname,time(1),0,nsqref,stat)if (stat.ne.0) goto 997varname='RHOREF'print*,'W RHOREF ',trim(pvsrcfile)call putdat(cdfid,varname,time(1),0,rhoref,stat)if (stat.ne.0) goto 997varname='THETAREF'print*,'W THETAREF ',trim(pvsrcfile)call putdat(cdfid,varname,time(1),0,thetaref,stat)if (stat.ne.0) goto 997varname='PREREF'print*,'W PREREF ',trim(pvsrcfile)call putdat(cdfid,varname,time(1),0,pressref,stat)if (stat.ne.0) goto 997varname='ZREF'print*,'W ZREF ',trim(pvsrcfile)call putdat(cdfid,varname,time(1),0,zref,stat)if (stat.ne.0) goto 997c Close output netcdf filecall clscdf(cdfid,stat)if (stat.ne.0) goto 997returnc Exception handling997 print*,'Write_Ref: Problem with input netcdf file... Stop'stopendc --------------------------------------------------------------------------------c Read input fields for reference profilec --------------------------------------------------------------------------------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 specifiedc by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed whether the inputc files are consitent with this grid. The missing data value is set to <mdv>.implicit nonec Declaration of subroutine parametersinteger nx,ny,nzreal field(0:nx,0:ny,0:nz)character*80 fieldnamecharacter*80 pvsrcfilereal dx,dy,dz,xmin,ymin,zminreal mdvc Numerical and physical parametersreal epsparameter (eps=0.01)c Auxiliary variablesinteger cdfid,stat,cdfid99integer vardim(4)real misdatreal varmin(4),varmax(4),stag(4)integer ndimin,outid,i,j,kreal max_threal tmp(nx,ny,nz)integer ntimesreal time(200)integer nvarscharacter*80 vnam(100),varnameinteger isokc Open the input netcdf filecall cdfopn(pvsrcfile,cdfid,stat)if (stat.ne.0) goto 998c Check whether needed variables are on filecall getvars(cdfid,nvars,vnam,stat)if (stat.ne.0) goto 998isok=0varname=trim(fieldname)call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) goto 998c Get the grid parameterscall getdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 998time(1)=0.call gettimes(cdfid,time,ntimes,stat)if (stat.ne.0) goto 998c Check whether grid parameters are consistentif ( (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) )>thenprint*,'Input grid inconsitency...'print*,' Nx = ',vardim(1),nx+1print*,' Ny = ',vardim(2),ny+1print*,' Nz = ',vardim(3),nz+1print*,' Varminx = ',varmin(1),xminprint*,' Varminy = ',varmin(2),yminprint*,' Varminz = ',varmin(3),zminprint*,' Dx = ',(varmax(1)-varmin(1))/real(nx-1),dxprint*,' Dy = ',(varmax(2)-varmin(2))/real(ny-1),dyprint*,' Dz = ',(varmax(3)-varmin(3))/real(nz-1),dzgoto 998endifc Load variablescall getdef(cdfid,varname,ndimin,misdat,vardim,> varmin,varmax,stag,stat)if (stat.ne.0) goto 998call getdat(cdfid,varname,time(1),0,field,stat)print*,'R ',trim(varname),' ',trim(pvsrcfile)if (stat.ne.0) goto 998c Close input netcdf filecall clscdf(cdfid,stat)if (stat.ne.0) goto 998c Set missing data value to <mdv>do i=1,nxdo j=1,nydo k=1,nzif (abs(field(i,j,k)-misdat).lt.eps) thenfield(i,j,k)=mdvendifenddoenddoenddoreturnc Exception handling998 print*,'Read_Inp: Problem with input netcdf file... Stop'stopendc --------------------------------------------------------------------------------c Check whether variable is found on netcdf filec --------------------------------------------------------------------------------subroutine check_varok (isok,varname,varlist,nvars)c Check whether the variable <varname> is in the list <varlist(nvars)>. If this isC the case, <isok> is incremented by 1. Otherwise <isok> keeps its value.implicit nonec Declaraion of subroutine parametersinteger isokinteger nvarscharacter*80 varnamecharacter*80 varlist(nvars)c Auxiliary variablesinteger ic Maindo i=1,nvarsif (trim(varname).eq.trim(varlist(i))) isok=isok+1enddoendc --------------------------------------------------------------------------------c Get grid parametersc --------------------------------------------------------------------------------subroutine read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv,> pvsrcfile)c Get the grid parameters from the variable <TH> on the input file <pvsrcfile>.c The grid parameters arec nx,ny,nz : Number of grid points in x, y and z directionc xmin,ymin,zmin : Minimum domain coordinates in x, y and z directionc xmax,ymax,zmax : Maximal domain coordinates in x, y and z directionc dx,dy,dz : Horizontal and vertical resolutionc 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 nonec Declaration of subroutine parameterscharacter*80 pvsrcfileinteger nx,ny,nzreal dx,dy,dzreal xmin,ymin,zmin,xmax,ymax,zmaxreal mdvc Numerical epsilon and other physical/geoemtrical parametersreal epsparameter (eps=0.01)c Auxiliary variablesinteger cdfid,cstidinteger ierrcharacter*80 vnam(100),varnameinteger nvarsinteger isokinteger vardim(4)real misdatreal varmin(4),varmax(4),stag(4)real aklev(1000),bklev(1000),aklay(1000),bklay(1000)real dhcharacter*80 csninteger ndiminteger ic Get all grid parameterscall cdfopn(pvsrcfile,cdfid,ierr)if (ierr.ne.0) goto 998call getvars(cdfid,nvars,vnam,ierr)if (ierr.ne.0) goto 998isok=0varname='T'call check_varok(isok,varname,vnam,nvars)if (isok.eq.0) goto 998call getcfn(cdfid,csn,ierr)if (ierr.ne.0) goto 998call cdfopn(csn,cstid,ierr)if (ierr.ne.0) goto 998call getdef(cdfid,varname,ndim,misdat,vardim,varmin,varmax,> stag,ierr)if (ierr.ne.0) goto 998nx=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 998call getgrid(cstid,dx,dy,ierr)if (ierr.ne.0) goto 998xmax=varmax(1)ymax=varmax(2)zmax=varmax(3)dz=(zmax-zmin)/real(nz-1)call clscdf(cstid,ierr)if (ierr.ne.0) goto 998call clscdf(cdfid,ierr)if (ierr.ne.0) goto 998c Check whether the grid is equallay spaced in the verticaldo i=1,nz-1dh=aklev(i+1)-aklev(i)if (abs(dh-dz).gt.eps) thenprint*,'Aklev: Vertical grid must be equally spaced... Stop'print*,(aklev(i),i=1,nz)stopendifdh=aklay(i+1)-aklay(i)if (abs(dh-dz).gt.eps) thenprint*,'Aklay: Vertical grid must be equally spaced... Stop'print*,(aklay(i),i=1,nz)stopendifenddoc Set missing data valuemdv=misdatreturnc Exception handling998 print*,'Read_Dim: Problem with input netcdf file... Stop'stopendc ********************************************************************************c * DEFINE REFERENCE PROFILE *c ********************************************************************************c --------------------------------------------------------------------------------c Calculate area meanc --------------------------------------------------------------------------------SUBROUTINE mean(a,m,nx,ny,nz,mdv,weight)c Calculate the area-mean of <m> and save it on <a>.implicit nonec Declaration of subroutine parametersreal mdvinteger nx,ny,nzreal m(0:nx,0:ny,0:nz),a(0:2*nz)real weight(0:nx,0:ny)c Numerical epsilonreal epsparameter (eps=0.01)c Auxiliary varaiblesreal mea(0:nz)integer i,j,k,kkreal counterc Determine the mean over all levels (handle missing data)do k=0,nzmea(k)=0.counter=0.do i=0,nxdo j=0,nyif (abs(m(i,j,k)-mdv).gt.eps) thenmea(k)=mea(k)+m(i,j,k)*weight(i,j)counter=counter+weight(i,j)endifenddoenddoif (counter.gt.0) thenmea(k)=mea(k)/counterelsemea(k)=mdvendifenddoc Prepare the output array: split layers and levelsdo k=0,nz-1kk=2*ka(kk)=mea(k)a(kk+1)=0.5*(mea(k)+mea(k+1))enddoa(2*nz)=mea(nz)end