/tags/1.0/LICENSE.pdf |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/pdf |
Property changes: |
Added: svn:mime-type |
+application/pdf |
\ No newline at end of property |
/tags/1.0/3d_labelling_and_fold_id.f90 |
---|
0,0 → 1,1492 |
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 |
! ------------------------------------------------------------------ |
/tags/1.0/3d_labelling_and_fold_id_20150126.zip |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/zip |
Property changes: |
Added: svn:mime-type |
+application/zip |
\ No newline at end of property |
/tags/1.0/EMAC.nml |
---|
0,0 → 1,15 |
! -*- f90 -*- |
&CTRL |
file_input = '/ptmp/andrep/ZANIS/ZANIS__________20000801_0000_fold.nc' |
file_output = 'test.nc' |
X_name = 'lon' |
Y_name = 'lat' |
Z_name = 'lev' |
T_name = 'time' |
APS_name = 'aps' |
HYAM_name = 'hyam' |
HYBM_name = 'hybm' |
Q_name = 'qm1' |
PV_name = 'PV' |
PT_name = 'tpot' |
/ |
/tags/1.0/Makefile |
---|
0,0 → 1,26 |
# -*- Makefile -*- |
# contact: Andrea Pozzer MPIC (andrea.pozzer@mpic.de) |
# ---------------------------------------------- |
export |
SHELL = sh |
# hydra intel fortran |
F90 = ifort |
#debugging |
#F90FLAGS = -autodouble -cpp -g -debug full -traceback -O3 |
#production |
F90FLAGS = -autodouble -cpp -O3 |
FC = $(F90) |
FFLAGS = $(F90FLAGS) |
NETCDF_ROOT = /ptmp/mpcdata/software/x86_64-suse-linux/netcdf/v3.6.3_i |
LIBS = -L$(NETCDF_ROOT)/lib -lnetcdf |
INCLUDES = -I$(NETCDF_ROOT)/include |
INSTALLDIR = . |
# ---------------------------------------------- |
include main.mk |
# ---------------------------------------------- |
/tags/1.0/README.txt |
---|
0,0 → 1,54 |
Tropopause folding calculator: |
(*original reference to be added*) |
original work by B.Skerlak (bojan.skerlak@env.ethz.ch) |
extended for netcdf data by A.Pozzer (andrea.pozzer@mpic.de) |
------------------------------------------------------------------ |
To use the algorithm: |
1) Extract the zip file |
2) Modify the Makefile to the current machine set-up |
3) Compile to code with the command "make". |
Other options possible with "make help". |
4) Create a namelist file (filename.nml) with the specific of the |
netcdf files to be analyzed (see EMAC.nml for example). |
5) run the code with the command "3d_labelling_and_fold_id.exe filename.nml" |
------------------------------------------------------------------- |
NML format: |
the namelist file should contain the following fields: |
------------------------------------------------------------------ |
&CTRL |
! input file (path included) |
file_input = '/ptmp/andrep/ZANIS/ZANIS__________20000801_0000_fold.nc' |
! output file (path included) |
file_output = 'test.nc' |
! name of the longitude dimension in the file |
X_name = 'lon' |
! name of the latitude dimension in the file |
Y_name = 'lat' |
! name of the level dimension in the file |
Z_name = 'lev' |
! name of the time dimension in the file |
T_name = 'time' |
! name of the surface pressure |
APS_name = 'aps' |
! name of the hybrid coefficient A |
HYAM_name = 'hyam' |
! name of the hybrid coefficient B |
HYBM_name = 'hybm' |
! name of the specific humidity field |
Q_name = 'qm1' |
! name of the potential vorticity field |
PV_name = 'PV' |
! name of the potential temperature field |
PT_name = 'tpot' |
/ |
------------------------------------------------------------------ |
WARNINGS: |
1) The code works automatically only if all the needed data (i.e. Q,PV,PT) |
are included in the same input file. |
2) Only hybrid pressure coordinates included in the pressure |
calculation. |
------------------------------------------------------------------ |
/tags/1.0/libipo.f |
---|
0,0 → 1,1368 |
real function int2d(ar,n1,n2,rid,rjd) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 2d-array to an arbitrary |
c location within the grid. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2) |
c n1,n2 int input dimensions of ar |
c ri,rj real input grid location to be interpolated to |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2 |
real ar(n1,n2), rid,rjd |
c local declarations |
integer i,j,ip1,jp1,ih,jh |
real frac0i,frac0j,frac1i,frac1j,ri,rj |
c do linear interpolation |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
ih=nint(ri) |
jh=nint(rj) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-3) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
int2d=ar(i,j) |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int2d = ar(i ,j ) * frac1i * frac1j |
& + ar(i ,jp1) * frac1i * frac0j |
& + ar(ip1,j ) * frac0i * frac1j |
& + ar(ip1,jp1) * frac0i * frac0j |
endif |
end |
real function int2dm(ar,n1,n2,rid,rjd,misdat) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 2d-array to an arbitrary |
c location within the grid. The interpolation includes the |
c testing of the missing data flag 'misdat'. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2) |
c n1,n2 int input dimensions of ar |
c ri,rj real input grid location to be interpolated to |
c misdat real input missing data flag (on if misdat<>0) |
c Warning: |
c This routine has not yet been seriously tested |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2 |
real ar(n1,n2), rid,rjd, misdat |
c local declarations |
integer i,j,ip1,jp1,ih,jh |
real frac0i,frac0j,frac1i,frac1j,ri,rj,int2d |
c check if routine without missing data checking can be called instead |
if (misdat.eq.0.) then |
int2dm=int2d(ar,n1,n2,rid,rjd) |
return |
endif |
c do linear interpolation |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
ih=nint(ri) |
jh=nint(rj) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-3) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
int2dm=ar(i,j) |
else |
if ((misdat.eq.ar(i ,j )).or. |
& (misdat.eq.ar(i ,jp1)).or. |
& (misdat.eq.ar(ip1,j )).or. |
& (misdat.eq.ar(ip1,jp1))) then |
int2dm=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int2dm = ar(i ,j ) * frac1i * frac1j |
& + ar(i ,jp1) * frac1i * frac0j |
& + ar(ip1,j ) * frac0i * frac1j |
& + ar(ip1,jp1) * frac0i * frac0j |
endif |
endif |
end |
real function int2dp(ar,n1,n2,rid,rjd) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 2d-array to an arbitrary |
c location within the grid. The 2d-array is periodic in the |
c i-direction: ar(0,.)=ar(n1,.) and ar(1,.)=ar(n1+1,.). |
c Therefore rid can take values in the range 0,...,n1+1 |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2) |
c n1,n2 int input dimensions of ar |
c ri,rj real input grid location to be interpolated to |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2 |
real ar(0:n1+1,n2), rid,rjd |
c local declarations |
integer i,j,ip1,jp1,ih,jh |
real frac0i,frac0j,frac1i,frac1j,ri,rj |
c do linear interpolation |
ri=amax1(0.,amin1(float(n1+1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
ih=nint(ri) |
jh=nint(rj) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-5) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-5) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
int2dp=ar(i,j) |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int2dp = ar(i ,j ) * frac1i * frac1j |
& + ar(i ,jp1) * frac1i * frac0j |
& + ar(ip1,j ) * frac0i * frac1j |
& + ar(ip1,jp1) * frac0i * frac0j |
endif |
end |
real function cint2d(ar,n1,n2,n3,rid,rjd,ikd) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 3d-array to an arbitrary |
c location in the horizontal. ikd specifies the level (must |
c be an integer). A bicubic method is applied (following |
c the Numerical Recipes). |
c Arguments: |
c ar real input field, define as ar(n1,n2,n3) |
c n1,n2 int input dimensions of ar |
c rid,rjd real input grid location to be interpolated to |
c ikd int input level for interpolation |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3,ikd |
real ar(n1,n2,n3), rid,rjd |
c local declarations |
integer i,j,k |
real y(4),y1(4),y2(4),y12(4) |
c indices of lower left corner of interpolation grid |
i=int(rid) |
j=int(rjd) |
k=ikd |
c do not interpolate if i or j are at the boundaries |
if ((i.eq.1).or.(j.eq.1).or.(i.eq.n1).or.(j.eq.n2)) then |
cint2d=ar(i,j,k) |
return |
endif |
c define the arrays y,y1,y2,y12 necessary for the bicubic |
c interpolation (following the Numerical Recipes). |
y(1)=ar(i,j,k) |
y(2)=ar(i+1,j,k) |
y(3)=ar(i+1,j+1,k) |
y(4)=ar(i,j+1,k) |
y1(1)=-(ar(i-1,j,k)-ar(i+1,j,k))/2. |
y1(2)=-(ar(i,j,k)-ar(i+2,j,k))/2. |
y1(3)=-(ar(i,j+1,k)-ar(i+2,j+1,k))/2. |
y1(4)=-(ar(i-1,j+1,k)-ar(i+1,j+1,k))/2. |
y2(1)=-(ar(i,j-1,k)-ar(i,j+1,k))/2. |
y2(2)=-(ar(i+1,j-1,k)-ar(i+1,j+1,k))/2. |
y2(3)=-(ar(i+1,j,k)-ar(i+1,j+2,k))/2. |
y2(4)=-(ar(i,j,k)-ar(i,j+2,k))/2. |
y12(1)=(ar(i+1,j+1,k)-ar(i+1,j-1,k)-ar(i-1,j+1,k)+ar(i-1,j-1,k))/4. |
y12(2)=(ar(i+2,j+1,k)-ar(i+2,j-1,k)-ar(i,j+1,k)+ar(i,j-1,k))/4. |
y12(3)=(ar(i+2,j+2,k)-ar(i+2,j,k)-ar(i,j+2,k)+ar(i,j,k))/4. |
y12(4)=(ar(i+1,j+2,k)-ar(i+1,j,k)-ar(i-1,j+2,k)+ar(i-1,j,k))/4. |
call bcuint(y,y1,y2,y12,i,j,rid,rjd,cint2d) |
return |
end |
real function int3d(ar,n1,n2,n3,rid,rjd,rkd) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 3d-array to an arbitrary |
c location within the grid. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,n2,n3 int input dimensions of ar |
c ri,rj,rk real input grid location to be interpolated to |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3 |
real ar(n1,n2,n3), rid,rjd,rkd |
c local declarations |
integer i,j,k,ip1,jp1,kp1,ih,jh,kh |
real frac0i,frac0j,frac0k,frac1i,frac1j,frac1k,ri,rj,rk |
c do linear interpolation |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
rk=amax1(1.,amin1(float(n3),rkd)) |
ih=nint(ri) |
jh=nint(rj) |
kh=nint(rk) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
if (abs(float(jh)-rj).lt.1.e-3) then |
j =jh |
jp1=jh |
else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
endif |
c Check for interpolation in k |
* if (abs(float(kh)-rk).lt.1.e-3) then |
* k =kh |
* kp1=kh |
* else |
k =min0(int(rk),n3-1) |
kp1=k+1 |
* endif |
if (k.eq.kp1) then |
c no interpolation in k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
int3d=ar(i,j,k) |
c print *,'int3d 00: ',rid,rjd,rkd,int3d |
else |
c horizontal interpolation only |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3d = ar(i ,j ,k ) * frac1i * frac1j |
& + ar(i ,jp1,k ) * frac1i * frac0j |
& + ar(ip1,j ,k ) * frac0i * frac1j |
& + ar(ip1,jp1,k ) * frac0i * frac0j |
c print *,'int3d 10: ',rid,rjd,rkd,int3d |
endif |
else |
frac0k=rk-float(k) |
frac1k=1.-frac0k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c vertical interpolation only |
int3d = ar(i ,j ,k ) * frac1k |
& + ar(i ,j ,kp1) * frac0k |
c print *,'int3d 01: ',rid,rjd,rkd,int3d |
else |
c full 3d interpolation |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3d = ar(i ,j ,k ) * frac1i * frac1j * frac1k |
& + ar(i ,jp1,k ) * frac1i * frac0j * frac1k |
& + ar(ip1,j ,k ) * frac0i * frac1j * frac1k |
& + ar(ip1,jp1,k ) * frac0i * frac0j * frac1k |
& + ar(i ,j ,kp1) * frac1i * frac1j * frac0k |
& + ar(i ,jp1,kp1) * frac1i * frac0j * frac0k |
& + ar(ip1,j ,kp1) * frac0i * frac1j * frac0k |
& + ar(ip1,jp1,kp1) * frac0i * frac0j * frac0k |
c print *,'int3d 11: ',rid,rjd,rkd,int3d |
endif |
endif |
end |
real function int3dm(ar,n1,n2,n3,rid,rjd,rkd,misdat) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 3d-array to an arbitrary |
c location within the grid. The interpolation includes the |
c testing of the missing data flag 'misdat'. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,n2,n3 int input dimensions of ar |
c ri,rj,rk real input grid location to be interpolated to |
c misdat real input missing data flag (on if misdat<>0) |
c Warning: |
c This routine has not yet been seriously tested |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3 |
real ar(n1,n2,n3), rid,rjd,rkd, misdat |
c local declarations |
integer i,j,k,ip1,jp1,kp1,ih,jh,kh |
real frac0i,frac0j,frac0k,frac1i,frac1j,frac1k,ri,rj,rk,int3d |
c check if routine without missing data checking can be called instead |
if (misdat.eq.0.) then |
int3dm=int3d(ar,n1,n2,n3,rid,rjd,rkd) |
return |
endif |
c do linear interpolation |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
rk=amax1(1.,amin1(float(n3),rkd)) |
ih=nint(ri) |
jh=nint(rj) |
kh=nint(rk) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-3) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
c Check for interpolation in k |
* if (abs(float(kh)-rk).lt.1.e-3) then |
* k =kh |
* kp1=kh |
* else |
k =min0(int(rk),n3-1) |
kp1=k+1 |
* endif |
if (k.eq.kp1) then |
c no interpolation in k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
if (misdat.eq.ar(i,j,k)) then |
int3dm=misdat |
else |
int3dm=ar(i,j,k) |
endif |
c print *,'int3dm 00: ',rid,rjd,rkd,int3dm |
else |
c horizontal interpolation only |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,jp1,k )).or. |
& (misdat.eq.ar(ip1,j ,k )).or. |
& (misdat.eq.ar(ip1,jp1,k ))) then |
int3dm=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dm = ar(i ,j ,k ) * frac1i * frac1j |
& + ar(i ,jp1,k ) * frac1i * frac0j |
& + ar(ip1,j ,k ) * frac0i * frac1j |
& + ar(ip1,jp1,k ) * frac0i * frac0j |
c print *,'int3dm 10: ',rid,rjd,rkd,int3dm |
endif |
endif |
else |
frac0k=rk-float(k) |
frac1k=1.-frac0k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c vertical interpolation only |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,j ,kp1))) then |
int3dm=misdat |
else |
int3dm = ar(i ,j ,k ) * frac1k |
& + ar(i ,j ,kp1) * frac0k |
c print *,'int3dm 01: ',rid,rjd,rkd,int3dm |
endif |
else |
c full 3d interpolation |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,jp1,k )).or. |
& (misdat.eq.ar(ip1,j ,k )).or. |
& (misdat.eq.ar(ip1,jp1,k )).or. |
& (misdat.eq.ar(i ,j ,kp1)).or. |
& (misdat.eq.ar(i ,jp1,kp1)).or. |
& (misdat.eq.ar(ip1,j ,kp1)).or. |
& (misdat.eq.ar(ip1,jp1,kp1))) then |
int3dm=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dm = ar(i ,j ,k ) * frac1i * frac1j * frac1k |
& + ar(i ,jp1,k ) * frac1i * frac0j * frac1k |
& + ar(ip1,j ,k ) * frac0i * frac1j * frac1k |
& + ar(ip1,jp1,k ) * frac0i * frac0j * frac1k |
& + ar(i ,j ,kp1) * frac1i * frac1j * frac0k |
& + ar(i ,jp1,kp1) * frac1i * frac0j * frac0k |
& + ar(ip1,j ,kp1) * frac0i * frac1j * frac0k |
& + ar(ip1,jp1,kp1) * frac0i * frac0j * frac0k |
c print *,'int3dm 11: ',rid,rjd,rkd,int3dm |
endif |
endif |
endif |
end |
real function int3dmlog(ar,n1,n2,n3,rid,rjd,rkd,misdat) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 3d-array to an arbitrary |
c location within the grid. The interpolation includes the |
c testing of the missing data flag 'misdat'. |
c Prior to vertical interpolations the log is taken from the array. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,n2,n3 int input dimensions of ar |
c ri,rj,rk real input grid location to be interpolated to |
c misdat real input missing data flag (on if misdat<>0) |
c Warning: |
c This routine has not yet been seriously tested |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3 |
real ar(n1,n2,n3), rid,rjd,rkd, misdat |
c local declarations |
integer i,j,k,ip1,jp1,kp1,ih,jh,kh |
real frac0i,frac0j,frac0k,frac1i,frac1j,frac1k,ri,rj,rk,int3d |
c print*,'hallo in SR int3dmlog' |
c check if routine without missing data checking can be called instead |
if (misdat.eq.0.) then |
int3dmlog=int3d(ar,n1,n2,n3,rid,rjd,rkd) |
return |
endif |
c do linear interpolation |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
rk=amax1(1.,amin1(float(n3),rkd)) |
ih=nint(ri) |
jh=nint(rj) |
kh=nint(rk) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-3) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
c Check for interpolation in k |
* if (abs(float(kh)-rk).lt.1.e-3) then |
* k =kh |
* kp1=kh |
* else |
k =min0(int(rk),n3-1) |
kp1=k+1 |
* endif |
if (k.eq.kp1) then |
c no interpolation in k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
if (misdat.eq.ar(i,j,k)) then |
int3dmlog=misdat |
else |
int3dmlog=ar(i,j,k) |
endif |
c print *,'int3dmlog 00: ',rid,rjd,rkd,int3dmlog |
else |
c horizontal interpolation only |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,jp1,k )).or. |
& (misdat.eq.ar(ip1,j ,k )).or. |
& (misdat.eq.ar(ip1,jp1,k ))) then |
int3dmlog=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dmlog = ar(i ,j ,k ) * frac1i * frac1j |
& + ar(i ,jp1,k ) * frac1i * frac0j |
& + ar(ip1,j ,k ) * frac0i * frac1j |
& + ar(ip1,jp1,k ) * frac0i * frac0j |
c print *,'int3dmlog 10: ',rid,rjd,rkd,int3dmlog |
endif |
endif |
else |
frac0k=rk-float(k) |
frac1k=1.-frac0k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c vertical interpolation only |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,j ,kp1))) then |
int3dmlog=misdat |
else |
int3dmlog = log(ar(i ,j ,k )) * frac1k |
& + log(ar(i ,j ,kp1)) * frac0k |
int3dmlog = exp(int3dmlog) |
c print *,'int3dmlog 01: ',rid,rjd,rkd,int3dmlog |
endif |
else |
c full 3d interpolation |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,jp1,k )).or. |
& (misdat.eq.ar(ip1,j ,k )).or. |
& (misdat.eq.ar(ip1,jp1,k )).or. |
& (misdat.eq.ar(i ,j ,kp1)).or. |
& (misdat.eq.ar(i ,jp1,kp1)).or. |
& (misdat.eq.ar(ip1,j ,kp1)).or. |
& (misdat.eq.ar(ip1,jp1,kp1))) then |
int3dmlog=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dmlog = log(ar(i ,j ,k )) * frac1i * frac1j * frac1k |
& + log(ar(i ,jp1,k )) * frac1i * frac0j * frac1k |
& + log(ar(ip1,j ,k )) * frac0i * frac1j * frac1k |
& + log(ar(ip1,jp1,k )) * frac0i * frac0j * frac1k |
& + log(ar(i ,j ,kp1)) * frac1i * frac1j * frac0k |
& + log(ar(i ,jp1,kp1)) * frac1i * frac0j * frac0k |
& + log(ar(ip1,j ,kp1)) * frac0i * frac1j * frac0k |
& + log(ar(ip1,jp1,kp1)) * frac0i * frac0j * frac0k |
int3dmlog = exp(int3dmlog) |
c print *,'int3dmlog 11: ',rid,rjd,rkd,int3dmlog |
endif |
endif |
endif |
end |
real function int3dmvc(ar,n1,n2,n3,rid,rjd,rkd,misdat) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 3d-array to an arbitrary |
c location within the grid. The interpolation includes the |
c testing of the missing data flag 'misdat'. |
c In the vertical a Lagrangian cubic interpolation is |
c performed. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,n2,n3 int input dimensions of ar |
c ri,rj,rk real input grid location to be interpolated to |
c misdat real input missing data flag (on if misdat<>0) |
c Warning: |
c This routine has not yet been seriously tested |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3 |
real ar(n1,n2,n3), rid,rjd,rkd, misdat |
c local declarations |
integer i,j,k,ip1,jp1,kp1,ih,jh,kh,klow,n |
real frac0i,frac0j,frac1i,frac1j,ri,rj,rk |
real int2d(4) |
real int3dm |
c if n3 < 4 then do call linear interpolation in the vertical |
if (n3.lt.4) then |
int3dmvc=int3dm(ar,n1,n2,n3,rid,rjd,rkd,misdat) |
return |
endif |
c do linear interpolation in the horizontal |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
rk=amax1(1.,amin1(float(n3),rkd)) |
ih=nint(ri) |
jh=nint(rj) |
kh=nint(rk) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-3) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
c Check for interpolation in k |
* if (abs(float(kh)-rk).lt.1.e-3) then |
* k =kh |
* kp1=kh |
* else |
k =min0(int(rk),n3-1) |
kp1=k+1 |
* endif |
if (k.eq.kp1) then |
c no interpolation in k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
int3dmvc=ar(i,j,k) |
c print *,'int3dmvc 00: ',rid,rjd,rkd,int3dmvc |
else |
c horizontal interpolation only |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,jp1,k )).or. |
& (misdat.eq.ar(ip1,j ,k )).or. |
& (misdat.eq.ar(ip1,jp1,k ))) then |
int3dmvc=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dmvc = ar(i ,j ,k ) * frac1i * frac1j |
& + ar(i ,jp1,k ) * frac1i * frac0j |
& + ar(ip1,j ,k ) * frac0i * frac1j |
& + ar(ip1,jp1,k ) * frac0i * frac0j |
c print *,'int3dmvc 10: ',rid,rjd,rkd,int3dmvc |
endif |
endif |
else |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c vertical interpolation only |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,j ,kp1))) then |
int3dmvc=misdat |
else |
if (k-1.lt.1) then |
klow=1 |
else if (k+2.gt.n3) then |
klow=n3-3 |
else |
klow=k-1 |
endif |
call cubint(ar(i,j,klow),ar(i,j,klow+1),ar(i,j,klow+2), |
& ar(i,j,klow+3),klow,rk,int3dmvc) |
endif |
else |
c full 3d interpolation |
if ((misdat.eq.ar(i ,j ,k )).or. |
& (misdat.eq.ar(i ,jp1,k )).or. |
& (misdat.eq.ar(ip1,j ,k )).or. |
& (misdat.eq.ar(ip1,jp1,k )).or. |
& (misdat.eq.ar(i ,j ,kp1)).or. |
& (misdat.eq.ar(i ,jp1,kp1)).or. |
& (misdat.eq.ar(ip1,j ,kp1)).or. |
& (misdat.eq.ar(ip1,jp1,kp1))) then |
int3dmvc=misdat |
else |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
if (k-1.lt.1) then |
klow=1 |
else if (k+2.gt.n3) then |
klow=n3-3 |
else |
klow=k-1 |
endif |
do n=1,4 |
int2d(n) = ar(i ,j ,klow-1+n ) * frac1i * frac1j |
& + ar(i ,jp1,klow-1+n ) * frac1i * frac0j |
& + ar(ip1,j ,klow-1+n ) * frac0i * frac1j |
& + ar(ip1,jp1,klow-1+n ) * frac0i * frac0j |
enddo |
call cubint(int2d(1),int2d(2),int2d(3),int2d(4), |
& klow,rk,int3dmvc) |
endif |
endif |
endif |
end |
real function int4d(ar,n1,n2,n3,n4,rid,rjd,rkd,rld) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 4d-array to an arbitrary |
c location within the grid. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,..,n4 int input dimensions of ar |
c ri,..,rl real input grid location to be interpolated to |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3,n4 |
real ar(n1,n2,n3,n4), rid,rjd,rkd,rld |
c local declarations |
integer l,lp1,lh |
real frac0l,frac1l,rl,int3d |
c do linear interpolation in l-direction |
rl=amax1(1.,amin1(float(n4),rld)) |
lh=nint(rl) |
c Check for interpolation in l |
* if (abs(float(lh)-rl).lt.1.e-3) then |
* l =lh |
* lp1=lh |
* else |
l =min0(int(rl),n4-1) |
lp1=l+1 |
* endif |
if (l.eq.lp1) then |
c no interpolation in l |
int4d=int3d(ar(1,1,1,l),n1,n2,n3,rid,rjd,rkd) |
else |
c interpolation in l |
frac0l=rl-float(l) |
frac1l=1.-frac0l |
int4d = int3d(ar(1,1,1,l ),n1,n2,n3,rid,rjd,rkd) * frac1l |
& + int3d(ar(1,1,1,lp1),n1,n2,n3,rid,rjd,rkd) * frac0l |
endif |
end |
real function int4dm(ar,n1,n2,n3,n4,rid,rjd,rkd,rld,misdat) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 4d-array to an arbitrary |
c location within the grid. The interpolation includes the |
c testing of the missing data flag 'misdat'. |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,..,n4 int input dimensions of ar |
c ri,..,rl real input grid location to be interpolated to |
c misdat real input missing data flag (on if misdat<>0) |
c Warning: |
c This routine has not yet been seriously tested. |
c History: |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3,n4 |
real ar(n1,n2,n3,n4), rid,rjd,rkd,rld, misdat |
c local declarations |
integer l,lp1,lh |
real frac0l,frac1l,rl,rint0,rint1,int4d,int3dm |
c check whether missing data checking is required |
if (misdat.eq.0.) then |
int4dm=int4d(ar,n1,n2,n3,n4,rid,rjd,rkd,rld) |
return |
endif |
c do linear interpolation in l-direction |
rl=amax1(1.,amin1(float(n4),rld)) |
lh=nint(rl) |
c Check for interpolation in l |
* if (abs(float(lh)-rl).lt.1.e-3) then |
* l =lh |
* lp1=lh |
* else |
l =min0(int(rl),n4-1) |
lp1=l+1 |
* endif |
if (l.eq.lp1) then |
c no interpolation in l |
int4dm = int3dm(ar(1,1,1,l),n1,n2,n3,rid,rjd,rkd,misdat) |
else |
c interpolation in l |
frac0l=rl-float(l) |
frac1l=1.-frac0l |
rint0 = int3dm(ar(1,1,1,l ),n1,n2,n3,rid,rjd,rkd,misdat) |
rint1 = int3dm(ar(1,1,1,lp1),n1,n2,n3,rid,rjd,rkd,misdat) |
if ((rint0.eq.misdat).or.(rint1.eq.misdat)) then |
int4dm = misdat |
else |
int4dm = rint0*frac1l + rint1*frac0l |
endif |
endif |
end |
real function int3dl(ar,n1,n2,n3,levels,rid,rjd,rkd) |
c----------------------------------------------------------------------- |
c Purpose: |
c This subroutine interpolates a 3d-array to an arbitrary |
c location within the grid. The vertical interpolation is linear |
c in log(pressure). |
c Arguments: |
c ar real input surface pressure, define as ar(n1,n2,n3) |
c n1,n2,n3 int input dimensions of ar |
c levels real input array contains pressure levels for ar |
c ri,rj,rk real input grid location to be interpolated to |
c History: |
c Based on int3d July 93 |
c----------------------------------------------------------------------- |
c argument declarations |
integer n1,n2,n3 |
real ar(n1,n2,n3), rid,rjd,rkd |
real levels(n3) |
c local declarations |
real pval |
integer i,j,k,ip1,jp1,kp1,ih,jh,kh |
real frac0i,frac0j,frac0k,frac1i,frac1j,frac1k,ri,rj,rk |
c do linear interpolation |
ri=amax1(1.,amin1(float(n1),rid)) |
rj=amax1(1.,amin1(float(n2),rjd)) |
rk=amax1(1.,amin1(float(n3),rkd)) |
ih=nint(ri) |
jh=nint(rj) |
kh=nint(rk) |
c Check for interpolation in i |
* if (abs(float(ih)-ri).lt.1.e-3) then |
* i =ih |
* ip1=ih |
* else |
i =min0(int(ri),n1-1) |
ip1=i+1 |
* endif |
c Check for interpolation in j |
* if (abs(float(jh)-rj).lt.1.e-3) then |
* j =jh |
* jp1=jh |
* else |
j =min0(int(rj),n2-1) |
jp1=j+1 |
* endif |
c Check for interpolation in k |
* if (abs(float(kh)-rk).lt.1.e-3) then |
* k =kh |
* kp1=kh |
* else |
k =min0(int(rk),n3-1) |
kp1=k+1 |
* endif |
if (k.eq.kp1) then |
c no interpolation in k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c no interpolation at all |
int3dl=ar(i,j,k) |
c print *,'int3dl 00: ',rid,rjd,rkd,int3dl |
else |
c horizontal interpolation only |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dl = ar(i ,j ,k ) * frac1i * frac1j |
& + ar(i ,jp1,k ) * frac1i * frac0j |
& + ar(ip1,j ,k ) * frac0i * frac1j |
& + ar(ip1,jp1,k ) * frac0i * frac0j |
c print *,'int3dl 10: ',rid,rjd,rkd,int3dl |
endif |
else |
* frac0k=rk-float(k) |
c calculate the pressure value to be interpolated to |
pval=levels(int(rk)) |
> -(rk-aint(rk))*(levels(int(rk))-levels(int(rk)+1)) |
frac0k=log(levels(int(rk))/pval) |
& /log(levels(int(rk))/levels(int(rk)+1)) |
frac1k=1.-frac0k |
if ((i.eq.ip1).and.(j.eq.jp1)) then |
c vertical interpolation only |
int3dl = ar(i ,j ,k ) * frac1k |
& + ar(i ,j ,kp1) * frac0k |
c print *,'int3dl 01: ',rid,rjd,rkd,int3dl |
else |
c full 3d interpolation |
frac0i=ri-float(i) |
frac0j=rj-float(j) |
frac1i=1.-frac0i |
frac1j=1.-frac0j |
int3dl = ar(i ,j ,k ) * frac1i * frac1j * frac1k |
& + ar(i ,jp1,k ) * frac1i * frac0j * frac1k |
& + ar(ip1,j ,k ) * frac0i * frac1j * frac1k |
& + ar(ip1,jp1,k ) * frac0i * frac0j * frac1k |
& + ar(i ,j ,kp1) * frac1i * frac1j * frac0k |
& + ar(i ,jp1,kp1) * frac1i * frac0j * frac0k |
& + ar(ip1,j ,kp1) * frac0i * frac1j * frac0k |
& + ar(ip1,jp1,kp1) * frac0i * frac0j * frac0k |
c print *,'int3dl 11: ',rid,rjd,rkd,int3dl |
endif |
endif |
end |
subroutine bcucof(y,y1,y2,y12,c) |
c----------------------------------------------------------------------- |
c Given arrays y,y1,y2 and y12, each of length 4, containing the |
c function, gradients, and cross derivative at the four grid points |
c of a rectangular grid cell (numbered counterclockwise from the |
c lower left), and given d1 and d2, the length of the grid cell in |
c the 1- and 2-directions, this routine returns the table c that is |
c used by routine bcuint for biqubic interpolation. |
c Source: Numerical Recipes, Fortran Version, p.99 |
c----------------------------------------------------------------------- |
real c(4,4),y(4),y1(4),y2(4),y12(4),cl(16),x(16) |
integer wt(16,16) |
data wt/1,0,-3,2,4*0,-3,0,9,-6,2,0,-6,4, |
> 8*0,3,0,-9,6,-2,0,6,-4, |
> 10*0,9,-6,2*0,-6,4,2*0,3,-2,6*0,-9,6,2*0,6,-4, |
> 4*0,1,0,-3,2,-2,0,6,-4,1,0,-3,2,8*0,-1,0,3,-2,1,0,-3,2, |
> 10*0,-3,2,2*0,3,-2,6*0,3,-2,2*0,-6,4,2*0,3,-2, |
> 0,1,-2,1,5*0,-3,6,-3,0,2,-4,2,9*0,3,-6,3,0,-2,4,-2, |
> 10*0,-3,3,2*0,2,-2,2*0,-1,1,6*0,3,-3,2*0,-2,2, |
> 5*0,1,-2,1,0,-2,4,-2,0,1,-2,1,9*0,-1,2,-1,0,1,-2,1, |
> 10*0,1,-1,2*0,-1,1,6*0,-1,1,2*0,2,-2,2*0,-1,1/ |
real xx |
integer i,j,k,l |
do i=1,4 ! pack a temporary vector x |
x(i)=y(i) |
x(i+4)=y1(i) |
x(i+8)=y2(i) |
x(i+12)=y12(i) |
enddo |
do i=1,16 ! matrix multiply by the stored table |
xx=0. |
do k=1,16 |
xx=xx+wt(i,k)*x(k) |
enddo |
cl(i)=xx |
enddo |
l=0 |
do i=1,4 ! unpack the result into the output table |
do j=1,4 |
l=l+1 |
c(i,j)=cl(l) |
enddo |
enddo |
return |
end |
subroutine bcuint(y,y1,y2,y12,x1l,x2l,x1,x2,ansy) |
c----------------------------------------------------------------------- |
c Bicubic interpolation within a grid square. Input quantities are |
c y,y1,y2,y12 (as described in bcucof); x1l and x1u, the lower and |
c upper coordinates of the grid square in the 1-direction; x2l and |
c x2u likewise for the 2-direction; and x1,x2, the coordinates of |
c the desired point for the interpolation. The interplated function |
c value is returned as ansy. This routine calls bcucof. |
c Source: Numerical Recipes, Fortran Version, p.99/100 |
c !!! changed the proposed code !!! |
c----------------------------------------------------------------------- |
real y(4),y1(4),y2(4),y12(4),c(4,4) |
real ansy,x1,x2,t,u |
integer i,x1l,x2l |
call bcucof(y,y1,y2,y12,c) |
t=x1-real(x1l) |
u=x2-real(x2l) |
ansy=0. |
do i=4,1,-1 |
ansy=t*ansy+((c(i,4)*u+c(i,3))*u+c(i,2))*u+c(i,1) |
enddo |
return |
end |
subroutine cubint(ya1,ya2,ya3,ya4,k,x,y) |
c----------------------------------------------------------------------- |
c Interface routine for SR polint for special case of cubic |
c interpolation in index space, with xa=k,k+1,k+2,k+3 |
c----------------------------------------------------------------------- |
integer k |
real ya1,ya2,ya3,ya4,x,y |
integer n |
real xa(4),ya(4),dy |
do n=1,4 |
xa(1)=real(k) |
xa(2)=real(k+1) |
xa(3)=real(k+2) |
xa(4)=real(k+3) |
ya(1)=ya1 |
ya(2)=ya2 |
ya(3)=ya3 |
ya(4)=ya4 |
enddo |
call polint(xa,ya,4,x,y,dy) |
return |
end |
subroutine polint(xa,ya,n,x,y,dy) |
c----------------------------------------------------------------------- |
c Given arrays xa and ya, each of length n, and given a value x, this |
c routine returns a value y, and an error estimate dy. If P(x) is the |
c polynomial of degree n-1 such that p(xa(i))=ya(i),i=1,...,n, then |
c the returned value y=p(x) |
c Source: Numerical Recipes, Fortran Version, p.82 |
c----------------------------------------------------------------------- |
integer nmax,n |
parameter(nmax=10) |
real xa(n),ya(n),x,y,dy |
integer i,m,ns |
real c(nmax),d(nmax),den,dif,dift,ho,hp,w |
ns=1 |
dif=abs(x-xa(1)) |
do i=1,n |
dift=abs(x-xa(i)) |
if (dift.lt.dif) then |
ns=i |
dif=dift |
endif |
c(i)=ya(i) |
d(i)=ya(i) |
enddo |
y=ya(ns) |
ns=ns-1 |
do m=1,n-1 |
do i=1,n-m |
ho=xa(i)-x |
hp=xa(i+m)-x |
w=c(i+1)-d(i) |
den=ho-hp |
den=w/den |
d(i)=hp*den |
c(i)=ho*den |
enddo |
if (2*ns.lt.n-m) then |
dy=c(ns+1) |
else |
dy=d(ns) |
ns=ns-1 |
endif |
y=y+dy |
enddo |
return |
end |
subroutine filt2d (a,af,f1,f2,nx,ny,fil,misdat, |
& iperx,ipery,ispol,inpol) |
c ============================================================= |
c Apply a conservative diffusion operator onto the 2d field a, |
c with full missing data checking. |
c |
c a real inp array to be filtered, dimensioned (nx,ny) |
c af real out filtered array, dimensioned (nx,ny), can be |
c equivalenced with array a in the calling routine |
c f1 real workarray, dimensioned (nx+1,ny) |
c f2 real workarray, dimensioned (nx,ny+1) |
c fil real inp filter-coeff., 0<afil<=1. Maximum filtering with afil=1 |
c corresponds to one application of the linear filter. |
c misdat real inp missing-data value, a(i,j)=misdat indicates that |
c the corresponding value is not available. The |
c misdat-checking can be switched off with with misdat=0. |
c iperx int inp periodic boundaries in the x-direction (1=yes,0=no) |
c ipery int inp periodic boundaries in the y-direction (1=yes,0=no) |
c inpol int inp northpole at j=ny (1=yes,0=no) |
c ispol int inp southpole at j=1 (1=yes,0=no) |
c |
c Christoph Schaer, 1993 |
c argument declaration |
integer nx,ny |
real a(nx,ny),af(nx,ny),f1(nx+1,ny),f2(nx,ny+1),fil,misdat |
integer iperx,ipery,inpol,ispol |
c local variable declaration |
integer i,j,is |
real fh |
c compute constant fh |
fh=0.125*fil |
c compute fluxes in x-direction |
if (misdat.eq.0.) then |
do j=1,ny |
do i=2,nx |
f1(i,j)=a(i-1,j)-a(i,j) |
enddo |
enddo |
else |
do j=1,ny |
do i=2,nx |
if ((a(i,j).eq.misdat).or.(a(i-1,j).eq.misdat)) then |
f1(i,j)=0. |
else |
f1(i,j)=a(i-1,j)-a(i,j) |
endif |
enddo |
enddo |
endif |
if (iperx.eq.1) then |
c do periodic boundaries in the x-direction |
do j=1,ny |
f1(1,j)=f1(nx,j) |
f1(nx+1,j)=f1(2,j) |
enddo |
else |
c set boundary-fluxes to zero |
do j=1,ny |
f1(1,j)=0. |
f1(nx+1,j)=0. |
enddo |
endif |
c compute fluxes in y-direction |
if (misdat.eq.0.) then |
do j=2,ny |
do i=1,nx |
f2(i,j)=a(i,j-1)-a(i,j) |
enddo |
enddo |
else |
do j=2,ny |
do i=1,nx |
if ((a(i,j).eq.misdat).or.(a(i,j-1).eq.misdat)) then |
f2(i,j)=0. |
else |
f2(i,j)=a(i,j-1)-a(i,j) |
endif |
enddo |
enddo |
endif |
c set boundary-fluxes to zero |
do i=1,nx |
f2(i,1)=0. |
f2(i,ny+1)=0. |
enddo |
if (ipery.eq.1) then |
c do periodic boundaries in the x-direction |
do i=1,nx |
f2(i,1)=f2(i,ny) |
f2(i,ny+1)=f2(i,2) |
enddo |
endif |
if (iperx.eq.1) then |
if (ispol.eq.1) then |
c do south-pole |
is=(nx-1)/2 |
do i=1,nx |
f2(i,1)=-f2(mod(i-1+is,nx)+1,2) |
enddo |
endif |
if (inpol.eq.1) then |
c do north-pole |
is=(nx-1)/2 |
do i=1,nx |
f2(i,ny+1)=-f2(mod(i-1+is,nx)+1,ny) |
enddo |
endif |
endif |
c compute flux-convergence -> filter |
if (misdat.eq.0.) then |
do j=1,ny |
do i=1,nx |
af(i,j)=a(i,j)+fh*(f1(i,j)-f1(i+1,j)+f2(i,j)-f2(i,j+1)) |
enddo |
enddo |
else |
do j=1,ny |
do i=1,nx |
if (a(i,j).eq.misdat) then |
af(i,j)=misdat |
else |
af(i,j)=a(i,j)+fh*(f1(i,j)-f1(i+1,j)+f2(i,j)-f2(i,j+1)) |
endif |
enddo |
enddo |
endif |
end |
subroutine pipo(var3d,p3d,lev,var,nx,ny,nz,mdv,mode) |
C ==================================================== |
C Interpolates the 3d variable var3d on the pressure surface |
C defined by lev. The interpolated field is returned as var. |
C p3d denotes the 3d pressure array. |
C mode determines the way of vertical interpolation: |
C mode=0 is for linear interpolation |
C mode=1 is for logarithmic interpolation |
integer nx,ny,nz,mode |
real lev,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 |
kind=0. |
do k=1,nz-1 |
if ((p3d(i,j,k).ge.lev).and.(p3d(i,j,k+1).le.lev)) then |
kind=float(k)+(p3d(i,j,k)-lev)/ |
> (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 |
enddo |
enddo |
return |
end |
subroutine thipo(var3d,th3d,lev,var,nx,ny,nz,mdv,mode) |
C ====================================================== |
C Interpolates the 3d variable var3d on the isentropic surface |
C defined by lev. The interpolated field is returned as var. |
C th3d denotes the 3d theta array. |
C mode determines the way of vertical interpolation: |
C mode=0 is for linear interpolation |
C mode=1 is for logarithmic interpolation |
integer nx,ny,nz,mode |
real lev,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 |
kind=0 |
do k=1,nz-1 |
if ((th3d(i,j,k).le.lev).and.(th3d(i,j,k+1).ge.lev)) then |
kind=float(k)+(th3d(i,j,k)-lev)/ |
> (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 |
enddo |
enddo |
return |
end |
/tags/1.0/main.mk |
---|
0,0 → 1,56 |
### name of the executable that will be produced |
PROG = $(INSTALLDIR)/3d_labelling_and_fold_id.exe |
DATE=$(shell date +"%Y%m%d") |
# complete list of all f90 source files |
SRCS = mo_f2kcli.f90 netcdf_tools.f90 libipo.f 3d_labelling_and_fold_id.f90 |
# -------------------------------------------------------------------- |
OBJS = mo_f2kcli.o netcdf_tools.o libipo.o 3d_labelling_and_fold_id.o |
all: $(PROG) |
$(PROG): $(OBJS) |
$(F90) $(F90FLAGS) $(OBJS) $(LIBS) -o $@ |
list: |
@echo "------------------------------------------------" |
@echo "SRCS = $(SRCS)" |
@echo "------------------------------------------------" |
@echo |
@echo "------------------------------------------------" |
@echo "OBJS = $(OBJS)" |
@echo "------------------------------------------------" |
zip: |
zip -r 3d_labelling_and_fold_id_$(DATE).zip * |
clean: |
rm -f *.mod |
rm -f *.o |
distclean: clean |
rm -f $(PROG) |
help: |
@echo '' |
@echo ' posible make targets:' |
@echo ' -------------------------------------------------------' |
@echo ' make : build all' |
@echo ' make all : (= make)' |
@echo '' |
@echo ' make clean : delete libs/mod/obj' |
@echo ' gmake distclean : clean up distribution' |
@echo '' |
@echo ' gmake zip : zip source-code' |
@echo ' -------------------------------------------------------' |
@echo '' |
%.o: %.f90 |
$(F90) $(F90FLAGS) $(LIBS) $(INCLUDES) -c $< |
%.o: %.f |
$(FC) $(FFLAGS) $(LIBS) $(INCLUDES) -c $< |
## ------------------------------------------------------------------ |
/tags/1.0/mo_f2kcli.f90 |
---|
0,0 → 1,205 |
! F2KCLI : Fortran 200x Command Line Interface |
! copyright Interactive Software Services Ltd. 2001 |
! For conditions of use see manual.txt |
! |
! Platform : Unix/Linux |
! Compiler : Any Fortran 9x compiler supporting IARGC/GETARG |
! which counts the first true command line argument |
! after the program name as argument number one. |
! (Excludes compilers which require a special USE |
! statement to make IARGC/GETARG available). |
! To compile : f90 -c f2kcli.f90 |
! (exact compiler name will vary) |
! Implementer : Lawson B. Wakefield, I.S.S. Ltd. |
! Date : February 2001 |
! |
MODULE MO_F2KCLI |
#if defined (NAG) |
USE f90_unix |
!#else |
! EXTERNAL :: GETARG, IARG, IARGC |
#endif |
! INTRINSIC :: LEN_TRIM, PRESENT, LEN |
! PRIVATE :: LEN_TRIM, PRESENT, LEN |
! INTEGER :: IARGC |
! |
CONTAINS |
! |
SUBROUTINE GET_COMMAND(COMMAND,LENGTH,STATUS) |
! |
! Description. Returns the entire command by which the program was |
! invoked. |
! |
! Class. Subroutine. |
! |
! Arguments. |
! COMMAND (optional) shall be scalar and of type default character. |
! It is an INTENT(OUT) argument. It is assigned the entire command |
! by which the program was invoked. If the command cannot be |
! determined, COMMAND is assigned all blanks. |
! LENGTH (optional) shall be scalar and of type default integer. It is |
! an INTENT(OUT) argument. It is assigned the significant length |
! of the command by which the program was invoked. The significant |
! length may include trailing blanks if the processor allows commands |
! with significant trailing blanks. This length does not consider any |
! possible truncation or padding in assigning the command to the |
! COMMAND argument; in fact the COMMAND argument need not even be |
! present. If the command length cannot be determined, a length of |
! 0 is assigned. |
! STATUS (optional) shall be scalar and of type default integer. It is |
! an INTENT(OUT) argument. It is assigned the value 0 if the |
! command retrieval is sucessful. It is assigned a processor-dependent |
! non-zero value if the command retrieval fails. |
! |
CHARACTER(LEN=*), INTENT(OUT), OPTIONAL :: COMMAND |
INTEGER , INTENT(OUT), OPTIONAL :: LENGTH |
INTEGER , INTENT(OUT), OPTIONAL :: STATUS |
! |
INTEGER :: IARG,NARG,IPOS |
INTEGER , SAVE :: LENARG |
CHARACTER(LEN=2000), SAVE :: ARGSTR |
LOGICAL , SAVE :: GETCMD = .TRUE. |
! |
! Under Unix we must reconstruct the command line from its constituent |
! parts. This will not be the original command line. Rather it will be |
! the expanded command line as generated by the shell. |
! |
IF (GETCMD) THEN |
NARG = IARGC() |
IF (NARG > 0) THEN |
IPOS = 1 |
DO IARG = 1,NARG |
CALL GETARG(IARG,ARGSTR(IPOS:)) |
LENARG = LEN_TRIM(ARGSTR) |
IPOS = LENARG + 2 |
IF (IPOS > LEN(ARGSTR)) EXIT |
END DO |
ELSE |
ARGSTR = ' ' |
LENARG = 0 |
ENDIF |
GETCMD = .FALSE. |
ENDIF |
IF (PRESENT(COMMAND)) COMMAND = ARGSTR |
IF (PRESENT(LENGTH)) LENGTH = LENARG |
IF (PRESENT(STATUS)) STATUS = 0 |
RETURN |
END SUBROUTINE GET_COMMAND |
! |
INTEGER FUNCTION COMMAND_ARGUMENT_COUNT() |
! |
! Description. Returns the number of command arguments. |
! |
! Class. Inquiry function |
! |
! Arguments. None. |
! |
! Result Characteristics. Scalar default integer. |
! |
! Result Value. The result value is equal to the number of command |
! arguments available. If there are no command arguments available |
! or if the processor does not support command arguments, then |
! the result value is 0. If the processor has a concept of a command |
! name, the command name does not count as one of the command |
! arguments. |
! |
COMMAND_ARGUMENT_COUNT = IARGC() |
RETURN |
END FUNCTION COMMAND_ARGUMENT_COUNT |
! |
SUBROUTINE GET_COMMAND_ARGUMENT(NUMBER,VALUE,LENGTH,STATUS) |
! |
! Description. Returns a command argument. |
! |
! Class. Subroutine. |
! |
! Arguments. |
! NUMBER shall be scalar and of type default integer. It is an |
! INTENT(IN) argument. It specifies the number of the command |
! argument that the other arguments give information about. Useful |
! values of NUMBER are those between 0 and the argument count |
! returned by the COMMAND_ARGUMENT_COUNT intrinsic. |
! Other values are allowed, but will result in error status return |
! (see below). Command argument 0 is defined to be the command |
! name by which the program was invoked if the processor has such |
! a concept. It is allowed to call the GET_COMMAND_ARGUMENT |
! procedure for command argument number 0, even if the processor |
! does not define command names or other command arguments. |
! The remaining command arguments are numbered consecutively from |
! 1 to the argument count in an order determined by the processor. |
! VALUE (optional) shall be scalar and of type default character. |
! It is an INTENT(OUT) argument. It is assigned the value of the |
! command argument specified by NUMBER. If the command argument value |
! cannot be determined, VALUE is assigned all blanks. |
! LENGTH (optional) shall be scalar and of type default integer. |
! It is an INTENT(OUT) argument. It is assigned the significant length |
! of the command argument specified by NUMBER. The significant |
! length may include trailing blanks if the processor allows command |
! arguments with significant trailing blanks. This length does not |
! consider any possible truncation or padding in assigning the |
! command argument value to the VALUE argument; in fact the |
! VALUE argument need not even be present. If the command |
! argument length cannot be determined, a length of 0 is assigned. |
! STATUS (optional) shall be scalar and of type default integer. |
! It is an INTENT(OUT) argument. It is assigned the value 0 if |
! the argument retrieval is sucessful. It is assigned a |
! processor-dependent non-zero value if the argument retrieval fails. |
! |
! NOTE |
! One possible reason for failure is that NUMBER is negative or |
! greater than COMMAND_ARGUMENT_COUNT(). |
! |
INTEGER , INTENT(IN) :: NUMBER |
CHARACTER(LEN=*), INTENT(OUT), OPTIONAL :: VALUE |
INTEGER , INTENT(OUT), OPTIONAL :: LENGTH |
INTEGER , INTENT(OUT), OPTIONAL :: STATUS |
! |
! A temporary variable for the rare case case where LENGTH is |
! specified but VALUE is not. An arbitrary maximum argument length |
! of 1000 characters should cover virtually all situations. |
! |
CHARACTER(LEN=1000) :: TMPVAL |
! |
! Possible error codes: |
! 1 = Argument number is less than minimum |
! 2 = Argument number exceeds maximum |
! |
IF (NUMBER < 0) THEN |
IF (PRESENT(VALUE )) VALUE = ' ' |
IF (PRESENT(LENGTH)) LENGTH = 0 |
IF (PRESENT(STATUS)) STATUS = 1 |
RETURN |
ELSE IF (NUMBER > IARGC()) THEN |
IF (PRESENT(VALUE )) VALUE = ' ' |
IF (PRESENT(LENGTH)) LENGTH = 0 |
IF (PRESENT(STATUS)) STATUS = 2 |
RETURN |
END IF |
! |
! Get the argument if VALUE is present |
! |
IF (PRESENT(VALUE)) CALL GETARG(NUMBER,VALUE) |
! |
! The LENGTH option is fairly pointless under Unix. |
! Trailing spaces can only be specified using quotes. |
! Since the command line has already been processed by the |
! shell before the application sees it, we have no way of |
! knowing the true length of any quoted arguments. LEN_TRIM |
! is used to ensure at least some sort of meaningful result. |
! |
IF (PRESENT(LENGTH)) THEN |
IF (PRESENT(VALUE)) THEN |
LENGTH = LEN_TRIM(VALUE) |
ELSE |
CALL GETARG(NUMBER,TMPVAL) |
LENGTH = LEN_TRIM(TMPVAL) |
END IF |
END IF |
! |
! Since GETARG does not return a result code, assume success |
! |
IF (PRESENT(STATUS)) STATUS = 0 |
RETURN |
END SUBROUTINE GET_COMMAND_ARGUMENT |
! |
END MODULE MO_F2KCLI |
/tags/1.0/netcdf_tools.f90 |
---|
0,0 → 1,654 |
module netcdf_tools |
USE netcdf |
implicit none |
INTRINSIC :: TRIM, ADJUSTL, NINT, SIZE |
interface read_file |
module procedure read_file_1d |
module procedure read_file_2d |
module procedure read_file_3d |
module procedure read_file_4d |
end interface |
contains |
SUBROUTINE inquire_file(fname, & |
x_name, y_name, z_name,t_name, & |
nx, ny, nz, nt) |
IMPLICIT NONE |
! I/O |
CHARACTER(LEN=*), INTENT(IN) :: fname ! filename |
CHARACTER(LEN=*), INTENT(IN) :: x_name ! name of dimension in file dimension |
CHARACTER(LEN=*), INTENT(IN) :: y_name ! name of dimension in file dimension |
CHARACTER(LEN=*), INTENT(IN) :: z_name ! name of dimension in file dimension |
CHARACTER(LEN=*), INTENT(IN) :: t_name ! name of dimension in file dimension |
INTEGER, INTENT(OUT) :: nx ! file dimension lenght |
INTEGER, INTENT(OUT) :: ny ! file dimension length |
INTEGER, INTENT(OUT) :: nz ! file dimension length |
INTEGER, INTENT(OUT) :: nt ! file dimension length |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'inquire_file' |
INTEGER,SAVE :: ncid ! netCDF-ID |
INTEGER :: dimid, varid |
LOGICAL :: file_exists ! checking existence of file |
INTEGER, DIMENSION(:), ALLOCATABLE :: date_file |
CHARACTER(LEN=30) :: name_dim ! line |
INQUIRE(FILE=TRIM(fname), EXIST=file_exists) |
IF (.not.file_exists) THEN |
WRITE(*,*) 'File ',TRIM(fname),' does NOT exist! skipping....' |
STOP |
ENDIF |
! OPEN FILE |
CALL NFERR( status, & |
nf90_open(TRIM(fname), NF90_NOWRITE, ncid) & |
,1) |
! latitude dimension check |
CALL NFERR( status, & |
nf90_inq_dimid(ncid, x_name, dimid ) & |
,2) |
CALL NFERR( status, & |
nf90_Inquire_Dimension(ncid, dimid, name_dim, nx ) & |
,3) |
! longitude dimension check |
CALL NFERR( status, & |
nf90_inq_dimid(ncid, y_name, dimid ) & |
,4) |
CALL NFERR( status, & |
nf90_Inquire_Dimension(ncid, dimid, name_dim, ny ) & |
,5) |
! vertical dimension check |
CALL NFERR( status, & |
nf90_inq_dimid(ncid, z_name, dimid ) & |
,6) |
CALL NFERR( status, & |
nf90_Inquire_Dimension(ncid, dimid, name_dim, nz ) & |
,7) |
! time dimension check |
CALL NFERR( status, & |
nf90_inq_dimid(ncid, t_name, dimid ) & |
,8) |
CALL NFERR( status, & |
nf90_Inquire_Dimension(ncid, dimid, name_dim, nt ) & |
,9) |
!CLOSE FILE |
CALL NFERR( status, & |
nf90_close(ncid) & |
,14) |
! RETURN |
status = 0 |
END SUBROUTINE inquire_file |
! ------------------------------------------------------------------ |
! ------------------------------------------------------------------------ |
SUBROUTINE read_file_1D(fname, varname, data_file) |
IMPLICIT NONE |
! I/O |
CHARACTER(LEN=*), INTENT(IN) :: fname ! filename |
CHARACTER(LEN=*), INTENT(IN) :: varname ! variable name |
REAL, DIMENSION(:), INTENT(OUT):: data_file ! INTENT(OUT) |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'read_file_1d' |
INTEGER,SAVE :: ncid ! netCDF-ID |
INTEGER :: dimid, varid |
! OPEN FILE |
CALL NFERR( status, & |
nf90_open(TRIM(fname), NF90_NOWRITE, ncid) & |
,21) |
CALL NFERR( status, & |
nf90_inq_varid(ncid, TRIM(varname), varid ) & |
,22) |
IF (status.ne.0) then |
write(*,*) "variable not found in NetCDF file, skipping" |
STOP |
ENDIF |
CALL NFERR( status, & |
nf90_get_var(ncid, varid, data_file ) & |
,23) |
!CLOSE FILE |
CALL NFERR( status, & |
nf90_close(ncid) & |
,24) |
! RETURN |
status = 0 |
END SUBROUTINE read_file_1D |
! ------------------------------------------------------------------------ |
! ------------------------------------------------------------------------ |
SUBROUTINE read_file_2D(fname, varname, data_file) |
IMPLICIT NONE |
! I/O |
CHARACTER(LEN=*), INTENT(IN) :: fname ! filename |
CHARACTER(LEN=*), INTENT(IN) :: varname ! variable name |
REAL, DIMENSION(:,:), INTENT(OUT):: data_file ! INTENT(OUT) |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'read_file_2d' |
INTEGER,SAVE :: ncid ! netCDF-ID |
INTEGER :: dimid, varid |
! OPEN FILE |
CALL NFERR( status, & |
nf90_open(TRIM(fname), NF90_NOWRITE, ncid) & |
,21) |
CALL NFERR( status, & |
nf90_inq_varid(ncid, TRIM(varname), varid ) & |
,22) |
IF (status.ne.0) then |
write(*,*) "variable not found in NetCDF file, skipping" |
STOP |
ENDIF |
CALL NFERR( status, & |
nf90_get_var(ncid, varid, data_file ) & |
,23) |
!CLOSE FILE |
CALL NFERR( status, & |
nf90_close(ncid) & |
,24) |
! RETURN |
status = 0 |
END SUBROUTINE read_file_2D |
! ------------------------------------------------------------------------ |
! ------------------------------------------------------------------------ |
SUBROUTINE read_file_3D(fname, varname, data_file) |
IMPLICIT NONE |
! I/O |
CHARACTER(LEN=*), INTENT(IN) :: fname ! filename |
CHARACTER(LEN=*), INTENT(IN) :: varname ! variable name |
REAL, DIMENSION(:,:,:), INTENT(OUT):: data_file ! INTENT(OUT) |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'read_file_3d' |
INTEGER,SAVE :: ncid ! netCDF-ID |
INTEGER :: dimid, varid |
! OPEN FILE |
CALL NFERR( status, & |
nf90_open(TRIM(fname), NF90_NOWRITE, ncid) & |
,21) |
CALL NFERR( status, & |
nf90_inq_varid(ncid, TRIM(varname), varid ) & |
,22) |
IF (status.ne.0) then |
write(*,*) "variable not found in NetCDF file, skipping" |
STOP |
ENDIF |
CALL NFERR( status, & |
nf90_get_var(ncid, varid, data_file ) & |
,23) |
!CLOSE FILE |
CALL NFERR( status, & |
nf90_close(ncid) & |
,24) |
! RETURN |
status = 0 |
END SUBROUTINE read_file_3D |
! ------------------------------------------------------------------------ |
! ------------------------------------------------------------------------ |
SUBROUTINE read_file_4D(fname, varname, data_file) |
IMPLICIT NONE |
! I/O |
CHARACTER(LEN=*), INTENT(IN) :: fname ! filename |
CHARACTER(LEN=*), INTENT(IN) :: varname ! variable name |
REAL, DIMENSION(:,:,:,:), INTENT(OUT):: data_file ! INTENT(OUT) |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'read_file_4d' |
INTEGER,SAVE :: ncid ! netCDF-ID |
INTEGER :: dimid, varid |
! OPEN FILE |
CALL NFERR( status, & |
nf90_open(TRIM(fname), NF90_NOWRITE, ncid) & |
,21) |
CALL NFERR( status, & |
nf90_inq_varid(ncid, TRIM(varname), varid ) & |
,22) |
IF (status.ne.0) then |
write(*,*) "variable not found in NetCDF file, skipping" |
STOP |
ENDIF |
CALL NFERR( status, & |
nf90_get_var(ncid, varid, data_file ) & |
,23) |
!CLOSE FILE |
CALL NFERR( status, & |
nf90_close(ncid) & |
,24) |
! RETURN |
status = 0 |
END SUBROUTINE read_file_4D |
! ------------------------------------------------------------------------ |
! ------------------------------------------------------------------------ |
SUBROUTINE read_att(fname, varname, attname, str) |
IMPLICIT NONE |
! I/O |
CHARACTER(LEN=*), INTENT(IN) :: fname ! filename |
CHARACTER(LEN=*), INTENT(IN) :: varname ! variable name |
CHARACTER(LEN=*), INTENT(IN) :: attname ! attribute name |
CHARACTER(LEN=*), INTENT(OUT) :: str ! date string |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'read_startdate' |
INTEGER,SAVE :: ncid ! netCDF-ID |
INTEGER :: dimid, varid |
! OPEN FILE |
CALL NFERR( status, & |
nf90_open(TRIM(fname), NF90_NOWRITE, ncid) & |
,21) |
CALL NFERR( status, & |
nf90_inq_varid(ncid, TRIM(varname), varid ) & |
,22) |
IF (status.ne.0) then |
write(*,*) "variable not found in NetCDF file, skipping" |
STOP |
ENDIF |
CALL NFERR( status, & |
nf90_get_att(ncid, varid, TRIM(attname), str ) & |
,23) |
!CLOSE FILE |
CALL NFERR( status, & |
nf90_close(ncid) & |
,24) |
! RETURN |
status = 0 |
END SUBROUTINE read_att |
! ------------------------------------------------------------------------ |
! ------------------------------------------------------------------------ |
SUBROUTINE nc_dump(fname, x_data, y_data,z_data,t_data, & |
x_units,y_units, z_units,t_units, aps, ak, bk, & |
label,fold, sfold, mfold, dfold, tp, dp, pmin, pmax) |
USE netcdf |
IMPLICIT NONE |
CHARACTER(LEN=*), INTENT(IN) :: fname |
REAL, DIMENSION(:), INTENT(IN) :: x_data, y_data,z_data,t_data |
CHARACTER(LEN=*), INTENT(IN) :: x_units,y_units, z_units,t_units |
REAL, DIMENSION(:,:,:), INTENT(IN) :: aps |
REAL, DIMENSION(:), INTENT(IN) :: ak,bk |
REAL, DIMENSION(:,:,:,:), INTENT(IN) :: label |
REAL, DIMENSION(:,:,:), INTENT(IN) :: fold |
REAL, DIMENSION(:,:,:), INTENT(IN) :: sfold |
REAL, DIMENSION(:,:,:), INTENT(IN) :: mfold |
REAL, DIMENSION(:,:,:), INTENT(IN) :: dfold |
REAL, DIMENSION(:,:,:), INTENT(IN) :: dp |
REAL, DIMENSION(:,:,:), INTENT(IN) :: tp |
REAL, DIMENSION(:,:,:), INTENT(IN) :: pmin |
REAL, DIMENSION(:,:,:), INTENT(IN) :: pmax |
! LOCAL |
INTEGER :: status |
CHARACTER(LEN=*), PARAMETER :: substr = 'nc_dump' |
INTEGER :: ncid ! netCDF-ID |
INTEGER :: nlon,nlat,nlev,ntime |
INTEGER :: dimid_lat, dimid_lon, dimid_lev, dimid_ilev, dimid_time |
INTEGER :: varid_lat, varid_lon, varid_lev, varid_ilev, varid_time |
INTEGER :: varid_aps, varid_hyam, varid_hybm, varid_label |
INTEGER :: varid_fold, varid_sfold, varid_mfold, varid_dfold, varid_tp, varid_dp |
INTEGER :: varid_pmin, varid_pmax |
! |
CHARACTER(LEN=8) :: date |
CHARACTER(LEN=10) :: time |
CHARACTER(LEN=5) :: zone |
nlon = SIZE(x_data) |
nlat = SIZE(y_data) |
nlev = SIZE(z_data) |
ntime = SIZE(t_data) |
! CREATE NEW FILE |
CALL NFERR(status, & |
nf90_create(TRIM(fname), NF90_CLOBBER, ncid) & |
,51) |
! ADD GLOBALE ATTRIBUTES |
! - VERSION |
CALL NFERR(status, & |
nf90_put_att(ncid, NF90_GLOBAL, 'contact:', & |
'Andrea Pozzer, MPIC, Mainz') & |
,52) |
! - DATE AND TIME |
CALL DATE_AND_TIME(date, time, zone) |
CALL NFERR(status, & |
nf90_put_att(ncid, NF90_GLOBAL, 'date', date) & |
,53) |
CALL NFERR(status, & |
nf90_put_att(ncid, NF90_GLOBAL, 'time', TRIM(time)//TRIM(zone)) & |
,54) |
! DEFINE DIMENSIONS |
CALL NFERR(status, & |
nf90_def_dim(ncid, 'lon', nlon, dimid_lon) & |
,56) |
CALL NFERR(status, & |
nf90_def_dim(ncid, 'lat', nlat, dimid_lat) & |
,57) |
CALL NFERR(status, & |
nf90_def_dim(ncid, 'lev', nlev, dimid_lev) & |
,58) |
CALL NFERR(status, & |
nf90_def_dim(ncid, 'time', NF90_UNLIMITED, dimid_time) & |
,59) |
! DEFINE COORDINATE VARIABLES WITH ATTRIBUTES |
CALL NFERR(status, & |
nf90_def_var(ncid, 'lon', NF90_FLOAT, (/ dimid_lon /), varid_lon) & |
,60) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_lon, 'long_name', 'longitude') & |
,61) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_lon, 'units', x_units) & |
,62) |
CALL NFERR(status, & |
nf90_def_var(ncid, 'lat', NF90_FLOAT, (/ dimid_lat /), varid_lat) & |
,63) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_lat, 'long_name', 'latitude') & |
,63) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_lat, 'units', y_units) & |
,64) |
CALL NFERR(status, & |
nf90_def_var(ncid, 'lev', NF90_FLOAT, (/ dimid_lev /), varid_lev) & |
,65) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_lev, 'long_name', 'level index') & |
,66) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_lev, 'units', z_units) & |
,67) |
CALL NFERR(status, & |
nf90_def_var(ncid, 'time', NF90_FLOAT, (/ dimid_time /), varid_time) & |
,68) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_time, 'long_name', 'time') & |
,69) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_time, 'units', t_units) & |
,70) |
! DEFINE VARIABLES |
! - aps |
CALL NFERR(status, & |
nf90_def_var(ncid, 'APS', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_aps) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_aps, 'long_name' & |
,'Surface Pressure') & |
,79) |
! - ak |
CALL NFERR(status, & |
nf90_def_var(ncid, 'hyam', NF90_FLOAT & |
, (/ dimid_lev /), varid_hyam) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_hyam, 'long_name' & |
,'"hybrid A coefficient at layer midpoints') & |
,79) |
! - bk |
CALL NFERR(status, & |
nf90_def_var(ncid, 'hybm', NF90_FLOAT & |
, (/ dimid_lev /), varid_hybm) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_hybm, 'long_name' & |
,'hybrid B coefficient at layer midpoints') & |
,79) |
! - label |
CALL NFERR(status, & |
nf90_def_var(ncid, 'label', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_lev, dimid_time /), varid_label) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_label, 'long_name' & |
,'TR=1,ST=2,ST.CUTOFF=3,TR.TR.CUTOFF=4,PV.BLOB=5') & |
,79) |
! - fold |
CALL NFERR(status, & |
nf90_def_var(ncid, 'fold', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_fold) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_fold, 'long_name' & |
, 'Tropopause folding: 1=YES, 2=NO') & |
,79) |
! - sfold |
CALL NFERR(status, & |
nf90_def_var(ncid, 'sfold', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_sfold) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_sfold, 'long_name' & |
, 'Shallow tropopause folding (50< >200 hPa) : 1=YES, 2=NO') & |
,79) |
! - mfold |
CALL NFERR(status, & |
nf90_def_var(ncid, 'mfold', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_mfold) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_mfold, 'long_name' & |
, 'Medium Tropopause folding (200< >350 hPa): 1=YES, 2=NO') & |
,79) |
! - dfold |
CALL NFERR(status, & |
nf90_def_var(ncid, 'dfold', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_dfold) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_dfold, 'long_name' & |
, 'Deep Tropopause folding (>=350 hPa): 1=YES, 2=NO') & |
,79) |
! - tropopause |
CALL NFERR(status, & |
nf90_def_var(ncid, 'tp', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_tp) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_tp, 'long_name' & |
, 'Tropopause') & |
,79) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_tp, 'units' & |
, 'hPa') & |
,79) |
! - folding extension |
CALL NFERR(status, & |
nf90_def_var(ncid, 'dp', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_dp) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_dp, 'long_name' & |
, 'vertical extend of folding') & |
,79) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_dp, 'units' & |
, 'hPa') & |
,79) |
CALL NFERR(status, & |
nf90_def_var(ncid, 'pmin', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_pmin) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_pmin, 'long_name' & |
, 'vertical extend of folding') & |
,79) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_pmin, 'units' & |
, 'hPa') & |
,79) |
CALL NFERR(status, & |
nf90_def_var(ncid, 'pmax', NF90_FLOAT & |
, (/ dimid_lon, dimid_lat, dimid_time /), varid_pmax) & |
,78) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_pmax, 'long_name' & |
, 'vertical extend of folding') & |
,79) |
CALL NFERR(status, & |
nf90_put_att(ncid, varid_pmax, 'units' & |
, 'hPa') & |
,79) |
! SWITCH MODUS |
CALL NFERR(status, & |
nf90_enddef(ncid) & |
,82) |
! SAVE COORDINATE VARIBLES |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_lon, x_data) & |
,83) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_lat, y_data) & |
,84) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_lev, z_data) & |
,85) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_time, t_data) & |
,86) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_aps, aps) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_hyam, ak) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_hybm, bk) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_label, label) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_fold, fold) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_sfold, sfold) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_mfold, mfold) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_dfold, dfold) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_tp, tp) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_dp, dp) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_pmin, pmin) & |
,89) |
CALL NFERR(status, & |
nf90_put_var(ncid, varid_pmax, pmax) & |
,89) |
! CLOSE FILE |
CALL NFERR(status, & |
nf90_close(ncid) & |
,90) |
END SUBROUTINE nc_dump |
! ------------------------------------------------------------------ |
SUBROUTINE NFERR(status,command,pos) |
IMPLICIT NONE |
! I/O |
INTEGER, INTENT(OUT) :: status |
INTEGER, INTENT(IN) :: command |
INTEGER, INTENT(IN) :: pos |
status=command |
IF (status /= NF90_NOERR) THEN |
WRITE(*,*) 'netCDF ERROR at position: ', pos |
WRITE(*,*) 'netCDF ERROR status : ',status |
WRITE(*,*) 'netCDF ERROR : ',nf90_strerror(status) |
END IF |
END SUBROUTINE NFERR |
! ------------------------------------------------------------------ |
end module netcdf_tools |