PROGRAM uebung
!*********************************************************************
!
! Description:
! Numerics exercise extracted from V. Wirth "Das Eliassen-Problem:
! Reaktion einer balancierten Stroemung auf eine schwache externe
! Stoerung. Ein numerischer Praktikumsversuch", Universitaet Mainz
!
! Full exercise:
! www.staff.uni-mainz.de/vwirth/ps/projekt_eliassen.ps
!
! There are several publications that are based on the original code (and I think that
! Prof. Wirth would be glad to provide it in case you are interested in using
! it in your future research):
!
! Wirth, V. Thermal versus dynamical tropopause in upper tropospheric
! balanced flow anomalies Quart. J.~Roy. Met. Soc., 2000, 126, 299-317
!
! Wirth, V. Cyclone-Anticyclone Asymmetry Concerning the Height of the Thermal
! and the Dynamical Tropopause J.~Atmos. Sci., 2001, 58, 26-37
!
! Wirth, V. A Dynamical Mechanism for Tropopause Sharpening,
! Meteorol. Zeitschrift, N.F. , 2004, 13, 477-484
!
! Method: define idealized jet as base state
! calculate ageostophic mass stream function due to weak Rayleigh damping
!
! Output Files:
! ../run/out.nc
!
! History:
! Student version
!
!**********************************************************************
! mo_output provides a simplified interface for writing netCDF data
! see supplement.pdf for details
USE mo_output, ONLY: open_out_file, &
init_out, &
write_out, &
close_out_file
! subroutine to initialize the zonal wind field
USE mo_jet, ONLY : init_jet
IMPLICIT NONE
! 1. variable declaration (parameters) -----------------------------------
! number of grid-points in y-direction
INTEGER, PARAMETER :: jmax = 80
! number of grid-points in z-direction
INTEGER, PARAMETER :: kmax = 80
! horizontal domain length in km
DOUBLE PRECISION, PARAMETER :: lykm = 1000.D0
! vertical domain length in km
DOUBLE PRECISION, PARAMETER :: lzkm = 10.D0
! relaxation time in days
DOUBLE PRECISION, PARAMETER :: tau = 5.D0
! Coriolis parameter
DOUBLE PRECISION, PARAMETER :: fcori = 1.D-4
! Bouyancy frequency
DOUBLE PRECISION, PARAMETER :: Nbouy = 1.D-2
! density
DOUBLE PRECISION, PARAMETER :: rho0=1.0D0
! 2. other variables -----------------------------------
DOUBLE PRECISION, POINTER :: deltay, deltaz ! grid spacings in y- and z-direction
! (pointer attribute needed for netCDF interface)
! stream function
DOUBLE PRECISION, POINTER, DIMENSION(:,:) :: phi
! zonal wind
DOUBLE PRECISION, POINTER, DIMENSION(:,:) :: uwnd
! damping term
DOUBLE PRECISION, POINTER, DIMENSION(:,:) :: xdamp
! partial derivative w.r.t z of x
DOUBLE PRECISION, POINTER, DIMENSION(:,:) :: dxodz
! right hand side of Poisson Eq.
DOUBLE PRECISION, POINTER, DIMENSION(:,:) :: rhs
! coefficients in Poisson Eq.
DOUBLE PRECISION :: acoeff, bcoeff
! grid spacings in m
DOUBLE PRECISION :: ly, lz
! netcdf output unit
INTEGER :: ncid
! for choice of iteration style
CHARACTER (len=1) :: choice
!-end variable declaration --------------------------------
! write to screen:
WRITE(6,*) 'This is uebung.exe'
ALLOCATE(deltay)
ALLOCATE(deltaz)
ALLOCATE(phi(jmax,kmax))
ALLOCATE(uwnd(jmax,kmax))
ALLOCATE(xdamp(jmax,kmax))
ALLOCATE(dxodz(jmax,kmax))
ALLOCATE(rhs(jmax,kmax))
! convert to km
ly=1.d3*lykm
lz=1.d3*lzkm
! grid spacings (m)
deltay = ly/DBLE((jmax-1))
deltaz = lz/DBLE((kmax-1))
! coefficients in Poisson eq.
acoeff = Nbouy**2 / rho0
bcoeff = fcori**2 / rho0
! initialize phi
phi=0.D0
! initalize the zonal wind field
CALL init_jet(uwnd, jmax, kmax, deltay, deltaz)
! the Rayleigh damping term
xdamp=-uwnd/(tau*86400.D0)
! calculate dxodz (partial derivative of X w.r.t. z)
CALL zderiv(xdamp, dxodz, deltaz, jmax,kmax)
! right hand side of the Poisson equation
rhs=fcori*dxodz
!===================================================================================!
! choosing iterative solver
print*, '========================================================================='
print*, 'To continue, choose and type either:'
print*, '"c" for Jacobi, or "d" for Gauss-Seidel"'
READ(5,*) choice
IF (choice .EQ. 'c') THEN
CALL solve_with_Jacobi(phi, rhs, deltay, deltaz, acoeff, bcoeff, jmax, kmax)
END IF
IF (choice .EQ. 'd') THEN
CALL solve_with_Gauss_Seidel(phi, rhs, deltay, deltaz, acoeff, bcoeff, jmax, kmax)
END IF
!===================================================================================!
! write netCDF output
CALL open_out_file(ncid, "out.nc")
CALL init_out(ncid, uwnd, "uwnd", "m/s","y","z")
CALL init_out(ncid, phi, "phi", "kg -1 m-1)","y","z")
CALL init_out(ncid, deltay, "dy","m")
CALL init_out(ncid, deltaz, "dz","m")
CALL init_out(ncid, dxodz, "dxodz", "s-3","y","z")
CALL write_out(ncid)
CALL close_out_file(ncid)
! deallocate memory
DEALLOCATE(phi, uwnd, xdamp, dxodz, rhs)
WRITE(6,*) 'uebung.exe: DONE.'
END PROGRAM uebung
SUBROUTINE zderiv( f, der, deltaz, jmax, kmax)
IMPLICIT NONE
DOUBLE PRECISION, INTENT(IN ) :: deltaz
INTEGER, INTENT(IN ) :: jmax, kmax
DOUBLE PRECISION, DIMENSION( jmax , kmax ) :: f, der
INTEGER :: j,k
DO j = 1,jmax
DO k = 2, kmax-1
der(j,k) = (f(j,k+1) - f(j,k-1))/(2.D0*deltaz)
END DO
der(j,1) = (f(j,2) - 0.D0)/(2.D0*deltaz)
der(j,kmax) = (0.D0 - f(j,kmax-1))/(2.D0*deltaz)
END DO
END SUBROUTINE zderiv
!================================MY CODE===============================================!
SUBROUTINE solve_with_Jacobi(ufct, rhs, deltax, deltay, acoeff, bcoeff, jmax, kmax )
IMPLICIT NONE
INTEGER, INTENT(IN ) :: jmax, kmax
DOUBLE PRECISION, INTENT(IN ) :: deltax, deltay, acoeff, bcoeff
DOUBLE PRECISION, DIMENSION( jmax, kmax ) :: ufct, rhs, pfct
INTEGER :: j, k, m, n
DOUBLE PRECISION, PARAMETER :: c=0.5d0
DO WHILE (1336 .lt. 1337)
pfct=ufct
DO k=2, kmax-1
ufct(1,k)=(acoeff/(deltax**2.d0)*0.D0+pfct(2,k))+&
bcoeff/(deltay**2.d0)*(pfct(1,k-1)+pfct(1,k+1))-&
rhs(1,k))/&
(2.d0*(acoeff/deltax**2+bcoeff/deltay**2))
END DO
ufct(
DO j=2,jmax-1
DO k=2, kmax-1
ufct(j,k)=(acoeff/(deltax**2.d0)*(pfct(j-1,k)+pfct(j+1,k))+&
bcoeff/(deltay**2.d0)*(pfct(j,k-1)+pfct(j,k+1))-&
rhs(j,k))/&
(2.d0*(acoeff/deltax**2+bcoeff/deltay**2))
END DO
END DO
n=n+1
IF (c .GT. MAXVAL(ufct-pfct)) EXIT
END DO
print*,'Anzahl der Durchlaeufe mit Jacobi:', n
print*, '========================================================================='
END SUBROUTINE solve_with_Jacobi
SUBROUTINE solve_with_Gauss_Seidel(ufct, rhs, deltax, deltay, acoeff, bcoeff, jmax, kmax )
IMPLICIT NONE
INTEGER, INTENT(IN ) :: jmax, kmax
DOUBLE PRECISION, INTENT(IN ) :: deltax, deltay, acoeff, bcoeff
DOUBLE PRECISION, DIMENSION( jmax, kmax ) :: ufct, rhs, pfct
INTEGER :: j, k, m, n
DOUBLE PRECISION, PARAMETER :: c=1.d-10
DO WHILE (1336 .lt. 1337)
pfct=ufct
ufct(1,1)=(acoeff/(deltax**2.d0)*(pfct(1-1,1)+pfct(1+1,1))+&
bcoeff/(deltay**2.d0)*(pfct(1,1-1)+pfct(1,1+1))-&
rhs(1,1))/&
(2.d0*(acoeff/deltax**2+bcoeff/deltay**2))
DO j=2,jmax
DO k=2, kmax
ufct(j,k)=(acoeff/(deltax**2.d0)*(ufct(j-1,k)+pfct(j+1,k))+&
bcoeff/(deltay**2.d0)*(ufct(j,k-1)+pfct(j,k+1))-&
rhs(j,k))/&
(2.d0*(acoeff/deltax**2+bcoeff/deltay**2))
END DO
END DO
n=n+1
IF (c .GT. MAXVAL(ufct-pfct)) EXIT
END DO
print*,'Anzahl der Durchlaeufe mit Gauss-Seidel:', n
print*, '========================================================================='
END SUBROUTINE solve_with_Gauss_Seidel