Blame | Last modification | View Log | Download | RSS feed
PROGRAM def_anomalyc ************************************************************************c * Define a PV anomaly and set it up for inversion. Additionally, the *c * lateral and upper/lower boundary values for potential temperature *c * and wind are set *c * Michael Sprenger / Spring 2005 *c ************************************************************************implicit nonec ------------------------------------------------------------------------c Declaration of subroutine parametersc ------------------------------------------------------------------------c Numerical epsilonreal epsparameter (eps=0.01)c Variables for input Z file : height levelcharacter*80 in_zfn,in_varnamereal in_varmin(4),in_varmax(4),in_stag(4)integer in_vardim(4)real in_mdvinteger in_ndiminteger in_nx,in_ny,in_nzreal in_xmin,in_xmax,in_ymin,in_ymax,in_dx,in_dyinteger in_ntimesreal in_aklev(1000),in_bklev(1000)real in_aklay(1000),in_bklay(1000)real in_timereal in_pollon,in_pollatinteger in_idate(5)integer in_nvarscharacter*80 in_vnam(100)real,allocatable, dimension (:,:,:) :: in_fieldreal,allocatable, dimension (:,:,:) :: in_filtreal,allocatable, dimension (:,:,:) :: in_anomreal,allocatable, dimension (:,:) :: in_x,in_yreal,allocatable, dimension (:,:,:) :: th_anomreal,allocatable, dimension (:,:,:) :: uu_anom,vv_anomc Filteringreal f_xmin,f_xmaxreal f_ymin,f_ymaxreal f_zmin,f_zmaxinteger nfiltreal boundxy,boundzreal,allocatable, dimension (:,:) :: tmpc Auxiliary variablesinteger i,j,k,l,ninteger cdfid,cstidinteger ierr,statcharacter*80 cfnreal xpt,ypt,zptinteger isokcharacter*80 varname,cdfnamecharacter*80 parfilereal distxy,distz,distz1,distz2integer indx,indy,indzreal suminteger countcharacter*80 namec Externalsreal kinkexternal kinkc ------------------------------------------------------------------------c Preparationsc ------------------------------------------------------------------------print*,'*********************************************************'print*,'* def_anomaly *'print*,'*********************************************************'c Set name of the PV variablein_varname='PV'c Read parametersopen(10,file='fort.10')read(10,*) in_zfnread(10,*) name,f_xminif ( trim(name).ne.'BOX_XMIN') stopread(10,*) name,f_xmaxif ( trim(name).ne.'BOX_XMAX') stopread(10,*) name,f_yminif ( trim(name).ne.'BOX_YMIN') stopread(10,*) name,f_ymaxif ( trim(name).ne.'BOX_YMAX') stopread(10,*) name,f_zminif ( trim(name).ne.'BOX_ZMIN') stopread(10,*) name,f_zmaxif ( trim(name).ne.'BOX_ZMAX') stopread(10,*) name,nfiltif ( trim(name).ne.'NFILTER' ) stopread(10,*) name,boundxyif ( trim(name).ne.'BOUND_XY') stopread(10,*) name,boundzif ( trim(name).ne.'BOUND_Z') stopclose(10)print*,'Filter domain, x: ', f_xmin,f_xmaxprint*,' y: ', f_ymin,f_ymaxprint*,' z: ', f_zmin,f_zmaxprint*,'Nfilt: ',nfiltprint*,'Boundxy,z: ',boundxy,boundzc Get grid description for Z file : height levelscall cdfopn(in_zfn,cdfid,ierr)if (ierr.ne.0) goto 998call getcfn(cdfid,cfn,ierr)if (ierr.ne.0) goto 998call cdfopn(cfn,cstid,ierr)if (ierr.ne.0) goto 998call getvars(cdfid,in_nvars,in_vnam,ierr)if (ierr.ne.0) goto 998call getdef(cdfid,in_varname,in_ndim,in_mdv,in_vardim,> in_varmin,in_varmax,in_stag,ierr)if (ierr.ne.0) goto 998in_nx =in_vardim(1)in_ny =in_vardim(2)in_nz =in_vardim(3)in_xmin=in_varmin(1)in_ymin=in_varmin(2)call getlevs(cstid,in_nz,in_aklev,in_bklev,in_aklay,in_bklay,ierr)if (ierr.ne.0) goto 998call getgrid(cstid,in_dx,in_dy,ierr)if (ierr.ne.0) goto 998in_xmax=in_xmin+real(in_nx-1)*in_dxin_ymax=in_ymin+real(in_ny-1)*in_dycall gettimes(cdfid,in_time,in_ntimes,ierr)if (ierr.ne.0) goto 998call getstart(cstid,in_idate,ierr)if (ierr.ne.0) goto 998call getpole(cstid,in_pollon,in_pollat,ierr)if (ierr.ne.0) goto 998call clscdf(cstid,ierr)if (ierr.ne.0) goto 998call clscdf(cdfid,ierr)c Allocate memory for grid descriptionallocate(in_x(in_nx,in_ny),stat=stat)if (stat.ne.0) print*,'*** error allocating array in_x ***'allocate(in_y(in_nx,in_ny),stat=stat)if (stat.ne.0) print*,'*** error allocating array in_y ***'c Allocate memory for input and output fieldsallocate(in_field(in_nx,in_ny,in_nz),stat=stat)if (stat.ne.0) print*,'*** error allocating array in_field ***'allocate(in_anom(in_nx,in_ny,in_nz),stat=stat)if (stat.ne.0) print*,'*** error allocating array in_anom ***'allocate(in_filt(in_nx,in_ny,in_nz),stat=stat)if (stat.ne.0) print*,'*** error allocating array in_filt ***'allocate(th_anom(in_nx,in_ny,in_nz),stat=stat)if (stat.ne.0) print*,'*** error allocating array th_anom ***'allocate(uu_anom(in_nx,in_ny,in_nz),stat=stat)if (stat.ne.0) print*,'*** error allocating array uu_anom ***'allocate(vv_anom(in_nx,in_ny,in_nz),stat=stat)if (stat.ne.0) print*,'*** error allocating array vvnom ***'c Allocate memory for filteringallocate(tmp(in_nx,in_ny),stat=stat)if (stat.ne.0) print*,'*** error allocating array tmp ***'c Read variables from filecall cdfopn(in_zfn,cdfid,ierr)if (ierr.ne.0) goto 998varname=trim(in_varname)print*,'R ',trim(varname),' ',trim(in_zfn)call gettimes(cdfid,in_time,in_ntimes,ierr)if (ierr.ne.0) goto 998call getdat(cdfid,varname,in_time,0,in_field,ierr)if (ierr.ne.0) goto 998varname='X'print*,'R ',trim(varname),' ',trim(in_zfn)call gettimes(cdfid,in_time,in_ntimes,ierr)if (ierr.ne.0) goto 998call getdat(cdfid,varname,in_time,0,in_x,ierr)if (ierr.ne.0) goto 998varname='Y'print*,'R ',trim(varname),' ',trim(in_zfn)call gettimes(cdfid,in_time,in_ntimes,ierr)if (ierr.ne.0) goto 998call getdat(cdfid,varname,in_time,0,in_y,ierr)if (ierr.ne.0) goto 998call clscdf(cdfid,ierr)if (ierr.ne.0) goto 998c ------------------------------------------------------------------------c Get the average along the x axis: "zonal" averagec ------------------------------------------------------------------------print*,'A ',trim(in_varname)do k=1,in_nzdo j=1,in_nyc Get the mean along x axissum=0.count=0do i=1,in_nxif (abs(in_field(i,j,k)-in_mdv).gt.eps) thensum=sum+in_field(i,j,k)count=count+1endifenddoif (count.ge.1) thensum=sum/real(count)elsesum=in_mdvendifc Get the difference relative to the "zonal" meando i=1,in_nxxpt=in_x(i,j)ypt=in_y(i,j)zpt=in_aklay(k)if ( (xpt.ge.f_xmin).and.> (xpt.le.f_xmax).and.> (ypt.ge.f_ymin).and.> (ypt.le.f_ymax).and.> (zpt.ge.f_zmin).and.> (zpt.le.f_zmax)) thenin_filt(i,j,k)=sumelsein_filt(i,j,k)=in_field(i,j,k)endifenddoenddoenddoc ------------------------------------------------------------------------c Get the anomaly fieldc ------------------------------------------------------------------------cc Determine the difference between filtered and unfiltered fielddo i=1,in_nxdo j=1,in_nydo k=1,in_nzif ( (abs(in_field(i,j,k)-in_mdv).gt.eps).and.> (abs(in_filt (i,j,k)-in_mdv).gt.eps)) thenin_anom(i,j,k)=in_field(i,j,k)-in_filt(i,j,k)elsein_anom(i,j,k)=in_mdvendifenddoenddoenddoc Take only the positive part of the difference (mdv is set to 0)do i=1,in_nxdo j=1,in_nydo k=1,in_nzif ( (abs(in_anom(i,j,k)-in_mdv).lt.eps) ) thenin_anom(i,j,k)=0.else if ( in_anom(i,j,k).lt.0.) thenin_anom(i,j,k)=0.endifenddoenddoenddoc Smooth transition to zero at boundariesdo i=1,in_nxdo j=1,in_nydo k=1,in_nzif ( (abs(in_anom (i,j,k)-in_mdv).gt.eps) ) thenin_anom(i,j,k)=in_anom(i,j,k)*> kink(f_zmax -in_aklay(k),boundz )*> kink(in_aklay(k)-f_zmin ,boundz )*> kink(in_x(i,j) -f_xmin ,boundxy)*> kink(f_xmax -in_x(i,j) ,boundxy)*> kink(in_y(i,j) -f_ymin ,boundxy)*> kink(f_ymax -in_y(i,j) ,boundxy)endifenddoenddoenddoc ------------------------------------------------------------------------c Apply a digital filter to the anomaly fieldc ------------------------------------------------------------------------print*,'F ',trim(in_varname)do k=1,in_nzdo i=1,in_nxdo j=1,in_nytmp(i,j)=in_anom(i,j,k)enddoenddodo n=1,nfiltcall filt2d (tmp,tmp,in_nx,in_ny,1.,in_mdv,0,0,0,0)enddodo i=1,in_nxdo j=1,in_nyin_anom(i,j,k)=tmp(i,j)enddoenddoenddoc ------------------------------------------------------------------------c Get the modified PV field (original minus anomaly)c ------------------------------------------------------------------------do i=1,in_nxdo j=1,in_nydo k=1,in_nzif ( (abs(in_anom (i,j,k)-in_mdv).gt.eps).and.> (abs(in_field(i,j,k)-in_mdv).gt.eps) ) thenin_filt(i,j,k)=in_field(i,j,k)-in_anom(i,j,k)elsein_filt(i,j,k)=in_mdvendifenddoenddoenddoc -----------------------------------------------------------------c Define the boundary values for wind and potential temperaturec -----------------------------------------------------------------do i=1,in_nxdo j=1,in_nydo k=1,in_nzth_anom(i,j,k)=0.uu_anom(i,j,k)=0.vv_anom(i,j,k)=0.enddoenddoenddoc -----------------------------------------------------------------c Write outputc -----------------------------------------------------------------c Open output netcdf filecall cdfwopn(in_zfn,cdfid,ierr)if (ierr.ne.0) goto 997c Write the 3d filtered fieldisok=0varname=trim(in_varname)//'_FILT'print*,'Write ',trim(varname),' ',trim(in_zfn)call check_varok(isok,varname,in_vnam,in_nvars)if (isok.eq.0) thencall putdef(cdfid,varname,4,in_mdv,in_vardim,> in_varmin,in_varmax,in_stag,ierr)if (ierr.ne.0) goto 997endifcall putdat(cdfid,varname,in_time,0,in_filt,ierr)if (ierr.ne.0) goto 997c Write the 3d anomaly fieldisok=0varname=trim(in_varname)//'_ANOM'print*,'Write ',trim(varname),' ',trim(in_zfn)call check_varok(isok,varname,in_vnam,in_nvars)if (isok.eq.0) thencall putdef(cdfid,varname,4,in_mdv,in_vardim,> in_varmin,in_varmax,in_stag,ierr)if (ierr.ne.0) goto 997endifcall putdat(cdfid,varname,in_time,0,in_anom,ierr)if (ierr.ne.0) goto 997c Write lower and upper boundaryisok=0varname='TH_ANOM'print*,'Write ',trim(varname),' ',trim(in_zfn)call check_varok(isok,varname,in_vnam,in_nvars)if (isok.eq.0) thencall putdef(cdfid,varname,4,in_mdv,in_vardim,> in_varmin,in_varmax,in_stag,ierr)if (ierr.ne.0) goto 997endifcall putdat(cdfid,varname,in_time,0,th_anom,ierr)if (ierr.ne.0) goto 997c Write lateral boundaryisok=0varname='UU_ANOM'print*,'Write ',trim(varname),' ',trim(in_zfn)call check_varok(isok,varname,in_vnam,in_nvars)if (isok.eq.0) thencall putdef(cdfid,varname,4,in_mdv,in_vardim,> in_varmin,in_varmax,in_stag,ierr)if (ierr.ne.0) goto 997endifcall putdat(cdfid,varname,in_time,0,uu_anom,ierr)if (ierr.ne.0) goto 997isok=0varname='VV_ANOM'print*,'Write ',trim(varname),' ',trim(in_zfn)call check_varok(isok,varname,in_vnam,in_nvars)if (isok.eq.0) thencall putdef(cdfid,varname,4,in_mdv,in_vardim,> in_varmin,in_varmax,in_stag,ierr)if (ierr.ne.0) goto 997endifcall putdat(cdfid,varname,in_time,0,vv_anom,ierr)if (ierr.ne.0) goto 997c Close output netcdf filecall clscdf(cdfid,ierr)if (ierr.ne.0) goto 997c -----------------------------------------------------------------c Exception handling and format specsc -----------------------------------------------------------------stop998 print*,'Problems with input netcdf file'stop997 print*,'Problems with output netcdf file'stopENDc ******************************************************************c * 2D FILTERING *c ******************************************************************c -----------------------------------------------------------------c Horizontal filterc -----------------------------------------------------------------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.cc a real inp array to be filtered, dimensioned (nx,ny)c af real out filtered array, dimensioned (nx,ny), can bec equivalenced with array a in the calling routinec 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=1c corresponds to one application of the linear filter.c misdat real inp missing-data value, a(i,j)=misdat indicates thatc the corresponding value is not available. Thec 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)cc Christoph Schaer, 1993c argument declarationinteger nx,nyreal a(nx,ny),af(nx,ny),fil,misdatinteger iperx,ipery,inpol,ispolc local variable declarationinteger i,j,isreal fhreal f1(nx+1,ny),f2(nx,ny+1)c compute constant fhfh=0.125*filc compute fluxes in x-directionif (misdat.eq.0.) thendo j=1,nydo i=2,nxf1(i,j)=a(i-1,j)-a(i,j)enddoenddoelsedo j=1,nydo i=2,nxif ((a(i,j).eq.misdat).or.(a(i-1,j).eq.misdat)) thenf1(i,j)=0.elsef1(i,j)=a(i-1,j)-a(i,j)endifenddoenddoendifif (iperx.eq.1) thenc do periodic boundaries in the x-directiondo j=1,nyf1(1,j)=f1(nx,j)f1(nx+1,j)=f1(2,j)enddoelsec set boundary-fluxes to zerodo j=1,nyf1(1,j)=0.f1(nx+1,j)=0.enddoendifc compute fluxes in y-directionif (misdat.eq.0.) thendo j=2,nydo i=1,nxf2(i,j)=a(i,j-1)-a(i,j)enddoenddoelsedo j=2,nydo i=1,nxif ((a(i,j).eq.misdat).or.(a(i,j-1).eq.misdat)) thenf2(i,j)=0.elsef2(i,j)=a(i,j-1)-a(i,j)endifenddoenddoendifc set boundary-fluxes to zerodo i=1,nxf2(i,1)=0.f2(i,ny+1)=0.enddoif (ipery.eq.1) thenc do periodic boundaries in the x-directiondo i=1,nxf2(i,1)=f2(i,ny)f2(i,ny+1)=f2(i,2)enddoendifif (iperx.eq.1) thenif (ispol.eq.1) thenc do south-poleis=(nx-1)/2do i=1,nxf2(i,1)=-f2(mod(i-1+is,nx)+1,2)enddoendifif (inpol.eq.1) thenc do north-poleis=(nx-1)/2do i=1,nxf2(i,ny+1)=-f2(mod(i-1+is,nx)+1,ny)enddoendifendifc compute flux-convergence -> filterif (misdat.eq.0.) thendo j=1,nydo i=1,nxaf(i,j)=a(i,j)+fh*(f1(i,j)-f1(i+1,j)+f2(i,j)-f2(i,j+1))enddoenddoelsedo j=1,nydo i=1,nxif (a(i,j).eq.misdat) thenaf(i,j)=misdatelseaf(i,j)=a(i,j)+fh*(f1(i,j)-f1(i+1,j)+f2(i,j)-f2(i,j+1))endifenddoenddoendifendc ******************************************************************c * AUXILIARY SUBROUTINES *c ******************************************************************C -----------------------------------------------------------------c Rene's KINK function (for smoothing at bounadries)C -----------------------------------------------------------------real function kink (x,a)implicit nonec declaration of parametersreal x,ac parametersreal piparameter (pi=3.1415926535)if (x.lt.0.) thenkink=0.elseif (x.gt.a) thenkink=1.elsekink=(1.+cos(pi*(x-a)/a))/2.endifreturnendc ---------------------------------------------------------c Subroutines to write the netcdf output filec ---------------------------------------------------------subroutine writecdf2D(cdfname,> varname,arr,time,> dx,dy,xmin,ymin,nx,ny,> crefile,crevar)c Create and write to the netcdf file <cdfname>. The variablec with name <varname> and with time <time> is written. The datac are in the two-dimensional array <arr>. The list <dx,dy,xmin,c ymin,nx,ny> specifies the output grid. The flags <crefile> andc <crevar> determine whether the file and/or the variable shouldc be created. 1: create / 0: not createdIMPLICIT NONEc Declaration of input parameterscharacter*80 cdfname,varnameinteger nx,nyreal arr(nx,ny)real dx,dy,xmin,yminreal timeinteger crefile,crevarc Further variablesreal varmin(4),varmax(4),stag(4)integer ierr,cdfid,ndim,vardim(4)character*80 cstnamereal mdvinteger datar(14),stdate(5)integer iC Definitionsvarmin(1)=xminvarmin(2)=yminvarmin(3)=1050.varmax(1)=xmin+real(nx-1)*dxvarmax(2)=ymin+real(ny-1)*dyvarmax(3)=1050.cstname=trim(cdfname)//'_cst'ndim=4vardim(1)=nxvardim(2)=nyvardim(3)=1stag(1)=0.stag(2)=0.stag(3)=0.mdv=-999.98999C Create the fileif (crefile.eq.0) thencall cdfwopn(cdfname,cdfid,ierr)if (ierr.ne.0) goto 906else if (crefile.eq.1) thencall crecdf(cdfname,cdfid,> varmin,varmax,ndim,cstname,ierr)if (ierr.ne.0) goto 903C Write the constants filedatar(1)=vardim(1)datar(2)=vardim(2)datar(3)=int(1000.*varmax(2))datar(4)=int(1000.*varmin(1))datar(5)=int(1000.*varmin(2))datar(6)=int(1000.*varmax(1))datar(7)=int(1000.*dx)datar(8)=int(1000.*dy)datar(9)=1datar(10)=1datar(11)=0 ! data versiondatar(12)=0 ! cstfile versiondatar(13)=0 ! longitude of poledatar(14)=90000 ! latitude of poledo i=1,5stdate(i)=0enddocall wricst(cstname,datar,0.,0.,0.,0.,stdate)endifc Write the data to the netcdf file, and close the fileif (crevar.eq.1) thencall putdef(cdfid,varname,ndim,mdv,> vardim,varmin,varmax,stag,ierr)if (ierr.ne.0) goto 904endifcall putdat(cdfid,varname,time,0,arr,ierr)if (ierr.ne.0) goto 905call clscdf(cdfid,ierr)returnc Error handling903 print*,'*** Problem to create netcdf file ***'stop904 print*,'*** Problem to write definition ***'stop905 print*,'*** Problem to write data ***'stop906 print*,'*** Problem to open netcdf file ***'stopENDc ------------------------------------------------------------------c Auxiliary routinesc ------------------------------------------------------------------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> keepsc 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+1enddoend