!--------------------------------------- LICENCE BEGIN -----------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
! version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------
module verticalCoord_mod 12,2
use mpi_mod
use MathPhysConstants_mod
use Vgrid_Descriptors
implicit none
private
! public derived type
public :: struct_vco
! public procedures
public :: vco_SetupFromFile, vco_getNumLev
! public entities accessed through inheritance
public :: vgd_get,vgd_levels,vgd_ok,vgd_dpidpis,vgd_write
type struct_vco
logical :: initialized=.false.
integer :: nlev_T= 0
integer :: nlev_M= 0
real*8 :: dpt_T, dpt_M ! Pressure at top level (Thermo/Moment)
real*8 :: dprf_T, dprf_M ! Reference pressure (Thermo/Moment)
real*8 :: drcf1, drcf2 ! Expansion coefficients
integer,pointer,dimension(:) :: ip1_T,ip1_M ! encoded IP1 levels (Thermo/Moment)
real*8 ,pointer,dimension(:) :: da_T,db_T ! A, B values for Thermo levels
real*8 ,pointer,dimension(:) :: da_M,db_M ! A, B values for Momentum levels
real*8 ,pointer,dimension(:) :: db_dhyb_M,db_dhyb_T ! factor needed for TLM/AD of tt2phi
real*8 ,pointer,dimension(:) :: da_dhyb_M,da_dhyb_T ! factor needed for TLM/AD of tt2phi
real*8 ,pointer,dimension(:) :: dhyb_T,dhyb_M !decoded IP1 levels (Thermo/Momentum)
type(vgrid_descriptor) :: vgrid
end type struct_vco
contains
subroutine vco_allocate(vco) 1,3
implicit none
type(struct_vco), pointer :: vco
integer :: ilnk,stat,nl_stat
stat = 0
ilnk = vco_getNumLev
(vco,'MM')
allocate (vco%ip1_M(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%da_M(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%db_M(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%da_dhyb_M(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%db_dhyb_M(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%dhyb_M(ilnk),stat=nl_stat)
stat = stat + nl_stat
ilnk = vco_getNumLev
(vco,'TH')
allocate (vco%ip1_T(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%da_T(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%db_T(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%da_dhyb_T(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%db_dhyb_T(ilnk),stat=nl_stat)
stat = stat + nl_stat
allocate (vco%dhyb_T(ilnk),stat=nl_stat)
stat = stat + nl_stat
if(stat .ne. 0 ) then
call abort3d
(' vco: problem with allocate in vco ')
endif
end subroutine vco_allocate
subroutine vco_SetupFromFile(vco,templatefile,lprecision) 5,11
! s/r vco_SetupFromFile - Initialize structure for a standard file using vgrid_descriptors library.
implicit none
type(struct_vco),pointer :: vco
character(len=*) :: templatefile
logical :: lprecision
integer :: ivcode,kind,jlev,stat,sigdigits,nultemplate,ierr
integer :: fnom,fstouv,fstfrm,fclos
integer, dimension(:), pointer :: my_ip1_m,my_ip1_t
real :: hyb_r4
real*8 :: dl_ptM,dl_ptT,dl_pref,dl_rcf1,dl_rcf2,zterm
real*8, dimension(:), pointer :: my_a, my_b
REAL*8 precision
character(len=10) :: blk_S
logical :: isExist_L
integer :: nlev_M,nlev_T
if(mpi_myid.eq.0) write(*,*) 'vco_SetupFromFile: TEMPLATEFILE=', templatefile
inquire(file=templatefile,exist=isExist_L)
IF ( isExist_L )then
nultemplate=0
ierr=fnom(nultemplate,templatefile,'RND+OLD+R/O',0)
if ( ierr .eq. 0 ) then
if(mpi_myid.eq.0) write(*,*) ' opened as unit file ',nultemplate
ierr = fstouv(nultemplate,'RND+OLD')
else
call abort3d
('vco_SetupFromFile: CANNOT OPEN TEMPLATE FILE!')
endif
else
call abort3d
('vco_SetupFromFile: CANNOT FIND TEMPLATE FILE!')
endif
if(.not.associated(vco)) allocate(vco)
!==========================================================================
! Get vertical coordinate descriptors from standard file(vgd_new reads "!!" record)
stat = vgd_new(vco%vgrid,unit=nultemplate,format="fst",ip1=-1,ip2=-1)
if(stat.ne.VGD_OK)then
call abort3d
('ERROR with vgd_new')
endif
! Print out vertical structure
stat = vgd_print(vco%vgrid)
if(stat.ne.VGD_OK)then
call abort3d
('ERROR with vgd_print')
endif
!==========================================================================
! Get version of the vertical coordinate
stat = 0
stat = vgd_get(vco%vgrid,key='ig_1 - vertical coord code',value=ivcode)
if(stat.ne.VGD_OK) then
call abort3d
('vco: problem with vgd_get: key= ig_1 - vertical coord code')
endif
!==========================================================================
! Set the number of vertical levels and allocate vco arrays
nlev_M = vco_getNumLev
(vco,'MM')
nlev_T = vco_getNumLev
(vco,'TH')
if(mpi_myid.eq.0) write(*,*) 'nlev_M, nlev_T=',nlev_M,nlev_T
call vco_allocate
(vco)
!==========================================================================
! Process levels (ip1, A, B)
! (unstaggered vertical coord are stored in levels in "!!" records)
stat = 0
stat = vgd_get(vco%vgrid,key='ca_m - vertical a coefficient (m)',value=vco%da_M)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get ca_m vgd_ok= ',VGD_OK
stat = vgd_get(vco%vgrid,key='ca_t - vertical a coefficient (t)',value=vco%da_T)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get ca_t vgd_ok= ',VGD_OK
!
stat = vgd_get(vco%vgrid,key='cb_m - vertical b coefficient (m)',value=vco%db_M)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get cb_m vgd_ok= ',VGD_OK
stat = vgd_get(vco%vgrid,key='cb_t - vertical b coefficient (t)',value=vco%db_T)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get cb_t vgd_ok= ',VGD_OK
!
stat = vgd_get(vco%vgrid,key='vipm - vertical levels (m)',value=my_ip1_m)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get ip1m vgd_ok= ',VGD_OK
!
stat = vgd_get(vco%vgrid,key='ptop - pressure at top level (m)',value=dl_ptM)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get ptm vgd_ok= ',VGD_OK
!
stat = vgd_get(vco%vgrid,key='pref - reference pressure (m)',value=dl_pref)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get vipm vgd_ok= ',VGD_OK
!
stat = vgd_get(vco%vgrid,key='rc_1 - coefficient value for rectification (m)',value=dl_rcf1)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get vipm vgd_ok= ',VGD_OK
!
if(stat.ne.0) then
call abort3d
('vco: problem with vgd_get')
endif
if(size(vco%da_M).gt.0 .and. size(vco%db_M).gt.0 .and. size(my_ip1_m).gt.0 )then
if(mpi_myid.eq.0) write(*,*) 'vco: size(a,b,ip1)(m)= ',size(vco%da_M),size(vco%db_M),size(my_ip1_m)
else
if(mpi_myid.eq.0) write(*,*) 'vco: problem with size(a,b,ip1)(m) in vgd_get'
return
endif
vco%dprf_M = dl_pref
vco%dprf_T = dl_pref ! not sure if this will ever be different for thermo levels
vco%dpt_M = dl_ptM
vco%dpt_T = dl_ptM
vco%drcf1 = dl_rcf1
if(ivcode.eq.5002) then
! temporarily compute a single pressure roughly corresponding to top trial field level
! (vgrid descriptor gives a pressure for a higher non-existant level, currently 7.5Pa)
vco%dpt_M = exp( vco%da_M(1) + vco%db_M(1)*log(100000.0/dl_pref) )
if(mpi_myid.eq.0) write(*,*) 'vco_setupFromFile: computed ptop(MM)=',vco%dpt_M
if(mpi_myid.eq.0) write(*,*) 'vco_setupFromFile: read ptop(MM)=',dl_ptM
vco%dpt_T = exp( vco%da_T(1) + vco%db_T(1)*log(100000.0/dl_pref) )
if(mpi_myid.eq.0) write(*,*) 'vco_setupFromFile: computed ptop(TH)=',vco%dpt_T
if(mpi_myid.eq.0) write(*,*) 'vco_setupFromFile: read ptop(TH)=',dl_ptM
endif
!
! Set to zero the non-significant digits (due to conversion from real*4)
!
if(lprecision) then
sigdigits=7
precision=10.0d0**(sigdigits-int(log10(vco%dpt_M)))
vco%dpt_M = real(nint(precision*vco%dpt_M),8)/precision
precision=10.0d0**(sigdigits-int(log10(vco%dprf_M)))
vco%dprf_M = real(nint(precision*vco%dprf_M),8)/precision
precision=10.0d0**(sigdigits-int(log10(vco%drcf1)))
vco%drcf1 = real(nint(precision*vco%drcf1),8)/precision
endif
!==========================================================================
! Assign values for Momentum levels
if(mpi_myid.eq.0) write(*,*) 'vco: size(hyb_M)= ',size(vco%dhyb_M)
do jlev = 1, nlev_M
vco%ip1_M(jlev) = my_ip1_m(jlev)
call convip(my_ip1_m(jlev),hyb_r4,kind,-1,blk_s,.false.)
vco%dhyb_M(jlev) = hyb_r4
if(mpi_myid.eq.0) write(*,*) 'vco: jlev,nk,ip1,hyb(moment)= ' &
,jlev,nlev_M,vco%ip1_M(jlev),vco%dhyb_M(jlev)
! Devrait probablement etre enleve car avec la nouvelle facon de calculer
! l'equation hydrostatique zterm ne sera plus requis
if((vco%drcf1-1.0d0) .lt. epsilon(vco%drcf1)) then
zterm = 1.0d0
else
zterm = (vco%dhyb_M(jlev) - vco%dpt_M/vco%dprf_M)
if (zterm <= 0.0D0) then
zterm = 0.0D0
else
zterm = (zterm /(1.0d0-vco%dpt_M/vco%dprf_M))**(vco%drcf1-1.0d0)
endif
endif
vco%db_dhyb_M(jlev)= vco%drcf1 * zterm
vco%da_dhyb_M(jlev)= vco%dprf_M*(1.0d0 - vco%db_dhyb_M(jlev))
enddo
!==========================================================================
! Process thermodynamic levels
stat = 0
stat = vgd_get(vco%vgrid,key='vipt - vertical ip1 levels (t)',value=my_ip1_t)
stat = stat + VGD_OK
if(mpi_myid.eq.0) write(*,*) 'vco: vgd_get vipt vgd_ok= ',VGD_OK
if(stat.ne.0) then
call abort3d
('vco: problem with vgd_get')
endif
if(size(vco%da_T).gt.0 .and. size(vco%db_T).gt.0 .and. size(my_ip1_t).gt.0 )then
if(mpi_myid.eq.0) write(*,*) 'vco: size(a,b,ip1)(t)= ',size(vco%da_T),size(vco%db_T),size(my_ip1_t)
else
call abort3d
('vco: problem with size(a,b,ip1)(t) in vgd_get')
endif
if(mpi_myid.eq.0) write(*,*) 'vco: size(hyb_T)= ',size(vco%dhyb_T)
do jlev = 1,nlev_T
vco%ip1_T(jlev) = my_ip1_t(jlev)
call convip(my_ip1_t(jlev),hyb_r4,kind,-1,blk_s,.false.)
vco%dhyb_T(jlev) = hyb_r4
if(mpi_myid.eq.0) write(*,*) 'vco: jlev,nk,ip1,hyb(thermo)= ' &
,jlev,nlev_T,vco%ip1_T(jlev),vco%dhyb_T(jlev)
if((vco%drcf1-1.0d0) .lt. epsilon(vco%drcf1)) then
zterm = 1.0d0
else
zterm = (vco%dhyb_T(jlev) - vco%dpt_T/vco%dprf_T)
if (zterm <= 0.0d0 ) then
zterm=0.0d0
else
zterm = (zterm /(1.0d0-vco%dpt_T/vco%dprf_T))**(vco%drcf1-1.0d0)
endif
endif
vco%db_dhyb_T(jlev)= vco%drcf1 * zterm
vco%da_dhyb_T(jlev)= vco%dprf_T*(1.0d0 - vco%db_dhyb_T(jlev))
enddo
vco%initialized=.true.
ierr = fstfrm(nultemplate)
ierr = fclos (nultemplate)
end subroutine vco_SetupFromFile
function vco_getNumLev(vco,varType) result(nlev) 11,1
implicit none
type(struct_vco), intent(inout) :: vco
character(len=*), intent(in) :: varType
integer :: nlev
integer :: stat
integer, pointer :: ip_ptr(:)
if(varType.eq.'MM') then
if(vco%nlev_M.le.0) then
! stat = vgd_get(vco%vgrid,key='nl_m - number of momentum levels',value=nlev)
stat = vgd_get(vco%vgrid,key='VIPM',value=ip_ptr)
vco%nlev_M = size(ip_ptr)
deallocate(ip_ptr)
endif
nlev = vco%nlev_M
elseif(varType.eq.'TH') then
if(vco%nlev_T.le.0) then
! stat = vgd_get(vco%vgrid,key='nl_t - number of thermo levels',value=nlev)
stat = vgd_get(vco%vgrid,key='VIPT',value=ip_ptr)
vco%nlev_T = size(ip_ptr)
deallocate(ip_ptr)
endif
nlev = vco%nlev_T
elseif(varType.eq.'SF') then
nlev = 1
else
call abort3d
('vco_getNumLev: Unknown variable type! ' // varType)
endif
end function vco_getNumLev
end module VerticalCoord_mod