Blame | Last modification | View Log | Download | RSS feed
PROGRAM clustering
! *********************************************************************************
! * Interpolate fields to tropopause and assign labels with clustering algorithm *
! * Michael Sprenger / Spring 2006: initial version *
! * Michael Sprenger / 2012: horizontal propagation of LABEL 2 prohibited in *
! * lower troposphere *
! * Bojan Skerlak / Spring 2012 / Fall 2012: advanced LABEL 1-5 handling *
! * Jan 2013: - change horiz. prop. decision method to height(log(pressure)) *
! * - perform check of label for exotic cases where the pressure *
! * is higher than 800 hPa (deep folds) *
! * - additional cutoff-special-treatment prohibits identification *
! * of strat. air as cutoffs if below horizontal prop. limit *
! * (e.g. deep 'funnels' with 'bumps' on the side) *
! * - additional check in strat. (TH>380) for 'wrong' sign of PV *
! * that can lead to errors in calculating TROPO *
! * - additional check for PV towers (whole column gets label 2) *
! * July 2013: - replace fixed tropo_pv,tropo_th by user-defined values *
! * Jan 2014: - v2.0 Add specific humidity criterion for diabatic PV *
! * Feb 2014: - v2.1 Correct 'filling' when labels 2/3 or 2/5 meet *
! * Mar 2014: - v2.2 Filling of 2/3 and 2/5 also propagates downward via *
! * 'connect' subroutine. Thus, now also dird/diru have to be *
! * specified. *
! * - v2.3 Identify and write out tropopause folds (FOLD) 1/0 *
! * Nov 2014: - remove some commented sections and delete temporary stuff *
! * Dec 2014: - simply the code to only contain the core algorithm and no *
! * input/output section (which depends on data format and *
! * model setup) *
! * Andrea Pozzer (MPIC):
! * Dec 2014: - Implementation for netcdf I/O, Makefile and namelist reading *
! *********************************************************************************
!????????????????????????????????????????????????????????????????????????????????
!????????????????????????????????????????????????????????????????????????????????
!????????????????????????????????????????????????????????????????????????????????
!??????????????? ??????????????????????????
!??????????????? 1) 3D-LABELLING ??????????????????????????
!??????????????? 2) TROPOPAUSE FOLD IDENTIFICATION ??????????????????????????
!??????????????? ??????????????????????????
!????????????????????????????????????????????????????????????????????????????????
!????????????????????????????????????????????????????????????????????????????????
!MMM?????????????????????????????????????????????????????????????????????????????
!.....DMMI???????????????????????????????????????????MMMMMMMMMMM?I???????????????
!.........IMO????????????????????????????????????IMM ........... 8MM8???????????
!............MM?????????????????????????????????M$ ..............MMMI??????
!............. MD?????????????????????????????IM. PMIN .................OMMI??
!................MI???????????????????????????M . ^ ......................NM
!.................MO?????????????????????????M... | .............................
!.................. M???????????????????????M.... | .............................
!....................M8?????????????????????M.... | .........................
!.....................:M????????????????????M ... | DP .........................
!.......................MO???????????????????M... | .........................
!........................ M??????????????????M~.. | .............................
!..........................MM????????????????IM.. | .............................
!............................MI????????????????M. v .............................
!.............................:MI???????????????M. .............................
!...............................DMI??????????????M$ .............................
!................................ MM??????????????DM ............................
!.................................. MMI????????????IM ...........................
!.....................................MMI????????????M ..........................
!........................................MM??????????IM..........................
!......................................... $MMI???????M .........................
!........................................... MMMMMMM7. ..........................
!............................................. .............................
!............................................. PMAX .............................
!............................................. .............................
!................................................................................
USE mo_f2kcli ! command line interface
USE netcdf_tools
implicit none
! VERSION
character(len=*), parameter :: VERSION = '1.4'
! ... INTERNAL parameter
integer, parameter :: str_short = 30 ! length of short strings
integer, parameter :: str_long = 100 ! length of long strings
integer, parameter :: str_vlong = 500 ! length of very long strings
integer, parameter :: iou = 21 ! I/O unit
! FOR COMMAND LINE
CHARACTER(LEN=256) :: EXE ! program name
CHARACTER(LEN=80) :: CMD ! argument
INTEGER :: NARG ! number of arguments
! VARIABLES
INTEGER :: status ! status flag
LOGICAL :: l_invert = .FALSE. ! invert axis
LOGICAL :: l_Pa = .FALSE. ! convert units Pa->hPa
! Set tropopause thresholds
real :: tropo_pv,tropo_th
! diabatically produced PV (Q-threshold), Feb 2014:
real :: q_th
! masking number
real, parameter :: mdv =-999.0
! DATA/VARIABLE
! - input data
real, allocatable, dimension(:) :: x_data, y_data,z_data,t_data
real, allocatable, dimension(:) :: ak,bk
real, allocatable, dimension(:,:,:) :: aps
real, allocatable, dimension(:,:,:,:) :: press
real, allocatable, dimension(:,:,:,:) :: q_in,pv_in,pt_in
real, allocatable, dimension(:,:,:,:) :: q,pv,pt
character(len=str_long) :: x_units,y_units, z_units,t_units
character(len=str_long) :: aps_units
! - final results
real, allocatable, dimension(:,:,:) :: fold ! fold yes/no
real, allocatable, dimension(:,:,:) :: sfold ! shallow fold yes/no
real, allocatable, dimension(:,:,:) :: mfold ! medium fold yes/no
real, allocatable, dimension(:,:,:) :: dfold ! deep fold yes/no
real, allocatable, dimension(:,:,:) :: tp ! tropopause
real, allocatable, dimension(:,:,:) :: dp ! folding depth (Pa)
real, allocatable, dimension(:,:,:) :: pmin ! folding depth (Pa)
real, allocatable, dimension(:,:,:) :: pmax ! folding depth (Pa)
real, allocatable, dimension(:,:,:,:) :: label ! folding classification
real, allocatable, dimension(:,:,:,:) :: label_out
! Auxiliary variables
integer :: stat
integer :: i,j,k,t
real :: lev(100)
!namelist...
character(len=str_long) file_input
character(len=str_long) file_output
character(len=str_short) x_name,y_name,z_name,t_name
character(len=str_short) aps_name,hyam_name, hybm_name
character(len=str_short) q_name, pv_name, pt_name
! DATA DIMENSION
integer :: nx,ny,nz,nt
! -----------------------------------------------------------------
! Initialisation paramaters
! -----------------------------------------------------------------
! Humidity criterion for diabatically produced PV, BOJAN: this is the threshold Q=0.1g/kg
q_th=0.0001
tropo_pv = 2.0
tropo_th = 380.0
! -----------------------------------------------------------------
! Read command line
! -----------------------------------------------------------------
narg = command_argument_count() ! number of arguments
call get_command_argument(0,exe) ! program name
!
if (narg > 1) then
write(*,*) 'command-line error: too many arguments !'
call usage(trim(exe))
stop
end if
!
if (narg == 0) then
call usage(trim(exe))
stop
end if
!
call get_command_argument(1,cmd)
! -----------------------------------------------------------------
! Read namelist file
! -----------------------------------------------------------------
CALL read_nml(status, iou, TRIM(CMD))
IF (status /= 0) STOP
! -----------------------------------------------------------------
! Inquire netcdf file
! -----------------------------------------------------------------
CALL inquire_file(TRIM(file_input), &
x_name, y_name, z_name,t_name, &
nx, ny, nz, nt )
! IF (status > 0) STOP ! ERROR
WRITE(*,*) '==========================================================='
WRITE(*,*) " FILE DIMENSION: "
WRITE(*,*) " X :", nx
WRITE(*,*) " Y :", ny
WRITE(*,*) " Z :", nz
WRITE(*,*) " T :", nt
WRITE(*,*) '==========================================================='
! -----------------------------------------------------------------
! allocate data file
! -----------------------------------------------------------------
ALLOCATE(x_data(nx))
ALLOCATE(y_data(ny))
ALLOCATE(z_data(nz))
ALLOCATE(t_data(nt))
ALLOCATE(aps(nx,ny,nt))
ALLOCATE(ak(nz))
ALLOCATE(bk(nz))
ALLOCATE(press(nx,ny,nz,nt))
!
ALLOCATE(q(nx,ny,nz,nt))
ALLOCATE(pt(nx,ny,nz,nt))
ALLOCATE(pv(nx,ny,nz,nt))
ALLOCATE(q_in(nx,ny,nz,nt))
ALLOCATE(pt_in(nx,ny,nz,nt))
ALLOCATE(pv_in(nx,ny,nz,nt))
ALLOCATE(label(nx,ny,nz,nt))
ALLOCATE(fold(nx,ny,nt))
ALLOCATE(sfold(nx,ny,nt))
ALLOCATE(mfold(nx,ny,nt))
ALLOCATE(dfold(nx,ny,nt))
ALLOCATE(tp(nx,ny,nt))
ALLOCATE(dp(nx,ny,nt))
ALLOCATE(pmin(nx,ny,nt))
ALLOCATE(pmax(nx,ny,nt))
ALLOCATE(label_out(nx,ny,nz,nt))
! -----------------------------------------------------------------
! read netcdf file
! -----------------------------------------------------------------
call read_file(TRIM(file_input), TRIM(x_name), x_data)
call read_file(TRIM(file_input), TRIM(y_name), y_data)
call read_file(TRIM(file_input), TRIM(z_name), z_data)
call read_file(TRIM(file_input), TRIM(t_name), t_data)
call read_att(TRIM(file_input), TRIM(x_name), "units", x_units)
call read_att(TRIM(file_input), TRIM(y_name), "units", y_units)
call read_att(TRIM(file_input), TRIM(z_name), "units", z_units)
call read_att(TRIM(file_input), TRIM(t_name), "units", t_units)
! pressure data
call read_file(TRIM(file_input), TRIM(aps_name), aps)
call read_file(TRIM(file_input), TRIM(hyam_name), ak)
call read_file(TRIM(file_input), TRIM(hybm_name), bk)
! presure units
call read_att(TRIM(file_input), TRIM(aps_name), "units", aps_units)
! humidity
call read_file(TRIM(file_input), TRIM(q_name), q_in)
! potential temperature
call read_file(TRIM(file_input), TRIM(pt_name), pt_in)
! potential vorticity
call read_file(TRIM(file_input), TRIM(pv_name), pv_in)
! -----------------------------------------------------------------
! create pressure field and
! invert vertical axis (if needed)
! -----------------------------------------------------------------
! bottom => high pressure = 1
! top => low pressure = nz
if ((ak(1)+bk(1)*101325).lt.(ak(2)+bk(2)*101325)) then
l_invert=.TRUE.
write (*,*) 'Invert vertical axis'
endif
if (aps_units == "Pa") then
write (*,*) 'convert pressure from Pa to hPa'
l_Pa=.TRUE.
endif
if (l_invert) then
! to be inverted
do i=1,nx
do j=1,ny
do k=1,nz
do t=1,nt
if (l_Pa) then
press(i,j,nz-k+1,t)= (ak(k)+aps(i,j,t)*bk(k))/100.0 ! Pa -> hPa
else
press(i,j,nz-k+1,t)= (ak(k)+aps(i,j,t)*bk(k))
endif
q(i,j,nz-k+1,t) = q_in(i,j,k,t)
pt(i,j,nz-k+1,t)= pt_in(i,j,k,t)
pv(i,j,nz-k+1,t)= pv_in(i,j,k,t)
enddo
enddo
enddo
enddo
ELSE
! NOT to be inverted
do i=1,nx
do j=1,ny
do k=1,nz
do t=1,nt
if (l_Pa) then
press(i,j,k,t)= (ak(k)+aps(i,j,t)*bk(k))/100.0 ! Pa -> hPa
else
press(i,j,k,t)= ak(k)+aps(i,j,t)*bk(k)
endif
enddo
enddo
enddo
enddo
q(1:nx,1:ny,1:nz,1:nt) = q_in(1:nx,1:ny,1:nz,1:nt)
pt(1:nx,1:ny,1:nz,1:nt) = pt_in(1:nx,1:ny,1:nz,1:nt)
pv(1:nx,1:ny,1:nz,1:nt) = pv_in(1:nx,1:ny,1:nz,1:nt)
ENDIF
! -----------------------------------------------------------------
! perform calculation for each timestep
! -----------------------------------------------------------------
! TIME LOOP
do t=1,nt
write(*,*) "time step",t,"/", nt
! -------------------------------------------------------------------
! Part 1) Run clustering algorithm, get labels and interpolate to tropopause
! -------------------------------------------------------------------
! ------------------------------
! Running clustering algorithm
! ------------------------------
call tropopause (tp(:,:,t),label(:,:,:,t),press(:,:,:,t),pv(:,:,:,t),pt(:,:,:,t),q(:,:,:,t), &
mdv,y_data(:),nx,ny,nz,tropo_pv,tropo_th,q_th)
! -------------------------------------------------------------------
! Part 2) Identify tropopause folds from vertical cross-sections
! -----------------------------------------------------------------
! ------------------------------
! Identifying tropopause folds
! ------------------------------
call tropofold (label(:,:,:,t),press(:,:,:,t),pv(:,:,:,t),pt(:,:,:,t), &
fold(:,:,t), dp(:,:,t), pmin(:,:,t), pmax(:,:,t), sfold(:,:,t), mfold(:,:,t), dfold(:,:,t), &
mdv,nx,ny,nz,tropo_pv,tropo_th)
enddo
! END OF TIME LOOP
! -----------------------------------------------------------------
! re-invert vertical axis (if needed)
! -----------------------------------------------------------------
if (l_invert) then
! to be inverted
do i=1,nx
do j=1,ny
do k=1,nz
do t=1,nt
label_out(i,j,nz-k+1,t) = label(i,j,k,t)
enddo
enddo
enddo
enddo
ELSE
! NOT to be inverted
label_out(1:nx,1:ny,1:nz,1:nt) = label(1:nx,1:ny,1:nz,1:nt)
ENDIF
! -----------------------------------------------------------------
! write netcdf files
! -----------------------------------------------------------------
call nc_dump (TRIM(file_output), x_data, y_data, z_data, t_data, &
x_units,y_units, z_units,t_units, aps, ak, bk, label_out, fold, &
sfold, mfold, dfold, tp, dp, pmin, pmax)
! -----------------------------------------------------------------
! deallocate data file
! -----------------------------------------------------------------
DEALLOCATE(x_data)
DEALLOCATE(y_data)
DEALLOCATE(z_data)
DEALLOCATE(t_data)
DEALLOCATE(aps)
DEALLOCATE(ak)
DEALLOCATE(bk)
DEALLOCATE(press)
!
DEALLOCATE(q_in)
DEALLOCATE(pt_in)
DEALLOCATE(pv_in)
DEALLOCATE(q)
DEALLOCATE(pt)
DEALLOCATE(pv)
DEALLOCATE(label)
DEALLOCATE(label_out)
DEALLOCATE(fold)
DEALLOCATE(sfold)
DEALLOCATE(mfold)
DEALLOCATE(dfold)
DEALLOCATE(tp)
DEALLOCATE(dp)
DEALLOCATE(pmin)
DEALLOCATE(pmax)
CONTAINS
! ------------------------------------------------------------------------
SUBROUTINE USAGE(EXE)
CHARACTER (LEN=*) :: EXE
WRITE(*,*) '--------------------------------------------'
WRITE(*,*) '3d_labelling_and_fold_id, version: ',VERSION
WRITE(*,*) 'Authors: Andrea Pozzer, MPICH '
WRITE(*,*) ' Bojan Skerlak, ETH '
WRITE(*,*) ' Michael Sprenger, ETH '
WRITE(*,*) '--------------------------------------------'
WRITE(*,*) 'Usage: '//TRIM(EXE)//' <namelist-file>'
WRITE(*,*) 'See README.txt or EMAC.nml for example'
WRITE(*,*) '--------------------------------------------'
END SUBROUTINE USAGE
! ------------------------------------------------------------------------
! ------------------------------------------------------------------------
SUBROUTINE read_nml(status, iou, fname)
IMPLICIT NONE
! I/O
INTEGER, INTENT(OUT) :: status
INTEGER, INTENT(IN) :: iou
CHARACTER(LEN=*), INTENT(IN) :: fname
! LOCAL
CHARACTER(LEN=*), PARAMETER :: substr = 'read_nml'
LOGICAL :: lex ! file exists
INTEGER :: fstat ! file status
NAMELIST /CTRL/ file_input,file_output,X_name,Y_name,Z_name,T_name, &
APS_name,HYAM_name,HYBM_name,Q_name,PV_name,PT_name
status = 1 ! ERROR
WRITE(*,*) '==========================================================='
! CHECK IF FILE EXISTS
INQUIRE(file=TRIM(fname), exist=lex)
IF (.NOT.lex) THEN
WRITE(*,*) substr,': FILE DOES NOT EXIST (',TRIM(fname),')'
status = 1
RETURN
END IF
! OPEN FILE
OPEN(iou,file=TRIM(fname))
! READ NEMELIST
WRITE(*,*) 'READING NAMELIST ''CTRL'''//&
&' FROM '''//TRIM(fname),''' (unit ',iou,') ...'
!
READ(iou, NML=CTRL, IOSTAT=fstat)
!
IF (fstat /= 0) THEN
WRITE(*,*) substr,': READ ERROR IN NAMELIST ''CTRL'' (',TRIM(fname),')'
status = 3 ! READ ERROR IN NAMELIST
RETURN
END IF
WRITE(*,*) ' FILE INPUT : ', TRIM(file_input)
WRITE(*,*) ' FILE OUTPUT : ', TRIM(file_output)
WRITE(*,*) ' X_NAME : ', TRIM(x_name)
WRITE(*,*) ' Y_NAME : ', TRIM(y_name)
WRITE(*,*) ' Z_NAME : ', TRIM(z_name)
WRITE(*,*) ' T_NAME : ', TRIM(t_name)
WRITE(*,*) ' APS_NAME : ', TRIM(aps_name)
WRITE(*,*) ' HYAM_NAME : ', TRIM(hyam_name)
WRITE(*,*) ' HYBM_NAME : ', TRIM(hybm_name)
WRITE(*,*) ' Q_NAME : ', TRIM(q_name)
WRITE(*,*) ' PV_NAME : ', TRIM(pv_name)
WRITE(*,*) ' PT_NAME : ', TRIM(pt_name)
! CLOSE FILE
CLOSE(iou)
WRITE(*,*) '==========================================================='
status = 0
END SUBROUTINE read_nml
! ------------------------------------------------------------------------
end program clustering
! *******************************************************************************
! * Subroutine Section *
! *******************************************************************************
! --------------------------------------------------------
! Get grid points which are connected to a grid point: BOJAN: this is the 3D-connectedness criterion of the 3D-labelling algorithm
! --------------------------------------------------------
SUBROUTINE connect (outar,label,inx,iny,inz,dirh,dird,diru,nx,ny,nz)
! The input array <outar(nx,ny,nz)> is 0/1 labeled. Given a starting point
! <inx,iny,inz> where the label is 1, find all points with label 1 which are
! connected and attribute to all these points the label <label>.
! The 3D arrays <dir*(nx,ny,nz)> specifie whether an expansion is allowed
! dirh=1 where horizontal propagation is allowed,
! dird=1 where vertical propagation is allowed downward,
! diru=1 where vertical propagation is allowed upward, and
! a value of dir*=0 prohibits the respective propagation
! Declaration of subroutine parameters
integer :: nx,ny,nz
integer :: inx,iny,inz
integer :: outar(nx,ny,nz)
integer :: label
integer :: dirh(nx,ny,nz)
integer :: diru(nx,ny,nz)
integer :: dird(nx,ny,nz)
! Auxiliary variables
integer :: il,ir,jb,jf,ku,kd,im,jm,km
integer :: i,j,k
integer :: stack
integer :: indx(nx*ny*nz),indy(nx*ny*nz),indz(nx*ny*nz)
! Push the starting elements on the stack
stack=1
indx(stack)=inx
indy(stack)=iny
indz(stack)=inz
outar(inx,iny,inz)=label
! Define the indices of the neighbouring elements
100 continue
il=indx(stack)-1
if (il.lt.1) il=nx
ir=indx(stack)+1
if (ir.gt.nx) ir=1
jb=indy(stack)-1
if (jb.lt.1) jb=1
jf=indy(stack)+1
if (jf.gt.ny) jf=ny
ku=indz(stack)+1
if (ku.gt.nz) ku=nz
kd=indz(stack)-1
if (kd.lt.1) kd=1
im=indx(stack)
jm=indy(stack)
km=indz(stack)
stack=stack-1
! Check for index overflow
if (stack.ge.(nx*ny*nz-nx)) then
print*,'Stack overflow while clustering...'
stop
endif
! Mark all connected elements (build up the stack)
! Mark level below/above if dird/diru and dirh allowed
! BOJAN: U=up, D=down, R=right, L=left, M=mid, F=front, B=back (positions in a 27-element cube of nearest neighbours)
if ((dirh(im,jm,km).eq.1).and.(dird(im,jm,km).eq.1)) then
! below:
if ( outar(il,jf,kd).eq.1) then
outar(il,jf,kd)=label
stack=stack+1
indx(stack)=il
indy(stack)=jf
indz(stack)=kd
endif
if ( outar(im,jf,kd).eq.1) then
outar(im,jf,kd)=label
stack=stack+1
indx(stack)=im
indy(stack)=jf
indz(stack)=kd
endif
if ( outar(ir,jf,kd).eq.1) then
outar(ir,jf,kd)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jf
indz(stack)=kd
endif
if (outar(il,jm,kd).eq.1) then
outar(il,jm,kd)=label
stack=stack+1
indx(stack)=il
indy(stack)=jm
indz(stack)=kd
endif
if (outar(ir,jm,kd).eq.1) then
outar(ir,jm,kd)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jm
indz(stack)=kd
endif
if (outar(il,jb,kd).eq.1) then
outar(il,jb,kd)=label
stack=stack+1
indx(stack)=il
indy(stack)=jb
indz(stack)=kd
endif
if (outar(im,jb,kd).eq.1) then
outar(im,jb,kd)=label
stack=stack+1
indx(stack)=im
indy(stack)=jb
indz(stack)=kd
endif
if (outar(ir,jb,kd).eq.1) then
outar(ir,jb,kd)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jb
indz(stack)=kd
endif
endif
if ((dirh(im,jm,km).eq.1).and.(diru(im,jm,km).eq.1)) then
if (outar(il,jf,ku).eq.1) then
outar(il,jf,ku)=label
stack=stack+1
indx(stack)=il
indy(stack)=jf
indz(stack)=ku
endif
if (outar(im,jf,ku).eq.1) then
outar(im,jf,ku)=label
stack=stack+1
indx(stack)=im
indy(stack)=jf
indz(stack)=ku
endif
if (outar(ir,jf,ku).eq.1) then
outar(ir,jf,ku)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jf
indz(stack)=ku
endif
if (outar(il,jm,ku).eq.1) then
outar(il,jm,ku)=label
stack=stack+1
indx(stack)=il
indy(stack)=jm
indz(stack)=ku
endif
if (outar(ir,jm,ku).eq.1) then
outar(ir,jm,ku)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jm
indz(stack)=ku
endif
if (outar(il,jb,ku).eq.1) then
outar(il,jb,ku)=label
stack=stack+1
indx(stack)=il
indy(stack)=jb
indz(stack)=ku
endif
if (outar(im,jb,ku).eq.1) then
outar(im,jb,ku)=label
stack=stack+1
indx(stack)=im
indy(stack)=jb
indz(stack)=ku
endif
if (outar(ir,jb,ku).eq.1) then
outar(ir,jb,ku)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jb
indz(stack)=ku
endif
endif
! Mark level directly below and above if allowed (dird/u=1)
if (dird(im,jm,km).eq.1) then
if (outar(im,jm,kd).eq.1) then
outar(im,jm,kd)=label
stack=stack+1
indx(stack)=im
indy(stack)=jm
indz(stack)=kd
endif
endif
if (diru(im,jm,km).eq.1) then
if (outar(im,jm,ku).eq.1) then
outar(im,jm,ku)=label
stack=stack+1
indx(stack)=im
indy(stack)=jm
indz(stack)=ku
endif
endif
! Mark other points on same level if allowed (dirh=1)
if (dirh(im,jm,km).eq.1) then
if (outar(il,jf,km).eq.1) then
outar(il,jf,km)=label
stack=stack+1
indx(stack)=il
indy(stack)=jf
indz(stack)=km
endif
if (outar(im,jf,km).eq.1) then
outar(im,jf,km)=label
stack=stack+1
indx(stack)=im
indy(stack)=jf
indz(stack)=km
endif
if (outar(ir,jf,km).eq.1) then
outar(ir,jf,km)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jf
indz(stack)=km
endif
if (outar(il,jm,km).eq.1) then
outar(il,jm,km)=label
stack=stack+1
indx(stack)=il
indy(stack)=jm
indz(stack)=km
endif
if (outar(ir,jm,km).eq.1) then
outar(ir,jm,km)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jm
indz(stack)=km
endif
if (outar(il,jb,km).eq.1) then
outar(il,jb,km)=label
stack=stack+1
indx(stack)=il
indy(stack)=jb
indz(stack)=km
endif
if (outar(im,jb,km).eq.1) then
outar(im,jb,km)=label
stack=stack+1
indx(stack)=im
indy(stack)=jb
indz(stack)=km
endif
if (outar(ir,jb,km).eq.1) then
outar(ir,jb,km)=label
stack=stack+1
indx(stack)=ir
indy(stack)=jb
indz(stack)=km
endif
endif
if (stack.gt.0) goto 100
! Exit point
700 continue
return
end subroutine connect
! ---------------------------------------------------------
! Calculate the height of the tropopause: BOJAN: although this subroutine is called tropopause for historical reasons (long story), it actually is the core of the 3D-labelling algorithm :-)
! ---------------------------------------------------------
SUBROUTINE tropopause (f2,f3,p3,pv3,th3,q3,mdv,xlat,nx,ny,nz,tropo_pv,tropo_th,q_th)
! Get the pressure height of the tropopause (f2) and
! cluster the atmosphere into labels 1-5 (f3).
! Given: 3d field: Pressure <p3(nx,ny,nz)>,
! potential vorticity <pv3(nx,ny,nz)>, and potential
! temperature <th3(nx,ny,nz)>. The parameters <nx,ny,nz>
! characterize the grid. The missing data value is <mdv>.
! Bojan July 2013: tropo_pv and tropo_th have to be specified!
implicit none
! Declaration of subroutine parameters
integer,intent(in) :: nx,ny,nz
real,intent(out) :: f3(nx,ny,nz)
real,intent(out) :: f2(nx,ny)
real,intent(in) :: p3(nx,ny,nz)
real,intent(in) :: q3(nx,ny,nz)
real,intent(inout) :: pv3(nx,ny,nz)
real,intent(in) :: th3(nx,ny,nz)
real,intent(in) :: xlat(ny)
integer :: dirsh(nx,ny,nz),dirsd(nx,ny,nz),dirsu(nx,ny,nz)
integer :: dirth(nx,ny,nz),dirtd(nx,ny,nz),dirtu(nx,ny,nz)
integer :: dirdh(nx,ny,nz),dirdd(nx,ny,nz),dirdu(nx,ny,nz)
integer :: dirfh(nx,ny,nz),dirfd(nx,ny,nz),dirfu(nx,ny,nz)
real :: mdv
! Set tropopause thresholds
real :: tropo_pv,tropo_th
! diabatically produced PV (Q-threshold), Feb 2014:
real :: q_th
! Set permission for expansion of stratospheric label. A horizontal
! expansion is forbidden if less than <forbid_h> of the grid column
! below a grid point is tropospheric
real :: forbid_h
parameter (forbid_h=0.5)
! Internal variables
integer :: i,j,k,l
real :: pv2(nx,ny)
real :: th2(nx,ny)
real :: pvn(nx,ny),pvs(nx,ny)
real :: lat
integer :: st(nx,ny,nz),tr(nx,ny,nz),de(nx,ny,nz),fi(nx,ny,nz)
real :: sign
real :: lev(nx,ny)
integer :: tschk,kabove,kbelow,vertpvchk
real :: below, total
! ----- STEP 1a ----- BOJAN: these steps should be the same as described in the appendix of my PhD thesis
! Mark all points above 50 hPa as stratospheric
do i=1,nx
do j=1,ny
do k=1,nz
if (xlat(j).ge.0.) then
sign=1.
else
sign=-1.
endif
if (p3(i,j,k).lt.50.) then
pv3(i,j,k)=sign*1.5*tropo_pv
endif
enddo
enddo
enddo
! Mark points with PV > PV threshold (e.g. 2 pvu) OR TH > TH threshold (e.g. 380 K)
do i=1,nx
do j=1,ny
do k=1,nz
if ((abs(pv3(i,j,k)).ge.tropo_pv).or.(th3(i,j,k).ge.tropo_th)) then
st(i,j,k)=1 ! 'stratosphere'
tr(i,j,k)=0 ! 'tropopsphere'
de(i,j,k)=1 ! additional array for de-treatment
else
st(i,j,k)=0
tr(i,j,k)=1
de(i,j,k)=0
endif
enddo
enddo
enddo
! ----- STEP 1b -----
! Set the expansion permissions for the individual labels (1=allowed, 0=forbidden)
! h=horizontal, v=vertical
do i=1,nx
do j=1,ny
do k=1,nz
! Set permissions for stratospheric (st) label: always vertical, never horizontal
dirsh(i,j,k) = 0
dirsd(i,j,k) = 1
dirsu(i,j,k) = 1
! Set permissions for fill up thing label (fi): always horizontal, only downward, never upward
dirfh(i,j,k) = 1
dirfd(i,j,k) = 1
dirfu(i,j,k) = 0
! Set permissions for tropospheric label (can always propagate)
dirth(i,j,k) = 1
dirtd(i,j,k) = 1
dirtu(i,j,k) = 1
! Set permissions for deep fold (de) label: always horizontal, vertical only if air is dry
dirdh(i,j,k) = 1
! Allow vertical propagation of de label only for dry air (Q < Q-threshold)
if ( q3(i,j,k).le.q_th ) then
dirdd(i,j,k) = 1
dirdu(i,j,k) = 1
else
dirdd(i,j,k) = 0
dirdu(i,j,k) = 0
endif
!endif
enddo
enddo
enddo
! ----- STEP 2a -----
do i=1,nx
do j=1,ny
! Determine stratosphere by connectivity criterion: for all points (x/y) at highest
! model level with st=1, find all connected points with st=1 => they get label st=2
! this label can only propagate vertically and it is important that this happens before
! label st=5 can propagate from the bottom and overwrite st=1 with st=5
if ((st(i,j,nz).eq.1).and.(p3(i,j,nz).lt.500.)) then
call connect (st,2,i,j,nz,dirsh,dirsd,dirsu,nx,ny,nz)
endif
enddo
enddo
do i=1,nx
do j=1,ny
! ----- STEP 2b -----
! for de array, do the same thing. The big difference is that the horizontal propagation is
! always allowed. In the vertical direction, it is only allowed if RH<50%, ensuring that
! very deep tropopause folds, which are not connected by st are reached by de.
! This is needed because for some cases, stratospheric air (e.g. at the boundary of a deep-reaching
! streamer) is not identified as such (the label st=2 is not allowed to propagate
! horizontally). The de=2 label can always propagate horizontally and is in the end
! used to distinguish 'real' cutoffs (with st=1 and de=1) from
! deep reaching stratospheric air (with st=1 and de=2)
if ((de(i,j,nz).eq.1).and.(p3(i,j,nz).lt.500.)) then
call connect (de,2,i,j,nz,dirdh,dirdd,dirdu,nx,ny,nz)
endif
! ----- STEP 2c -----
! Determine troposphere analogeously: for all points (x/y) at lowest model
! level with tr=1 => all connected points get label tr=2
if ((tr(i,j,1).eq.1).and.(p3(i,j,1).gt.300.)) then
call connect (tr,2,i,j,1,dirth,dirtd,dirtu,nx,ny,nz)
endif
! ----- STEP 2d -----
! Determine surface-bound PV blobs (|PV|>2): for all points (x/y) at lowest
! model level with st=1 => all connected points get label st=5
! This label can always propagate! (use dirth,dirtv)
if ((st(i,j,1).eq.1).and.(p3(i,j,1).gt.300.)) then
call connect (st,5,i,j,1,dirth,dirtd,dirtu,nx,ny,nz)
endif
enddo
enddo
! ----- STEP 2e -----
! Remove tropospheric blobs in surface-bound PV blobs (tr=1 surrounded by st=5)
do i=1,nx
do j=1,ny
do k=1,nz
if (tr(i,j,k).eq.1) then
tschk=0
do l=k,nz
if (tschk.eq.0) then
! Check if air above is stratosphere (st=2) or top of atmosphere (nz)
if ( (st(i,j,l).eq.2) .or. (l.eq.nz) ) then
tschk=2
! Check if air above is surface-bound PV blob (st=5)
elseif (st(i,j,l).eq.5) then
tschk=5
endif
endif
enddo
! Mark this blob as tr=5
if (tschk.eq.5) then
call connect (tr,5,i,j,k,dirth,dirtd,dirtu,nx,ny,nz)
endif
endif
enddo
enddo
enddo
! ----- STEP 3 -----
! --------------------------------------------------------------------------------------------------
! Set the stratospheric and troposhperic labels (commented out version is 1=strat/0=everything else)
! --------------------------------------------------------------------------------------------------
do i=1,nx
do j=1,ny
do k=1,nz
f3(i,j,k)=0.
if (th3(i,j,k).gt.tropo_th) then
f3(i,j,k) = 2. ! stratosphere TH (2)
! f3(i,j,k) = 1. ! stratosphere TH (1)
else if (st(i,j,k).eq.2) then
f3(i,j,k) = 2. ! stratosphere PV (2)
! f3(i,j,k) = 1. ! stratosphere PV (1)
else if (tr(i,j,k).eq.2) then
f3(i,j,k) = 1. ! troposphere (1)
! f3(i,j,k) = 0. ! troposphere (0)
else if ((st(i,j,k).eq.1).and.(de(i,j,k).eq.1)) then
f3(i,j,k) = 3. ! strat cutoff (3)
! f3(i,j,k) = 0. ! strat cutoff (0)
else if ((st(i,j,k).eq.1).and.(de(i,j,k).eq.2)) then
f3(i,j,k) = 2. ! deep reaching stratospheric air (2)
! f3(i,j,k) = 1. ! deep reaching stratospheric air (1)
else if (tr(i,j,k).eq.1) then
f3(i,j,k) = 4. ! trop cutoff (4)
! f3(i,j,k) = 0. ! trop cutoff (0)
else if (st(i,j,k).eq.5) then
f3(i,j,k) = 5. ! surface-bound PV blob (5)
! f3(i,j,k) = 0. ! surface-bound PV blob (0)
else if (tr(i,j,k).eq.5) then
f3(i,j,k) = 1. ! tropospheric air within surface-bound PV blob (1)
! f3(i,j,k) = 0. ! tropospheric air within surface-bound PV blob (0)
endif
enddo
enddo
enddo
! --------------------------------------------------------------------------------------------------
! --------------------------------------------------------------------------------------------------
! ----- STEP 6 -----
do i=1,nx
do j=1,ny
do k=1,nz
fi(i,j,k)=0
if (( f3(i,j,k).eq.2 ) .or. ( f3(i,j,k).eq.3 ).or.( f3(i,j,k).eq.5 )) then
fi(i,j,k)=1 ! mark point as possible horizontal fill-up point
endif
end do
end do
end do
! Horizontally fill up 2/3 and 2/5 patches (only aestetically important ;-))
do i=1,nx
do j=1,ny
do k=1,nz
if ( f3(i,j,k).eq.3 ) then ! label 3
call connect (fi,3,i,j,k,dirfh,dirfd,dirfu,nx,ny,nz)
endif
if ( f3(i,j,k).eq.5 ) then ! label 3
call connect (fi,5,i,j,k,dirfh,dirfd,dirfu,nx,ny,nz)
endif
enddo
enddo
enddo
do i=1,nx
do j=1,ny
do k=1,nz
if ( fi(i,j,k).eq.3 ) then ! label 3 that was horizontally filled up
f3(i,j,k)=3.
do l=1,k-1 ! vertically fill up points below if label is 2
if ( f3(i,j,l).eq.2 ) then
f3(i,j,l)=3.
end if
end do
endif
if ( fi(i,j,k).eq.5 ) then ! label 5 that was horizontally filled up
f3(i,j,k)=5.
endif
enddo
enddo
enddo
! CHECK that all points obtained a label!
do i=1,nx
do j=1,ny
do k=1,nz
if ( f3(i,j,k).eq.0 ) then ! no label assigned
print*,'Error: no label assigned'
print*,'i,j,k = ',i,j,k
print*,'p3(i,j,k) = ',p3(i,j,k)
print*,'st(i,j,k) = ',st(i,j,k)
print*,'tr(i,j,k) = ',tr(i,j,k)
print*,'de(i,j,k) = ',de(i,j,k)
stop
endif
enddo
enddo
enddo
! --------------------------------------------------------------------------------------------------
! DONE with assigning labels, now interpolate field to tropopause pressure
! --------------------------------------------------------------------------------------------------
! BOJAN: here, we calculate the height of the tropopause (folds are ignored, see PhD thesis)
! Remove stratospheric blobs in troposphere and tropospheric blobs in stratosphere
! Brute force: Change PV values above and below tropo threshold
do i=1,nx
do j=1,ny
do k=1,nz
if (xlat(j).ge.0.) then
sign=1.
else
sign=-1.
endif
! Set PV of tropo. cutoff in stratosphere
if ( (st(i,j,k).eq.0).and.(tr(i,j,k).eq.1) ) then
pv3(i,j,k)=sign*1.5*tropo_pv
! Set PV of exotic cases where PV < -2 pvu (PV > +2 pvu) in NH (SH) => would otherwise be detected as TP
else if ( ((sign .gt. 0.).and.(pv3(i,j,k).lt.-tropo_pv).or.(sign .lt. 0.).and.(pv3(i,j,k).gt.tropo_pv)).and.(th3(i,j,k).gt.tropo_pv) ) then
pv3(i,j,k)=sign*1.5*tropo_pv
! Set PV of strat. cutoff in trop. or surface bound PV (only below 380K)
!else if ( (((st(i,j,k).eq.1).and.(de(i,j,k).eq.1)).or.(st(i,j,k).eq.5)).and.(th3(i,j,k).le.tropo_th) ) then
else if ( (f3(i,j,k).eq.3).or.(f3(i,j,k).eq.5) ) then
pv3(i,j,k)=sign*0.5*tropo_pv
endif
enddo
enddo
enddo
! Calculate the height of the dynamical tropopause (NH:2pvu, SH:-2pvu)
do i=1,nx
do j=1,ny
lev(i,j)=tropo_pv
enddo
enddo
call thipo_lev(p3,pv3,lev,pvn,nx,ny,nz,mdv,0) ! for NH
do i=1,nx
do j=1,ny
do k=1,nz
pv3(i,j,k)=-pv3(i,j,k) ! change sign of PV
enddo
enddo
enddo
call thipo_lev(p3,pv3,lev,pvs,nx,ny,nz,mdv,0) ! for SH
do i=1,nx
do j=1,ny
do k=1,nz
pv3(i,j,k)=-pv3(i,j,k) ! change sign of PV back
enddo
enddo
enddo
do j=1,ny
do i=1,nx
if (xlat(j).ge.0.) then
pv2(i,j)=pvn(i,j) ! NH
else
pv2(i,j)=pvs(i,j) ! SH
endif
enddo
enddo
! Special treatment for PV towers (in whole column, |PV|>2)
do i=1,nx
do j=1,ny
if (pv2(i,j).eq.mdv) then
vertpvchk=0
do k=1,nz
if (abs(pv3(i,j,k)).ge.tropo_pv) vertpvchk=vertpvchk+1
enddo
if(vertpvchk.eq.nz) then
!print*,'PV tower! Tropopause reaches ground: ',p3(i,j,1)
pv2(i,j)=p3(i,j,1)
endif
endif
enddo
enddo
! Calculate the height of the 380 K surface
do i=1,nx
do j=1,ny
lev(i,j)=tropo_th
enddo
enddo
call thipo_lev(p3,th3,lev,th2,nx,ny,nz,mdv,0)
! Set unreasonable values to mdv
do i=1,nx
do j=1,ny
if ((th2(i,j).lt.40.).or.(th2(i,j).gt.800.)) then ! Out of 'regular' limits => check label
if (th2(i,j).ne.mdv) then
!print*,'Warning: p(TP) (TH) out of limits:',th2(i,j)
!print*,'i,j = ',i,j
!print*,'LABEL profile:',f3(i,j,:)
do k=1,nz
if (p3(i,j,k).ge.th2(i,j)) then
kbelow=k
endif
if (p3(i,j,nz+1-k).le.th2(i,j)) then
kabove=nz+1-k
endif
enddo
if ((f3(i,j,kbelow).eq.1).and.(f3(i,j,kabove).eq.2)) then
!print*,'Point is okay!'
else
!print*,'Point is not okay => set to mdv'
th2(i,j)=mdv
endif
endif
endif
if ((pv2(i,j).lt.40.).or.(pv2(i,j).gt.800.)) then ! Out of 'regular' limits => check label
if (pv2(i,j).ne.mdv) then
!print*,'Warning: p(TP) (PV) out of limits:',pv2(i,j)
!print*,'i,j = ',i,j
!print*,'LABEL profile:',f3(i,j,:)
do k=1,nz
if (p3(i,j,k).ge.pv2(i,j)) then
kbelow=k
endif
if (p3(i,j,nz+1-k).le.pv2(i,j)) then
kabove=nz+1-k
endif
enddo
if ((f3(i,j,kbelow).eq.1).and.(f3(i,j,kabove).eq.2)) then
!print*,'Point is okay!'
elseif ((kabove.eq.1).and.(kbelow.eq.1)) then
!print*,'PV tower! Tropopause reaches ground: ',pv2(i,j)
else
!print*,'Point is not okay => set to mdv'
pv2(i,j)=mdv
endif
endif
endif
enddo
enddo
! --------------------------------------------------------------------------------------------------
! Set the resulting tropopause height (maximum pressure: 380 K, 2 PVU)
! --------------------------------------------------------------------------------------------------
do i=1,nx
do j=1,ny
if ((th2(i,j).ne.mdv).and.(pv2(i,j).eq.mdv)) then
f2(i,j)=th2(i,j)
else if ((th2(i,j).eq.mdv).and.(pv2(i,j).ne.mdv)) then
f2(i,j)=pv2(i,j)
else if (th2(i,j).gt.pv2(i,j)) then
f2(i,j)=th2(i,j)
else
f2(i,j)=pv2(i,j)
endif
enddo
enddo
! --------------------------------------------------------------------------------------------------
! DONE
! --------------------------------------------------------------------------------------------------
end subroutine tropopause
SUBROUTINE tropofold (label3,p3,pv3,th3,fold,dp, pmin, pmax, sfold,mfold,dfold,mdv,nx,ny,nz,tropo_pv,tropo_th)
! -------------------------------------------------------------------------------
! Part 2) Identify tropopause folds (multiple crossings of the tropopause in one column)
! -------------------------------------------------------------------------------
! Given the label field, determine whether a tropopause fold is present.
! The parameters <nx,ny,nx> characterize the grid. The missing data value is <mdv>.
implicit none
! Declaration of subroutine parameters
integer :: nx,ny,nz
real :: mdv
real :: label3(nx,ny,nz)
real :: p3(nx,ny,nz)
real :: pv3(nx,ny,nz)
real :: th3(nx,ny,nz)
real :: pre0,pre1,pre2,ok1,ok2
real :: tropo_pv,tropo_th
real :: fold(nx,ny)
real :: dp(nx,ny)
real :: pmin(nx,ny)
real :: pmax(nx,ny)
real :: sfold(nx,ny)
real :: mfold(nx,ny)
real :: dfold(nx,ny)
! Aux integers
integer :: i,j,k,l,k0,k1,k2,ncross
! Adjust fields (integer labels, absolute value of PV)
do i=1,nx
do j=1,ny
do k=1,nz
pv3(i,j,k) = abs(pv3(i,j,k))
enddo
enddo
enddo
! Definition of labels
! 1 : troposphere
! 2 : stratosphere
! 3 : stratosperic cutoff
! 4 : tropospheric cutoff
! 5 : surface-bound PV blobs
do i=1,nx
do j=1,ny
k0 = 0
k1 = 0
k2 = 0
ncross = 0
do k=nz-1,1,-1
! strat-trop transition
if ( (label3(i,j,k+1).eq.2).and.(label3(i,j,k).eq.1) ) then
ncross = ncross + 1
if ( k2.eq.0 ) then
k2 = k
elseif ( k1.ne.0 ) then
k0 = k
endif
endif
! special case for folds that are affected by the q-criterion (q<0.0001 only)
! example (top to bottom): 222211122231111 need to recognize the 2-3-1 transition
! transitions like 222222223111 should not be recognized, thus only if k2.ne.0
if ( (label3(i,j,k+1).eq.2).and.(label3(i,j,k).eq.3) ) then
ncross = ncross + 1
if (( k2.ne.0 ) .and. ( k1.ne.0 )) then
k0 = k
endif
endif
! trop-strat transition
if ( (label3(i,j,k+1).eq.1).and.(label3(i,j,k).eq.2) ) then
ncross = ncross + 1
if ( ( k2.ne.0 ).and.( k1.eq.0 ) ) then
k1 = k
endif
endif
enddo
! Skip further steps if we have a single tropopause
if ( ncross.le.2 ) goto 100
! Get the exact pressures at the crossings
pre0 = 0.
pre1 = 0.
pre2 = 0.
! lowest point (0) => pre0
ok1 = ( pv3(i,j,k0+1)-tropo_pv ) * ( pv3(i,j,k0)-tropo_pv )
ok2 = ( th3(i,j,k0+1)-tropo_th ) * ( th3(i,j,k0)-tropo_th )
if ( ok1.le.0. ) then
pre0 = p3(i,j,k0) + ( p3(i,j,k0+1) - p3(i,j,k0) ) * &
( tropo_pv - pv3(i,j,k0) )/( pv3(i,j,k0+1) - pv3(i,j,k0) )
elseif ( ok2.le.0. ) then
pre0 = p3(i,j,k0) + ( p3(i,j,k0+1) - p3(i,j,k0) ) * &
( tropo_th - th3(i,j,k0) )/( th3(i,j,k0+1) - th3(i,j,k0) )
endif
! middle point (1) => pre1
ok1 = ( pv3(i,j,k1+1)-tropo_pv ) * ( pv3(i,j,k1)-tropo_pv )
ok2 = ( th3(i,j,k1+1)-tropo_th ) * ( th3(i,j,k1)-tropo_th )
if ( ok1.le.0. ) then
pre1 = p3(i,j,k1) + ( p3(i,j,k1+1) - p3(i,j,k1) ) * &
( tropo_pv - pv3(i,j,k1) )/( pv3(i,j,k1+1) - pv3(i,j,k1) )
elseif ( ok2.le.0. ) then
pre1 = p3(i,j,k1) + ( p3(i,j,k1+1) - p3(i,j,k1) ) * &
( tropo_th - th3(i,j,k1) )/( th3(i,j,k1+1) - th3(i,j,k1) )
endif
! upper point (2) => pre2
ok1 = ( pv3(i,j,k2+1)-tropo_pv ) * ( pv3(i,j,k2)-tropo_pv )
ok2 = ( th3(i,j,k2+1)-tropo_th ) * ( th3(i,j,k2)-tropo_th )
if ( ok1.le.0. ) then
pre2 = p3(i,j,k2) + ( p3(i,j,k2+1) - p3(i,j,k2) ) * &
( tropo_pv - pv3(i,j,k2) )/( pv3(i,j,k2+1) - pv3(i,j,k2) )
elseif ( ok2.le.0. ) then
pre2 = p3(i,j,k2) + ( p3(i,j,k2+1) - p3(i,j,k2) ) * &
( tropo_th - th3(i,j,k2) )/( th3(i,j,k2+1) - th3(i,j,k2) )
endif
! Decide whether all pressure values are ok
if ( ( pre0.lt.p3(i,j,k0+1) ).or. &
( pre0.gt.p3(i,j,k0 ) ).or. &
( pre1.lt.p3(i,j,k1+1) ).or. &
( pre1.gt.p3(i,j,k1 ) ).or. &
( pre2.lt.p3(i,j,k2+1) ).or. &
( pre2.gt.p3(i,j,k2 ) ) ) goto 100
! Everything is fine: remember the fold
fold(i,j) = 1.
dp(i,j) = pre1 - pre2
pmin(i,j) = pre2
pmax(i,j) = pre0
! Exit point for loop
100 continue
enddo ! y
enddo ! x
where((fold .gt. 0.0) .and. (dp .ge. 50.0) .and. (dp .lt. 200.0))
sfold=1.0
elsewhere((fold .gt. 0.0) .and. (dp .ge. 200.0) .and. (dp .lt. 350.0))
mfold=1.0
elsewhere((fold .gt. 0.0) .and. (dp .ge. 350.0))
dfold=1.0
end where
end subroutine tropofold
! -----------------------------------------------------------
! Interpolation onto theta surface (top -> down): BOJAN: not sure you have all the interpolation subroutines used here, contact us or feel free to use any other interpolation routine that does the job :-)
! -----------------------------------------------------------
subroutine thipo_lev(var3d,th3d,lev,var,nx,ny,nz,mdv,mode)
! Interpolates the 3d variable var3d on the isentropic surface
! defined by lev. The interpolated field is returned as var.
! th3d denotes the 3d theta array.
! mode determines the way of vertical interpolation:
! mode=0 is for linear interpolation
! mode=1 is for logarithmic interpolation
integer :: nx,ny,nz,mode
real :: lev(nx,ny),mdv
real :: var3d(nx,ny,nz),th3d(nx,ny,nz),var(nx,ny)
integer :: i,j,k
real :: kind
real :: int3dm
do i=1,nx
do j=1,ny
if (lev(i,j).ne.mdv) then
kind=0.
do k=nz-1,1,-1
if ((th3d(i,j,k).le.lev(i,j)).and.(th3d(i,j,k+1).ge.lev(i,j))) then
kind=float(k)+(th3d(i,j,k)-lev(i,j))/(th3d(i,j,k)-th3d(i,j,k+1))
goto 100
endif
enddo
100 continue
if (kind.eq.0) then
var(i,j)=mdv
else
var(i,j)=int3dm(var3d,nx,ny,nz,float(i),float(j),kind,mdv)
endif
else
var(i,j)=mdv
endif
enddo
enddo
return
end subroutine thipo_lev
! -----------------------------------------------------------
! Interpolation onto theta surface (bottom -> up)
! -----------------------------------------------------------
subroutine pipo_lev(var3d,p3d,lev,var,nx,ny,nz,mdv,mode)
! Interpolates the 3d variable var3d on the pressure surface
! defined by lev. The interpolated field is returned as var.
! p3d denotes the 3d pressure array.
! mode determines the way of vertical interpolation:
! mode=0 is for linear interpolation
! mode=1 is for logarithmic interpolation
integer :: nx,ny,nz,mode
real :: lev(nx,ny),mdv
real :: var3d(nx,ny,nz),p3d(nx,ny,nz),var(nx,ny)
integer :: i,j,k
real :: kind
real :: int3dm
do i=1,nx
do j=1,ny
if (lev(i,j).ne.mdv) then
kind=0.
do k=1,nz-1
if ((p3d(i,j,k).ge.lev(i,j)).and.(p3d(i,j,k+1).le.lev(i,j))) then
kind=float(k)+(p3d(i,j,k)-lev(i,j))/(p3d(i,j,k)-p3d(i,j,k+1))
goto 100
endif
enddo
100 continue
if (kind.eq.0.) then
var(i,j)=mdv
else
var(i,j)=int3dm(var3d,nx,ny,nz,float(i),float(j),kind,mdv)
endif
else
var(i,j)=mdv
endif
enddo
enddo
return
end subroutine pipo_lev
! ------------------------------------------------------------------
! Auxiliary routines
! ------------------------------------------------------------------