0,0 → 1,1529 |
PROGRAM inv_cart |
|
c ******************************************************************************** |
c * CALCULATES FOR A PV AND THETA DISTRIBUTION OTHER PROGNOSTIC FIELDS BY * |
c * MEANS OF A PV INVERSION * |
c * * |
c * Rene Fehlmann 1994 / Code re-organization: Michael Sprenger, 2006 * |
c ******************************************************************************** |
|
c -------------------------------------------------------------------------------- |
c Declaration of variables, parameters, externals and common blocks |
c -------------------------------------------------------------------------------- |
|
implicit none |
|
c Grid parameters |
integer nx,ny,nz |
real xmin,ymin,zmin,xmax,ymax,zmax |
real dx,dy,dz |
real deltax,deltay,deltaz |
real mdv |
real, allocatable,dimension (:,:) :: coriol |
|
c Reference state |
real, allocatable,dimension (:) :: nsqref |
real, allocatable,dimension (:) :: thetaref |
real, allocatable,dimension (:) :: rhoref |
real, allocatable,dimension (:) :: pressref |
real, allocatable,dimension (:) :: zref |
|
|
C Boundary conditions |
real, allocatable,dimension (:,:) :: thetatop |
real, allocatable,dimension (:,:) :: thetabot |
real, allocatable,dimension (:,:) :: ua |
real, allocatable,dimension (:,:) :: ub |
real, allocatable,dimension (:,:) :: va |
real, allocatable,dimension (:,:) :: vb |
|
c Potentiual vorticity and stream function |
real, allocatable,dimension (:,:,:) :: psi |
real, allocatable,dimension (:,:,:) :: pv |
|
c Auxiliary arrays for numerics |
real, allocatable,dimension (:,:,:) :: a |
real, allocatable,dimension (:,:,:) :: b |
real, allocatable,dimension (:,:,:) :: c |
|
c Input parameters |
character*80 pvsrcfile |
character*80 referfile |
|
c Auxiliary variables |
integer i,j,k |
integer stat |
|
c -------------------------------------------------------------------------------- |
c Preparations |
c -------------------------------------------------------------------------------- |
|
print*,'********************************************************' |
print*,'* INV_CART *' |
print*,'********************************************************' |
|
c Read parameter file |
open(10,file='fort.10') |
read(10,*) pvsrcfile |
read(10,*) referfile |
close(10) |
print* |
print*,trim(pvsrcfile) |
|
|
c Get lat/lon gid parameters from input file |
call read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv, |
> pvsrcfile) |
print* |
print*,'Read_Dim: nx,ny,nz = ',nx,ny,nz |
print*,' dx,dy,dz = ',dx,dy,dz |
print*,' xmin,ymin,zmin = ',xmin,ymin,zmin |
print*,' mdv = ',mdv |
print* |
|
c Count from 0, not from 1 |
nx=nx-1 |
ny=ny-1 |
nz=nz-1 |
|
c Allocate memory for boundary conditions |
allocate(thetatop(0:nx,0:ny),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array thetatop ***' |
allocate(thetabot(0:nx,0:ny),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array thetabot ***' |
allocate(ua(0:nx,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array ua ***' |
allocate(ub(0:nx,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array ub ***' |
allocate(va(0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array va ***' |
allocate(vb(0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array vb ***' |
|
c Allocate memory for 3d PV and stream function |
allocate(psi(0:nx,0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array psi ***' |
allocate(pv(0:nx,0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array pv ***' |
|
c Alllocate memory for matrix elements for inversion operator |
allocate(a(0:nx,0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array a ***' |
allocate(b(0:nx,0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array b ***' |
allocate(c(0:nx,0:ny,0:nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array c ***' |
|
c Allocate memory for reference profile |
allocate(nsqref(0:2*nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array nsqref ***' |
allocate(thetaref(0:2*nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array thetaref ***' |
allocate(rhoref(0:2*nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array rhoref ***' |
allocate(pressref(0:2*nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array pressref ***' |
allocate(zref(0:2*nz),stat=stat) |
if (stat.ne.0) print*,'*** error allocating array zref ***' |
|
c Allocate memory for Coriolis parameter |
allocate(coriol(0:nx,0:ny),STAT=stat) |
if (stat.ne.0) print*,'error allocating coriol' |
|
c -------------------------------------------------------------------------------- |
c Input |
c -------------------------------------------------------------------------------- |
|
c Read reference profile and grid parameters |
call read_ref (nsqref,rhoref,thetaref,pressref,zref, |
> nx,ny,nz,deltax,deltay,deltaz,coriol, |
> referfile) |
deltax=1000.*deltax |
deltay=1000.*deltay |
|
c Read input fields from netcdf |
call read_inp (pv,thetabot,thetatop,ua,ub,va,vb, |
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin, |
> pvsrcfile) |
|
c -------------------------------------------------------------------------------- |
c Perform the inversion |
c -------------------------------------------------------------------------------- |
|
C Init matrix elements for inversion |
call matrixel(a,b,c,coriol,nx,ny,nz,nsqref,rhoref, |
> deltax,deltay,deltaz) |
|
c Inversion |
call sor(psi,nsqref,thetatop,thetabot,thetaref,rhoref,coriol, |
> pv,ua,ub,va,vb,a,b,c,nx,ny,nz,deltax,deltay,deltaz) |
|
c -------------------------------------------------------------------------------- |
c Output |
c -------------------------------------------------------------------------------- |
|
c Write output to netcdf |
print* |
call write_out (psi,thetabot,thetatop,ua,ub,va,vb, |
> nx,ny,nz,deltax,deltay,deltaz, |
> coriol,thetaref,rhoref,pressref,pvsrcfile) |
|
|
END |
|
|
c ******************************************************************************** |
c * NETCDF AND ASCII INPUT AND OUTPUT * |
c ******************************************************************************** |
|
c -------------------------------------------------------------------------------- |
c Output to netcdf file |
c -------------------------------------------------------------------------------- |
|
SUBROUTINE write_out (psi,thetabot,thetatop,ua,ub,va,vb,nx,ny,nz, |
> dx,dy,dz,coriol,thetaref,rhoref,pref, |
> pvsrcfile) |
|
c Write the result of the inversion to output netcdf |
c |
c psi : streamm function as calculated from inversion |
c thetabot,thetatop : potential temperature at lower and upper boundary |
c ua,ub : Zonal wind at western and eastern boundary |
c va,vb : Meridional wind at southern and northern boundary |
c nx,ny,nz : Grid dimension in x, y and z direction |
c dx,dy,dz : Grid resolution |
c coriol : Coriolis parameter |
c thetaref : Reference profile of potential temperature |
c rhoref : Reference profile of density |
c pref : Reference profile of pressure |
c pvsrcfile : Name of the output netcdf file |
|
implicit none |
|
c Declaration of subroutine parameters |
integer nx,ny,nz |
real psi(0:nx,0:ny,0:nz) |
real thetatop(0:nx,0:ny) |
real thetabot(0:nx,0:ny) |
real ua(0:nx,0:nz) |
real ub(0:nx,0:nz) |
real va(0:ny,0:nz) |
real vb(0:ny,0:nz) |
character*(30) pvsrcfile |
real dx,dy,dz |
real thetaref(0:2*nz) |
real rhoref(0:2*nz) |
real pref(0:2*nz) |
real coriol(0:nx,0:ny) |
|
c Numerical and physical parameters |
real eps |
parameter (eps=0.01) |
real g |
parameter (g=9.81) |
real preunit |
parameter (preunit=0.01) |
real kappa |
parameter (kappa=0.286) |
|
c Auxiliary variables |
integer cdfid,stat |
integer vardim(4) |
real misdat |
integer ndimin |
real varmin(4),varmax(4),stag(4) |
integer i,j,k,nf1,jj,kk |
real tmp(0:nx,0:ny,0:nz) |
real pr (0:nx,0:ny,0:nz) |
real th (0:nx,0:ny,0:nz) |
integer ntimes |
real time(200) |
character*80 vnam(100),varname |
integer nvars |
integer isok,ierr |
real meanpsi,meancnt |
|
c Get grid description |
call cdfopn(pvsrcfile,cdfid,stat) |
if (stat.ne.0) goto 997 |
call getvars(cdfid,nvars,vnam,stat) |
if (stat.ne.0) goto 997 |
isok=0 |
varname='QGPV' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
time(1)=0. |
call gettimes(cdfid,time,ntimes,stat) |
if (stat.ne.0) goto 997 |
call clscdf(cdfid,stat) |
if (stat.ne.0) goto 997 |
|
c Open output netcdf file |
call cdfwopn(pvsrcfile,cdfid,stat) |
if (stat.ne.0) goto 997 |
|
c Create the variable if necessary |
call getvars(cdfid,nvars,vnam,stat) |
if (stat.ne.0) goto 997 |
isok=0 |
varname='PSI' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) then |
call putdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
endif |
isok=0 |
varname='U' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) then |
call putdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
endif |
isok=0 |
varname='V' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) then |
call putdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
endif |
isok=0 |
varname='TH' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) then |
call putdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
endif |
isok=0 |
varname='T' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) then |
call putdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
endif |
isok=0 |
varname='P' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) then |
call putdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
endif |
|
c Write stream function |
varname='PSI' |
call putdat(cdfid,varname,time(1),0,psi,ierr) |
if (stat.ne.0) goto 997 |
print*,'W PSI ',trim(pvsrcfile) |
|
c Calculate and write velocity U: keep southern and northern boundary |
do k=0,nz |
do i=0,nx |
do j=1,ny-1 |
tmp(i,j,k)=(psi(i,j-1,k)-psi(i,j+1,k))/ |
> (2.*dy*coriol(i,j)) |
enddo |
tmp(i,0,k) =ua(i,k) |
tmp(i,ny,k)=ub(i,k) |
enddo |
enddo |
varname='U' |
call putdat(cdfid,varname,time(1),0,tmp,ierr) |
if (stat.ne.0) goto 997 |
print*,'W U ',trim(pvsrcfile) |
|
C Calculate and write velocity V: keep western and eastern boundary |
do k=0,nz |
do j=0,ny |
do i=1,nx-1 |
tmp(i,j,k)=(psi(i+1,j,k)-psi(i-1,j,k))/ |
> (2.*dx*coriol(i,j)) |
enddo |
tmp(0,j,k)=va(j,k) |
tmp(nx,j,k)=vb(j,k) |
enddo |
enddo |
varname='V' |
call putdat(cdfid,varname,time(1),0,tmp,ierr) |
if (stat.ne.0) goto 997 |
print*,'W V ',trim(pvsrcfile) |
|
c Calculate and write potential temperature: keep lower and upper boundary |
c Potential temperature is needed for calculation of temperature: keep it |
do i=0,nx |
do j=0,ny |
th(i,j,0)=thetabot(i,j) |
do k=1,nz-1 |
th(i,j,k)=thetaref(2*k)* |
> (psi(i,j,k+1)-psi(i,j,k-1))/(2.*dz*g) |
|
enddo |
th(i,j,nz)=thetatop(i,j) |
enddo |
enddo |
varname='TH' |
call putdat(cdfid,varname,time(1),0,th,ierr) |
if (stat.ne.0) goto 997 |
print*,'W TH ',trim(pvsrcfile) |
|
c Calculate and write pressure: The pressure is directly proportional to the |
c streamfunction. But the streamfunction is determined only up to an additive |
c constant. Shift the streamfunction in such a way that it vanish in the mean |
c on the boundaries. Pressure is needed for calculation of temperature: keep it |
meanpsi=0. |
meancnt=0. |
do i=0,nx |
do j=0,ny |
meanpsi=meanpsi+psi(i,j,0)+psi(i,j,nz) |
meancnt=meancnt+2 |
enddo |
enddo |
do i=0,nx |
do k=0,nz |
meanpsi=meanpsi+psi(i,0,k)+psi(i,ny,k) |
meancnt=meancnt+2 |
enddo |
enddo |
do j=0,ny |
do k=0,nz |
meanpsi=meanpsi+psi(0,j,k)+psi(nx,j,k) |
meancnt=meancnt+2 |
enddo |
enddo |
meanpsi=meanpsi/meancnt |
do i=0,nx |
do j=0,ny |
do k=0,nz |
kk=2*k |
pr(i,j,k)=preunit*rhoref(kk)*(psi(i,j,k)-meanpsi) |
enddo |
enddo |
enddo |
varname='P' |
call putdat(cdfid,varname,time(1),0,pr,ierr) |
if (stat.ne.0) goto 997 |
print*,'W P ',trim(pvsrcfile) |
|
c Calculate and write temperature |
do i=0,nx |
do j=0,ny |
do k=0,nz |
kk=2*k |
tmp(i,j,k)=((pref(kk)/1000.)**kappa) * |
> (th(i,j,k)+kappa*thetaref(kk)*pr(i,j,k)/pref(kk)) |
enddo |
enddo |
enddo |
varname='T' |
call putdat(cdfid,varname,time(1),0,tmp,ierr) |
if (stat.ne.0) goto 997 |
print*,'W T ',trim(pvsrcfile) |
|
c Close output netcdf file |
call clscdf(cdfid,stat) |
if (stat.ne.0) goto 997 |
|
return |
|
c Exception handling |
997 print*,'Problem with output netcdf file... Stop' |
stop |
|
end |
|
|
c -------------------------------------------------------------------------------- |
c Read the reference file |
c -------------------------------------------------------------------------------- |
|
SUBROUTINE read_ref (nsqref,rhoref,thetaref,pressref,zref, |
> nx,ny,nz,deltax,deltay,deltaz,coriol, |
> pvsrcfile) |
|
c Read the reference profile from file |
c |
c thetaref : Reference potential temperature (K) |
c pressref : Reference pressure (Pa) |
c rhoref : Reference density (kg/m^3) |
c nsqref : Stratification (s^-1) |
c zref : Reference height (m) |
c nx,nny,nz : Grid dimension in x,y,z direction |
c deltax,deltay,deltaz : Grid spacings used for calculations (m) |
c coriol : Coriolis parameter (s^-1) |
c pvsrcfile : Input file |
|
implicit none |
|
c Declaration of subroutine parameters |
integer nx,ny,nz |
real nsqref (0:2*nz) |
real thetaref(0:2*nz) |
real rhoref (0:2*nz) |
real pressref(0:2*nz) |
real zref (0:2*nz) |
real deltax,deltay,deltaz |
real coriol (0:nx,0:ny) |
character*80 pvsrcfile |
|
c Numerical and physical parameters |
real eps |
parameter (eps=0.01) |
|
c Auxiliary variables |
integer cdfid,stat |
integer vardim(4) |
real misdat |
integer ndimin |
real varmin(4),varmax(4),stag(4) |
integer i,j,k,nf1 |
integer ntimes |
real time(200) |
character*80 vnam(100),varname |
integer nvars |
integer isok,ierr |
real x(0:nx,0:ny),y(0:nx,0:ny) |
real mean,count |
|
c Get grid description from topography |
call cdfopn(pvsrcfile,cdfid,stat) |
if (stat.ne.0) goto 997 |
call getvars(cdfid,nvars,vnam,stat) |
if (stat.ne.0) goto 997 |
isok=0 |
varname='ORO' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 997 |
time(1)=0. |
call gettimes(cdfid,time,ntimes,stat) |
if (stat.ne.0) goto 997 |
call clscdf(cdfid,stat) |
if (stat.ne.0) goto 997 |
|
c Open output netcdf file |
call cdfopn(pvsrcfile,cdfid,stat) |
if (stat.ne.0) goto 997 |
|
c Create the variable if necessary |
call getvars(cdfid,nvars,vnam,stat) |
if (stat.ne.0) goto 997 |
|
c Read data from netcdf file |
isok=0 |
varname='NSQREF' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,nsqref,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='RHOREF' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,rhoref,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='THETAREF' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,thetaref,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='PREREF' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,pressref,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='ZREF' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,zref,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='CORIOL' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,coriol,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='X' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,x,stat) |
if (stat.ne.0) goto 997 |
|
isok=0 |
varname='Y' |
print*,'R ',trim(varname),' ',trim(pvsrcfile) |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 997 |
call getdat(cdfid,varname,time(1),0,y,stat) |
if (stat.ne.0) goto 997 |
|
c Close netcdf file |
call clscdf(cdfid,stat) |
if (stat.ne.0) goto 997 |
|
c Determine the grid spacings <deltax, deltay, deltaz> |
mean=0. |
count=0. |
do i=1,nx |
do j=0,ny |
mean=mean+abs(x(i,j)-x(i-1,j)) |
count=count+1. |
enddo |
enddo |
deltax=mean/count |
|
mean=0. |
count=0. |
do j=1,ny |
do i=0,nx |
mean=mean+abs(y(i,j)-y(i,j-1)) |
count=count+1. |
enddo |
enddo |
deltay=mean/count |
|
mean=0. |
count=0. |
do k=1,nz-1 |
mean=mean+abs(zref(k+1)-zref(k-1)) |
count=count+1. |
enddo |
deltaz=mean/count |
|
return |
|
c Exception handling |
997 print*,'Read_Ref: Problem with input netcdf file... Stop' |
stop |
|
end |
|
|
c -------------------------------------------------------------------------------- |
c Get grid parameters |
c -------------------------------------------------------------------------------- |
|
subroutine read_dim (nx,ny,nz,dx,dy,dz,xmin,ymin,zmin,mdv, |
> pvsrcfile) |
|
c Get the grid parameters from the variable <THETA> on the input file <pvsrcfile>. |
c The grid parameters are |
c nx,ny,nz : Number of grid points in x, y and z direction |
c xmin,ymin,zmin : Minimum domain coordinates in x, y and z direction |
c xmax,ymax,zmax : Maximal domain coordinates in x, y and z direction |
c dx,dy,dz : Horizontal and vertical resolution |
c Additionally, it is checked whether the vertical grid is equally spaced. If ok, |
c the grid paramters are transformed from lon/lat to distance (in meters) |
|
implicit none |
|
c Declaration of subroutine parameters |
character*80 pvsrcfile |
integer nx,ny,nz |
real dx,dy,dz |
real xmin,ymin,zmin,xmax,ymax,zmax |
real mdv |
|
c Numerical epsilon and other physical/geoemtrical parameters |
real eps |
parameter (eps=0.01) |
|
c Auxiliary variables |
integer cdfid,cstid |
integer ierr |
character*80 vnam(100),varname |
integer nvars |
integer isok |
integer vardim(4) |
real misdat |
real varmin(4),varmax(4),stag(4) |
real aklev(1000),bklev(1000),aklay(1000),bklay(1000) |
real dh |
character*80 csn |
integer ndim |
integer i |
|
c Get all grid parameters |
call cdfopn(pvsrcfile,cdfid,ierr) |
if (ierr.ne.0) goto 998 |
call getvars(cdfid,nvars,vnam,ierr) |
if (ierr.ne.0) goto 998 |
isok=0 |
varname='QGPV' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.eq.0) goto 998 |
call getcfn(cdfid,csn,ierr) |
if (ierr.ne.0) goto 998 |
call cdfopn(csn,cstid,ierr) |
if (ierr.ne.0) goto 998 |
call getdef(cdfid,varname,ndim,misdat,vardim,varmin,varmax, |
> stag,ierr) |
if (ierr.ne.0) goto 998 |
nx=vardim(1) |
ny=vardim(2) |
nz=vardim(3) |
xmin=varmin(1) |
ymin=varmin(2) |
zmin=varmin(3) |
call getlevs(cstid,nz,aklev,bklev,aklay,bklay,ierr) |
if (ierr.ne.0) goto 998 |
call getgrid(cstid,dx,dy,ierr) |
if (ierr.ne.0) goto 998 |
xmax=varmax(1) |
ymax=varmax(2) |
zmax=varmax(3) |
dz=(zmax-zmin)/real(nz-1) |
call clscdf(cstid,ierr) |
if (ierr.ne.0) goto 998 |
call clscdf(cdfid,ierr) |
if (ierr.ne.0) goto 998 |
|
c Check whether the grid is equallay spaced in the vertical |
do i=1,nz-1 |
dh=aklev(i+1)-aklev(i) |
if (abs(dh-dz).gt.eps) then |
print*,'Aklev: Vertical grid must be equally spaced... Stop' |
print*,(aklev(i),i=1,nz) |
stop |
endif |
dh=aklay(i+1)-aklay(i) |
if (abs(dh-dz).gt.eps) then |
print*,'Aklay: Vertical grid must be equally spaced... Stop' |
print*,(aklay(i),i=1,nz) |
stop |
endif |
enddo |
|
c Set missing data value |
mdv=misdat |
|
return |
|
c Exception handling |
998 print*,'Read_Dim: Problem with input netcdf file... Stop' |
stop |
|
end |
|
|
c ------------------------------------------------------------------------------- |
c Read the input netcdf file |
c -------------------------------------------------------------------------------- |
|
SUBROUTINE read_inp (pv,thetabot,thetatop,ua,ub,va,vb, |
> nx,ny,nz,dx,dy,dz,xmin,ymin,zmin, |
> pvsrcfile) |
|
c Read all needed field from netcdf file <pvsrcfile>. The input fields are: |
c pv : quasigeostrophic potential vorticity |
c thetabot,thetatop : potential temperature at lower and upper boundary |
c ua,ub : Zonal wind at western and eastern boundary |
c va,vb : Meridional wind at southern and northern boundary |
c The grid is specified by <nx,ny,nz,dx,dy,dz,xmin,ymin,zmin>. A check is performed |
c whether the input files are consitent with this grid. The input netcdf file must |
c contain the variables <QGPV,THETA,U,V>. If the netcdf file also contains the fields |
c <DQGPV,DTHETA,DU,DV>, these increments are added to <QGPV,THETA,U,V>. |
|
implicit none |
|
c Declaration of subroutine parameters |
integer nx,ny,nz |
real pv(0:nx,0:ny,0:nz) |
real thetatop(0:nx,0:ny) |
real thetabot(0:nx,0:ny) |
real ua(0:nx,0:nz) |
real ub(0:nx,0:nz) |
real va(0:ny,0:nz) |
real vb(0:ny,0:nz) |
character*(30) pvsrcfile |
real dx,dy,dz,xmin,ymin,zmin |
|
c Numerical and physical parameters |
real eps |
parameter (eps=0.01) |
|
c Auxiliary variables |
integer cdfid,stat |
integer vardim(4) |
real misdat |
real varmin(4),varmax(4),stag(4) |
integer ndimin,outid,i,j,k |
real max_th |
real tmp(0:nx,0:ny,0:nz) |
integer ntimes |
real time(200) |
integer nvars |
character*80 vnam(100),varname |
integer isok |
|
c Open the input netcdf file |
call cdfopn(pvsrcfile,cdfid,stat) |
if (stat.ne.0) goto 998 |
|
c Check whether needed variables are on file |
call getvars(cdfid,nvars,vnam,stat) |
if (stat.ne.0) goto 998 |
isok=0 |
varname='TH' |
call check_varok(isok,varname,vnam,nvars) |
varname='U' |
call check_varok(isok,varname,vnam,nvars) |
varname='V' |
call check_varok(isok,varname,vnam,nvars) |
varname='QGPV' |
call check_varok(isok,varname,vnam,nvars) |
if (isok.ne.4) goto 998 |
|
c Get the grid parameters |
varname='QGPV' |
call getdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 998 |
time(1)=0. |
call gettimes(cdfid,time,ntimes,stat) |
if (stat.ne.0) goto 998 |
|
c Check whether grid parameters are consitent |
if ( (vardim(1).ne.nx+1).or. |
> (vardim(2).ne.ny+1).or. |
> (vardim(3).ne.nz+1).or. |
> (abs(varmin(1)-xmin).gt.eps).or. |
> (abs(varmin(2)-ymin).gt.eps).or. |
> (abs(varmin(3)-zmin).gt.eps).or. |
> (abs((varmax(1)-varmin(1))/real(nx)-dx).gt.eps).or. |
> (abs((varmax(2)-varmin(2))/real(ny)-dy).gt.eps).or. |
> (abs((varmax(3)-varmin(3))/real(nz)-dz).gt.eps) ) then |
print*,'Input grid inconsitency...' |
print*,'xmin : ',xmin,varmin(1) |
print*,'ymin : ',ymin,varmin(2) |
print*,'zmin : ',zmin,varmin(3) |
print*,'dx : ',dx,(varmax(1)-varmin(1))/real(nx) |
print*,'dy : ',dy,(varmax(2)-varmin(2))/real(ny) |
print*,'dz : ',dz,(varmax(3)-varmin(3))/real(nz) |
print*,'nx : ',nx |
print*,'ny : ',ny |
print*,'nz : ',nz |
goto 998 |
endif |
|
c THETA: Load upper and lower boundary values |
varname='TH' |
call getdat(cdfid,varname,time(1),0,tmp,stat) |
print*,'R TH ',trim(pvsrcfile) |
if (stat.ne.0) goto 998 |
do i=0,nx |
do j=0,ny |
if ( abs(tmp(i,j,0)-misdat).lt.eps ) then |
thetabot(i,j)=0. |
else |
thetabot(i,j)=tmp(i,j,0) |
endif |
if ( abs(tmp(i,j,nz)-misdat).lt.eps ) then |
thetatop(i,j)=0. |
else |
thetatop(i,j)=tmp(i,j,nz) |
endif |
enddo |
enddo |
|
c U: Load zonal velocity at southern and northern boundary |
varname='U' |
call getdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 998 |
call getdat(cdfid,varname,time(1),0,tmp,stat) |
print*,'R U ',trim(pvsrcfile) |
if (stat.ne.0) goto 998 |
do i=0,nx |
do k=0,nz |
if ( abs(tmp(i,0,k)-misdat).lt.eps ) then |
ua(i,k)=0. |
else |
ua(i,k)=tmp(i,0,k) |
endif |
if ( abs(tmp(i,ny,k)-misdat).lt.eps ) then |
ub(i,k)=0. |
else |
ub(i,k)=tmp(i,ny,k) |
endif |
enddo |
enddo |
|
c Load meridional velocity at western and eastern boundary |
varname='V' |
call getdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 998 |
call getdat(cdfid,varname,time(1),0,tmp,stat) |
print*,'R V ',trim(pvsrcfile) |
if (stat.ne.0) goto 998 |
do j=0,ny |
do k=0,nz |
if ( abs(tmp(0,j,k)-misdat).lt.eps ) then |
va(j,k)=0. |
else |
va(j,k)=tmp(0,j,k) |
endif |
if ( abs(tmp(nx,j,k)-misdat).lt.eps ) then |
vb(j,k)=0. |
else |
vb(j,k)=tmp(nx,j,k) |
endif |
enddo |
enddo |
|
c Load qgPV |
varname='QGPV' |
call getdef(cdfid,varname,ndimin,misdat,vardim, |
> varmin,varmax,stag,stat) |
if (stat.ne.0) goto 998 |
call getdat(cdfid,varname,time(1),0,tmp,stat) |
print*,'R QGPV ',trim(pvsrcfile) |
if (stat.ne.0) goto 998 |
do i=0,nx |
do j=0,ny |
do k=0,nz |
if ( abs(tmp(i,j,k)-misdat).lt.eps ) then |
pv(i,j,k)=0. |
else |
pv(i,j,k)=tmp(i,j,k) |
endif |
enddo |
enddo |
enddo |
|
c Close input netcdf file |
call clscdf(cdfid,stat) |
if (stat.ne.0) goto 998 |
|
return |
|
c Exception handling |
998 print*,'Problem with input netcdf file... Stop' |
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)>. If this is |
C the case, <isok> is incremented by 1. Otherwise <isok> 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 * INVERSION ROUTINES * |
c ******************************************************************************** |
|
c -------------------------------------------------------------------------------- |
c SOR algorithm (successive over relaxation) |
c -------------------------------------------------------------------------------- |
|
SUBROUTINE sor(psi,nsq,thetatop,thetabot,thetaref,rhoref, |
> coriol,pv,ua,ub,va,vb,a,b,c,nx,ny,nz,dx,dy,dz) |
|
c Solve the qgPV equation by succesive over relaxation (SOR). The subroutine |
c parameters are: |
c |
c psi : Streamfunction, i.e. result of the PV inversion |
c nsq,rhoref,thetaref : Reference profile |
c thetatop,thetabot : Upper and lower boundary condition |
c pv : quasigeostrophic potential vorticity (qgPV) |
c ua,ub,va,vb : lateral boundary condition for wind |
c a,b,c : Matrices for the inversion operator |
c nx,ny,nz,dx,dy,dz : Grid specification |
c coriol : Coriolis parameter |
|
implicit none |
|
c Declaration of subroutine parameters |
integer nx,ny,nz |
real dx,dy,dz |
real psi (0:nx,0:ny,0:nz) |
real nsq (0:2*nz) |
real thetatop(0:nx,0:ny) |
real thetabot(0:nx,0:ny) |
real thetaref(0:2*nz) |
real rhoref (0:2*nz) |
real pv (0:nx,0:ny,0:nz) |
real ua (0:nx,0:nz) |
real ub (0:nx,0:nz) |
real va (0:ny,0:nz) |
real vb (0:ny,0:nz) |
real a (0:nx,0:ny,0:nz) |
real b (0:nx,0:ny,0:nz) |
real c (0:nx,0:ny,0:nz) |
real coriol (0:nx,0:ny) |
|
c Numerical and physical parameters |
real maxspec |
parameter (maxspec=2.0) |
integer nofiter |
parameter (nofiter=500) |
real omega |
parameter (omega=1.81) |
|
c Auxiliary variables |
integer counter |
integer i,j,k |
real deltasq,psigauge |
real specx,specy,specz |
real helpx,helpy,helpz |
|
c Init the output array |
do i=0,nx |
do j=0,ny |
do k=0,nz |
psi(i,j,k)=0. |
enddo |
enddo |
enddo |
|
c Calculate the spectrum of the matrix |
i=nx/2 |
specx=4.*a(i,0,0)/ |
> (2.*a(i,0,0)+b(i,0,0)+b(i,1,0)+c(i,0,0)+c(i,0,1)) |
specy=2.*(b(i,0,0)+b(i,1,0))/ |
> (2.*a(i,0,0)+b(i,0,0)+b(i,1,0)+c(i,0,0)+c(i,0,1)) |
specz=2.*(c(i,0,0)+c(i,0,1))/ |
> (2.*a(i,0,0)+b(i,0,0)+b(i,1,0)+c(i,0,0)+c(i,0,1)) |
do k=1,nz-2 |
do j=1,ny-2 |
|
helpx=4.*a(i,j,k)/ |
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k)+c(i,j,k-1)) |
if (helpx.gt.specx) specx=helpx |
|
helpy=2.*(b(i,j,k)+b(i,j+1,k))/ |
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k)+c(i,j,k-1)) |
if (helpy.gt.specy) specy=helpy |
|
helpz=2.*(c(i,j,k)+c(i,j,k+1))/ |
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k)+c(i,j,k-1)) |
if (helpz.gt.specz) specz=helpz |
|
enddo |
enddo |
|
c Check whether the dimensions of the grid are sufficient |
print * |
print *, 'Spectrum of the matrix in each direction ' |
print *, 'Spectrum = ', specx, specy, specz |
print * |
if ((maxspec*specx.lt.specy).or.(maxspec*specx.lt.specz)) then |
print*,' Nx too small... Stop' |
stop |
endif |
if ((maxspec*specy.lt.specx).or.(maxspec*specy.lt.specz)) then |
print*,'Ny too small... Stop' |
stop |
endif |
if ((maxspec*specz.lt.specx).or.(maxspec*specz.lt.specy)) then |
print*,'Nz too small... Stop' |
stop |
endif |
|
c Calculate error: control variable for the iteration |
psigauge=0. |
deltasq=0. |
do k=1,nz-1 |
do i=1,nx-1 |
do j=1,ny-1 |
deltasq=deltasq+(-pv(i,j,k)+( |
> a(i,j,k)*(psi(i+1,j,k)+psi(i-1,j,k)- |
> 2.*psi(i,j,k)) + |
> b(i,j,k)*(psi(i,j+1,k)-psi(i,j,k))- |
> b(i,j-1,k)*(psi(i,j,k)-psi(i,j-1,k))+ |
> c(i,j,k)*(psi(i,j,k+1)-psi(i,j,k))- |
> c(i,j,k-1)*(psi(i,j,k)-psi(i,j,k-1)) |
> )/(dx*dy*dz*rhoref(2*k)))**2. |
|
enddo |
enddo |
enddo |
print 102, 'psigauge', psigauge, 'deltasq', |
> deltasq/(real(nx)*real(ny)*real(nz)) |
|
c Iterations |
do counter=1,nofiter |
|
C Perform one iteration step |
call psiappsor(omega,pv,psi,nsq,rhoref,thetatop, |
> thetabot,thetaref,coriol,ua,ub,va,vb, |
> a,b,c,nx,ny,nz,dx,dy,dz) |
|
|
c Adjustment |
if (mod(counter,100).eq.0) then |
psigauge=0. |
do i=0,nx |
do j=0,ny |
if (psi(i,j,0).lt.psigauge) then |
psigauge=psi(i,j,0) |
endif |
enddo |
enddo |
do k=0,nz |
do i=0,nx |
do j=0,ny |
psi(i,j,k)=psi(i,j,k)-psigauge |
enddo |
enddo |
enddo |
endif |
|
c Calculate error: control variable for the iteration |
if (mod(counter,nofiter/10).eq.0) then |
deltasq=0. |
do k=1,nz-1 |
do i=1,nx-1 |
do j=1,ny-1 |
deltasq=deltasq+(-pv(i,j,k)+( |
> a(i,j,k)*(psi(i+1,j,k)+psi(i-1,j,k)- |
> 2.*psi(i,j,k)) + |
> b(i,j,k)*(psi(i,j+1,k)-psi(i,j,k))- |
> b(i,j-1,k)*(psi(i,j,k)-psi(i,j-1,k))+ |
> c(i,j,k)*(psi(i,j,k+1)-psi(i,j,k))- |
> c(i,j,k-1)*(psi(i,j,k)-psi(i,j,k-1)) |
> )/(dx*dy*dz*rhoref(2*k)))**2. |
enddo |
enddo |
enddo |
print 102, 'psigauge', psigauge, 'deltasq', |
> deltasq/(real(nx)*real(ny)*real(nz)) |
endif |
|
enddo |
|
return |
|
c Format specifications |
102 format (a11, ' = ',e10.3,a11, ' = ',e10.3) |
|
end |
|
c -------------------------------------------------------------------------------- |
c SOR algorithm (successive over relaxation) |
c -------------------------------------------------------------------------------- |
|
subroutine psiappsor(omega,pv,psi,nsq,rhoref,thetatop, |
> thetabot,thetaref,coriol,ua,ub,va,vb, |
> a,b,c,nx,ny,nz,dx,dy,dz) |
|
c Perform one relaxation step |
c |
c psi : Streamfunction, i.e. result of the PV inversion |
c nsq,rhoref,thetaref : Reference profile |
c thetatop,thetabot : Upper and lower boundary condition |
c pv : quasigeostrophic potential vorticity (qgPV) |
c ua,ub,va,vb : lateral boundary condition for wind |
c a,b,c : Matrices for the inversion operator |
c nx,ny,nz,dx,dy,dz : Grid specification |
c nofiter : Number of iterations |
c omega : Relaxation parameter |
c coriol : Coriolis parameter |
|
implicit none |
|
c Declaration of subroutine parameters |
integer nx,ny,nz |
real pv(0:nx,0:ny,0:nz) |
real psi(0:nx,0:ny,0:nz) |
real nsq(0:2*nz) |
real rhoref(0:2*nz) |
real thetatop(0:nx,0:ny) |
real thetabot(0:nx,0:ny) |
real thetaref(0:2*nz) |
real ua(0:nx,0:nz) |
real ub(0:nx,0:nz) |
real va(0:ny,0:nz) |
real vb(0:ny,0:nz) |
real a(0:nx,0:ny,0:nz) |
real b(0:nx,0:ny,0:nz) |
real c(0:nx,0:ny,0:nz) |
real coriol(0:nx,0:ny) |
real dx,dy,dz |
real omega |
|
c Numerical and physical parameters |
real g |
parameter (g=9.81) |
|
c Auxiliary variables |
integer i,j,k |
real dxy,dxz,dyz,dxyz |
|
c Set the area and volume infinitesimals for integration |
dxy=dx*dy |
dxz=dx*dz |
dyz=dy*dz |
dxyz=dx*dy*dz |
|
c Inner |
do k=1,nz-1 |
do i=1,nx-1 |
do j=1,ny-1 |
psi(i,j,k)=omega*(-dxyz* |
> rhoref(2*k)*pv(i,j,k)+a(i,j,k)* |
> (psi(i+1,j,k)+psi(i-1,j,k))+b(i,j,k)* |
> psi(i,j+1,k)+b(i,j-1,k)*psi(i,j-1,k)+c(i,j,k)* |
> psi(i,j,k+1)+c(i,j,k-1)*psi(i,j,k-1))/ |
> (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k-1)+ |
> c(i,j,k))+(1.-omega)*psi(i,j,k) |
enddo |
enddo |
enddo |
|
c ZY plane |
do k=1,nz-1 |
do j=1,ny-1 |
psi(0,j,k)=omega*(-dyz* |
> rhoref(2*k)*(dx*pv(0,j,k)+va(j,k))+ |
> a(0,j,k)*psi(1,j,k)+ |
> b(0,j,k)*psi(0,j+1,k)+b(0,j-1,k)*psi(0,j-1,k)+ |
> c(0,j,k)*psi(0,j,k+1)+c(0,j,k-1)*psi(0,j,k-1))/ |
> (a(0,j,k)+b(0,j,k)+b(0,j-1,k)+c(0,j,k-1)+c(0,j,k)) |
> +(1.-omega)*psi(0,j,k) |
c |
psi(nx,j,k)=omega*(-dyz* |
> rhoref(2*k)*(dx*pv(nx,j,k)-vb(j,k))+ |
> a(nx,j,k)*psi(nx-1,j,k)+ |
> b(nx,j,k)*psi(nx,j+1,k)+b(nx,j-1,k)*psi(nx,j-1,k)+ |
> c(nx,j,k)*psi(nx,j,k+1)+c(nx,j,k-1)*psi(nx,j,k-1))/ |
> (a(nx,j,k)+b(nx,j-1,k)+b(nx,j,k)+c(nx,j,k-1)+c(nx,j,k)) |
> +(1.-omega)*psi(nx,j,k) |
enddo |
enddo |
|
c ZX plane |
do k=1,nz-1 |
do i=1,nx-1 |
psi(i,0,k)=omega*(-dxz* |
> rhoref(2*k)*(dy*pv(i,0,k)-ua(i,k))+ |
> a(i,0,k)*(psi(i+1,0,k)+psi(i-1,0,k))+ |
> b(i,0,k)*psi(i,1,k)+ |
> c(i,0,k)*psi(i,0,k+1)+c(i,0,k-1)*psi(i,0,k-1))/ |
> (2.*a(i,0,k)+b(i,0,k)+c(i,0,k-1)+c(i,0,k)) |
> +(1.-omega)*psi(i,0,k) |
c |
psi(i,ny,k)=omega*(-dxz* |
> rhoref(2*k)*(dy*pv(i,ny,k)+ub(i,k))+ |
> a(i,ny-1,k)*(psi(i+1,ny,k)+psi(i-1,ny,k))+ |
> b(i,ny-1,k)*psi(i,ny-1,k)+ |
> c(i,ny-1,k)*psi(i,ny,k+1)+c(i,ny-1,k-1)* |
> psi(i,ny,k-1))/(2.*a(i,ny-1,k)+b(i,ny-1,k)+ |
> c(i,ny-1,k-1)+c(i,ny-1,k)) |
> +(1.-omega)*psi(i,ny,k) |
enddo |
enddo |
|
c XY plane |
do i=1,nx-1 |
do j=1,ny-1 |
psi(i,j,0)=omega*(-dxy*rhoref(0)*( |
> dz*pv(i,j,0)+g*coriol(i,j)*thetabot(i,j)/ |
> (nsq(0)*thetaref(0)))+ |
> a(i,j,0)*(psi(i+1,j,0)+psi(i-1,j,0))+ |
> b(i,j,0)*psi(i,j+1,0)+b(i,j-1,0)*psi(i,j-1,0)+ |
> c(i,j,0)*psi(i,j,1))/ |
> (2.*a(i,j,0)+b(i,j-1,0)+b(i,j,0)+c(i,j,0)) |
> +(1.-omega)*psi(i,j,0) |
c |
psi(i,j,nz)=omega*(-dxy*rhoref(2*nz)*( |
> dz*pv(i,j,nz)-g*coriol(i,j)*thetatop(i,j)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(i,j,nz)*(psi(i+1,j,nz)+psi(i-1,j,nz))+ |
> b(i,j,nz)*psi(i,j+1,nz)+b(i,j-1,nz)*psi(i,j-1,nz)+ |
> c(i,j,nz-1)*psi(i,j,nz-1))/ |
> (2.*a(i,j,nz)+b(i,j-1,nz)+b(i,j,nz)+c(i,j,nz-1)) |
> +(1.-omega)*psi(i,j,nz) |
enddo |
enddo |
|
c Y edges |
do j=1,ny-1 |
psi(0,j,0)=omega*(-dy*rhoref(0)*(dxz*pv(0,j,0)+ |
> dz*va(j,0)+dx*g*coriol(0,j)*thetabot(0,j)/ |
> (nsq(0)*thetaref(0)))+ |
> a(0,j,0)*psi(1,j,0)+ |
> b(0,j,0)*psi(0,j+1,0)+b(0,j-1,0)*psi(0,j-1,0)+ |
> c(0,j,0)*psi(0,j,1))/ |
> (a(0,j,0)+b(0,j-1,0)+b(0,j,0)+c(0,j,0)) |
> +(1.-omega)*psi(0,j,0) |
c |
psi(nx,j,0)=omega*(-dy*rhoref(0)*(dxz*pv(nx,j,0)- |
> dz*vb(j,0)+dx*g*coriol(nx,j)*thetabot(nx,j)/ |
> (nsq(0)*thetaref(0)))+ |
> a(nx,j,0)*psi(nx-1,j,0)+ |
> b(nx,j,0)*psi(nx,j+1,0)+b(nx,j-1,0)*psi(nx,j-1,0)+ |
> c(nx,j,0)*psi(nx,j,1))/ |
> (a(nx,j,0)+b(nx,j-1,0)+b(nx,j,0)+c(nx,j,0)) |
> +(1.-omega)*psi(nx,j,0) |
c |
psi(0,j,nz)=omega*(-dy*rhoref(2*nz)*(dxz*pv(0,j,nz)+ |
> dz*va(j,nz)-dx*g*coriol(0,j)*thetatop(0,j)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(0,j,nz)*psi(1,j,nz)+ |
> b(0,j,nz)*psi(0,j+1,nz)+b(0,j-1,nz)*psi(0,j-1,nz)+ |
> c(0,j,nz-1)*psi(0,j,nz-1))/ |
> (a(0,j,nz)+b(0,j-1,nz)+b(0,j,nz)+c(0,j,nz-1)) |
> +(1.-omega)*psi(0,j,nz) |
c |
psi(nx,j,nz)=omega*(-dy*rhoref(2*nz)*(dxz*pv(nx,j,nz)- |
> dz*vb(j,nz)-dx*g*coriol(nx,j)*thetatop(nx,j)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(nx,j,nz)*psi(nx-1,j,nz)+ |
> b(nx,j,nz)*psi(nx,j+1,nz)+b(nx,j-1,nz)*psi(nx,j-1,nz)+ |
> c(nx,j,nz-1)*psi(nx,j,nz-1))/ |
> (a(nx,j,nz)+b(nx,j-1,nz)+b(nx,j,nz)+c(nx,j,nz-1)) |
> +(1.-omega)*psi(nx,j,nz) |
enddo |
|
c X edges |
do i=1,nx-1 |
psi(i,0,0)=omega*(-dx*rhoref(0)*(dyz*pv(i,0,0)- |
> dz*ua(i,0)+dy*g*coriol(i,0)*thetabot(i,0)/ |
> (nsq(0)*thetaref(0)))+ |
> a(i,0,0)*(psi(i+1,0,0)+psi(i-1,0,0))+ |
> b(i,0,0)*psi(i,1,0)+ |
> c(i,0,0)*psi(i,0,1))/ |
> (2.*a(i,0,0)+b(i,0,0)+c(i,0,0)) |
> +(1.-omega)*psi(i,0,0) |
c |
psi(i,ny,0)=omega*(-dx*rhoref(0)*(dyz*pv(i,ny,0)+ |
> dz*ub(i,0)+dy*g*coriol(i,ny)*thetabot(i,ny)/ |
> (nsq(0)*thetaref(0)))+ |
> a(i,ny,0)*(psi(i+1,ny,0)+psi(i-1,ny,0))+ |
> b(i,ny-1,0)*psi(i,ny-1,0)+ |
> c(i,ny,0)*psi(i,ny,1))/ |
> (2.*a(i,ny,0)+b(i,ny-1,0)+c(i,ny,0)) |
> +(1.-omega)*psi(i,ny,0) |
c |
psi(i,0,nz)=omega*(-dx*rhoref(2*nz)*(dyz*pv(i,0,nz)- |
> dz*ua(i,nz)-dy*g*coriol(i,0)*thetatop(i,0)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(i,0,nz)*(psi(i+1,0,nz)+psi(i-1,0,nz))+ |
> b(i,0,nz)*psi(i,1,nz)+ |
> c(i,0,nz-1)*psi(i,0,nz-1))/ |
> (2.*a(i,0,nz)+b(i,0,nz)+c(i,0,nz-1)) |
> +(1.-omega)*psi(i,0,nz) |
c |
psi(i,ny,nz)=omega*(-dx*rhoref(2*nz)*(dyz*pv(i,ny,nz)+ |
> dz*ub(i,nz)-dy*g*coriol(i,ny)*thetatop(i,ny)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(i,ny,nz)*(psi(i+1,ny,nz)+psi(i-1,ny,nz))+ |
> b(i,ny-1,nz)*psi(i,ny-1,nz)+ |
> c(i,ny,nz-1)*psi(i,ny,nz-1))/ |
> (2.*a(i,ny,nz)+b(i,ny-1,nz)+c(i,ny,nz-1)) |
> +(1.-omega)*psi(i,ny,nz) |
enddo |
|
c Z edges |
do k=1,nz-1 |
psi(0,0,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(0,0,k)+ |
> dy*va(0,k)-dx*ua(0,k))+ |
> a(0,0,k)*psi(1,0,k)+ |
> b(0,0,k)*psi(0,1,k)+ |
> c(0,0,k)*psi(0,0,k+1)+c(0,0,k-1)*psi(0,0,k-1))/ |
> (a(0,0,k)+b(0,0,k)+c(0,0,k-1)+c(0,0,k)) |
> +(1.-omega)*psi(0,0,k) |
c |
psi(nx,0,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(nx,0,k)- |
> dy*vb(0,k)-dx*ua(nx,k))+ |
> a(nx,0,k)*psi(nx-1,0,k)+ |
> b(nx,0,k)*psi(nx,1,k)+ |
> c(nx,0,k)*psi(nx,0,k+1)+c(nx,0,k-1)*psi(nx,0,k-1))/ |
> (a(nx,0,k)+b(nx,0,k)+c(nx,0,k-1)+c(nx,0,k)) |
> +(1.-omega)*psi(nx,0,k) |
c |
psi(0,ny,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(0,ny,k)+ |
> dy*va(ny,k)+dx*ub(0,k))+ |
> a(0,ny,k)*psi(1,ny,k)+ |
> b(0,ny-1,k)*psi(0,ny-1,k)+ |
> c(0,ny,k)*psi(0,ny,k+1)+c(0,ny,k-1)*psi(0,ny,k-1))/ |
> (a(0,ny,k)+b(0,ny-1,k)+c(0,ny,k-1)+c(0,ny,k)) |
> +(1.-omega)*psi(0,ny,k) |
c |
psi(nx,ny,k)=omega*(-dz*rhoref(2*k)*(dxy*pv(nx,ny,k)- |
> dy*vb(ny,k)+dx*ub(nx,k))+ |
> a(nx,ny,k)*psi(nx-1,ny,k)+ |
> b(nx,ny-1,k)*psi(nx,ny-1,k)+ |
> c(nx,ny,k)*psi(nx,ny,k+1)+c(nx,ny,k-1)*psi(nx,ny,k-1))/ |
> (a(nx,ny,k)+b(nx,ny-1,k)+c(nx,ny,k-1)+c(nx,ny,k)) |
> +(1.-omega)*psi(nx,ny,k) |
enddo |
|
c Points |
psi(0,0,0)=omega*(-rhoref(0)*(dxyz*pv(0,0,0)+dyz*va(0,0)- |
> dxz*ua(0,0)+dxy*g*coriol(0,0)*thetabot(0,0)/ |
> (nsq(0)*thetaref(0)))+ |
> a(0,0,0)*psi(1,0,0)+ |
> b(0,0,0)*psi(0,1,0)+ |
> c(0,0,0)*psi(0,0,1))/ |
> (a(0,0,0)+b(0,0,0)+c(0,0,0))+ |
> (1.-omega)*psi(0,0,0) |
c |
psi(nx,0,0)=omega*(-rhoref(0)*(dxyz*pv(nx,0,0)-dyz*vb(0,0)- |
> dxz*ua(nx,0)+dxy*g*coriol(nx,0)*thetabot(nx,0)/ |
> (nsq(0)*thetaref(0)))+ |
> a(nx,0,0)*psi(nx-1,0,0)+ |
> b(nx,0,0)*psi(nx,1,0)+ |
> c(nx,0,0)*psi(nx,0,1))/ |
> (a(nx,0,0)+b(nx,0,0)+c(nx,0,0))+ |
> (1.-omega)*psi(nx,0,0) |
c |
psi(0,ny,0)=omega*(-rhoref(0)*(dxyz*pv(0,ny,0)+dyz*va(ny,0)+ |
> dxz*ub(0,0)+dxy*g*coriol(0,ny)*thetabot(0,ny)/ |
> (nsq(0)*thetaref(0)))+ |
> a(0,ny,0)*psi(1,ny,0)+ |
> b(0,ny-1,0)*psi(0,ny-1,0)+ |
> c(0,ny,0)*psi(0,ny,1))/ |
> (a(0,ny,0)+b(0,ny-1,0)+c(0,ny,0))+ |
> (1.-omega)*psi(0,ny,0) |
c |
psi(nx,ny,0)=omega*(-rhoref(0)*(dxyz*pv(nx,ny,0)-dyz*vb(ny,0)+ |
> dxz*ub(nx,0)+dxy*g*coriol(nx,ny)*thetabot(nx,ny)/ |
> (nsq(0)*thetaref(0)))+ |
> a(nx,ny,0)*psi(nx-1,ny,0)+ |
> b(nx,ny-1,0)*psi(nx,ny-1,0)+ |
> c(nx,ny,0)*psi(nx,ny,1))/ |
> (a(nx,ny,0)+b(nx,ny-1,0)+c(nx,ny,0))+ |
> (1.-omega)*psi(nx,ny,0) |
c |
psi(0,0,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(0,0,nz)+dyz*va(0,nz)- |
> dxz*ua(0,nz)-dxy*g*coriol(0,0)*thetatop(0,0)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(0,0,nz)*psi(1,0,nz)+ |
> b(0,0,nz)*psi(0,1,nz)+ |
> c(0,0,nz-1)*psi(0,0,nz-1))/ |
> (a(0,0,nz)+b(0,0,nz)+c(0,0,nz-1))+ |
> (1.-omega)*psi(0,0,nz) |
c |
psi(nx,0,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(nx,0,nz)-dyz*vb(0,nz) |
> -dxz*ua(nx,nz)-dxy*g*coriol(nx,0)*thetatop(nx,0)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(nx,0,nz)*psi(nx-1,0,nz)+ |
> b(nx,0,nz)*psi(nx,1,nz)+ |
> c(nx,0,nz-1)*psi(nx,0,nz-1))/ |
> (a(nx,0,nz)+b(nx,0,nz)+c(nx,0,nz-1))+ |
> (1.-omega)*psi(nx,0,nz) |
c |
psi(0,ny,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(0,ny,nz)+ |
> dyz*va(ny,nz)+dxz*ub(0,nz)- |
> dxy*g*coriol(0,ny)*thetatop(0,ny)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(0,ny,nz)*psi(1,ny,nz)+ |
> b(0,ny-1,nz)*psi(0,ny-1,nz)+ |
> c(0,ny,nz-1)*psi(0,ny,nz-1))/ |
> (a(0,ny,nz)+b(0,ny-1,nz)+c(0,ny,nz-1))+ |
> (1.-omega)*psi(0,ny,nz) |
c |
psi(nx,ny,nz)=omega*(-rhoref(2*nz)*(dxyz*pv(nx,ny,nz)- |
> dyz*vb(ny,nz)+dxz*ub(nx,nz)- |
> dxy*g*coriol(nx,ny)*thetatop(nx,ny)/ |
> (nsq(2*nz)*thetaref(2*nz)))+ |
> a(nx,ny,nz)*psi(nx-1,ny,nz)+ |
> b(nx,ny-1,nz)*psi(nx,ny-1,nz)+ |
> c(nx,ny,nz-1)*psi(nx,ny,nz-1))/ |
> (a(nx,ny,nz)+b(nx,ny-1,nz)+c(nx,ny,nz-1))+ |
> (1.-omega)*psi(nx,ny,nz) |
c |
|
end |
|
c -------------------------------------------------------------------------------- |
c Init matrix elements for the inversion |
c -------------------------------------------------------------------------------- |
|
subroutine matrixel(a,b,c,coriol,nx,ny,nz,nsq,rhoref,dx,dy,dz) |
|
c Define the coefficients for the inversion problem (see page 119ff in Rene's |
c dissertation). |
|
implicit none |
|
c Declaration of subroutine parameters |
integer nx,nz,ny |
real a (0:nx,0:ny,0:nz) |
real b (0:nx,0:ny,0:nz) |
real c (0:nx,0:ny,0:nz) |
real coriol(0:nx,0:ny) |
real nsq (0:2*nz) |
real rhoref(0:2*nz) |
real dx,dy,dz |
|
c Auxiliary variables |
integer i,j,k |
|
c Calculate coefficients |
do i=0,nx |
do j=0,ny |
do k=0,nz |
a(i,j,k)=dy*dz*rhoref(2*k)/(dx*coriol(i,j)) |
if (j.lt.ny) then |
b(i,j,k)=dx*dz*rhoref(2*k)/ |
> (dy*0.5*(coriol(i,j)+coriol(i,j+1))) |
else |
b(i,j,k)=0. |
endif |
if (k.lt.nz) then |
c(i,j,k)=dx*dy*rhoref(2*k+1)*coriol(i,j)/ |
> (dz*nsq(2*k+1)) |
else |
c(i,j,k)=0. |
endif |
enddo |
enddo |
enddo |
|
end |
|
|
|
|
Property changes: |
Added: svn:executable |