Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed
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