!-------------------------------------- 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 --------------------------------------
!
subroutine tovs_fill_profiles_tl(lcolumn,lcolumng) 1,31
#if defined (doc)
!
!**s/r tovs_fill_profiles_tl - tangent linear of interpolation of obs.space to rttov space
! (adapted from part of code of lvtov)
!
!
!author : j. halle *cmda/aes april 12, 2005
!
!revision 001 : a. beaulne *cmda/smc june 2006
! -add ozone from climatology to all sensors
!
!revision 002 : j. halle *cmda/smc march 2007
! -fix zvlev for hybrid coordinate
!revision 003 : S. Heilliette septembre 2011
! -adapt to rttv-10
!revision 004 : s. macpherson nov 2012
! - remove #include "comtovst.cdk"
!
! -------------------
! purpose: fill tangent linear profiles structure with info from obs. space
!
!arguments
!
!
#endif
use MathPhysConstants_mod
use tovs_nl_mod
use tovs_lin_mod
use obsSpaceData_mod
use columnData_mod
use tovs_extrap_mod
use rttov_const ,only : q_mixratio_to_ppmv
Use parkind1, Only : jpim ,jprb
implicit none
type(struct_columnData) :: lcolumn,lcolumng
type(struct_vco), pointer :: vco_anl
integer, allocatable :: iptobs (:)
integer, allocatable :: iptobscma (:)
integer :: alloc_status(40)
integer :: omp_get_num_threads, nthreads
integer :: istride, ilen, imodulo
integer :: nlevels,knlev,nobmax
integer :: j, i, krtid, jf, iobs, jj, stat
integer :: ilowlvl_M,ilowlvl_T, knpf, jo
integer :: jk, jn, jl
real*8, allocatable :: to_tl (:,:)
real*8, allocatable :: lqo_tl (:,:)
real*8, allocatable :: toext_tl (:,:)
real*8, allocatable :: qoext_tl (:,:)
real*8, allocatable :: zvlev (:,:)
real*8, allocatable :: dPdPs (:,:)
real*8, allocatable :: zt_tl (:,:)
real*8, allocatable :: zlq_tl (:,:)
real*8, allocatable :: zt (:,:)
real*8, allocatable :: zlq (:,:)
real*8, allocatable :: qoext (:,:)
real*8, allocatable :: zps_tl (:)
real*8, allocatable :: xpres (:)
real*8 :: zptop, zptopmbs
external intavg
external exthum4
if(NOBTOV.eq.0) return ! exit if there are not tovs data
! 1. Set index for model's lowest level and model top
! . ------------------------------------------------
vco_anl => col_getVco
(lcolumng)
knlev = col_getNumLev
(lcolumng,'TH')
if ( col_getPressure
(lcolumng,1,1,'TH') .lt. col_getPressure
(lcolumng,knlev,1,'TH') ) then
ilowlvl_M = col_getNumLev
(lcolumng,'MM')
ilowlvl_T = col_getNumLev
(lcolumng,'TH')
else
ilowlvl_M = 1
ilowlvl_T = 1
endif
nlevels=coefs(1) %coef% nlevels
allocate (xpres(nlevels))
xpres(1:nlevels) = coefs(1)% coef % ref_prfl_p(1:nlevels)
! find model level top, within 0.000001 mbs.
zptop = col_getPressure
(lcolumng,1,1,'TH')
zptopmbs = zptop/100.d0
zptopmbs = zptopmbs - 0.000001d0
jpmotop = 1
do jl = 2, nlevels
if ( zptopmbs .ge. xpres(jl-1) .and. &
zptopmbs .lt. xpres(jl) ) then
jpmotop = jl
exit
endif
enddo
jpmolev = (nlevels-jpmotop+1)
! 1.1 Number of threads and memory allocation
! . ---------------------------------------
!$omp parallel
nthreads = omp_get_num_threads()
!$omp end parallel
alloc_status(:) = 0
allocate (iptobs (jppf*nthreads) ,stat= alloc_status(1) )
allocate (iptobscma (jppf*nthreads) ,stat= alloc_status(2) )
allocate (to_tl (jpmolev,jppf*nthreads) ,stat= alloc_status(3) )
allocate (lqo_tl (jpmolev,jppf*nthreads) ,stat= alloc_status(4) )
allocate (toext_tl (nlevels ,jppf*nthreads),stat= alloc_status(5) )
allocate (qoext_tl (nlevels ,jppf*nthreads),stat= alloc_status(6) )
allocate (zvlev (knlev,jppf*nthreads) ,stat= alloc_status(7) )
allocate (dPdPs (knlev,jppf*nthreads) ,stat= alloc_status(8) )
allocate (zt_tl (knlev,jppf*nthreads) ,stat= alloc_status(9) )
allocate (zlq_tl (knlev,jppf*nthreads) ,stat= alloc_status(10))
allocate (zt (knlev,jppf*nthreads) ,stat= alloc_status(11))
allocate (zlq (knlev,jppf*nthreads) ,stat= alloc_status(12))
allocate (qoext (nlevels,jppf*nthreads) ,stat= alloc_status(13))
allocate (zps_tl (jppf*nthreads) ,stat= alloc_status(14))
if( any(alloc_status /= 0) ) then
write(*,*) ' tovs_fill_profiles_tl : memory allocation error'
call abort3d
('tovs_fill_profiles_tl ')
end if
iptobs (:) = 0
iptobscma(:) = 0
toext_tl (:,:) = 0.0d0
zvlev (:,:) = 0.0d0
dPdPs (:,:) = 0.0d0
zt_tl (:,:) = 0.0d0
zlq_tl (:,:) = 0.0d0
zt (:,:) = 0.0d0
zlq (:,:) = 0.0d0
qoext (:,:) = 0.0d0
zps_tl (:) = 0.0d0
to_tl (:,:) = 0.0d0
lqo_tl (:,:) = 0.0d0
!
! 2. Fill profiles structure
! . -----------------------
! loop over all instruments
binst: do krtid=1,nsensors
! loop over all obs.
knpf = 0
xpres(1:nlevels) = coefs(krtid)% coef % ref_prfl_p(1:nlevels)
bb: do iobs = NOBTOV,1,-1
if (lsensor(iobs)==krtid) then
NOBMAX=iobs
exit bb
endif
enddo bb
bobs: do iobs = 1, NOBTOV
if (lsensor(iobs)/=krtid) cycle bobs
jo = lobsno(iobs)
knpf = knpf + 1
zps_tl (knpf) = col_getElem
(lcolumn,1,jo,'P0')*MPC_MBAR_PER_PA_R8
do jl = 1, knlev
zt_tl (jl,knpf) = col_getElem
(lcolumn,jl,jo,'TT')
zlq_tl (jl,knpf) = col_getElem
(lcolumn,jl,jo,'HU')
zt (jl,knpf) = col_getElem
(lcolumng,jl,jo,'TT')
zlq (jl,knpf) = col_getElem
(lcolumng,jl,jo,'HU')
zvlev(jl,knpf) = col_getPressure
(lcolumng,jl,jo,'TH') *MPC_MBAR_PER_PA_R8
dPdPs(jl,knpf) = col_getPressureDeriv
(lcolumng,jl,jo,'TH')
enddo
!!! Fix pour eviter probleme au toit avec GEM 4
!!! (grosse varibilite temperature au dernier niveau thermo due a l'extrapolation utilisee)
zt_tl (1,knpf) = 0.d0
zlq_tl (1,knpf) = 0.d0
zt (1,knpf) = zt (2,knpf) - 8.0d0 ! base sur derniere couche environ 4km, lapse rate 2K/km
zlq (1,knpf) = zlq (2,knpf)
!!!!
iptobs (knpf) = iobs
iptobscma(knpf) = jo
if ( knpf .le. 0 ) cycle bobs
if ( knpf .ne. jppf*nthreads .and. iobs .ne. NOBMAX ) cycle bobs
! . 2.1 Vertical interpolation of model temperature and logarithm of
! specific humidity to pressure levels required by tovs rt model
! . --------------------------------------------------------------
do jn = 1, knpf
qoext(1:nlevels,jn) = profiles(iptobs(jn)) % q(1:nlevels) / q_mixratio_to_ppmv
enddo
to_tl (:,:) = 0.0d0
lqo_tl(:,:) = 0.0d0
imodulo = mod(knpf,nthreads)
if ( imodulo .eq. 0 ) then
istride = max(1,(knpf/nthreads))
else
istride = max(1,(knpf/nthreads)+1)
endif
!$omp parallel
!$omp do private(jn,ilen)
do jn=1,knpf,istride
ilen = min (knpf-jn+1,istride)
if ( ilen .gt. 0) then
call intavgtl
(zvlev(:,jn:jn+ilen-1),dPdPs(:,jn:jn+ilen-1),zt_tl(:,jn:jn+ilen-1),zt(:,jn:jn+ilen-1), &
zps_tl(jn:jn+ilen-1),knlev,knlev,ilen, &
jpmolev,xpres(jpmotop:nlevels),to_tl(:,jn:jn+ilen-1))
call intavgtl
(zvlev(:,jn:jn+ilen-1),dPdPs(:,jn:jn+ilen-1),zlq_tl(:,jn:jn+ilen-1),zlq(:,jn:jn+ilen-1), &
zps_tl(jn:jn+ilen-1),knlev,knlev,ilen, &
jpmolev,xpres(jpmotop:nlevels),lqo_tl(:,jn:jn+ilen-1))
endif
enddo
!$omp end do
!$omp end parallel
! . 2.2 Extrapolation of temperature profile above 10mb
! . -----------------------------------------------
toext_tl(:,:) = 0.0d0
if ( abs( zptopmbs - 10.0d0 ) > .1d0 ) then
do jn = 1, knpf
toext_tl(jpmotop:nlevels,jn)=to_tl(1:jpmolev,jn)
toext_tl(1:jpmotop-1,jn)=0.d0
enddo
else
call lextrap
(to_tl,toext_tl,jpmolev,nlevels,knpf)
endif
! . 2.3 Extrapolation of humidity profile (kg/kg)
! above rlimlvhu (normally 300mbs or 70mbs)
! . -----------------------------------------
qoext_tl(:,:) = 0.0d0
do jn = 1, knpf
do jk = 1, jpmotop-1
qoext_tl(jk,jn) = 0.d0
enddo
do jk = 1, jpmolev
qoext_tl(nlevels-jpmolev+jk,jn) = qoext(nlevels-jpmolev+jk,jn)*lqo_tl(jk,jn)
enddo
enddo
if ( abs( zptopmbs - 10.0d0 ) < .1d0 ) then
if ( ldbgtov ) then
do jn = 1, knpf
write(*,*)'qoext_tl*1000 avant exthum4 = '
write(*,9263)(qoext_tl(i,jn)*1000.d0,i=1,nlevels)
write(*,*)' '
enddo
endif
call lexthum4
(knpf,nlevels,xpres(1:nlevels),qoext_tl,qoext)
if ( ldbgtov ) then
do jn = 1, knpf
write(*,*)'qoext_tl*1000 apres exthum4 = '
write(*,9263)(qoext_tl(i,jn)*1000.d0,i=1,nlevels)
write(*,*)' '
enddo
endif
endif
! . 2.4 Fill profiles_tl structure
! . --------------------------
do j = 1 , knpf
jj=iptobs(j)
profiles_tl(jj) % nlevels = nlevels
profiles_tl(jj) % nlayers = nlevels - 1
profiles_tl(jj) % o3(:) = 0.0d0
if(coefs(krtid)%coef%nco2 > 0) then
profiles_tl(jj) % co2(:) = 0.d0
endif
if(coefs(krtid)%coef%nn2o > 0) then
profiles_tl(jj) % n2o(:) = 0.d0
endif
if(coefs(krtid)%coef%nco > 0) then
profiles_tl(jj) % co(:) = 0.d0
endif
if(coefs(krtid)%coef%nch4 > 0) then
profiles_tl(jj) % ch4(:) = 0.d0
endif
profiles_tl(jj) % ctp = 0.0d0
profiles_tl(jj) % cfraction = 0.0d0
profiles_tl(jj) % zenangle = 0.0d0
profiles_tl(jj) % azangle = 0.0d0
profiles_tl(jj) % skin % surftype = 0
profiles_tl(jj) % skin % t = col_getElem
(lcolumn,1,iptobscma(j),'TG')
profiles_tl(jj) % skin % fastem(:)= 0.0d0
profiles_tl(jj) % skin % salinity = 0.0d0
profiles_tl(jj) % s2m % t = col_getElem
(lcolumn,ilowlvl_T,iptobscma(j),'TT')
!! The following line has been commented out because qoext(ilowlvl_T,j) may be out of bound
!!! profiles_tl(jj) % s2m % q = qoext(ilowlvl_T,j) * col_getElem(lcolumn,ilowlvl_T,iptobscma(j),'HU') * q_mixratio_to_ppmv
!! The right code should be
!!profiles_tl(jj) % s2m % q = exp(gomq1(ilowlvl_T,iptobscma(j))) * pgomq_tl(ilowlvl_T,iptobscma(j)) * q_mixratio_to_ppmv
!! but since the logical flag 'use_q2m' is set to .false. in rttov_const.F90 (in RTTOV code)
!! this variable profiles_tl(jj) % s2m % q is not used so it can be set to 0
profiles_tl(jj) % s2m % q = 0.d0
profiles_tl(jj) % s2m % p = col_getElem
(lcolumn,1,iptobscma(j),'P0')*MPC_MBAR_PER_PA_R8
profiles_tl(jj) % s2m % u = col_getElem
(lcolumn,ilowlvl_M,iptobscma(j),'UU')
profiles_tl(jj) % s2m % v = col_getElem
(lcolumn,ilowlvl_M,iptobscma(j),'VV')
profiles_tl(jj) % p(1:nlevels) = 0.d0
profiles_tl(jj) % t(1:nlevels) = toext_tl(1:nlevels,j)
profiles_tl(jj) % q(1:nlevels) = qoext_tl(1:nlevels,j) * q_mixratio_to_ppmv
end do
! next bunch !
knpf = 0
enddo bobs
enddo binst
alloc_status(:) = 0
deallocate (iptobs ,stat= alloc_status(1) )
deallocate (iptobscma ,stat= alloc_status(2) )
deallocate (to_tl ,stat= alloc_status(3) )
deallocate (lqo_tl ,stat= alloc_status(4) )
deallocate (toext_tl ,stat= alloc_status(5) )
deallocate (qoext_tl ,stat= alloc_status(6) )
deallocate (zvlev ,stat= alloc_status(7) )
deallocate (dPdPs ,stat= alloc_status(8) )
deallocate (zt_tl ,stat= alloc_status(9) )
deallocate (zlq_tl ,stat= alloc_status(10))
deallocate (zt ,stat= alloc_status(11))
deallocate (zlq ,stat= alloc_status(12))
deallocate (qoext ,stat= alloc_status(13))
deallocate (zps_tl ,stat= alloc_status(14))
deallocate (xpres ,stat= alloc_status(15))
if( any(alloc_status /= 0) ) then
write(*,*) ' tovs_fill_profiles_tl : memory deallocation error'
call abort3d
('tovs_fill_profiles_tl ')
end if
9263 format(1x,10f8.4)
! 3. Close up
! . --------
return
end subroutine tovs_fill_profiles_tl