-
Andi Walther authoredAndi Walther authored
cx_rttov_bridge_mod.f90 19.18 KiB
module cx_rttov_bridge_mod
!use cx_pfaast_constants_mod, only: tstd, ostd, wstd,pstd
! rttov_const contains useful RTTOV constants
USE rttov_const, ONLY : &
errorstatus_success, &
errorstatus_fatal, &
platform_name, &
inst_name
! rttov_types contains definitions of all RTTOV data types
USE rttov_types, ONLY : &
rttov_options, &
rttov_coefs, &
rttov_profile, &
rttov_transmission, &
rttov_radiance, &
rttov_chanprof, &
rttov_emissivity, &
rttov_reflectance
USE parkind1, ONLY : jpim, jprb, jplm
USE rttov_unix_env, ONLY : rttov_exit
IMPLICIT NONE
#include "rttov_direct.interface"
#include "rttov_parallel_direct.interface"
#include "rttov_read_coefs.interface"
#include "rttov_dealloc_coefs.interface"
#include "rttov_alloc_direct.interface"
#include "rttov_user_options_checkinput.interface"
#include "rttov_print_opts.interface"
#include "rttov_print_profile.interface"
#include "rttov_skipcommentline.interface"
!--------------------------
!
INTEGER(KIND=jpim), PARAMETER :: iup = 20 ! unit for input profile file
INTEGER(KIND=jpim), PARAMETER :: ioout = 21 ! unit for output
! RTTOV variables/structures
!====================
TYPE(rttov_options) :: opts ! Options structure
TYPE(rttov_coefs) :: coefs ! Coefficients structure
TYPE(rttov_chanprof), POINTER :: chanprof(:) => NULL() ! Input channel/profile list
LOGICAL(KIND=jplm), POINTER :: calcemis(:) => NULL() ! Flag to indicate calculation of emissivity within RTTOV
TYPE(rttov_emissivity), POINTER :: emissivity(:) => NULL() ! Input/output surface emissivity
LOGICAL(KIND=jplm), POINTER :: calcrefl(:) => NULL() ! Flag to indicate calculation of BRDF within RTTOV
TYPE(rttov_reflectance), POINTER :: reflectance(:) => NULL() ! Input/output surface BRDF
TYPE(rttov_profile), POINTER :: profiles(:) => NULL() ! Input profiles
TYPE(rttov_transmission) :: transmission ! Output transmittances
TYPE(rttov_radiance) :: radiance ! Output radiances
INTEGER(KIND=jpim) :: errorstatus ! Return error status of RTTOV subroutine calls
INTEGER(KIND=jpim) :: alloc_status
CHARACTER(LEN=11) :: NameOfRoutine = 'test_rttovv'
! variables for input
!====================
CHARACTER(LEN=256) :: coef_filename,cld_coef_filename
INTEGER(KIND=jpim) :: nthreads
INTEGER(KIND=jpim) :: dosolar
INTEGER(KIND=jpim) :: nlevels
INTEGER(KIND=jpim) :: nprof
INTEGER(KIND=jpim) :: nchannels
INTEGER(KIND=jpim) :: nchanprof
INTEGER(KIND=jpim), ALLOCATABLE :: channel_list(:)
REAL(KIND=jprb) :: trans_out(10)
! loop variables
INTEGER(KIND=jpim) :: j, jch
INTEGER(KIND=jpim) :: np, nch
INTEGER(KIND=jpim) :: ilev, nprint
INTEGER(KIND=jpim) :: iprof, joff
INTEGER :: ios
contains
function channel_map (sensor,ancil_data_path, chn,coef_filename,cld_coef_filename) result (list)
#define STRINGIFY(x) x
implicit none
character(len = *) :: sensor
character(len = * ) :: ancil_data_path
integer :: chn
integer :: list
integer, allocatable:: chn_list(:)
! integer :: mod_list(5) = [20,22,29,31,32]
integer :: kk
character (len = *) :: coef_filename
character (len = *) :: cld_coef_filename
character (len=:), allocatable :: path
character (len = 100) :: sensor_string
character (len=1) :: rttov_version_string
character (len = 1) :: metop_nr
integer :: avhrr_num
#ifndef RTTOVPATH
print*,'RTTOV PATH not set ..stop'
print*,__TIMESTAMP__
! print*,RTTOVPATH
stop
#endif
path = trim(ancil_data_path) // "static/rttov/"
rttov_version_string = '9'
! --
! the mapping translates one channel infot
! RTTOV channel number
!
!
allocate(chn_list(45))
chn_list = -1
! metop
if (sensor .eq. 'AVHRR-METOPA') metop_nr = '2'
if (sensor .eq. 'AVHRR-METOPB') metop_nr = '1'
if (sensor .eq. 'AVHRR-METOPC') metop_nr = '3'
select case(sensor)
case('MTSAT-1')
list = chn
sensor_string = 'mtsat_1_imager'
case('MTSAT-2')
list = chn
sensor_string = 'mtsat_2_imager'
case( 'MODIS-AQUA')
!list = chn -19
! if ( chn .gt. 26) list = chn - 20
list = chn
sensor_string = 'eos_2_modis'
case( 'MODIS-TERRA')
!list = chn -19
! if ( chn .gt. 26) list = chn - 20
list = chn
sensor_string = 'eos_1_modis'
case ( 'VIIRS-SNPP')
chn_list = [6,9,3,4,10,14,15,1,2,-1,-1,-1,-1,-1,7,-1,-1,-1,-1,17,-1,18,-1,-1,-1,12,-1,-1,19,-1,20,22]
list = chn_list(chn)
sensor_string = 'jpss_0_viirs'
case ( 'VIIRS-N20')
chn_list = [6,9,3,4,10,14,15,1,2,-1,-1,-1,-1,-1,7,-1,-1,-1,-1,17,-1,18,-1,-1,-1,12,-1,-1,19,-1,20,22]
list = chn_list(chn)
sensor_string = 'noaa_20_viirs'
case ('AHI8')
chn_list(20:38) = [7,-1,-1,-1,-1,-1,-1,9,10,11,12,14,15,16,-1,-1,-1,8,13]
list = chn_list(chn)
sensor_string = 'himawari_8_ahi'
case ('AHI9')
chn_list(20:38) = [7,-1,-1,-1,-1,-1,-1,9,10,11,12,14,15,16,-1,-1,-1,8,13]
list = chn_list(chn)
sensor_string = 'himawari_9_ahi'
case ('GOES-16')
chn_list = [2,3,1,-1,-1,5,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,-1,7,-1,-1,-1,4,9,10,11,12,14,15,16,-1,-1,-1,8,13,-1,-1,-1,-1,-1,-1,-1]
list = chn_list(chn)
sensor_string = 'goes_16_abi'
case ('GOES-17')
chn_list = [2,3,1,-1,-1,5,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,-1,7,-1,-1,-1,4,9,10,11,12,14,15,16,-1,-1,-1,8,13,-1,-1,-1,-1,-1,-1,-1]
list = chn_list(chn)
sensor_string = 'goes_17_abi'
case ( 'SEVIRI-MSG08')
!---stw chn_list(20:33) = [1,-1,-1,-1,-1,-1,-1,2,3,4,5,6,7,8]
chn_list(20:33) = [4,-1,-1,-1,-1,-1,-1,5,6,7,8,9,10,11]
list = chn_list(chn)
sensor_string = 'msg_1_seviri'
case ( 'SEVIRI-MSG09')
!---stw chn_list(20:33) = [1,-1,-1,-1,-1,-1,-1,2,3,4,5,6,7,8]
chn_list(20:33) = [4,-1,-1,-1,-1,-1,-1,5,6,7,8,9,10,11]
list = chn_list(chn)
sensor_string = 'msg_2_seviri'
case ( 'SEVIRI-MSG10')
!---stw chn_list(20:33) = [1,-1,-1,-1,-1,-1,-1,2,3,4,5,6,7,8]
chn_list(20:33) = [4,-1,-1,-1,-1,-1,-1,5,6,7,8,9,10,11]
list = chn_list(chn)
sensor_string = 'msg_3_seviri'
case ( 'SEVIRI-MSG11')
!---stw chn_list(20:33) = [1,-1,-1,-1,-1,-1,-1,2,3,4,5,6,7,8]
chn_list(20:33) = [4,-1,-1,-1,-1,-1,-1,5,6,7,8,9,10,11]
list = chn_list(chn)
sensor_string = 'msg_4_seviri'
case('OLCI')
chn_list = [6,9,3,4,10,14,15,1,2,-1,-1,-1,-1,-1,7,-1,-1,-1,-1,7,-1,18,-1,-1,-1,12,-1,-1,19,-1,20,22]
list = chn
list = (chn-1)*5*3 + 1
sensor_string = 'sentinel3_1_olci'
case ('SLSTR2')
chn_list = [6,9,3,4,10,14,15,1,2,-1,-1,-1,-1,-1,7,-1,-1,-1,-1,7,-1,18,-1,-1,-1,12,-1,-1,19,-1,20,22]
list = chn
sensor_string = 'sentinel3_2_slstr'
case('FY3-D')
Chn_List(20:32) = [ 20,-1,-1,21,-1,-1,-1,-1, 22,23,-1,24,25 ]
list = chn_list(chn)
sensor_string = 'fy3_4_mersi2'
case default
if (index(sensor,'AVHRR') .gt. 0) then
chn_list(1) = 1
chn_list(2) = 2
select case(sensor(11:12))
! -- sensor name can be AVHRR-NOAA??
case ('15','16','17','18','19')
chn_list(6) = 3
chn_list(20) = 4
chn_list(31) = 5
chn_list(32) = 6
case default
chn_list(20) = 3
chn_list(31) = 4
chn_list(32) = 5
end select
if (index(sensor,'AVHRR-METOP') .gt. 0) then
chn_list(6) = 3
chn_list(20) = 4
chn_list(31) = 5
chn_list(32) = 6
end if
sensor_string = 'noaa_'//sensor(11:12)//'_avhrr'
if ( index(sensor, 'NOAA0' ) .gt. 0 ) then
sensor_string = 'noaa_'//sensor(12:12)//'_avhrr'
rttov_version_string = '8'
chn_list(20) = 1
chn_list(31) = 2
chn_list(32) = 3
end if
list = chn_list(chn)
if (index(sensor,'AVHRR-METOP') .gt. 0 ) then
sensor_string = 'metop_'//metop_nr//'_avhrr'
end if
if (index(sensor,'AVHRR-TIROSN') .gt. 0) then
sensor_string = 'noaa_5_avhrr'
rttov_version_string = '8'
chn_list(20) = 1
chn_list(31) = 2
chn_list(32) = 3
end if
else if (index(sensor,'HIRS') .gt. 0) then
! 20 23 24 25 27 28 30 31 32 33 34 35 36
chn_List(20:36) = [ 19,-1,-1,18,15,14,-1,12,11,-1,9, 8,10, 7, 6, 5, 4 ]
list = chn_list(chn)
sensor_string = 'noaa_'//sensor(10:11)//'_hirs-shifted'
rttov_version_string = '8'
if (index(sensor,'AVHRR-METOP') .gt. 0 ) then
sensor_string = 'metop_'//metop_nr//'_hirs-shifted'
end if
if (index(sensor,'AVHRR-TIROSN') .gt. 0) then
sensor_string = 'noaa_5_hirs-shifted'
end if
else if (index(sensor,'GOES-') .gt. 0) then
rttov_version_string = '8'
chn_list(1) = 1
chn_list(20) = 2
chn_list(27) = 3
chn_list(31) = 4
chn_list(32) = 5
chn_list(33) = 6
sensor_string = 'goes_'//sensor(6:7)//'_imager'
if ( sensor(6:6) .ne. '1' ) then
sensor_string = 'goes_'//sensor(6:6)//'_imager'
rttov_version_string = '7'
end if
list = chn_list(chn)
else
print*,trim(sensor)
stop ' missing sensor in channel mapping of RTTOV inform andi.walther@ssec.wisc.edu '
end if
end select
coef_filename = trim(path)//'/rtcoef_rttov12/rttov'//rttov_version_string//'pred54L/rtcoef_'//trim(sensor_string)//'.dat'
cld_coef_filename = trim(path)//'cldaer_ir/sccldcoef_'//trim(sensor_string)//'.dat'
if ( list .eq. 0) list = -1
!print*,'Sensor rttov mapping: ',sensor,chn,list
deallocate(chn_list)
end function channel_map
subroutine compute_transmission_rttov ( &
ancil_data_path &
& , pstd &
& ,temp &
& ,wvmr &
& ,ozmr &
& ,theta &
& ,sensor &
& ,kban_in &
& ,taut &
& , use_modis_channel_equivalent )
implicit none
character(len = * ) , intent(in) :: ancil_data_path
real, intent(in) :: pstd (:,:)
real, intent(in) :: temp (:,:)
real, intent(in) :: wvmr(:,:)
real, intent(in) :: ozmr(:,:)
real, intent(in) :: theta (:)
character (len =* ), intent(in) :: sensor
integer, intent(in) :: kban_in
logical , optional , intent(in) :: use_modis_channel_equivalent
real, intent(out) :: taut (:,:)
integer :: lll
real, parameter :: Q_MIXRATIO_TO_PPMV = 1.60771704e+6
opts % rt_ir % addsolar = .FALSE.
opts % interpolation % addinterp = .TRUE. ! Allow interpolation of input profile
opts % interpolation % interp_mode = 1 ! Set interpolation method
opts % rt_all % addrefrac = .TRUE. ! Include refraction in path calc
opts % rt_ir % addclouds = .FALSE. ! Don't include cloud effects
opts % rt_ir % addaerosl = .FALSE. ! Don't include aerosol effects
opts % rt_ir % ozone_data = .TRUE. ! Set the relevant flag to .TRUE.
opts % rt_ir % co2_data = .FALSE. ! when supplying a profile of the
opts % rt_ir % n2o_data = .FALSE. ! given trace gas (ensure the
opts % rt_ir % ch4_data = .FALSE. ! coef file supports the gas)
opts % rt_ir % co_data = .FALSE. !
opts % rt_ir % so2_data = .FALSE. !
opts % rt_mw % clw_data = .FALSE. !
opts % rt_mw % clw_scheme = 0
opts % config % verbose = .FALSE. ! Enable printing of warnings
!lll = channel_map (sensor,kban_in , coef_filename)
lll = channel_map (sensor,ancil_data_path, kban_in , coef_filename,cld_coef_filename)
nprof = size(temp(1,:))
nlevels = size(temp(:,1))
nthreads = 1
nchannels = 1
allocate(channel_list(nchannels))
if ( lll .lt. 0 ) then
if ( allocated(channel_list)) deallocate(channel_list)
return
end if
channel_list = [lll]
! --------------------------------------------------------------------------
! 2. Read coefficients
! --------------------------------------------------------------------------
CALL rttov_read_coefs(errorstatus, coefs, opts, file_coef=coef_filename)
IF (errorstatus /= errorstatus_success) THEN
WRITE(*,*) 'fatal error reading coefficients'
CALL rttov_exit(errorstatus)
ENDIF
! Ensure input number of channels is not higher than number stored in coefficient file
IF (nchannels > coefs % coef % fmv_chn) THEN
nchannels = coefs % coef % fmv_chn
ENDIF
! Ensure the options and coefficients are consistent
CALL rttov_user_options_checkinput(errorstatus, opts, coefs)
IF (errorstatus /= errorstatus_success) THEN
WRITE(*,*) 'error in rttov options'
CALL rttov_exit(errorstatus)
ENDIF
! --------------------------------------------------------------------------
! 3. Allocate RTTOV input and output structures
! --------------------------------------------------------------------------
! Determine the total number of radiances to simulate (nchanprof).
! In this example we simulate all specified channels for each profile, but
! in general one can simulate a different number of channels for each profile.
nchanprof = nchannels * nprof
! Allocate structures for rttov_direct
CALL rttov_alloc_direct( &
errorstatus, &
1_jpim, & ! 1 => allocate
nprof, &
nchanprof, &
nlevels, &
chanprof, &
opts, &
profiles, &
coefs, &
transmission, &
radiance, &
calcemis=calcemis, &
emissivity=emissivity, &
calcrefl=calcrefl, &
reflectance=reflectance, &
init=.TRUE._jplm)
IF (errorstatus /= errorstatus_success) THEN
WRITE(*,*) 'allocation error for rttov_direct structures'
CALL rttov_exit(errorstatus)
ENDIF
! --------------------------------------------------------------------------
! 4. Build the list of profile/channel indices in chanprof
! --------------------------------------------------------------------------
nch = 0_jpim
DO j = 1, nprof
DO jch = 1, nchannels
nch = nch + 1_jpim
chanprof(nch)%prof = j
chanprof(nch)%chan = channel_list(jch)
ENDDO
ENDDO
deallocate ( channel_list)
! --------------------------------------------------------------------------
! 5. Read profile data
! --------------------------------------------------------------------------
profiles(:) % gas_units = 2 !
! Gas units (must be same for all profiles)
! 0 => ppmv over dry air
! 1 => kg/kg over moist air
! 2 => ppmv over moist air
!
! Loop over all profiles and read data for each one
DO iprof = 1, nprof
profiles(iprof) % t(:) = temp(:,iprof)
profiles(iprof) % p(:) = pstd(:,iprof)
profiles(iprof) % o3(:) = max(ozmr(:,iprof),0.1001E-10)
profiles(iprof) % q(:) = wvmr(:, iprof) * Q_MIXRATIO_TO_PPMV /1000.
profiles(iprof) % s2m % p =pstd(96,iprof)
profiles(iprof) % s2m % t = temp(96,iprof)
profiles(iprof) % s2m % q = wvmr(96,iprof) * Q_MIXRATIO_TO_PPMV /1000.
profiles(iprof) % s2m % u = 0.
profiles(iprof) % s2m % v = 0.
profiles(iprof) % s2m % wfetc = 1000000.
profiles(iprof) % skin % t = temp(96,iprof) + 5.
profiles(iprof) % zenangle = theta(iprof)
profiles(iprof) % azangle = 0.
profiles(iprof) % latitude = 45.
profiles(iprof) % longitude = 19.
! profiles(iprof) % zenangle = theta
! profiles(iprof) % zenangle = theta
ENDDO
CLOSE(iup)
! --------------------------------------------------------------------------
! 6. Specify surface emissivity and reflectance
! --------------------------------------------------------------------------
! In this example we have no values for input emissivities
emissivity(:) % emis_in = 0._jprb
! Calculate emissivity within RTTOV where the input emissivity value is
! zero or less (all channels in this case)
calcemis(:) = (emissivity(:) % emis_in <= 0._jprb)
! In this example we have no values for input reflectances
reflectance(:) % refl_in = 0._jprb
! Calculate BRDF within RTTOV where the input BRDF value is zero or less
! (all channels in this case)
calcrefl(:) = (reflectance(:) % refl_in <= 0._jprb)
! Use default cloud top BRDF for simple cloud in VIS/NIR channels
reflectance(:) % refl_cloud_top = 0._jprb
! --------------------------------------------------------------------------
! 7. Call RTTOV forward model
! --------------------------------------------------------------------------
CALL rttov_direct( &
errorstatus, &! out error flag
chanprof, &! in channel and profile index structure
opts, &! in options structure
profiles, &! in profile array
coefs, &! in coefficients structure
transmission, &! inout computed transmittances
radiance, &! inout computed radiances
calcemis = calcemis, &! in flag for internal emissivity calcs
emissivity = emissivity, &! inout input/output emissivities per channel
calcrefl = calcrefl, &! in flag for internal BRDF calcs
reflectance = reflectance) ! inout input/output BRDFs per channel
IF (errorstatus /= errorstatus_success) THEN
WRITE (*,*) 'rttov_direct error'
CALL rttov_exit(errorstatus)
ENDIF
taut = transmission % tau_levels
! Deallocate structures for rttov_direct
CALL rttov_alloc_direct( &
errorstatus, &
0_jpim, & ! 0 => deallocate
nprof, &
nchanprof, &
nlevels, &
chanprof, &
opts, &
profiles, &
coefs, &
transmission, &
radiance, &
calcemis=calcemis, &
emissivity=emissivity, &
calcrefl=calcrefl, &
reflectance=reflectance)
IF (errorstatus /= errorstatus_success) THEN
WRITE(*,*) 'deallocation error for rttov_direct structures'
CALL rttov_exit(errorstatus)
ENDIF
CALL rttov_dealloc_coefs(errorstatus, coefs)
IF (errorstatus /= errorstatus_success) THEN
WRITE(*,*) 'coefs deallocation error'
ENDIF
end subroutine compute_transmission_rttov
end module cx_rttov_bridge_mod