Subversion Repositories pvinversion.ecmwf

Compare Revisions

No changes between revisions

Ignore whitespace Rev 2 → Rev 3

/trunk/post/add2p.f
0,0 → 1,1567
PROGRAM add2p
 
c *********************************************************************
c * Add output from the PV inversion to the original P file *
c * Zonal wind (U), meridional wind (V) and temperature (T) are *
c * modified. All other fields are not affected by the programme *
c * *
c * Michael Sprenger / Summer, Autumn 2006
c *********************************************************************
 
implicit none
 
c ---------------------------------------------------------------------
c Declaration of parameters and variables
c ---------------------------------------------------------------------
 
c Input parameters
character*80 ml_fn
character*80 zm_fn
character*80 or_fn
real transxy
 
c Variables for input P file : model level
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_idate(5)
integer ml_nvars
character*80 ml_vnam(80)
real,allocatable, dimension (:,:) :: ml_ps,ml_oro
real,allocatable, dimension (:,:,:) :: ml_t3,ml_u3,ml_v3,ml_z3
real,allocatable, dimension (:,:,:) :: ml_p3,ml_tv3,ml_q3,ml_p0
integer,allocatable, dimension (:,:,:) :: flag_ml
 
c Variables for GEO.MOD
real zm_varmin(4),zm_varmax(4),zm_stag(4)
integer zm_vardim(4)
real zm_mdv
integer zm_ndim
integer zm_nx,zm_ny,zm_nz
real zm_xmin,zm_xmax,zm_ymin,zm_ymax,zm_dx,zm_dy
integer zm_ntimes
real zm_aklev(500),zm_bklev(500)
real zm_aklay(500),zm_bklay(500)
real zm_time
real zm_pollon,zm_pollat
integer zm_idate(5)
integer zm_nvars
character*80 zm_vnam(80)
real,allocatable, dimension (:,:,:) :: zm_u3,zm_v3,zm_t3,zm_z3
real,allocatable, dimension (:,:,:) :: zm_p3
real,allocatable, dimension (:,:) :: zm_rlat,zm_rlon
integer,allocatable, dimension (:,:,:) :: flag_zm
 
c Variables for GEO.ORG
real or_varmin(4),or_varmax(4),or_stag(4)
integer or_vardim(4)
real or_mdv
integer or_ndim
integer or_nx,or_ny,or_nz
real or_xmin,or_xmax,or_ymin,or_ymax,or_dx,or_dy
integer or_ntimes
real or_time
real or_pollon,or_pollat
integer or_idate(5)
integer or_nvars
character*80 or_vnam(80)
real,allocatable, dimension (:,:,:) :: or_p3
real,allocatable, dimension (:,:,:) :: or_u3,or_v3,or_t3
 
c Anomalies
real,allocatable, dimension (:,:,:) :: an_p3,an_u3,an_v3,an_t3
 
c Array with the weighting function
real,allocatable, dimension (:,:) :: weight,dist
 
c Flag for test mode
integer test
parameter (test=1)
 
c Flag for Poisson filling
integer poisson
parameter (poisson=1)
 
c Physical and numerical parameters
real eps ! Numerical epsilon
parameter (eps=0.001)
real dpextra ! Allowed range for extrapolation (% of pressure)
parameter (dpextra=0.1)
real g ! Earth's gravity
parameter (g=9.80665)
real tzero ! Conversion Celius/Kelvin
parameter (tzero=273.15)
real kappa ! Kappa (Definition of potential temperature)
parameter (kappa=0.6078)
real zerodiv ! Zero division handling
parameter (zerodiv=0.0000000001)
real dpmin ! Pressure step for hydrostatic equation
parameter (dpmin=10.)
real rdg ! Ratio gas constant / Earth's gravity
parameter (rdg=29.271)
c Auxiliray variables
integer i,j,k,l
character*80 varname
integer isok
integer stat
integer cdfid,ierr,cstid
character*80 cfn
real p1(1000),z1(1000),f1(1000),tv1(1000)
real spline_f1(1000),spline_tv1(1000)
integer n1
real hh
real pmin,pmax
real boundlat(100000),boundlon(1000000)
integer nbound
integer il,ir,ju,jd,im,jm
real lat,lon
real distmin,distpos
character*80 name
real pu,po,zu,zo,p,z,dp,p0,tvu,tvo,ff
integer lmin,n
real mean,nmean
real psfc
integer count0,count1
 
c Externals
real sdis,kink
external sdis,kink
 
 
c -----------------------------------------------------------------
c Read input fields
c -----------------------------------------------------------------
 
print*,'*********************************************************'
print*,'* add2p *'
print*,'*********************************************************'
print*
 
