!-------------------------------------- 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(lcolumnghr,lobsSpaceData,datestamp,LIMLVHU,bgckMode) 2,39
!
!**s/r tovs_fill_profiles - interpolation of obs. space to rttov space
! (adapted from part of code of dobstovs)
!
!
!author : j. halle *cmda/aes december 13, 2004
!
!revision 001 : a. beaulne *cmda/smc june 2006
! -add ozone from climatology to all sensors
! -modifications for AIRS :
! + addition of geopotential field to subr argument
! + addition of latitude, longitude, height field,
! sun zenith angle and cloud fraction
! to personnalized profile structure
!
!revision 002 : j. halle *cmda/smc march 2007
! -fix zvlev for hybrid coordinate
!revision 003 : C. Charette - ARMA et N.Wagneur - CMDA - Juillet 2011
! . Ajout de la capacite de lire le champ d'essai de GEM Version 4
! . ayant une grille verticale decalee dite "STAGGERED"
!revision 004 : s. macpherson nov 2012
! - remove #include "comtovst.cdk"
!revision 005 : S. Heilliette october 2010
! -adapt to rttov10
!
! -------------------
! purpose: fill profiles structure with info from obs. space
!
!arguments
!
use EarthConstants_mod
use MathPhysConstants_mod
use tovs_nl_mod
use multi_ir_bgck_mod
use ozoneclim
use obsSpaceData_mod
use columnData_mod
use tovs_extrap_mod
Use rttov_const, only : q_mixratio_to_ppmv, &
gas_id_co2, &
gas_id_n2o, &
gas_id_co , &
gas_id_ch4, &
gas_id_ozone, &
gas_id_mixed, &
gas_id_watervapour, &
gas_id_wvcont, &
zenmax
implicit none
type(struct_obs) :: lobsSpaceData
type(struct_columnData) :: lcolumnghr
integer :: datestamp
real*8 :: LIMLVHU
logical :: bgckMode
integer, allocatable :: ksurf (:)
integer, allocatable :: iptobs (:)
integer, allocatable :: iptobscma (:)
integer, allocatable :: isatzen (:)
integer, allocatable :: isatazim (:)
integer, allocatable :: isunza (:)
real*8, allocatable :: zlat (:)
real*8, allocatable :: zlon (:)
real*8, allocatable :: ozo (:,:)
integer :: alloc_status(40)
integer :: omp_get_num_threads, nthreads
integer :: istride, ilen, imodulo
integer :: nlevels,nobmax
integer :: j, i, krtid, jf, iobs, jj
integer :: knpf, jo
integer :: jk, jn, jl
integer :: ilansea,ilowlvl_M,ilowlvl_T, ig
integer :: knlev
real*8, allocatable :: to (:,:)
real*8, allocatable :: lqo (:,:)
real*8, allocatable :: zho (:,:)
real*8, allocatable :: toext (:,:)
real*8, allocatable :: qoext (:,:)
real*8, allocatable :: zhoext(:,:)
real*8, allocatable :: zvlev (:,:)
real*8, allocatable :: zt (:,:)
real*8, allocatable :: zlq (:,:)
real*8, allocatable :: zht (:,:)
real*8, allocatable :: xpres (:)
real*8 :: zptop, zptopmbs
real*8, allocatable :: toto3obs(:),PP(:,:)
external intavg
external lintv2
external exthum4
write(*,*) "Entering tovs_fill_profiles subroutine"
if(NOBTOV.eq.0) return ! exit if there are no tovs data
knlev = col_getNumLev
(lcolumnghr,'TH')
!
! 1. Set index for model's lowest level and model top
! . ------------------------------------------------
100 continue
if ( col_getPressure
(lcolumnghr,1,1,'TH') .lt. col_getPressure
(lcolumnghr,knlev,1,'TH') ) then
ilowlvl_M = col_getNumLev
(lcolumnghr,'MM')
ilowlvl_T = col_getNumLev
(lcolumnghr,'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
(lcolumnghr,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 (ksurf (jppf*nthreads) ,stat= alloc_status(1) )
allocate (iptobs (jppf*nthreads) ,stat= alloc_status(2) )
allocate (iptobscma (jppf*nthreads) ,stat= alloc_status(3) )
allocate (isatzen (jppf*nthreads) ,stat= alloc_status(4) )
allocate (isatazim (jppf*nthreads) ,stat= alloc_status(5) )
allocate (isunza (jppf*nthreads) ,stat= alloc_status(6) )
allocate (zlat (jppf*nthreads) ,stat= alloc_status(8) )
allocate (zlon (jppf*nthreads) ,stat= alloc_status(9) )
allocate (ozo (nlevels,jppf*nthreads),stat= alloc_status(10))
allocate (to (jpmolev,jppf*nthreads),stat= alloc_status(11))
allocate (lqo (jpmolev,jppf*nthreads),stat= alloc_status(12))
allocate (zho (jpmolev,jppf*nthreads),stat= alloc_status(13))
allocate (toext (nlevels ,jppf*nthreads),stat= alloc_status(14))
allocate (qoext (nlevels ,jppf*nthreads),stat= alloc_status(15))
allocate (zhoext (nlevels ,jppf*nthreads),stat= alloc_status(16))
allocate (zvlev (knlev,jppf*nthreads),stat= alloc_status(17))
allocate (zt (knlev,jppf*nthreads),stat= alloc_status(18))
allocate (zlq (knlev,jppf*nthreads),stat= alloc_status(19))
allocate (zht (knlev,jppf*nthreads),stat= alloc_status(20))
if( any(alloc_status /= 0) ) then
write(*,*) ' tovs_fill_profiles : memory allocation error'
call abort3d
('tovs_fill_profiles ')
end if
! 1.2 Read ozone climatology
! . ----------------------
call ozo_read_climatology
(datestamp)
!
! 2. Fill profiles structure
! . -----------------------
! loop over all instruments
binst: do krtid=1,nsensors
xpres(1:nlevels) = coefs(krtid)% coef % ref_prfl_p(1:nlevels)
knpf = 0
bb: do iobs = NOBTOV,1,-1
if (lsensor(iobs)==krtid) then
NOBMAX=iobs
exit bb
endif
enddo bb
! loop over all obs.
bobs: do iobs = 1, NOBTOV
jo = lobsno(iobs)
if (lsensor(iobs)/=krtid) cycle bobs
knpf = knpf + 1
! extract land/sea/sea-ice flag (0=land, 1=sea, 2=sea-ice)
ilansea = obs_headElem_i
(lobsSpaceData,OBS_OFL,jo)
ksurf(knpf) = ilansea
! extract satellite zenith and azimuth angle,
! sun zenith angle, cloud fraction, latitude and longitude
isatzen(knpf) = obs_headElem_i
(lobsSpaceData,OBS_SZA,jo)
isatazim(knpf) = obs_headElem_i
(lobsSpaceData,OBS_AZA,jo)
isunza(knpf) = obs_headElem_i
(lobsSpaceData,OBS_SUN,jo)
zlat(knpf) = obs_headElem_r
(lobsSpaceData,OBS_LAT,jo) *MPC_DEGREES_PER_RADIAN_R8
zlon(knpf) = obs_headElem_r
(lobsSpaceData,OBS_LON,jo) *MPC_DEGREES_PER_RADIAN_R8
do jl = 1, knlev
zt (jl,knpf) = col_getElem
(lcolumnghr,jl,jo,'TT')
zlq (jl,knpf) = col_getElem
(lcolumnghr,jl,jo,'HU')
zvlev(jl,knpf) = col_getPressure
(lcolumnghr,jl,jo,'TH') * MPC_MBAR_PER_PA_R8
zht (jl,knpf) = col_getHeight
(lcolumnghr,jl,jo,'TH') / rg
enddo
!!! Fix temporaire (?) pour eviter probleme au toit avec GEM 4: on ne veut pas utiliser
!!! le premier niveau de GEM qui est disgnostique (extrapole a partir des deux niveaux plus bas)
!!! (grosse varibilite temperature au dernier niveau thermo due a l'extrapolation utilisee)
zt (1,knpf) = zt (2,knpf) - 8.0d0 ! base sur derniere couche environ 4km, lapse rate 2K/km
zlq (1,knpf) = zlq (2,knpf) ! extrapolation valeur constante pour H2O peu important a cette hauteur
!!!!
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, logarithm of
! specific humidity and height levels to pressure levels
! required by tovs rt model
! . ------------------------------------------
!$omp parallel private(istride)
imodulo = mod(knpf,nthreads)
if ( imodulo .eq. 0 ) then
istride = max(1,(knpf/nthreads))
else
istride = max(1,(knpf/nthreads)+1)
endif
!$omp do private(jn,ilen)
do jn=1,knpf,istride
ilen = min (knpf-jn+1,istride)
if ( ilen .gt. 0) then
call intavg
(zvlev(:,jn:jn+ilen-1),zt(:,jn:jn+ilen-1),knlev,knlev,ilen, &
jpmolev,xpres(jpmotop:nlevels),to(:,jn:jn+ilen-1))
call intavg
(zvlev(:,jn:jn+ilen-1),zlq(:,jn:jn+ilen-1),knlev,knlev,ilen, &
jpmolev,xpres(jpmotop:nlevels),lqo(:,jn:jn+ilen-1))
call lintv2
(zvlev(:,jn:jn+ilen-1),zht(:,jn:jn+ilen-1),knlev,knlev,ilen, &
jpmolev,xpres(jpmotop:nlevels),zho(:,jn:jn+ilen-1))
endif
enddo
!$omp end do
!$omp end parallel
! . 2.2 Extrapolation of temperature profile above model top
! . ----------------------------------------------------
toext(:,:) = 0.0d0
if ( abs( zptopmbs - 10.0d0 ) > .1d0 ) then ! si le toit n'est pas a 10. hPa
!constant value extrapolation for now modified with a bias....
do jn=1,knpf
toext(nlevels-jpmolev+1:nlevels,jn) = to(1:jpmolev,jn)
if (nlevels==51) then
! si coefficients sur 51 niveaux 2 niveaux au dessus de 0.1 hPa
toext(1,jn) = to(1,jn) - 33.77d0
toext(2,jn) = to(1,jn) - 22.33d0
else
! si coefficients sur 44 niveaux 1 niveau au dessus de 0.1 hPa
toext(1,jn) = to(1,jn) - 33.77d0
endif
enddo
else
! vieux code pour extrapolation du profil de temperature
call extrap
(to,toext,jpmolev,nlevels,knpf)
endif
! . 2.3 Extrapolation of height profile above model top
! . -----------------------------------------------
zhoext(:,:) = 0.0d0
call htextrap
(zhoext,zho,xpres(1:nlevels),nlevels,jpmolev,jpmotop,knpf)
! . 2.4 Extrapolation of humidity profile (kg/kg)
! above rlimlvhu (normally 300mbs or 70mbs)
! . -----------------------------------------
qoext(:,:) = 0.0d0
do jn = 1, knpf
do jk = 1, jpmolev
qoext(nlevels-jpmolev+jk,jn) = exp(lqo(jk,jn))
enddo
enddo
if ( abs( zptopmbs - 10.0d0 ) > .1d0 ) then ! si le toit n'est pas a 10. hPa
qoext(1:jpmotop,1:knpf) = MPC_MINIMUM_HU_R8
else
if ( ldbgtov ) then
do jn = 1, knpf
write(*,*)'qoext*1000 avant exthum4 = '
write(*,9263)(qoext(i,jn)*1000.d0,i=1,nlevels)
write(*,*)' '
enddo
endif
call exthum4
(knpf,nlevels,xpres(1:nlevels),qoext,LIMLVHU)
if ( ldbgtov ) then
do jn = 1, knpf
write(*,*)'qoext*1000 apres exthum4 = '
write(*,9263)(qoext(i,jn)*1000.d0,i=1,nlevels)
write(*,*)' '
enddo
endif
endif
! . 2.5 Get ozone profiles (ppmv)
! . -------------------------
allocate ( toto3obs(knpf) )
toto3obs(:) = 0.d0
allocate( PP(nlevels,knpf) )
DO J=1,knpf
PP(1:nlevels,J)=xpres(1:nlevels)
ENDDO
call ozo_get_profile
(ozo,toto3obs,zlat, &
pp,nlevels,knpf,datestamp)
deallocate( PP )
deallocate ( toto3obs )
! . 2.6 Fill profiles structure
! . -----------------------
do j = 1 , knpf
jj=iptobs(j)
profiles(jj) % id = "" ! profile id, up to 128 characters, to consider for use
profiles(jj) % nlevels = nlevels
profiles(jj) % nlayers = nlevels - 1
profiles(jj) % zenangle = (isatzen(j)-9000)/100.0
!pour ne pas faire planter RTTOV dans le cas (rare) ou isatzen n'est pas defini ou invalide
if (profiles(jj) % zenangle .lt.0.0d0 .or. &
profiles(jj) % zenangle .gt. zenmax ) then
write(*,*) "!!! WARNING !!!"
write(*,*) "INVALID ZENITH ANGLE"
write(*,*) "angle, profile number, sensor", profiles(jj) % zenangle, jj, krtid
write(*,*) "replaced by 0.0 !!!"
profiles(jj) % zenangle=0.d0
endif
!**********************************************************
profiles(jj) % azangle = (isatazim(j))/100.0d0
profiles(jj) % sunzenangle = (isunza(j)-9000)/100.0d0
profiles(jj) % sunazangle = 0.d0 ! necessaire pour radiation solaire a changer plus tard
profiles(jj) % latitude = zlat(j)
profiles(jj) % longitude = zlon(j)
profiles(jj) % elevation = 0.001d0*zht(ilowlvl_T,j) ! unite km
profiles(jj) % skin % surftype = ksurf(j)
profiles(jj) % skin % watertype= 1 !utilise pour calcul rayonnement solaire reflechi seulement
profiles(jj) % skin % t = col_getElem
(lcolumnghr,1,iptobscma(j),'TG')
profiles(jj) % skin % salinity = 35.d0 ! for FASTEM-4 only to revise (practical salinity units)
profiles(jj) % skin % fastem(:)= 0.0d0
!
profiles(jj) % s2m % t = col_getElem
(lcolumnghr,ilowlvl_T,iptobscma(j),'TT')
!!! profiles(jj) % s2m % q = exp(col_getElem(lcolumnghr,ilowlvl_T,iptobscma(j),'HU')) * q_mixratio_to_ppmv
profiles(jj) % s2m % q = 0.3D6 !! new a value between 0 and 0.6d6 so that RTTOV will not complain
profiles(jj) % s2m % p = col_getElem
(lcolumnghr,1 ,iptobscma(j),'P0')*MPC_MBAR_PER_PA_R8
profiles(jj) % s2m % u = col_getElem
(lcolumnghr,ilowlvl_M,iptobscma(j),'UU')
profiles(jj) % s2m % v = col_getElem
(lcolumnghr,ilowlvl_M,iptobscma(j),'VV')
profiles(jj) % s2m % o = 0.0d0 !surface ozone never used
profiles(jj) % s2m % wfetc = 100000.0d0 ! Wind fetch (in meter for rttov10 ?) used to calculate reflection of solar radiation by sea surface
!
profiles(jj) % idg = 0
profiles(jj) % ish = 0
profiles(jj) % snow_frac = 0.d0 ! Surface coverage snow fraction(0-1), used only by IR emissivity atlas
profiles(jj) % soil_moisture = 0.d0 ! soil moisure (m**3/m**3) not yet used
profiles(jj) % Be = 0.4d0 ! earth magnetic field strength (gauss) (must be non zero)
profiles(jj) % cosbk = 0.0d0 ! cosine of the angle between the earth magnetic field and wave propagation direction
if ( bgckMode ) then
profiles_qc(jj) % lat = zlat(j)
profiles_qc(jj) % lon = zlon(j)
profiles_qc(jj) % sunza = profiles(jj) % sunzenangle
endif
if(coefs(krtid)%coef%nco2 > 0) then
ig= coefs(krtid)%coef%fmv_gas_pos(gas_id_co2)
profiles(jj) % co2(:) = coefs(krtid)%coef%ref_prfl_mr(:,ig)
endif
if(coefs(krtid)%coef%nn2o > 0) then
ig = coefs(krtid)%coef%fmv_gas_pos(gas_id_n2o)
profiles(jj) % n2o(:) = coefs(krtid)%coef%ref_prfl_mr(:,ig)
endif
if(coefs(krtid)%coef%nco > 0) then
ig = coefs(krtid)%coef%fmv_gas_pos(gas_id_co)
profiles(jj) % co(:) = coefs(krtid)%coef%ref_prfl_mr(:,ig)
endif
if(coefs(krtid)%coef%nch4 > 0) then
ig = coefs(krtid)%coef%fmv_gas_pos(gas_id_ch4)
profiles(jj) % ch4(:) = coefs(krtid)%coef%ref_prfl_mr(:,ig)
endif
profiles(jj) % p(:) = coefs(krtid) %coef% ref_prfl_p(:)
profiles(jj) % t(:) = toext(:,j)
profiles(jj) % q(:) = qoext(:,j) * q_mixratio_to_ppmv
profiles(jj) % o3(:) = ozo(:,j)
if ( bgckMode ) profiles_qc(jj) % z(:) = zhoext(:,j)
profiles(jj) % ctp = 1013.25d0
profiles(jj) % cfraction = 0.d0
end do
! next bunch !
knpf = 0
enddo bobs
enddo binst
alloc_status(:) = 0
deallocate (ksurf ,stat= alloc_status(1) )
deallocate (iptobs ,stat= alloc_status(2) )
deallocate (iptobscma ,stat= alloc_status(3) )
deallocate (isatzen ,stat= alloc_status(4) )
deallocate (isatazim ,stat= alloc_status(5) )
deallocate (isunza ,stat= alloc_status(6) )
deallocate (zlat ,stat= alloc_status(8) )
deallocate (zlon ,stat= alloc_status(9) )
deallocate (ozo ,stat= alloc_status(10))
deallocate (to ,stat= alloc_status(11))
deallocate (lqo ,stat= alloc_status(12))
deallocate (zho ,stat= alloc_status(13))
deallocate (toext ,stat= alloc_status(14))
deallocate (qoext ,stat= alloc_status(15))
deallocate (zhoext ,stat= alloc_status(16))
deallocate (zvlev ,stat= alloc_status(17))
deallocate (zt ,stat= alloc_status(18))
deallocate (zlq ,stat= alloc_status(19))
deallocate (zht ,stat= alloc_status(20))
deallocate (xpres ,stat= alloc_status(21))
if( any(alloc_status /= 0) ) then
write(*,*) ' tovs_fill_profiles : memory deallocation error'
call abort3d
('tovs_fill_profiles ')
end if
9263 format(1x,10f8.4)
! 3. Close up
! . --------
return
end subroutine tovs_fill_profiles