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