c Read in the parameter file
open(10,file='fort.10')
read(10,*) ml_fn
read(10,*) zm_fn
read(10,*) or_fn
read(10,*) name,transxy
if ( trim(name).ne.'TRANS_XY' ) stop
read(10,*) name,psfc
if ( trim(name).ne.'PS_CHANGE' ) stop
close(10)
print*,trim(ml_fn)
print*,trim(zm_fn)
print*,trim(or_fn)
print*
c Get grid description for P file : model level
call cdfopn(ml_fn,cdfid,ierr)
if (ierr.ne.0) goto 998
call getvars(cdfid,ml_nvars,ml_vnam,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
isok=0
varname='T'
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)
if (ierr.ne.0) goto 998
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
if (ierr.ne.0) goto 998
call gettimes(cdfid,ml_time,ml_ntimes,ierr)
if (ierr.ne.0) goto 998
call getstart(cstid,ml_idate,ierr)
if (ierr.ne.0) goto 998
call getpole(cstid,ml_pollon,ml_pollat,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 grid description for MOD file
call cdfopn(zm_fn,cdfid,ierr)
if (ierr.ne.0) goto 997
call getvars(cdfid,zm_nvars,zm_vnam,ierr)
if (ierr.ne.0) goto 997
call getcfn(cdfid,cfn,ierr)
if (ierr.ne.0) goto 997
call cdfopn(cfn,cstid,ierr)
if (ierr.ne.0) goto 997
isok=0
varname='T'
call check_varok(isok,varname,zm_vnam,zm_nvars)
if (isok.ne.1) goto 997
call getdef(cdfid,varname,zm_ndim,zm_mdv,zm_vardim,
> zm_varmin,zm_varmax,zm_stag,ierr)
if (ierr.ne.0) goto 997
zm_nx =zm_vardim(1)
zm_ny =zm_vardim(2)
zm_nz =zm_vardim(3)
zm_xmin=zm_varmin(1)
zm_ymin=zm_varmin(2)
call getlevs(cstid,zm_nz,zm_aklev,zm_bklev,zm_aklay,zm_bklay,ierr)
if (ierr.ne.0) goto 997
call getgrid(cstid,zm_dx,zm_dy,ierr)
if (ierr.ne.0) goto 997
zm_xmax=zm_xmin+real(zm_nx-1)*zm_dx
zm_ymax=zm_ymin+real(zm_ny-1)*zm_dy
call gettimes(cdfid,zm_time,zm_ntimes,ierr)
if (ierr.ne.0) goto 997
call getstart(cstid,zm_idate,ierr)
if (ierr.ne.0) goto 997
call getpole(cstid,zm_pollon,zm_pollat,ierr)
if (ierr.ne.0) goto 997
call clscdf(cstid,ierr)
if (ierr.ne.0) goto 997
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 997
 
c Get grid description for ORG file
call cdfopn(or_fn,cdfid,ierr)
if (ierr.ne.0) goto 997
call getvars(cdfid,or_nvars,or_vnam,ierr)
if (ierr.ne.0) goto 997
call getcfn(cdfid,cfn,ierr)
if (ierr.ne.0) goto 997
call cdfopn(cfn,cstid,ierr)
if (ierr.ne.0) goto 997
isok=0
varname='P'
call check_varok(isok,varname,or_vnam,or_nvars)
if (isok.ne.1) goto 997
call getdef(cdfid,varname,or_ndim,or_mdv,or_vardim,
> or_varmin,or_varmax,or_stag,ierr)
if (ierr.ne.0) goto 997
or_nx =or_vardim(1)
or_ny =or_vardim(2)
or_nz =or_vardim(3)
or_xmin=or_varmin(1)
or_ymin=or_varmin(2)
call getgrid(cstid,or_dx,or_dy,ierr)
if (ierr.ne.0) goto 997
or_xmax=or_xmin+real(or_nx-1)*or_dx
or_ymax=or_ymin+real(or_ny-1)*or_dy
call gettimes(cdfid,or_time,or_ntimes,ierr)
if (ierr.ne.0) goto 997
call getstart(cstid,or_idate,ierr)
if (ierr.ne.0) goto 997
call getpole(cstid,or_pollon,or_pollat,ierr)
if (ierr.ne.0) goto 997
call clscdf(cstid,ierr)
if (ierr.ne.0) goto 997
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 997
 
c Consistency check for the grids
if ( (abs(ml_xmin-zm_xmin).gt.eps).or.
> (abs(ml_xmax-zm_xmax).gt.eps).or.
> (abs(ml_ymin-zm_ymin).gt.eps).or.
> (abs(ml_ymax-zm_ymax).gt.eps).or.
> (abs(ml_dx -zm_dx ).gt.eps).or.
> (abs(ml_dy -zm_dy ).gt.eps).or.
> (abs(ml_time-zm_time).gt.eps).or.
> (abs(ml_xmin-or_xmin).gt.eps).or.
> (abs(ml_xmax-or_xmax).gt.eps).or.
> (abs(ml_ymin-or_ymin).gt.eps).or.
> (abs(ml_ymax-or_ymax).gt.eps).or.
> (abs(ml_dx -or_dx ).gt.eps).or.
> (abs(ml_dy -or_dy ).gt.eps) )
>then
print*,'P, GEO.MOD, GEO.ORG grids not consistent... Stop'
print*,ml_xmin,zm_xmin,or_xmin
print*,ml_ymin,zm_ymin,or_ymin
print*,ml_dx, zm_dx ,or_dx
print*,ml_dy, zm_dy ,or_dy
print*,ml_time,zm_time,or_time
stop
endif
 
c Allocate memory for input and output P file
allocate(ml_p3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_p3'
allocate(ml_u3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_u3'
allocate(ml_v3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_v3'
allocate(ml_t3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_t3'
allocate(ml_tv3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_tv3'
allocate(ml_z3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_z3'
allocate(ml_q3 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_q3'
allocate(ml_ps (ml_nx,ml_ny ),stat=stat)
if (stat.ne.0) print*,'error allocating ml_ps'
allocate(ml_oro (ml_nx,ml_ny ),stat=stat)
if (stat.ne.0) print*,'error allocating ml_oro'
allocate(ml_p0 (ml_nx,ml_ny,ml_nz),stat=stat)
if (stat.ne.0) print*,'error allocating ml_p0'
 
c Allocate memory for input GEO.MOD file
allocate(zm_p3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_p3'
allocate(zm_u3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_u3'
allocate(zm_v3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_v3'
allocate(zm_t3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_t3'
allocate(zm_z3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_z3'
allocate(zm_rlat(zm_nx,zm_ny),stat=stat)
if (stat.ne.0) print*,'error allocating zm_rlat'
allocate(zm_rlon(zm_nx,zm_ny),stat=stat)
if (stat.ne.0) print*,'error allocating zm_rlon'
 
c Allocate memory for input GEO.ORG file
allocate(or_p3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_p3'
allocate(or_t3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_t3'
allocate(or_u3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_u3'
allocate(or_v3(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating zm_v3'
 
c Allocate memory for weighting function, flag and anomalies
allocate(weight(zm_nx,zm_ny),stat=stat)
if (stat.ne.0) print*,'error allocating weight'
allocate(dist (zm_nx,zm_ny),stat=stat)
if (stat.ne.0) print*,'error allocating dist'
allocate(flag_zm(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating flag'
allocate(flag_ml(zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating flag'
allocate(an_p3 (zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating an_p3'
allocate(an_t3 (zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating an_t3'
allocate(an_u3 (zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating an_u3'
allocate(an_v3 (zm_nx,zm_ny,zm_nz),stat=stat)
if (stat.ne.0) print*,'error allocating an_v3'
 
c Read variables from P file : model levels
call cdfopn(ml_fn,cdfid,ierr)
if (ierr.ne.0) goto 998
varname='T'
call getdat(cdfid,varname,ml_time,0,ml_t3,ierr)
if (ierr.ne.0) goto 998
print*,'R T ',trim(ml_fn)
varname='U'
call getdat(cdfid,varname,ml_time,0,ml_u3,ierr)
if (ierr.ne.0) goto 998
print*,'R U ',trim(ml_fn)
varname='V'
call getdat(cdfid,varname,ml_time,0,ml_v3,ierr)
if (ierr.ne.0) goto 998
print*,'R V ',trim(ml_fn)
varname='Z'
call getdat(cdfid,varname,ml_time,0,ml_z3,ierr)
if (ierr.ne.0) goto 998
print*,'R Z ',trim(ml_fn)
varname='Q'
call getdat(cdfid,varname,ml_time,0,ml_q3,ierr)
if (ierr.ne.0) goto 998
print*,'R Q ',trim(ml_fn)
varname='PS'
call getdat(cdfid,varname,ml_time,0,ml_ps,ierr)
if (ierr.ne.0) goto 998
print*,'R PS ',trim(ml_fn)
varname='ORO'
call getdat(cdfid,varname,ml_time,0,ml_oro,ierr)
if (ierr.ne.0) goto 998
print*,'R ORO ',trim(ml_fn)
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 998
 
c Read variables from GEO.MOD
call cdfopn(zm_fn,cdfid,ierr)
if (ierr.ne.0) goto 997
 
varname='T'
call getdat(cdfid,varname,zm_time,0,zm_t3,ierr)
if (ierr.ne.0) goto 997
print*,'R T ',trim(zm_fn)
varname='U'
call getdat(cdfid,varname,zm_time,0,zm_u3,ierr)
if (ierr.ne.0) goto 997
print*,'R U ',trim(zm_fn)
varname='V'
call getdat(cdfid,varname,zm_time,0,zm_v3,ierr)
if (ierr.ne.0) goto 997
print*,'R V ',trim(zm_fn)
varname='P'
call getdat(cdfid,varname,zm_time,0,zm_p3,ierr)
if (ierr.ne.0) goto 997
print*,'R P ',trim(zm_fn)
varname='RLAT'
call getdat(cdfid,varname,zm_time,0,zm_rlat,ierr)
if (ierr.ne.0) goto 997
print*,'R RLAT ',trim(zm_fn)
varname='RLON'
call getdat(cdfid,varname,zm_time,0,zm_rlon,ierr)
if (ierr.ne.0) goto 997
print*,'R RLON ',trim(zm_fn)
 
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 997
 
c Read variables from GEO.ORG
call cdfopn(or_fn,cdfid,ierr)
if (ierr.ne.0) goto 998
varname='P'
call getdat(cdfid,varname,or_time,0,or_p3,ierr)
if (ierr.ne.0) goto 998
print*,'R P ',trim(or_fn)
varname='U'
call getdat(cdfid,varname,or_time,0,or_u3,ierr)
if (ierr.ne.0) goto 998
print*,'R U ',trim(or_fn)
varname='V'
call getdat(cdfid,varname,or_time,0,or_v3,ierr)
if (ierr.ne.0) goto 998
print*,'R V ',trim(or_fn)
varname='T'
call getdat(cdfid,varname,or_time,0,or_t3,ierr)
if (ierr.ne.0) goto 998
print*,'R T ',trim(or_fn)
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 998
 
c Initialize the height levels of the Z file
do i=1,zm_nx
do j=1,zm_ny
do k=1,zm_nz
zm_z3(i,j,k)=zm_aklay(k)
enddo
enddo
enddo
 
c Calculate 3d pressure field on model levels
print*,'C P (ORIGINAL)'
do k=1,ml_nz
do i=1,ml_nx
do j=1,ml_ny
if (abs(ml_stag(3)+0.5).lt.eps) then
ml_p0(i,j,k)=ml_aklay(k)+ml_bklay(k)*ml_ps(i,j)
else
ml_p0(i,j,k)=ml_aklev(k)+ml_bklev(k)*ml_ps(i,j)
endif
enddo
enddo
enddo
 
c Calculate 3d anomalies due to inversion
print*,'C DP (MODIFIED-ORIGINAL)'
print*,'C DU (MODIFIED-ORIGINAL)'
print*,'C DV (MODIFIED-ORIGINAL)'
print*,'C DT (MODIFIED-ORIGINAL)'
do k=1,zm_nz
do i=1,zm_nx
do j=1,zm_ny
 
c P
if ( ( abs(zm_p3(i,j,k)-zm_mdv).gt.eps).and.
> ( abs(or_p3(i,j,k)-or_mdv).gt.eps) )
> then
an_p3(i,j,k) = zm_p3(i,j,k) - or_p3(i,j,k)
elseif ( poisson.eq.1 ) then
an_p3(i,j,k) = zm_mdv
else
an_p3(i,j,k) = 0.
endif
 
c T
if ( ( abs(zm_t3(i,j,k)-zm_mdv).gt.eps).and.
> ( abs(or_t3(i,j,k)-or_mdv).gt.eps) )
> then
an_t3(i,j,k) = zm_t3(i,j,k) - or_t3(i,j,k)
elseif ( poisson.eq.1 ) then
an_t3(i,j,k) = zm_mdv
else
an_t3(i,j,k) = 0.
endif
 
c U
if ( ( abs(zm_u3(i,j,k)-zm_mdv).gt.eps).and.
> ( abs(or_u3(i,j,k)-or_mdv).gt.eps) )
> then
an_u3(i,j,k) = zm_u3(i,j,k) - or_u3(i,j,k)
elseif ( poisson.eq.1 ) then
an_u3(i,j,k) = zm_mdv
else
an_u3(i,j,k) = 0.
endif
 
c V
if ( ( abs(zm_v3(i,j,k)-zm_mdv).gt.eps).and.
> ( abs(or_v3(i,j,k)-or_mdv).gt.eps) )
> then
an_v3(i,j,k) = zm_v3(i,j,k) - or_v3(i,j,k)
elseif ( poisson.eq.1 ) then
an_v3(i,j,k) = zm_mdv
else
an_v3(i,j,k) = 0.
endif
 
enddo
enddo
enddo
 
c ----------------------------------------------------------------
c Get the weight function for the inset (from 1 inside to 0 outside)
c ----------------------------------------------------------------
 
print*,'C BOUNDARY FILTER'
 
c Init the weight function (1 inside, 0 outside)
do i=1,ml_nx
do j=1,ml_ny
if ( (zm_rlat(i,j).lt. -90.).or.
> (zm_rlat(i,j).gt. 90.).or.
> (zm_rlon(i,j).lt.-180.).or.
> (zm_rlon(i,j).gt. 180.) ) then
weight(i,j)=0.
else
weight(i,j)=1.
endif
 
enddo
enddo
 
c Get a list of all boundary points
nbound=0
do i=1,ml_nx
do j=1,ml_ny
 
c Get neighbouring points
ir=i+1
if (ir.gt.ml_nx) ir=ml_nx
il=i-1
if (il.lt. 1) il=1
ju=j+1
if (ju.gt.ml_ny) ju=ml_ny
jd=j-1
if (jd.lt. 1) jd=1
 
c A boundary point has a 0/1 switch
if (abs(weight(i,j)-0.).lt.eps) then
if ( (abs(weight(ir, j)-1.).lt.eps).or.
> (abs(weight(il, j)-1.).lt.eps).or.
> (abs(weight(i ,ju)-1.).lt.eps).or.
> (abs(weight(i ,jd)-1.).lt.eps).or.
> (abs(weight(ir,ju)-1.).lt.eps).or.
> (abs(weight(ir,jd)-1.).lt.eps).or.
> (abs(weight(il,ju)-1.).lt.eps).or.
> (abs(weight(il,jd)-1.).lt.eps).or.
> (abs(weight(ir,ju)-1.).lt.eps).or.
> (abs(weight(il,ju)-1.).lt.eps).or.
> (abs(weight(ir,jd)-1.).lt.eps).or.
> (abs(weight(il,jd)-1.).lt.eps) ) then
 
nbound=nbound+1
boundlon(nbound)=ml_xmin+real(i-1)*ml_dx
boundlat(nbound)=ml_ymin+real(j-1)*ml_dy
endif
endif
enddo
enddo
 
c Get the distance from the subdomain
do i=1,ml_nx
do j=1,ml_ny
lon=ml_xmin+real(i-1)*ml_dx
lat=ml_ymin+real(j-1)*ml_dy
distmin=sdis(lon,lat,boundlon(1),boundlat(1))
do k=2,nbound
distpos=sdis(lon,lat,boundlon(k),boundlat(k))
if (distpos.lt.distmin) distmin=distpos
enddo
if ( abs(weight(i,j)-1.).lt.eps) then
dist(i,j)=distmin
else
dist(i,j)=-distmin
endif
enddo
enddo
 
c Set the new weights
do i=1,ml_nx
do j=1,ml_ny
if (weight(i,j).gt.0.) then
weight(i,j)=kink(dist(i,j),transxy)
endif
enddo
enddo
 
c ----------------------------------------------------------------
c Remove MDV regions in input field
c ----------------------------------------------------------------
 
if ( poisson.ne.1 ) goto 120
 
c Define region for mdv filling
do i=1,zm_nx
do j=1,zm_ny
do k=1,zm_nz
 
c Get neighbour of grid point
il = i-1
if (il.lt.1) il=1
ir = i+1
if ( ir.gt.zm_nx ) ir=zm_nx
jd = j-1
if (jd.lt.1) jd=1
ju = j+1
if ( ju.gt.zm_ny ) ju=zm_ny
 
c Set flag 2 for boundary and exterior points
if ( (abs(zm_rlat(il, j)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(ir, j)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(i , j)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(il,ju)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(ir,ju)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(i ,ju)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(il,jd)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(ir,jd)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(i ,jd)-zm_mdv).lt.eps) )
> then
flag_zm(i,j,k) = 2
an_p3(i,j,k) = 0.
an_u3(i,j,k) = 0.
an_v3(i,j,k) = 0.
an_t3(i,j,k) = 0.
 
c Set flag 1 for interior MDV points
elseif ( abs(an_p3(i,j,k)-zm_mdv).le.eps ) then
flag_zm(i,j,k) = 1
 
c Set flag 0 for interior valid points
else
flag_zm(i,j,k) = 0
endif
 
enddo
enddo
enddo
 
c Apply mdv filling
print*,'C DP (POISSON FILLING)'
call mdvfill(an_p3,an_p3,flag_zm,zm_nx,zm_ny,zm_nz,100)
print*,'C DT (POISSON FILLING)'
call mdvfill(an_t3,an_t3,flag_zm,zm_nx,zm_ny,zm_nz,100)
print*,'C DU (POISSON FILLING)'
call mdvfill(an_u3,an_u3,flag_zm,zm_nx,zm_ny,zm_nz,100)
print*,'C DV (POISSON FILLING)'
call mdvfill(an_v3,an_v3,flag_zm,zm_nx,zm_ny,zm_nz,100)
 
c Special treatment: if the number of missing values surpasses 50%
c on a level, then the anomaly is imported from the level above
do k=zm_nz-1,1,-1
 
count1 = 0
count0 = 0
do i=1,zm_nx
do j= 1,zm_ny
if ( flag_zm(i,j,k).eq.1 ) count1 = count1 + 1
if ( flag_zm(i,j,k).eq.0 ) count0 = count0 + 1
enddo
enddo
 
if ( count1.gt.count0 ) then
print*,'C P (IMPORTING FROM LEVEL ABOVE)',k
do i=1,zm_nx
do j= 1,zm_ny
an_p3(i,j,k) = an_p3(i,j,k+1)
flag_zm(i,j,k) = flag_zm(i,j,k+1)
enddo
enddo
print*,'C U (IMPORTING FROM LEVEL ABOVE)',k
do i=1,zm_nx
do j= 1,zm_ny
an_u3(i,j,k) = an_u3(i,j,k+1)
flag_zm(i,j,k) = flag_zm(i,j,k+1)
enddo
enddo
 
print*,'C V (IMPORTING FROM LEVEL ABOVE)',k
do i=1,zm_nx
do j= 1,zm_ny
an_v3(i,j,k) = an_v3(i,j,k+1)
flag_zm(i,j,k) = flag_zm(i,j,k+1)
enddo
enddo
 
print*,'C T (IMPORTING FROM LEVEL ABOVE)',k
do i=1,zm_nx
do j= 1,zm_ny
an_t3(i,j,k) = an_t3(i,j,k+1)
flag_zm(i,j,k) = flag_zm(i,j,k+1)
enddo
enddo
 
endif
 
enddo
 
c Write new fields for tests
if ( test.eq.1 ) then
 
call cdfwopn(zm_fn,cdfid,ierr)
if (ierr.ne.0) goto 994
 
isok=0
varname='P_ANO'
call check_varok(isok,varname,zm_vnam,zm_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,zm_ndim,zm_mdv,zm_vardim,
> zm_varmin,zm_varmax,zm_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,zm_time,0,an_p3,ierr)
if (ierr.ne.0) goto 994
print*,'W P_ANO ',trim(zm_fn)
 
isok=0
varname='T_ANO'
call check_varok(isok,varname,zm_vnam,zm_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,zm_ndim,zm_mdv,zm_vardim,
> zm_varmin,zm_varmax,zm_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,zm_time,0,an_t3,ierr)
if (ierr.ne.0) goto 994
print*,'W T_ANO ',trim(zm_fn)
 
isok=0
varname='U_ANO'
call check_varok(isok,varname,zm_vnam,zm_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,zm_ndim,zm_mdv,zm_vardim,
> zm_varmin,zm_varmax,zm_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,zm_time,0,an_u3,ierr)
if (ierr.ne.0) goto 994
print*,'W U_ANO ',trim(zm_fn)
 
isok=0
varname='V_ANO'
call check_varok(isok,varname,zm_vnam,zm_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,zm_ndim,zm_mdv,zm_vardim,
> zm_varmin,zm_varmax,zm_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,zm_time,0,an_v3,ierr)
if (ierr.ne.0) goto 994
print*,'W V_ANO ',trim(zm_fn)
 
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 994
 
endif
 
c Exit point for SOR solver
120 continue
 
c ----------------------------------------------------------------
c Change surface pressure and get 3d presure field
c ----------------------------------------------------------------
 
print*,'C PS'
 
c Change surface pressure: based on PV inversion on GEO
do i=1,ml_nx
do j=1,ml_ny
c Make vertical profile of pressure available
n1=0
do k=1,zm_nz
n1=n1+1
p1(n1)=an_p3(i,j,k)
z1(n1)=zm_z3(i,j,k)
enddo
 
if ( n1.ne.0 ) then
 
c Keep the original surface pressure (psfc=0)
if ( abs(psfc).lt.eps ) then
ml_ps(i,j) = ml_ps(i,j)
 
c Take the full change of surface pressure (psfc=1);
c Interpolation/extrapolation with a natural cubic spline
elseif ( abs(psfc-1.).lt.eps ) then
call spline (z1,p1,n1,1.e30,1.e30,spline_f1)
call splint (z1,p1,spline_f1,n1,ml_oro(i,j),hh)
ml_ps(i,j)=ml_ps(i,j) + hh*weight(i,j)
 
c Only take a fractional change of surface pressure
c Interpolation/extrapolation with a natural cubic spline
else
call spline (z1,p1,n1,1.e30,1.e30,spline_f1)
call splint (z1,p1,spline_f1,n1,ml_oro(i,j),hh)
ml_ps(i,j)=ml_ps(i,j) + hh*psfc*weight(i,j)
 
endif
 
endif
 
enddo
enddo
 
c Calculate 3d pressure field on model levels
print*,'C P'
do k=1,ml_nz
do i=1,ml_nx
do j=1,ml_ny
if (abs(ml_stag(3)+0.5).lt.eps) then
ml_p3(i,j,k)=ml_aklay(k)+ml_bklay(k)*ml_ps(i,j)
else
ml_p3(i,j,k)=ml_aklev(k)+ml_bklev(k)*ml_ps(i,j)
endif
enddo
enddo
enddo
 
c ----------------------------------------------------------------
c Get T,U,V at the new pressure levels, based on the original P file
c ----------------------------------------------------------------
 
c Interpolate T from original P file to new pressure levels
print*,'C T (ORIGINAL)'
do i=1,ml_nx
do j=1,ml_ny
 
n1=0
do k=ml_nz,1,-1
n1=n1+1
f1(n1)=ml_t3(i,j,k)
p1(n1)=ml_p0(i,j,k)
enddo
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_t3(i,j,k)=hh
enddo
 
enddo
enddo
 
c Interpolate U from original P file to new pressure levels
print*,'C U (ORIGINAL)'
do i=1,ml_nx
do j=1,ml_ny
 
n1=0
do k=ml_nz,1,-1
n1=n1+1
f1(n1)=ml_u3(i,j,k)
p1(n1)=ml_p0(i,j,k)
enddo
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_u3(i,j,k)=hh
enddo
 
enddo
enddo
 
c Interpolate V from original P file to new pressure levels
print*,'C V (ORIGINAL)'
do i=1,ml_nx
do j=1,ml_ny
 
n1=0
do k=ml_nz,1,-1
n1=n1+1
f1(n1)=ml_v3(i,j,k)
p1(n1)=ml_p0(i,j,k)
enddo
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_v3(i,j,k)=hh
enddo
 
enddo
enddo
 
c ----------------------------------------------------------------
c Add T,U,V anomalies at the new pressure levels
c ----------------------------------------------------------------
 
c Change temperature field
print*,'C T (ANOMALY)'
do i=1,ml_nx
do j=1,ml_ny
 
c Make vertical profile of temperature available
n1=0
pmax=-100.
pmin=2000.
do k=zm_nz,1,-1
if ((abs(an_t3(i,j,k)-zm_mdv).gt.eps).and.
> (zm_z3(i,j,k).gt.ml_oro(i,j)).and.
> (abs(zm_p3(i,j,k)-zm_mdv).gt.eps)) then
n1=n1+1
f1(n1)=an_t3(i,j,k)
p1(n1)=zm_p3(i,j,k)
if (p1(n1).lt.pmin) pmin=p1(n1)
if (p1(n1).gt.pmax) pmax=p1(n1)
endif
enddo
pmin=pmin-dpextra*pmin
pmax=pmax+dpextra+pmax
 
c Cubic spline interpolation
if (n1.gt.0) then
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
if ( (ml_p3(i,j,k).gt.pmin).and.
> (ml_p3(i,j,k).lt.pmax) ) then
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_t3(i,j,k)=ml_t3(i,j,k) + hh*weight(i,j)
endif
enddo
endif
 
enddo
enddo
 
c Change zonal velocity field
print*,'C U'
do i=1,ml_nx
do j=1,ml_ny
 
c Make vertical profile of zonal velocity available
n1=0
pmax=-100.
pmin=2000.
do k=zm_nz,1,-1
if ((abs(an_u3(i,j,k)-zm_mdv).gt.eps).and.
> (zm_z3(i,j,k).gt.ml_oro(i,j)).and.
> (abs(zm_p3(i,j,k)-zm_mdv).gt.eps)) then
n1=n1+1
f1(n1)=an_u3(i,j,k)
p1(n1)=zm_p3(i,j,k)
if (p1(n1).lt.pmin) pmin=p1(n1)
if (p1(n1).gt.pmax) pmax=p1(n1)
endif
enddo
pmin=pmin-dpextra*pmin
pmax=pmax+dpextra*pmax
 
c Cubic spline interpolation
if (n1.gt.0) then
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
if ( (ml_p3(i,j,k).gt.pmin).and.
> (ml_p3(i,j,k).lt.pmax) ) then
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_u3(i,j,k)=ml_u3(i,j,k) + hh*weight(i,j)
endif
enddo
endif
 
enddo
enddo
 
c Change meridional velocity field
print*,'C V'
do i=1,ml_nx
do j=1,ml_ny
 
c Make vertical profile of zonal velocity available
n1=0
pmax=-100.
pmin=2000.
do k=zm_nz,1,-1
if ((abs(an_v3(i,j,k)-zm_mdv).gt.eps).and.
> (zm_z3(i,j,k).gt.ml_oro(i,j)).and.
> (abs(zm_p3(i,j,k)-zm_mdv).gt.eps)) then
n1=n1+1
f1(n1)=an_v3(i,j,k)
p1(n1)=zm_p3(i,j,k)
if (p1(n1).lt.pmin) pmin=p1(n1)
if (p1(n1).gt.pmax) pmax=p1(n1)
endif
enddo
pmin=pmin-dpextra*pmin
pmax=pmax+dpextra*pmax
 
c Cubic spline interpolation
if (n1.gt.0) then
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
if ( (ml_p3(i,j,k).gt.pmin).and.
> (ml_p3(i,j,k).lt.pmax) ) then
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_v3(i,j,k)=ml_v3(i,j,k) + hh*weight(i,j)
endif
enddo
endif
 
enddo
enddo
 
c ---------------------------------------------------------------------
c Change geopotential height
c ---------------------------------------------------------------------
 
c Interpolate Z from original P file to new pressure levels
print*,'C Z (ORIGINAL)'
do i=1,ml_nx
do j=1,ml_ny
 
n1=0
do k=ml_nz,1,-1
n1=n1+1
f1(n1)=ml_z3(i,j,k)
p1(n1)=ml_p0(i,j,k)
enddo
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
ml_z3(i,j,k)=hh
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 Add geopotential height anomaly: first, the pressure anomaly is
c interpolated to the new position, then it is transformed into
c a correction of geopotential height with the hydrostatic equation
print*,'C DZ (MODIFIED -ORIGINAL)'
do i=1,ml_nx
do j=1,ml_ny
 
c Make vertical profile of pressure available
n1=0
pmax=-100.
pmin=2000.
do k=zm_nz,1,-1
if ((abs(an_p3(i,j,k)-zm_mdv).gt.eps).and.
> (zm_z3(i,j,k).gt.ml_oro(i,j)).and.
> (abs(zm_p3(i,j,k)-zm_mdv).gt.eps)) then
n1=n1+1
f1(n1)=an_p3(i,j,k)
p1(n1)=zm_p3(i,j,k)
if (p1(n1).lt.pmin) pmin=p1(n1)
if (p1(n1).gt.pmax) pmax=p1(n1)
endif
enddo
pmin=pmin-dpextra*pmin
pmax=pmax+dpextra*pmax
 
c Cubic spline interpolation and conversion dp -> dz
if (n1.gt.0) then
call spline (p1,f1,n1,1.e30,1.e30,spline_f1)
do k=1,ml_nz
if ( (ml_p3(i,j,k).gt.pmin).and.
> (ml_p3(i,j,k).lt.pmax) ) then
call splint (p1,f1,spline_f1,n1,ml_p3(i,j,k),hh)
hh = -rdg * ml_tv3(i,j,k) * hh/ml_p3(i,j,k)
ml_z3(i,j,k)=ml_z3(i,j,k) + hh*weight(i,j)
endif
enddo
endif
 
enddo
enddo
 
c ----------------------------------------------------------------
c Remove unrealistic values from final fields
c ----------------------------------------------------------------
 
if ( poisson.ne.1 ) goto 120
 
c Define region for mdv filling
count1 = 0
 
do i=1,ml_nx
do j=1,ml_ny
do k=1,ml_nz
 
c Get neighbour of grid point
il = i-1
if (il.lt.1) il=1
ir = i+1
if ( ir.gt.ml_nx ) ir=ml_nx
jd = j-1
if (jd.lt.1) jd=1
ju = j+1
if ( ju.gt.ml_ny ) ju=ml_ny
 
c Set flag 2 for boundary and exterior points
if ( (abs(zm_rlat(il, j)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(ir, j)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(i , j)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(il,ju)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(ir,ju)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(i ,ju)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(il,jd)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(ir,jd)-zm_mdv).lt.eps).or.
> (abs(zm_rlat(i ,jd)-zm_mdv).lt.eps) )
> then
flag_ml(i,j,k) = 2
 
c Set flag 1 for interior unphysical points
elseif ( ( abs(ml_t3(i,j,k)).gt.500. ).or.
> ( abs(ml_u3(i,j,k)).gt.500. ).or.
> ( abs(ml_v3(i,j,k)).gt.500. ) )
> then
flag_ml(i,j,k) = 1
count1 = count1 + 1
 
c Set flag 0 for interior valid points
else
flag_ml(i,j,k) = 0
endif
 
enddo
enddo
enddo
 
print*,'C MASK UNREALISTIC VALUES FOR T,U,V',count1
 
c Apply mdv filling
print*,'C T (POISSON FILLING)'
call mdvfill(ml_t3,ml_t3,flag_ml,ml_nx,ml_ny,ml_nz,10)
print*,'C U (POISSON FILLING)'
call mdvfill(ml_u3,ml_u3,flag_ml,ml_nx,ml_ny,ml_nz,10)
print*,'C V (POISSON FILLING)'
call mdvfill(ml_v3,ml_v3,flag_ml,ml_nx,ml_ny,ml_nz,10)
 
c ----------------------------------------------------------------
c Write modified fields to P file
c ----------------------------------------------------------------
 
c Open output file
call cdfwopn(ml_fn,cdfid,ierr)
if (ierr.ne.0) goto 994
 
c Write surface pressure
isok=0
varname='PS'
call check_varok(isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
ml_vardim(3)=3
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 994
ml_vardim(3)=4
endif
call putdat(cdfid,varname,ml_time,0,ml_ps,ierr)
if (ierr.ne.0) goto 994
print*,'W PS ',trim(ml_fn)
 
c Write temperature
isok=0
varname='T'
call check_varok(isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,ml_time,0,ml_t3,ierr)
if (ierr.ne.0) goto 994
print*,'W T ',trim(ml_fn)
 
c Write zonal wind
isok=0
varname='U'
call check_varok(isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,ml_time,0,ml_u3,ierr)
if (ierr.ne.0) goto 994
print*,'W U ',trim(ml_fn)
 
c Write meridional wind
isok=0
varname='V'
call check_varok(isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,ml_time,0,ml_v3,ierr)
if (ierr.ne.0) goto 994
print*,'W V ',trim(ml_fn)
 
c Write geopotential height
isok=0
varname='Z'
call check_varok(isok,varname,ml_vnam,ml_nvars)
if (isok.eq.0) then
call putdef(cdfid,varname,ml_ndim,ml_mdv,ml_vardim,
> ml_varmin,ml_varmax,ml_stag,ierr)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,ml_time,0,ml_z3,ierr)
if (ierr.ne.0) goto 994
print*,'W Z ',trim(ml_fn)
 
c Filter matrix (only in test mode)
if (test.eq.1) then
isok=0
varname='DIST'
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)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,ml_time,1,dist,ierr)
if (ierr.ne.0) goto 994
print*,'W DIST ',trim(ml_fn)
 
isok=0
varname='WEIGHT'
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)
if (ierr.ne.0) goto 994
endif
call putdat(cdfid,varname,ml_time,1,weight,ierr)
if (ierr.ne.0) goto 994
print*,'W WEIGHT ',trim(ml_fn)
 
endif
 
c Close output file
call clscdf(cdfid,ierr)
if (ierr.ne.0) goto 994
 
c ----------------------------------------------------------------
c Exception handling
c ----------------------------------------------------------------
 
stop
 
998 print*,'Problem with input netcdf file ',trim(ml_fn)
stop
 
997 print*,'Problem with input netcdf file ',trim(zm_fn)
stop
 
994 print*,'Problem with output netcdf file ',trim(ml_fn)
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 Natural cubic spline /from Numerical Recipes)
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 Spherical distance between two lat/lon points
c ---------------------------------------------------------
 
real function sdis(xp,yp,xq,yq)
c
c calculates spherical distance (in km) between two points given
c by their spherical coordinates (xp,yp) and (xq,yq), respectively.
c
real re
parameter (re=6370.)
real xp,yp,xq,yq,arg
arg=sind(yp)*sind(yq)+cosd(yp)*cosd(yq)*cosd(xp-xq)
if (arg.lt.-1.) arg=-1.
if (arg.gt.1.) arg=1.
sdis=re*acos(arg)
end
 
C -----------------------------------------------------------------
c Rene's KINK function (for smoothing at bounadries)
C -----------------------------------------------------------------
 
real function kink (x,a)
 
implicit none
 
c declaration of parameters
real x,a
 
c parameters
real pi
parameter (pi=3.1415926535)
 
if (x.lt.0.) then
kink=0.
elseif (x.gt.a) then
kink=1.
else
kink=(1.+cos(pi*(x-a)/a))/2.
endif
return
end
 
C -----------------------------------------------------------------
c Rene's KINK function (for smoothing at bounadries)
C -----------------------------------------------------------------
 
subroutine mdvfill (out,inp,flag,nx,ny,nz,maxiter)
 
implicit none
 
c Declaration of subroutine parameters
integer nx,ny,nz
real inp (nx,ny,nz)
real out (nx,ny,nz)
integer flag(nx,ny,nz)
integer maxiter
 
c Parameters
real omega ! Omega fopr SOR
parameter (omega=1.5)
 
c Auxiliary variables
integer i,j,k
integer iter
real tmp0(nx,ny,nz)
real tmp1(nx,ny,nz)
integer il,ir,ju,jd
integer count
real mean(nz)
 
c Calculate mean of variable for all levels
do k=1,nz
mean(k) = 0.
count = 0
do i=1,nx
do j=1,ny
if ( flag(i,j,k).eq.0 ) then
count = count + 1
mean(k) = mean(k) + inp(i,j,k)
endif
enddo
enddo
if ( count.ne.0 ) then
mean(k) = mean(k)/real(count)
else
mean(k) = 0.
endif
enddo
 
c Create first guess
do k=1,nz
do i=1,nx
do j=1,ny
if ( flag(i,j,k).eq.0 ) then
tmp0(i,j,k) = inp(i,j,k)
else
tmp0(i,j,k) = mean(k)
endif
enddo
enddo
enddo
 
c SOR iterations
iter = 0
122 continue
 
c Loop over all points
do k=1,nz
do i=1,nx
do j=1,ny
 
c Apply the updating only for specified points
if ( flag(i,j,k).ne.1 ) goto 121
 
c Get neighbouring points - no handling of periodic domains!
il = i-1
if (il.lt.1) il=1
ir = i+1
if ( ir.gt.nx ) ir=nx
jd = j-1
if (jd.lt.1) jd=1
ju = j+1
if ( ju.gt.ny ) ju=ny
 
c Update field
tmp1(i,j,k) = 0.25 * ( tmp0(il,j,k) + tmp0(ir,j,k) +
> tmp0(i,ju,k) + tmp0(i,jd,k) )
 
tmp0(i,j,k) = omega * tmp1(i,j,k) +
> (1. - omega) * tmp1(i,j,k)
 
c Exit point for loop
121 continue
 
enddo
enddo
enddo
 
c Decide whether further iterations are needed
iter = iter + 1
if ( iter.lt.maxiter) goto 122
 
c Save output
do i=1,nx
do j=1,ny
do k=1,nz
if ( flag(i,j,k).eq.1 ) then
out(i,j,k) = tmp0(i,j,k)
endif
enddo
enddo
enddo
 
end
 
c
Property changes:
Added: svn:executable
/trunk/post/rotate_lalo.f
0,0 → 1,1154
PROGRAM rotate_lalo
 
c *******************************************************************
c * Rotate to a geographical latitude/longitude grid *
c * Michael Sprenger / Autumn 2006 *
c *******************************************************************
 
implicit none
 
c -------------------------------------------------------------------
c Declaration of parameters and variables
c -------------------------------------------------------------------
 
c Specification of input parameters
real clon,clat,rotation
integer nx,ny
real dx,dy,xmin,ymin
integer nfield
character*80 fieldname(100)
 
c Numerical and physical parameters
real degrad
parameter (degrad=0.0174532925)
real omegaerd
parameter (omegaerd=7.292e-5 )
real eps
parameter (eps=0.001)
 
c Variables for input Z file : height level
character*80 in_cfn
real in_varmin(4),in_varmax(4),in_stag(4)
integer in_vardim(4)
real in_mdv
integer in_ndim
integer in_nx,in_ny,in_nz
real in_xmin,in_xmax,in_ymin,in_ymax,in_dx,in_dy
integer in_ntimes
real in_aklev(500),in_bklev(500)
real in_aklay(500),in_bklay(500)
real in_time
real in_pollon,in_pollat
integer in_nvars
character*80 in_vnam(100)
integer in_idate(5)
real,allocatable, dimension (:,:,:) :: in_field3
real,allocatable, dimension (:,:,:) :: in_vect1
real,allocatable, dimension (:,:,:) :: in_vect2
 
c Variables for output Z file : height level
character*80 out_cfn
real out_varmin(4),out_varmax(4),out_stag(4)
integer out_vardim(4)
real out_mdv
integer out_ndim
integer out_nx,out_ny,out_nz
real out_xmin,out_xmax,out_ymin,out_ymax,out_dx,out_dy
integer out_ntimes
real out_aklev(500),out_bklev(500)
real out_aklay(500),out_bklay(500)
real out_time
real out_pollon,out_pollat
integer out_idate(5)
real,allocatable, dimension (:,:,:) :: out_field3
real,allocatable, dimension (:,:,:) :: out_vect1
real,allocatable, dimension (:,:,:) :: out_vect2
real,allocatable, dimension (:,:) :: out_lat,out_lon
real,allocatable, dimension (:,:) :: out_x,out_y
real,allocatable, dimension (:,:) :: out_coriol
 
c Auxiliary variables
integer ifield
integer i,j,k
integer cdfid,cstid
character*80 cfn
integer stat,ierr,isok
real time
character*80 varname,cdfname,varname1,varname2
integer idate(5),stdate(5),datar(14)
integer rotmode
integer i1,i2,i3,i4
integer isvector
real lat
character*80 name
 
c Externals
real sdis
external sdis
 
c -------------------------------------------------------------------
c Preparations
c -------------------------------------------------------------------
print*,'*********************************************************'
print*,'* rotate_lalo *'
print*,'*********************************************************'
 
c Read parameter file
open(10,file='fort.10')
 
read(10,*) in_cfn
read(10,*) out_cfn
 
read(10,*) name,nx
if ( trim(name).ne.'GEO_NX' ) stop
read(10,*) name,ny
if ( trim(name).ne.'GEO_NY' ) stop
read(10,*) name,dx
if ( trim(name).ne.'GEO_DX' ) stop
read(10,*) name,dy
if ( trim(name).ne.'GEO_DY' ) stop
read(10,*) name,xmin
if ( trim(name).ne.'GEO_XMIN') stop
read(10,*) name,ymin
if ( trim(name).ne.'GEO_YMIN') stop
read(10,*) name,clon
if ( trim(name).ne.'CLON' ) stop
read(10,*) name,clat
if ( trim(name).ne.'CLAT' ) stop
read(10,*) name,rotation
if ( trim(name).ne.'CROT' ) stop
read(10,*) nfield
do i=1,nfield
read(10,*) fieldname(i)
enddo
close(10)
print*,clon,clat,rotation
print*,nx,ny,dx,dy,xmin,ymin
print*,trim(in_cfn),' -> ',trim(out_cfn)
 
c Get grid description for input Z file : height level
call cdfopn(in_cfn,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,in_nvars,in_vnam,ierr)
if (ierr.ne.0) goto 998
isok=0
varname=fieldname(1)
call check_varok (isok,varname,in_vnam,in_nvars)
if (isok.eq.0) goto 998
call getdef(cdfid,varname,in_ndim,in_mdv,in_vardim,
> in_varmin,in_varmax,in_stag,ierr)
if (ierr.ne.0) goto 998
in_nx =in_vardim(1)
in_ny =in_vardim(2)
in_xmin=in_varmin(1)
in_ymin=in_varmin(2)
call getlevs(cstid,in_nz,in_aklev,in_bklev,in_aklay,in_bklay,ierr)
call getgrid(cstid,in_dx,in_dy,ierr)
in_xmax=in_xmin+real(in_nx-1)*in_dx
in_ymax=in_ymin+real(in_ny-1)*in_dy
call gettimes(cdfid,in_time,in_ntimes,ierr)
call getstart(cstid,in_idate,ierr)
call getpole(cstid,in_pollon,in_pollat,ierr)
call clscdf(cstid,ierr)
call clscdf(cdfid,ierr)
 
c Set grid description for output file : height level
out_vardim(1) = nx
out_vardim(2) = ny
out_vardim(3) = in_nz
out_varmin(1) = xmin
out_varmin(2) = ymin
out_varmin(3) = in_varmin(3)
out_varmax(1) = xmin+real(nx-1)*dx
out_varmax(2) = ymin+real(ny-1)*dy
out_varmax(3) = in_varmax(3)
do i=1,in_nz
out_aklay(i) = in_aklay(i)
out_bklay(i) = in_bklay(i)
out_aklev(i) = in_aklev(i)
out_bklev(i) = in_bklev(i)
enddo
out_dx = dx
out_dy = dy
out_time = in_time
out_ntimes = in_ntimes
out_ndim = 4
out_mdv = in_mdv
out_nx = out_vardim(1)
out_ny = out_vardim(2)
out_nz = out_vardim(3)
out_xmin = out_varmin(1)
out_ymin = out_varmin(2)
out_pollon = 0.
out_pollat = 90.
do i=1,5
out_idate(i) = in_idate(i)
enddo
 
c Allocate memory for all fields
allocate(in_field3(in_nx,in_ny,in_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array in_field3 ***'
allocate(in_vect1(in_nx,in_ny,in_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array in_vect1 ***'
allocate(in_vect2(in_nx,in_ny,in_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array in_vect2 ***'
allocate(out_field3(out_nx,out_ny,out_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_field3 ***'
allocate(out_vect1(out_nx,out_ny,out_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_vect1 ***'
allocate(out_vect2(out_nx,out_ny,out_nz),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_vect2 ***'
allocate(out_lat(out_nx,out_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_lat ***'
allocate(out_lon(out_nx,out_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_lon ***'
allocate(out_x(out_nx,out_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_x ***'
allocate(out_y(out_nx,out_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_y ***'
allocate(out_coriol(out_nx,out_ny),stat=stat)
if (stat.ne.0) print*,'*** error allocating array out_coriol ***'
 
c Create constants file and output file (if requested)
datar(1)=out_nx
datar(2)=out_ny
datar(3)=int(1000.*out_varmax(2))
datar(4)=int(1000.*out_varmin(1))
datar(5)=int(1000.*out_varmin(2))
datar(6)=int(1000.*out_varmax(1))
datar(7)=int(1000.*out_dx)
datar(8)=int(1000.*out_dy)
datar(9)=out_nz
datar(10)=1
datar(11)=1
datar(12)=0
datar(13)=int(1000.*out_pollon)
datar(14)=int(1000.*out_pollat)
cfn=trim(out_cfn)//'_cst'
call wricst(cfn,datar,out_aklev,out_bklev,
> out_aklay,out_bklay,out_idate)
call crecdf(trim(out_cfn),cdfid,out_varmin,out_varmax,
> out_ndim,trim(cfn),ierr)
if (ierr.ne.0) goto 997
call clscdf(cdfid,ierr)
 
c -----------------------------------------------------------------
c Loop through all fields - rotate to new grid
c -----------------------------------------------------------------
 
do ifield=1,nfield
 
c Check if scalar or vectorial field (X for scalar, U.V for vector)
varname=fieldname(ifield)
i1=1
i2=1
i3=0
i4=0
100 if (varname(i1:i1).eq.' ') then
i1=i1+1
goto 100
endif
i2=i1
101 if ((varname(i2:i2).ne.' ').and.(varname(i2:i2).ne.'.')) then
i2=i2+1
goto 101
endif
if (varname(i2:i2).eq.'.') then
i3=i2+1
102 if (varname(i3:i3).eq.' ') then
i3=i3+1
goto 102
endif
i4=i3
104 if (varname(i4:i4).ne.' ') then
i4=i4+1
goto 104
endif
endif
if ((i3.ne.0).and.(i4.ne.0)) then
isvector=1
i2=i2-1
varname1=varname(i1:i2)
i4=i4-1
varname2=varname(i3:i4)
print*,'Rotating vector : ',
> trim(varname1),' / ',trim(varname2)
else
isvector=0
i2=i2-1
varname=varname(i1:i2)
print*,'Rotating scalar : ',trim(varname)
endif
c Rotate a scalar field
if (isvector.eq.0) then
 
c Read input field
call cdfopn(in_cfn,cdfid,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname,in_ndim,in_mdv,in_vardim,
> in_varmin,in_varmax,in_stag,ierr)
in_nz=in_vardim(3)
if (ierr.ne.0) goto 998
call getdat(cdfid,varname,in_time,0,in_field3,ierr)
if (ierr.ne.0) goto 998
call clscdf(cdfid,ierr)
 
c Rotate to new coordinate system
out_nz=in_nz
call getenvir (clon,clat,rotation,0,
> in_field3,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,in_nz,in_mdv,
> out_field3,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,out_nz)
 
c Write output scalar field
call cdfwopn(trim(out_cfn),cdfid,ierr)
if (ierr.ne.0) goto 997
out_vardim(3)=out_nz
call putdef(cdfid,varname,4,out_mdv,out_vardim,
> out_varmin,out_varmax,out_stag,ierr)
if (ierr.ne.0) goto 997
call putdat(cdfid,varname,out_time,0,out_field3,ierr)
if (ierr.ne.0) goto 997
call clscdf(cdfid,ierr)
 
c Rotate vector field
else if (isvector.eq.1) then
c Read input vector field
call cdfopn(in_cfn,cdfid,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname1,in_ndim,in_mdv,in_vardim,
> in_varmin,in_varmax,in_stag,ierr)
in_nz=in_vardim(3)
if (ierr.ne.0) goto 998
call getdat(cdfid,varname1,in_time,0,in_vect1,ierr)
if (ierr.ne.0) goto 998
call getdef(cdfid,varname2,in_ndim,in_mdv,in_vardim,
> in_varmin,in_varmax,in_stag,ierr)
in_nz=in_vardim(3)
if (ierr.ne.0) goto 998
call getdat(cdfid,varname2,in_time,0,in_vect2,ierr)
if (ierr.ne.0) goto 998
call clscdf(cdfid,ierr)
 
c Get new vector component in x direction
out_nz=in_nz
call getenvir (clon,clat,rotation,1,
> in_vect1,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,in_nz,in_mdv,
> out_field3,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,out_nz)
do i=1,out_nx
do j=1,out_ny
do k=1,out_nz
out_vect1(i,j,k)=out_field3(i,j,k)
enddo
enddo
enddo
call getenvir (clon,clat,rotation,2,
> in_vect2,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,in_nz,in_mdv,
> out_field3,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,out_nz)
do i=1,out_nx
do j=1,out_ny
do k=1,out_nz
if ( (abs(out_vect1 (i,j,k)-out_mdv).gt.eps).and.
> (abs(out_field3(i,j,k)-out_mdv).gt.eps) ) then
out_vect1(i,j,k)=out_vect1(i,j,k)-
> out_field3(i,j,k)
endif
enddo
enddo
enddo
 
c Get new vector component in y direction
out_nz=in_nz
call getenvir (clon,clat,rotation,2,
> in_vect1,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,in_nz,in_mdv,
> out_field3,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,out_nz)
do i=1,out_nx
do j=1,out_ny
do k=1,out_nz
out_vect2(i,j,k)=out_field3(i,j,k)
enddo
enddo
enddo
call getenvir (clon,clat,rotation,1,
> in_vect2,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,in_nz,in_mdv,
> out_field3,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,out_nz)
do i=1,out_nx
do j=1,out_ny
do k=1,out_nz
if ( (abs(out_vect2 (i,j,k)-out_mdv).gt.eps).and.
> (abs(out_field3(i,j,k)-out_mdv).gt.eps) ) then
out_vect2(i,j,k)=out_vect2(i,j,k)+
> out_field3(i,j,k)
endif
enddo
enddo
enddo
 
c Write output vector field
call cdfwopn(trim(out_cfn),cdfid,ierr)
if (ierr.ne.0) goto 997
out_vardim(3)=out_nz
call putdef(cdfid,varname1,4,out_mdv,out_vardim,
> out_varmin,out_varmax,out_stag,ierr)
if (ierr.ne.0) goto 997
call putdat(cdfid,varname1,out_time,0,out_vect1,ierr)
if (ierr.ne.0) goto 997
call putdef(cdfid,varname2,4,out_mdv,out_vardim,
> out_varmin,out_varmax,out_stag,ierr)
if (ierr.ne.0) goto 997
call putdat(cdfid,varname2,out_time,0,out_vect2,ierr)
if (ierr.ne.0) goto 997
call clscdf(cdfid,ierr)
 
endif
 
enddo
 
c -----------------------------------------------------------------
c Write additional fields: latitude, longitude, Coriolis parameter
c -----------------------------------------------------------------
 
c Open the output file
call cdfwopn(trim(out_cfn),cdfid,ierr)
if (ierr.ne.0) goto 997
 
c Geographical latitude
varname='RLAT'
print*,'Rotating scalar : ',trim(varname)
do i=1,in_nx
do j=1,in_ny
in_field3(i,j,1)=in_ymin+real(j-1)*in_dy
enddo
enddo
call getenvir (clon,clat,rotation,0,
> in_field3,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,1,in_mdv,
> out_lat,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,1)
out_vardim(3)=1
call putdef(cdfid,varname,4,out_mdv,out_vardim,
> out_varmin,out_varmax,out_stag,ierr)
if (ierr.ne.0) goto 997
call putdat(cdfid,varname,out_time,0,out_lat,ierr)
if (ierr.ne.0) goto 997
 
c Geographical longitude
varname='RLON'
print*,'Rotating scalar : ',trim(varname)
do i=1,in_nx
do j=1,in_ny
in_field3(i,j,1)=in_xmin+real(i-1)*in_dx
enddo
enddo
call getenvir (clon,clat,rotation,0,
> in_field3,in_dx,in_dy,
> in_xmin,in_ymin,in_nx,in_ny,1,in_mdv,
> out_lon,out_dx,out_dy,
> out_xmin,out_ymin,out_nx,out_ny,1)
out_vardim(3)=1
call putdef(cdfid,varname,4,out_mdv,out_vardim,
> out_varmin,out_varmax,out_stag,ierr)
if (ierr.ne.0) goto 997
call putdat(cdfid,varname,out_time,0,out_lon,ierr)
if (ierr.ne.0) goto 997
 
 
 
c Close output file
call clscdf(cdfid,ierr)
 
c -----------------------------------------------------------------
c Exception handling and format specs
c -----------------------------------------------------------------
 
stop
 
998 print*,'Z: Problems with input rotated grid'
stop
 
997 print*,'Z: Problems with output to lat/lon grid'
stop
 
end
 
 
c ********************************************************************************
c * SUBROUTINE: ROTATION TO LATITUDE/LONGITUDE COORDINATE SYSTEM *
c ********************************************************************************
 
c --------------------------------------------------------------------------------
c Subroutine to get environment of strcof
c --------------------------------------------------------------------------------
 
SUBROUTINE getenvir (clon,clat,rotation,rotmode,
> inar, rdx,rdy,rxmin,rymin,rnx,rny,rnz,mdv,
> outar, dx, dy, xmin, ymin, nx, ny, nz)
 
c Rotate from a local quasi-cartesian coordiante system into lat/lon coordinate
c system.
 
implicit none
 
c Declaration of input parameters
integer rnx,rny,rnz
real rdx,rdy,rxmin,rymin
real inar(rnx,rny,rnz)
real clon,clat,rotation
real mdv
integer rotmode
 
c Declaration of output parameters
integer nx,ny,nz
real dx,dy,xmin,ymin
real outar(nx,ny,nz)
 
c Set numerical and physical constants
real g2r
parameter (g2r=0.0174533)
real pi180
parameter (pi180=3.14159265359/180.)
real eps
parameter (eps=0.0001)
 
 
c Flag for test mode
integer test
parameter (test=0)
character*80 testfile
parameter (testfile='ROTGRID')
 
c Auxiliary variables
real pollon,pollat
integer i,j,k,l
real rlon(nx,ny),rlat(nx,ny)
real rlon1(nx,ny),rlat1(nx,ny)
real lon(nx,ny),lat(nx,ny)
real rotangle1(nx,ny),rotangle2(nx,ny)
real rotangle(nx,ny)
real sinoutar(nx,ny,nz),cosoutar(nx,ny,nz)
real rxmax,rymax
real xind,yind,pind
real outval
integer ix,iy
real ax,ay,az,bx,by,bz,zx,zy,zz
real clon1,clat1,clon2,clat2
real rindx,rindy
integer indx,indy,indr,indu
real frac0i,frac0j,frac1i,frac1j
character*80 cdfname,varname,cstname
real vx1,vx2,vy1,vy2,angle,vx2min
integer s
 
c Externals
real lmtolms,phtophs
external lmtolms,phtophs
 
c Get geographical coordinates
do i=1,nx
do j=1,ny
lon(i,j)=xmin+real(i-1)*dx
lat(i,j)=ymin+real(j-1)*dy
enddo
enddo
 
c First rotation
pollon=clon-180.
if (pollon.lt.-180.) pollon=pollon+360.
pollat=90.-clat
do i=1,nx
do j=1,ny
rlon1(i,j)=lmtolms(lat(i,j),lon(i,j),pollat,pollon)
rlat1(i,j)=phtophs(lat(i,j),lon(i,j),pollat,pollon)
enddo
enddo
 
c Second coordinate transformation
pollon=-180.
pollat=90.+rotation
do i=1,nx
do j=1,ny
rlon(i,j)=90.+lmtolms(rlat1(i,j),rlon1(i,j)-90.,pollat,pollon)
rlat(i,j)=phtophs(rlat1(i,j),rlon1(i,j)-90.,pollat,pollon)
enddo
enddo
 
c Get the angle between the rotated and non-rotated coordinate frame
if ((rotmode.eq.1).or.(rotmode.eq.2)) then
do i=2,nx-1
do j=2,ny-1
c Angle between latitude circles
vx1=1.
vy1=0.
vx2min=(rlon(i+1,j)-rlon(i-1,j))*cos(pi180*rlat(i,j))
do s=-1,1,2
vx2=(rlon(i+1,j)-rlon(i-1,j)+real(s)*360.)*
> cos(pi180*rlat(i,j))
if (abs(vx2).lt.abs(vx2min)) vx2min=vx2
enddo
vx2=vx2min
vy2=rlat(i+1,j)-rlat(i-1,j)
call getangle(vx1,vy1,vx2,vy2,angle)
rotangle1(i,j)=angle
 
c Angle between longitude circles
vx1=0.
vy1=1.
vx2min=(rlon(i,j+1)-rlon(i,j-1))*cos(pi180*rlat(i,j))
do s=-1,1,2
vx2=(rlon(i+1,j)-rlon(i-1,j)+real(s)*360.)*
> cos(pi180*rlat(i,j))
if (abs(vx2).lt.abs(vx2min)) vx2min=vx2
enddo
vx2=vx2min
vy2=rlat(i,j+1)-rlat(i,j-1)
call getangle(vx1,vy1,vx2,vy2,angle)
rotangle2(i,j)=angle
enddo
enddo
 
c Set the angle at the boundaries
do i=1,nx
rotangle1(i,ny)=2.0*rotangle1(i,ny-1)-rotangle1(i,ny-2)
rotangle1(i,1) =2.0*rotangle1(i,2)-rotangle1(i,3)
rotangle2(i,ny)=2.0*rotangle2(i,ny-1)-rotangle2(i,ny-2)
rotangle2(i,1) =2.0*rotangle2(i,2)-rotangle2(i,3)
enddo
do j=1,ny
rotangle1(nx,j)=2.0*rotangle1(nx-1,j)-rotangle1(nx-2,j)
rotangle1(1,j) =2.0*rotangle1(2,j)-rotangle1(3,j)
rotangle2(nx,j)=2.0*rotangle2(nx-1,j)-rotangle2(nx-2,j)
rotangle2(1,j) =2.0*rotangle2(2,j)-rotangle2(3,j)
enddo
c Set the final rotation angle
do i=1,nx
do j=1,ny
rotangle(i,j)=0.5*(rotangle1(i,j)+rotangle2(i,j))
enddo
enddo
 
endif
 
c Bring longitude into domain of geographical grid (shift by 360 deg)
do i=1,nx
do j=1,ny
100 if (rlon(i,j).lt.rxmin) then
rlon(i,j)=rlon(i,j)+360.
goto 100
endif
102 if (rlon(i,j).gt.(rxmin+real(rnx-1)*rdx)) then
rlon(i,j)=rlon(i,j)-360.
goto 102
endif
enddo
enddo
 
c Rotate the scalar or the vector component
do i=1,nx
do j=1,ny
do k=1,nz
 
c Get index
rindx=(rlon(i,j)-rxmin)/rdx+1.
rindy=(rlat(i,j)-rymin)/rdy+1.
indx=int(rindx)
indy=int(rindy)
if ((indx.lt.1).or.(indx.gt.rnx).or.
> (indy.lt.1).or.(indy.gt.rny)) then
outar(i,j,k)=mdv
goto 103
endif
 
c Get inidices of left and upper neighbours
indr=indx+1
if (indr.gt.rnx) indr=1
indu=indy+1
if (indu.gt.rny) indu=ny
c Do linear interpolation
if ( ( abs(inar(indx ,indy, k)-mdv).gt.eps ).and.
& ( abs(inar(indx ,indu, k)-mdv).gt.eps ).and.
& ( abs(inar(indr ,indy, k)-mdv).gt.eps ).and.
& ( abs(inar(indr ,indu, k)-mdv).gt.eps ) ) then
frac0i=rindx-float(indx)
frac0j=rindy-float(indy)
frac1i=1.-frac0i
frac1j=1.-frac0j
outval = inar(indx ,indy, k ) * frac1i * frac1j
& + inar(indx ,indu, k ) * frac1i * frac0j
& + inar(indr ,indy, k ) * frac0i * frac1j
& + inar(indr ,indu, k ) * frac0i * frac0j
else
outval=mdv
endif
 
c Update output array
outar(i,j,k)=outval
 
c Next
103 continue
 
enddo
enddo
enddo
 
c Get components for tests
if (test.eq.1) then
do i=1,nx
do j=1,ny
do k=1,nz
cosoutar(i,j,k)=outar(i,j,k)*cos(pi180*rotangle(i,j))
sinoutar(i,j,k)=-outar(i,j,k)*sin(pi180*rotangle(i,j))
enddo
enddo
enddo
endif
 
c Get correct component of rotated field
do i=1,nx
do j=1,ny
do k=1,nz
if ( abs(outar(i,j,k)-mdv).gt.eps ) then
if (rotmode.eq.1) then
outar(i,j,k)= outar(i,j,k)*cos(pi180*rotangle(i,j))
else if (rotmode.eq.2) then
outar(i,j,k)=-outar(i,j,k)*sin(pi180*rotangle(i,j))
else if (rotmode.eq.0) then
outar(i,j,k)=outar(i,j,k)
endif
endif
enddo
enddo
enddo
 
c Test mode: Write grids to cdf file
if (test.eq.1) then
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='RLON1'
call writecdf2D(cdfname,cstname,
> varname,rlon1,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 1,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='RLON'
call writecdf2D(cdfname,cstname,
> varname,rlon,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='LON'
call writecdf2D(cdfname,cstname,
> varname,lon,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='RLAT1'
call writecdf2D(cdfname,cstname,
> varname,rlat1,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='RLAT'
call writecdf2D(cdfname,cstname,
> varname,rlat,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='LAT'
call writecdf2D(cdfname,cstname,
> varname,lat,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='ANGLE1'
call writecdf2D(cdfname,cstname,
> varname,rotangle1,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='ANGLE2'
call writecdf2D(cdfname,cstname,
> varname,rotangle2,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='U'
call writecdf2D(cdfname,cstname,
> varname,cosoutar,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
cdfname=testfile
cstname=trim(testfile)//'_cst'
varname='V'
call writecdf2D(cdfname,cstname,
> varname,sinoutar,0.,
> rdx,rdy,rxmin,rymin,rnx,rny,
> 0,1)
 
endif
 
END
 
 
c --------------------------------------------------------------------------------
c Auxiliary routines: angle between two vectors
c --------------------------------------------------------------------------------
 
SUBROUTINE getangle (vx1,vy1,vx2,vy2,angle)
 
c Given two vectors <vx1,vy1> and <vx2,vy2>, determine the angle (in deg)
c between the two vectors.
 
implicit none
 
c Declaration of subroutine parameters
real vx1,vy1
real vx2,vy2
real angle
 
c Auxiliary variables and parameters
real len1,len2,len3
real val1,val2,val3
real pi
parameter (pi=3.14159265359)
 
len1=sqrt(vx1*vx1+vy1*vy1)
len2=sqrt(vx2*vx2+vy2*vy2)
 
if ((len1.gt.0.).and.(len2.gt.0.)) then
vx1=vx1/len1
vy1=vy1/len1
vx2=vx2/len2
vy2=vy2/len2
 
val1=vx1*vx2+vy1*vy2
val2=-vy1*vx2+vx1*vy2
 
len3=sqrt(val1*val1+val2*val2)
 
if ( (val1.ge.0.).and.(val2.ge.0.) ) then
val3=acos(val1/len3)
else if ( (val1.lt.0.).and.(val2.ge.0.) ) then
val3=pi-acos(abs(val1)/len3)
else if ( (val1.ge.0.).and.(val2.le.0.) ) then
val3=-acos(val1/len3)
else if ( (val1.lt.0.).and.(val2.le.0.) ) then
val3=-pi+acos(abs(val1)/len3)
endif
else
val3=0.
endif
 
angle=180./pi*val3
 
END
 
c --------------------------------------------------------------------------------
c Transformation routine: LMSTOLM and PHSTOPH from library gm2em
c --------------------------------------------------------------------------------
 
REAL FUNCTION LMTOLMS (PHI, LAM, POLPHI, POLLAM)
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
 
 
REAL FUNCTION PHTOPHS (PHI, LAM, POLPHI, POLLAM)
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
 
 
c ---------------------------------------------------------
c Spherical distance between two lat/lon points
c ---------------------------------------------------------
 
real function sdis(xp,yp,xq,yq)
c
c calculates spherical distance (in km) between two points given
c by their spherical coordinates (xp,yp) and (xq,yq), respectively.
c
real re
parameter (re=6370.)
real xp,yp,xq,yq,arg
arg=sind(yp)*sind(yq)+cosd(yp)*cosd(yq)*cosd(xp-xq)
if (arg.lt.-1.) arg=-1.
if (arg.gt.1.) arg=1.
sdis=re*acos(arg)
end
 
 
c ********************************************************************************
c * NETCDF INPUT/OUTPUT *
c ********************************************************************************
 
c ---------------------------------------------------------
c Subroutines to write the netcdf output file
c ---------------------------------------------------------
 
subroutine writecdf2D(cdfname,cstname,
> varname,arr,ctime,
> dx,dy,xmin,ymin,nx,ny,
> crefile,crevar)
 
c Create and write to the netcdf file <cdfname>. The variable
c with name <varname> and with time <time> is written. The data
c are in the two-dimensional array <arr>. The list <dx,dy,xmin,
c ymin,nx,ny> specifies the output grid. The flags <crefile> and
c <crevar> determine whether the file and/or the variable should
c be created. 1: create / 0: not created
 
IMPLICIT NONE
 
c Declaration of input parameters
character*80 cdfname,cstname,varname
integer nx,ny
real arr(nx,ny)
real dx,dy,xmin,ymin
integer ctime
integer crefile,crevar
 
c Further variables
real varmin(4),varmax(4),stag(4)
integer ierr,cdfid,ndim,vardim(4)
real mdv
integer datar(14),stdate(5)
integer i
real time
C Definitions
varmin(1)=xmin
varmin(2)=ymin
varmin(3)=1050.
varmax(1)=xmin+real(nx-1)*dx
varmax(2)=ymin+real(ny-1)*dy
varmax(3)=1050.
ndim=4
vardim(1)=nx
vardim(2)=ny
vardim(3)=1
stag(1)=0.
stag(2)=0.
stag(3)=0.
mdv=-999.98999
time=real(ctime)
 
C Create the file
if (crefile.eq.0) then
call cdfwopn(cdfname,cdfid,ierr)
if (ierr.ne.0) goto 906
else if (crefile.eq.1) then
call crecdf(cdfname,cdfid,
> varmin,varmax,ndim,cstname,ierr)
if (ierr.ne.0) goto 903
 
C Write the constants file
datar(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)=1
datar(10)=1
datar(11)=0 ! data version
datar(12)=0 ! cstfile version
datar(13)=0 ! longitude of pole
datar(14)=90000 ! latitude of pole
do i=1,5
stdate(i)=0
enddo
call wricst(cstname,datar,0.,0.,0.,0.,stdate)
endif
 
c Write the data to the netcdf file, and close the file
if (crevar.eq.1) then
call putdef(cdfid,varname,ndim,mdv,
> vardim,varmin,varmax,stag,ierr)
if (ierr.ne.0) goto 904
endif
call putdat(cdfid,varname,time,0,arr,ierr)
if (ierr.ne.0) goto 905
call clscdf(cdfid,ierr)
 
return
c Error handling
903 print*,'*** Problem to create netcdf file ***'
stop
904 print*,'*** Problem to write definition ***'
stop
905 print*,'*** Problem to write data ***'
stop
906 print*,'*** Problem to open netcdf file ***'
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)>.
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