tovsNL_mod sourceΒΆ

   1
   2module tovsNL_mod
   3  ! MODULE tovsNL_mod (prefix='tvs' category='5. Observation operators')
   4  !
   5  !:Purpose:  Derived types, public variables and procedures related to the
   6  !           nonlinear version of RTTOV
   7  !
   8  use rttovInterfaces_mod
   9  use rttov_types, only :   &
  10       rttov_coefs         ,&
  11       rttov_fast_coef     ,&
  12       rttov_scatt_coef    ,&
  13       rttov_options       ,&
  14       rttov_options_scatt ,&
  15       rttov_profile       ,&
  16       rttov_profile_cloud ,&
  17       rttov_radiance      ,&
  18       rttov_transmission  ,&
  19       rttov_chanprof      ,&
  20       rttov_emissivity
  21  use rttov_const, only :           &
  22       platform_name               ,&
  23       nplatforms                  ,&
  24       inst_name                   ,&
  25       ninst                       ,&
  26       inst_id_goesim              ,&
  27       inst_id_gmsim               ,&
  28       inst_id_mtsatim             ,&
  29       inst_id_amsua               ,&
  30       inst_id_mhs                 ,&
  31       sensor_id_mw                ,&
  32       sensor_id_po                ,&
  33       platform_id_jpss            ,&
  34       platform_id_himawari        ,&
  35       platform_id_eos             ,&
  36       errorstatus_success         ,&
  37       mair, mh2o, mo3             ,&
  38       surftype_land               ,&
  39       surftype_seaice             ,&
  40       surftype_sea                ,&
  41       watertype_ocean_water       ,&
  42       ngases_max                  ,&
  43       gas_id_mixed                ,&
  44       gas_unit_specconc           ,&
  45       interp_rochon_loglinear_wfn ,&
  46       zenmax                      ,&
  47       zenmaxv9                    ,&
  48       o3min                       ,&
  49       o3max                       ,&
  50       tmin                        ,&
  51       tmax                        ,&
  52       qmin                        ,&
  53       qmax                        ,&
  54       elevmax                     ,&
  55       wmax                        ,&
  56       pmin                        ,&
  57       pmax
  58  use parkind1, only : jpim, jplm
  59  use rttov_fast_coef_utils_mod, only: set_pointers, set_fastcoef_level_bounds
  60  use rttov_solar_refl_mod, only : rttov_refl_water_interp
  61  use midasMpi_mod
  62  use codtyp_mod
  63  use mpi
  64  use utilities_mod
  65  use obsSpaceData_mod
  66  use earthConstants_mod
  67  use MathPhysConstants_mod
  68  use ozoneClim_mod
  69  use columnData_mod 
  70  use mod_rttov_emis_atlas
  71  use verticalCoord_mod
  72  use codePrecision_mod
  73  use humidityLimits_mod
  74  use interpolation_mod
  75
  76  implicit none
  77  save
  78  private
  79
  80  type surface_params
  81    real(8)              :: albedo   ! surface albedo (0-1)
  82    real(8)              :: ice      ! ice cover (0-1) 
  83    real(8)              :: snow     ! snow cover (0-1)
  84    real(8)              :: pcnt_wat ! water percentage in pixel containing profile (0-1)
  85    real(8)              :: pcnt_reg ! water percentage in an area around profile (0-1)
  86    integer              :: ltype    ! surface type (1,...,20)
  87  end type surface_params
  88
  89  ! public variables (parameters)
  90  public :: tvs_maxChannelNumber, tvs_maxNumberOfChannels, tvs_maxNumberOfSensors, tvs_defaultEmissivity
  91  ! public variables (non-parameters)
  92  public :: tvs_nchan, tvs_ichan, tvs_lsensor, tvs_headerIndex, tvs_tovsIndex, tvs_nobtov
  93  public :: tvs_nchanMpiGlobal, tvs_ichanMpiGlobal
  94  public :: tvs_isReallyPresent,tvs_listSensors
  95  public :: tvs_isReallyPresentMpiGlobal
  96  public :: tvs_nsensors, tvs_platforms, tvs_satellites, tvs_instruments, tvs_channelOffset
  97  public :: tvs_debug, tvs_satelliteName, tvs_instrumentName, tvs_useO3Climatology
  98  public :: tvs_coefs, tvs_opts, tvs_transmission,tvs_emissivity
  99  public :: tvs_coef_scatt, tvs_opts_scatt
 100  public :: tvs_radiance, tvs_surfaceParameters
 101  public :: tvs_numMWInstrumUsingCLW, tvs_numMWInstrumUsingHydrometeors
 102  public :: tvs_mwInstrumUsingCLW_tl, tvs_mwInstrumUsingHydrometeors_tl
 103  public :: tvs_mwAllskyAssim
 104  ! public procedures
 105  public :: tvs_fillProfiles, tvs_rttov, tvs_printDetailledOmfStatistics, tvs_allocTransmission, tvs_cleanup
 106  public :: tvs_deallocateProfilesNlTlAd
 107  public :: tvs_setupAlloc,tvs_setup, tvs_isIdBurpTovs, tvs_isIdBurpHyperSpectral, tvs_isIdBurpInst, tvs_getAllIdBurpTovs
 108  public :: tvs_isInstrumGeostationary,  tvs_isNameHyperSpectral
 109  public :: tvs_isNameGeostationary
 110  public :: tvs_getInstrumentId, tvs_getPlatformId, tvs_mapSat, tvs_mapInstrum
 111  public :: tvs_isInstrumHyperSpectral, tvs_getChanprof, tvs_countRadiances
 112  public :: tvs_ChangedStypValue
 113  public :: tvs_getHIREmissivities, tvs_getOtherEmissivities, tvs_rttov_read_coefs
 114  public :: tvs_getLocalChannelIndexFromChannelNumber
 115  public :: tvs_getMWemissivityFromAtlas, tvs_getProfile
 116  public :: tvs_getCorrectedSatelliteAzimuth
 117  public :: tvs_isInstrumUsingCLW, tvs_isInstrumUsingHydrometeors, tvs_getChannelNumIndexFromPPP
 118  public :: tvs_isInstrumAllskyTtAssim, tvs_isInstrumAllskyHuAssim
 119  ! Module parameters
 120  ! units conversion from  mixing ratio to ppmv and vice versa
 121  real(8), parameter :: qMixratio2ppmv  = (1000000.0d0 * mair) / mh2o
 122  real(8), parameter :: qppmv2Mixratio  = mh2o / (1000000.0d0 * mair)
 123  real(8), parameter :: o3Mixratio2ppmv = (1000000.0d0 * mair) / mo3
 124  real(8), parameter :: o3ppmv2Mixratio = mo3 / (1000000.0d0 * mair)
 125  real(pre_obsReal), parameter :: tvs_defaultEmissivity = 0.95
 126
 127  integer, parameter :: tvs_maxChannelNumber   = 8461   ! Max. value for channel number
 128  integer, parameter :: tvs_maxNumberOfChannels = 2211  ! Max. no. of channels (for one profile/spectra)
 129  integer, parameter :: tvs_maxNumberOfSensors  = 100   ! Max no sensors to be used
 130  integer, parameter :: tvs_nlevels     = 101           ! Maximum No. of RTTOV pressure levels including 'rttov top' at 0.005 hPa
 131
 132  ! Module variables
 133  integer, allocatable :: tvs_bodyIndexFromBtIndex(:)  ! Provides the bodyIndex in ObsSpaceData based on btIndex
 134  integer, allocatable :: tvs_nchan(:)             ! Number of channels per instrument (local)
 135  integer, allocatable :: tvs_ichan(:,:)           ! List of channels per instrument (local)
 136  integer, allocatable :: tvs_nchanMpiGlobal(:)     ! Number of channels per instrument (global)
 137  integer, allocatable :: tvs_ichanMpiGlobal(:,:)  ! List of channels per instrument  (global)
 138  integer, allocatable :: tvs_lsensor(:)           ! Sensor number for each profile
 139  integer, allocatable :: tvs_headerIndex (:)      ! Observation position in obsSpaceData header for each profile
 140  integer, allocatable :: tvs_tovsIndex (:)        ! Index in TOVS structures for each observation header in obsSpaceData
 141  logical, allocatable :: tvs_isReallyPresent(:)   ! Logical flag to identify instruments really assimilated (local)
 142  logical, allocatable :: tvs_isReallyPresentMpiGLobal(:)   ! Logical flag to identify instruments really assimilated (global)
 143  integer, allocatable :: tvs_listSensors(:,:)     ! Sensor list
 144  type (rttov_emis_atlas_data), allocatable :: tvs_atlas(:)     ! Emissivity atlases
 145  type(surface_params), allocatable :: tvs_surfaceParameters(:) ! surface parameters 
 146  integer tvs_nobtov                               ! Number of tovs observations
 147  integer tvs_nsensors                             ! Number of individual sensors.
 148  integer tvs_platforms(tvs_maxNumberOfSensors)    ! RTTOV platform ID's (e.g., 1=NOAA; 2=DMSP; ...)
 149  integer tvs_satellites(tvs_maxNumberOfSensors)   ! RTTOV satellite ID's (e.g., 1 to 16 for NOAA; ...)
 150  integer tvs_instruments(tvs_maxNumberOfSensors)  ! RTTOVinstrument ID's (e.g., 3=AMSU-A; 4=AMSU-B; 6=SSMI; ...)
 151  integer tvs_channelOffset(tvs_maxNumberOfSensors)! BURP to RTTOV channel mapping offset
 152  integer instrumentIdsUsingCLW(tvs_maxNumberOfSensors)
 153  integer instrumentIdsUsingHydrometeors(tvs_maxNumberOfSensors)
 154  integer tvs_numMWInstrumUsingCLW 
 155  integer tvs_numMWInstrumUsingHydrometeors
 156  logical tvs_mwInstrumUsingCLW_tl
 157  logical tvs_mwInstrumUsingHydrometeors_tl
 158  logical tvs_mwAllskyAssim
 159  logical :: tvs_mpiTask0ReadCoeffs 
 160  real(8) :: tvs_cloudScaleFactor 
 161  logical tvs_debug                                ! Logical key controlling statements to be  executed while debugging TOVS only
 162  logical tvs_useO3Climatology                     ! Determine if ozone model field or climatology is used
 163                                                   ! If ozone model field is specified, related increments will be generated in assimilation
 164  logical tvs_regLimitExtrap                       ! use RTTOV reg_limit_extrap option
 165  logical tvs_doAzimuthCorrection(tvs_maxNumberOfSensors)
 166  logical tvs_isAzimuthValid(tvs_maxNumberOfSensors)
 167  logical tvs_userDefinedDoAzimuthCorrection
 168  logical tvs_userDefinedIsAzimuthValid
 169
 170  character(len=15) tvs_satelliteName(tvs_maxNumberOfSensors)
 171  character(len=15) tvs_instrumentName(tvs_maxNumberOfSensors)
 172  character(len=8) radiativeTransferCode           ! RadiativeTransferCode : TOVS radiation model used
 173  real(8), allocatable :: tvs_emissivity(:,:)      ! Surface emissivities organized by profiles and channels
 174  integer, parameter :: kslon=2160, kslat=1080     ! CERES file dimension in grid points
 175
 176  ! High resolution surface fields
 177  integer :: surfaceType(kslon,kslat)  
 178  real(8) :: waterFraction(kslon,kslat) 
 179
 180  ! Derived typeso
 181  type(rttov_coefs), allocatable           :: tvs_coefs(:)          ! rttov coefficients
 182  type(rttov_options), allocatable         :: tvs_opts(:)           ! rttov options
 183  type(rttov_scatt_coef),allocatable       :: tvs_coef_scatt(:)     ! rttovscatt coefficients
 184  type(rttov_options_scatt), allocatable   :: tvs_opts_scatt(:)     ! rttovscatt options
 185  type(rttov_profile), target, allocatable :: tvs_profiles_nl(:)    ! all profiles on trial vertical coordinate for nl obs operator
 186  type(rttov_profile), target, allocatable :: tvs_profiles_tlad(:)  ! all profiles on increments vertical coordinates for linearized obs. operator
 187  type(rttov_radiance), allocatable        :: tvs_radiance(:)       ! radiances organized by profile
 188  type(rttov_transmission), allocatable    :: tvs_transmission(:)   ! transmittances all profiles for HIR quality control
 189  type(rttov_profile_cloud), target, allocatable :: tvs_cld_profiles_nl(:)! rttov scatt cloud profiles on trial vertical coordinate
 190  type(rttov_profile_cloud), target, allocatable :: tvs_cld_profiles_tlad(:) ! rttov scatt cloud profiles on increment vertical coordinates
 191
 192  ! Namelist variables:
 193  logical useUofWIREmiss                           ! Flag to activate use of RTTOV U of W IR emissivity Atlases
 194  logical useMWEmissivityAtlas                     ! Flag to activate use of RTTOV built-in MW emissivity Atlases      
 195  integer mWAtlasId                                ! MW Atlas Id used when useMWEmissivityAtlas == .true. ; 1 TELSEM2, 2 CNRM atlas
 196
 197  integer, external :: get_max_rss
 198 
 199contains
 200
 201  !--------------------------------------------------------------------------
 202  !  validateRttovVariable
 203  !--------------------------------------------------------------------------
 204  subroutine validateRttovVariable(value, variableName, obsSpaceData, headerIndex, minimum_opt, maximum_opt) 
 205    !
 206    !:Purpose:  check variable for validity for RTTOV-13, 
 207    !            if invalid replace by acceptable value and reject
 208    !
 209    implicit none
 210
 211    ! Arguments:
 212    real(8),           intent(inout) :: value           ! Value of the RTTOV input variable to check for validity
 213    character(len=*),  intent(in)    :: variableName    ! Name of the checked variable for output in listings
 214    type(struct_obs),  intent(inout) :: obsSpaceData    ! obsSpaceData object
 215    integer,           intent(in)    :: headerIndex     ! Index of the observation in obsSpaceData header table 
 216    real(8), optional, intent(in)    :: minimum_opt     ! Minimum acceptable value
 217    real(8), optional, intent(in)    :: maximum_opt     ! Maximum acceptable value
 218
 219    ! Locals:
 220    real(8)                         :: minimum, maximum
 221
 222    if (present(minimum_opt)) then
 223      minimum = minimum_opt
 224    else
 225      minimum = - huge(0.d0)
 226    end if
 227    
 228    if (present(maximum_opt)) then
 229      maximum = maximum_opt
 230    else
 231      maximum = huge(0.d0)
 232    end if
 233    
 234    if ( value < minimum .or. value > maximum ) then
 235      write(*,*) 'validateRttovVariable: !!! WARNING !!!'
 236      write(*,*) 'validateRttovVariable: INVALID ' // trim(variableName)
 237      write(*,*) 'validateRttovVariable: headerIndex ', headerIndex, " !"
 238      write(*,*) 'validateRttovVariable: ', value, ' should be between ', minimum, ' and ', maximum
 239      value = max(minimum, min(value, maximum) )
 240      write(*,*) 'validateRttovVariable: replaced with ', value, ' !'
 241      call rejectObs(obsSpaceData, headerIndex)
 242    end if
 243
 244  end subroutine validateRttovVariable
 245
 246  !--------------------------------------------------------------------------
 247  !  validateRttovProfile
 248  !--------------------------------------------------------------------------
 249  subroutine validateRttovProfile(profile, profileName, minimum, maximum, obsSpaceData, headerIndex) 
 250    !
 251    !:Purpose:  check profile for validity for RTTOV-13, 
 252    !            if invalid replace by acceptable value(s) and reject
 253    !
 254    implicit none
 255
 256    ! Arguments:
 257    real(8),          intent(inout) :: profile(:)    ! Vertical profile of input variables to check for validity
 258    character(len=*), intent(in)    :: profileName   ! Name of the checked profile for output in listings
 259    real(8),          intent(in)    :: minimum       ! Minimum acceptable value
 260    real(8),          intent(in)    :: maximum       ! Maximum acceptable value
 261    type(struct_obs), intent(inout) :: obsSpaceData  ! obsSpaceData object
 262    integer,          intent(in)    :: headerIndex   ! Index of the observation in obsSpaceData header table
 263
 264    ! Locals:
 265    logical                         :: ltest(size(profile))
 266    integer                         :: levelIndex
 267    
 268    ltest(:) = (profile(:) > maximum .or. profile(:) < minimum)
 269    
 270    if ( any(ltest) ) then
 271      write(*,*) 'validateRttovProfile: !!! WARNING !!!'
 272      write(*,*) 'validateRttovProfile: some INVALID ' // trim(profileName)
 273      write(*,*) 'validateRttovProfile: headerIndex ', headerIndex, " !"
 274      do levelIndex = 1, size(profile)
 275        if ( ltest(levelIndex) ) then
 276          write(*,*) 'validateRttovProfile: ', profile(levelIndex), &
 277              'should be between ', minimum, ' and ', maximum
 278          profile(levelIndex) = max(minimum, min(profile(levelIndex), maximum) )
 279          write(*,*) 'validateRttovProfile: replaced with ', profile(levelIndex) 
 280        end if
 281      end do
 282      call rejectObs(obsSpaceData, headerIndex)
 283    end if
 284    
 285  end subroutine validateRttovProfile
 286  
 287  !--------------------------------------------------------------------------
 288  ! rejectObs
 289  !--------------------------------------------------------------------------
 290  subroutine rejectObs(obsSpaceData, headerIndex)
 291    !
 292    !:Purpose: reject all data corresponding to headerIndex
 293    !
 294    implicit none
 295
 296    ! Arguments:
 297    type(struct_obs), intent(inout) :: obsSpaceData ! obsSpaceData object
 298    integer,          intent(in)    :: headerIndex  ! Index of the observation in obsSpaceData header table
 299
 300    ! Locals:
 301    integer :: bodyIndex
 302    
 303    call obs_set_current_body_list(obsSpaceData, headerIndex)
 304    BODY:do 
 305      bodyIndex = obs_getBodyIndex(obsSpaceData)
 306      if (bodyIndex < 0) exit BODY
 307      call obs_bodySet_i(obsSpaceData, OBS_ASS, bodyIndex, obs_notAssimilated)
 308    end do BODY
 309  end subroutine rejectObs
 310  
 311  !--------------------------------------------------------------------------
 312  ! tvs_setupAlloc
 313  !--------------------------------------------------------------------------
 314  subroutine tvs_setupAlloc(obsSpaceData)
 315    !
 316    !:Purpose: Memory allocation for the non linear radiative transfer model variables.
 317    !
 318    implicit none
 319
 320    ! Arguments:
 321    type(struct_obs), intent(inout) :: obsSpaceData
 322
 323    ! Locals:
 324    integer :: allocStatus(9)
 325    integer :: satelliteCode, instrumentCode, iplatform, isat, instrum
 326    integer :: tovsIndex, idatyp, sensorIndex
 327    integer :: channelNumber, nosensor, channelIndex
 328    integer :: errorStatus
 329    integer :: headerIndex, bodyIndex, taskIndex
 330    logical :: runObsOperatorWithClw
 331    logical :: runObsOperatorWithHydrometeors
 332    logical, allocatable :: logicalBuffer(:)
 333    character(len=32) :: hydroTableFilename
 334
 335    if (tvs_nsensors == 0) return
 336
 337    !  1. Determine the number of radiances to be assimilated.
 338    !      Construct a list of channels for each sensor.
 339    !      Construct a list of sensor number for each profile
 340
 341    write(*,*) 'tvs_setupAlloc: Starting' 
 342
 343    allocStatus = 0
 344    allocate (tvs_nchan(tvs_nsensors),                         stat= allocStatus(1))
 345    allocate (tvs_ichan(tvs_maxNumberOfChannels,tvs_nsensors), stat= allocStatus(2))
 346    allocate (tvs_lsensor(obs_numheader(obsSpaceData)),        stat= allocStatus(3))
 347    allocate (tvs_headerIndex (obs_numheader(obsSpaceData)),   stat= allocStatus(4))
 348    allocate (tvs_tovsIndex(obs_numheader(obsSpaceData)),      stat= allocStatus(5))
 349    allocate (tvs_isReallyPresent(tvs_nsensors),               stat= allocStatus(6))
 350    allocate (tvs_nchanMpiGlobal(tvs_nsensors),                stat= allocStatus(7))
 351    allocate (tvs_ichanMpiGlobal(tvs_maxNumberOfChannels,tvs_nsensors), stat= allocStatus(8))
 352    allocate (tvs_isReallyPresentMpiGlobal(tvs_nsensors), stat= allocStatus(9))
 353
 354    call utl_checkAllocationStatus(allocStatus, ' tvs_setupAlloc')
 355
 356    tvs_nchan(:) = 0 
 357    tvs_ichan(:,:) = 0
 358    tvs_isReallyPresent(:) = .true.
 359    tvs_lsensor(:) = -1
 360    tvs_headerIndex(:) = -1
 361    tvs_tovsIndex (:) = -1
 362
 363    tvs_nobtov = 0
 364
 365    ! Loop over all header indices of the 'TO' family
 366    ! Set the header list & start at the beginning of the list
 367    call obs_set_current_header_list(obsSpaceData,'TO')
 368    HEADER: do
 369      headerIndex = obs_getHeaderIndex(obsSpaceData)
 370      if (headerIndex < 0) exit HEADER
 371
 372      idatyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
 373
 374      if ( .not. tvs_isIdBurpTovs(idatyp) ) then
 375        write(*,*) 'tvs_setupAlloc: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
 376        call rejectObs(obsSpaceData, headerIndex)
 377        cycle HEADER   ! Proceed to the next headerIndex
 378      end if
 379      tvs_nobtov = tvs_nobtov + 1
 380     
 381      !    Construct list of channels for each sensor:
 382      !          map burp satellite info to RTTOV platform and satellite.
 383      satelliteCode = obs_headElem_i(obsSpaceData,OBS_SAT,headerIndex)
 384      call tvs_mapSat(satelliteCode,iplatform,isat)
 385      if (iplatform == -1) then
 386        write(*,*) 'Unknown OBS_SAT !', satelliteCode
 387        call utl_abort('tvs_setupAlloc')
 388      end if
 389      !    map burp instrument info to RTTOV instrument.
 390      instrumentCode = obs_headElem_i(obsSpaceData,OBS_INS,headerIndex)
 391      call tvs_mapInstrum(instrumentCode,instrum)
 392      if (instrum == -1) then
 393        write(*,*) 'Unknown OBS_INS !', instrumentCode
 394        call utl_abort('tvs_setupAlloc')
 395      end if
 396      !    find sensor number for this obs.
 397      nosensor =0
 398      do sensorIndex = 1, tvs_nsensors
 399        if ( iplatform == tvs_platforms  (sensorIndex) .and. &
 400             isat      == tvs_satellites (sensorIndex) .and. &
 401             instrum   == tvs_instruments(sensorIndex)      ) then
 402          nosensor = sensorIndex
 403          exit
 404        end if
 405      end do
 406
 407      if (nosensor > 0) then
 408        tvs_lsensor(tvs_nobtov) = nosensor
 409        tvs_headerIndex (tvs_nobtov) = headerIndex
 410        tvs_tovsIndex (headerIndex) = tvs_nobtov
 411      else
 412        write(*,*) ' tvs_setupAlloc: Warning Invalid Sensor ', iplatform, isat, instrum, ' skipping ...'
 413      end if
 414
 415      ! Loop over all body indices (still in the 'TO' family)
 416      ! Set the body list & start at the beginning of the list
 417      call obs_set_current_body_list(obsSpaceData, headerIndex)
 418      BODY: do 
 419        bodyIndex = obs_getBodyIndex(obsSpaceData)
 420        if (bodyIndex < 0) exit BODY
 421        if (nosensor > 0) then
 422          if ( obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated ) then
 423            call tvs_getChannelNumIndexFromPPP( obsSpaceData, headerIndex, bodyIndex, &
 424                                                channelNumber, channelIndex )
 425            if ( channelIndex == 0 ) then
 426              tvs_nchan(nosensor) = tvs_nchan(nosensor) + 1
 427              tvs_ichan(tvs_nchan(nosensor),nosensor) = channelNumber
 428            end if
 429            
 430            if ( tvs_debug .and. mmpi_myid == 0 .and. &
 431                 trim(tvs_instrumentName(nosensor)) == 'AMSUA' ) then
 432              write(*,*) 'test channelNumber:', headerIndex, bodyIndex, nosensor, &
 433                   tvs_satelliteName(nosensor), channelNumber, channelIndex
 434            end if
 435          end if
 436        else           
 437          ! set to notAssimilated if instrument not in NAMTOV namelist
 438          call obs_bodySet_i(obsSpaceData, OBS_ASS, bodyIndex, obs_notAssimilated)
 439        end if
 440      end do BODY
 441    end do HEADER
 442
 443    if ( .not. tvs_userDefinedDoAzimuthCorrection) then 
 444      ! tvs_doAzimuthCorrection user defined values will be overwriten by the old default values 
 445      do sensorIndex = 1, tvs_nsensors
 446        tvs_doAzimuthCorrection(sensorIndex) = ( tvs_platforms(sensorIndex) /= platform_id_eos .and. &
 447             ( tvs_instruments(sensorIndex) == inst_id_amsua .or. tvs_instruments(sensorIndex) == inst_id_mhs )  )     
 448      end do
 449      if ( mmpi_myId == 0 ) write(*,*) ' tvs_setupAlloc: Warning tvs_doAzimuthCorrection user defined values overwriten by the old default values'
 450    end if
 451
 452    if ( .not. tvs_userDefinedIsAzimuthValid ) then 
 453      ! tvs_isAzimuthValid  user defined values will be overwriten by the current default values 
 454      do sensorIndex = 1, tvs_nsensors
 455        tvs_isAzimuthValid(sensorIndex) = .not. ( tvs_isInstrumGeostationary(tvs_instruments(sensorIndex)) )
 456      end do
 457      if ( mmpi_myId == 0 ) write(*,*) ' tvs_setupAlloc: Warning tvs_isAzimuthValid user defined values overwriten by the current default values'
 458    end if
 459
 460    if ( mmpi_myId == 0 ) then
 461      write(*,*) ' tvs_setupAlloc: platform satellite id tvs_doAzimuthCorrection tvs_isAzimuthValid'
 462      do sensorIndex = 1, tvs_nsensors
 463        write(*,'(18x,a,1x,a,1x,i2,1x,L1,10x,L1)') inst_name(tvs_instruments(sensorIndex)), &
 464             platform_name(tvs_platforms(sensorIndex)), tvs_satellites(sensorIndex), &
 465             tvs_doAzimuthCorrection(sensorIndex), tvs_isAzimuthValid(sensorIndex)
 466      end do
 467    end if
 468    
 469    ! Sort list of channels in ascending order.Also force at least one channel, if none are found.
 470    do sensorIndex = 1, tvs_nsensors
 471      call isort(tvs_ichan(:,sensorIndex),tvs_nchan(sensorIndex))
 472      if ( tvs_nchan(sensorIndex) == 0 ) then
 473        tvs_isReallyPresent ( sensorIndex ) =.false.
 474        tvs_nchan(sensorIndex) = 1
 475        tvs_ichan(1,sensorIndex) = 1
 476      end if
 477    end do
 478
 479    write(*,*) ' tvs_setupAlloc: tvs_nobtov = ', tvs_nobtov
 480
 481    do sensorIndex = 1, tvs_nsensors
 482      call tvs_getCommonChannelSet(tvs_ichan(:,sensorIndex),tvs_nchanMpiGlobal(sensorIndex), tvs_ichanMpiGlobal(:,sensorIndex))
 483      print *, 'sensorIndex,tvs_nchan(sensorIndex),tvs_nchanMpiGlobal(sensorIndex)', sensorIndex, tvs_nchan(sensorIndex),tvs_nchanMpiGlobal(sensorIndex)
 484    end do
 485
 486    if (mmpi_myid ==0) then
 487      allocate(logicalBuffer(mmpi_nprocs))
 488    else
 489      allocate(logicalBuffer(1))
 490    end if
 491    
 492    do sensorIndex = 1, tvs_nsensors
 493      call RPN_COMM_gather( tvs_isReallyPresent ( sensorIndex ) , 1, 'MPI_LOGICAL', logicalBuffer, 1,'MPI_LOGICAL', 0, 'GRID', errorStatus )
 494      if (mmpi_myid ==0) then
 495        tvs_isReallyPresentMpiGlobal ( sensorIndex ) =.false.
 496        do taskIndex=1, mmpi_nprocs
 497          tvs_isReallyPresentMpiGlobal ( sensorIndex ) =  tvs_isReallyPresentMpiGlobal ( sensorIndex ) .or. logicalBuffer(taskIndex)
 498        end do
 499      end if
 500      call rpn_comm_bcast(tvs_isReallyPresentMpiGlobal ( sensorIndex ), 1, 'MPI_LOGICAL', 0, 'GRID', errorStatus )
 501    end do
 502    
 503    deallocate(logicalBuffer)
 504
 505    if ( tvs_debug .and. mmpi_myid == 0 ) then
 506      do sensorIndex = 1, tvs_nsensors
 507        write(*,*) 'sensorIndex, tvs_instrumentName(sensorIndex), tvs_satelliteName(sensorIndex)'
 508        write(*,*) sensorIndex, tvs_instrumentName(sensorIndex), tvs_satelliteName(sensorIndex)
 509        write(*,*) 'tvs_channelOffset(sensorIndex), tvs_nchan(sensorIndex)'
 510        write(*,*) tvs_channelOffset(sensorIndex), tvs_nchan(sensorIndex)
 511        write(*,*) 'tvs_ichan(1:tvs_nchan(sensorIndex),sensorIndex)'
 512        write(*,*) tvs_ichan(1:tvs_nchan(sensorIndex),sensorIndex)
 513        write(*,*) 
 514      end do
 515    end if
 516
 517    !  3. Initialize TOVS radiance transfer model
 518
 519    if ( radiativeTransferCode == 'RTTOV' ) then
 520
 521      write(*,'(//,10x,A)') '-rttov_setup: initializing the TOVS radiative transfer model'
 522
 523      allocate (tvs_coefs(tvs_nsensors)          ,stat= allocStatus(1))
 524      allocate (tvs_listSensors (3,tvs_nsensors) ,stat= allocStatus(2))
 525      allocate (tvs_opts (tvs_nsensors)          ,stat= allocStatus(3))
 526      if (tvs_numMWInstrumUsingHydrometeors  > 0) then
 527        allocate (tvs_opts_scatt (tvs_nsensors) ,stat= allocStatus(4))
 528        allocate (tvs_coef_scatt (tvs_nsensors) ,stat= allocStatus(5))
 529      end if
 530      call utl_checkAllocationStatus(allocStatus(1:5), ' tvs_setupAlloc before rttov initialization')
 531
 532      do sensorIndex=1, tvs_nsensors
 533        tvs_listSensors(1,sensorIndex) = tvs_platforms  (sensorIndex)
 534        tvs_listSensors(2,sensorIndex) = tvs_satellites (sensorIndex)
 535        tvs_listSensors(3,sensorIndex) = tvs_instruments(sensorIndex)
 536
 537        runObsOperatorWithClw = (tvs_numMWInstrumUsingCLW /= 0 .and. &
 538                                 tvs_isInstrumUsingCLW(tvs_instruments(sensorIndex)))
 539        runObsOperatorWithHydrometeors = (tvs_numMWInstrumUsingHydrometeors /= 0 .and. &
 540                                          tvs_isInstrumUsingHydrometeors(tvs_instruments(sensorIndex)))
 541
 542        !< General configuration options
 543        tvs_opts(sensorIndex) % config % apply_reg_limits = .true. ! if true application of profiles limits
 544        tvs_opts(sensorIndex) % config % verbose = .false. ! verbose output
 545        tvs_opts(sensorIndex) % config % do_checkinput = .true. ! to check if input profiles are within absolute and regression limits
 546        tvs_opts(sensorIndex) % config % fix_hgpl = .false. ! for backward compatibility with RTTOV-12 should be changed later
 547        !< General RT options
 548        tvs_opts(sensorIndex) % rt_all % switchrad = .true.  ! to use brightness temperature (true) or radiance (false) units in AD routine
 549        tvs_opts(sensorIndex) % rt_all % use_q2m = .false.   ! if true use of surface humidity (false for compatibility with the way rttov 8.7 was compiled)
 550        tvs_opts(sensorIndex) % rt_all % addrefrac = .true.  ! to account for atmospheric refraction
 551        tvs_opts(sensorIndex) % rt_all % dtau_test = .true.  ! for backward compatibility with RTTOV-12 may be changed later
 552        tvs_opts(sensorIndex) % rt_all % use_t2m_opdep = .false. ! for backward compatibility with RTTOV-12 may be changed later
 553        !< VIS/IR RT options
 554        tvs_opts(sensorIndex) % rt_ir % addsolar = .false.  ! to model solar component in the near IR (2000 cm-1 et plus)
 555        tvs_opts(sensorIndex) % rt_ir % addaerosl = .false. ! to account for scattering due to aerosols
 556        tvs_opts(sensorIndex) % rt_ir % addclouds = .false. ! to account for scattering due to clouds
 557        tvs_opts(sensorIndex) % rt_ir % ir_sea_emis_model = 2 ! ISEM (ir_sea_emis_model 1) useful for GEORAD
 558                                                              ! 2 selects IREMIS which is more sophisticated 
 559        tvs_opts(sensorIndex) % rt_ir % pc % ipcreg = -1         ! index of the required PC predictors... to see later
 560        tvs_opts(sensorIndex) % rt_ir % pc % addpc = .false.     ! to carry out principal component calculations 
 561        tvs_opts(sensorIndex) % rt_ir % pc % addradrec = .false. ! to reconstruct radiances from principal components
 562        !< MW RT options
 563        tvs_opts(sensorIndex) % rt_mw % clw_data = tvs_isInstrumUsingCLW(tvs_instruments(sensorIndex)) ! disponibilite du profil d'eau liquide
 564        tvs_opts(sensorIndex) % rt_mw % fastem_version = 6  ! use fastem version 6 microwave sea surface emissivity model (1-6)
 565        tvs_opts(sensorIndex) % rt_mw % clw_scheme = 1 ! default and recommended is 2 just for backward compatibility
 566        !< Interpolation options
 567        tvs_opts(sensorIndex) % interpolation % addinterp = .true. ! use of internal profile interpolator (rt calculation on model levels)
 568        tvs_opts(sensorIndex) % interpolation % lgradp = .true.    ! allow tl/ad of user pressure levels
 569        tvs_opts(sensorIndex) % interpolation % interp_mode = interp_rochon_loglinear_wfn ! see table 9 page 37 of RTTOV 12.1 users guide
 570        tvs_opts(sensorIndex) % interpolation % reg_limit_extrap = tvs_regLimitExtrap 
 571
 572        tvs_opts(sensorIndex) % rt_all % co2_data = .false.
 573        tvs_opts(sensorIndex) % rt_all % n2o_data = .false.
 574        tvs_opts(sensorIndex) % rt_all % co_data  = .false.
 575        tvs_opts(sensorIndex) % rt_all % ch4_data = .false.
 576
 577        if (runObsOperatorWithHydrometeors) then
 578          tvs_opts_scatt(sensorIndex) % interp_mode =  tvs_opts(sensorIndex) % interpolation % interp_mode ! Set interpolation method
 579          tvs_opts_scatt(sensorIndex) % reg_limit_extrap = tvs_regLimitExtrap 
 580          tvs_opts_scatt(sensorIndex) % fastem_version = tvs_opts(sensorIndex) % rt_mw % fastem_version  
 581          tvs_opts_scatt(sensorIndex) % supply_foam_fraction = .false.
 582          tvs_opts_scatt(sensorIndex) % use_t2m_opdep = tvs_opts(sensorIndex) % rt_all % use_t2m_opdep
 583          tvs_opts_scatt(sensorIndex) % use_q2m = tvs_opts(sensorIndex) % rt_all % use_q2m
 584          tvs_opts_scatt(sensorIndex) % lgradp = .true.
 585          tvs_opts_scatt(sensorIndex) % lusercfrac = .false. !< Switch to enable user-specified effective cloud fraction ??
 586          tvs_opts_scatt(sensorIndex) % config % do_checkinput = tvs_opts(sensorIndex) % config % do_checkinput
 587          tvs_opts_scatt(sensorIndex) % config % apply_reg_limits = tvs_opts(sensorIndex) % config % apply_reg_limits
 588          tvs_opts_scatt(sensorIndex) % config % verbose = .true.
 589          tvs_opts_scatt(sensorIndex) % config % fix_hgpl= tvs_opts(sensorIndex) % config % fix_hgpl
 590          ! other option may be considered:
 591          !real(jprb)    :: cc_threshold          = 1.E-3_jprb    !< Minimum effective cloud fraction threshold to consider scattering
 592          !real(jprb)    :: ice_polarisation      = 1.40_jprb     !< Polarised scattering factor for ice hydrometeors (<0 = no polarisation)
 593          !logical(jplm) :: ozone_data            = .false.       !< Switch to enable input of O3 profile
 594                                                                  ! because standard RTTOV coefficients in the MW have no ozone sensitivity
 595          !logical(jplm) :: rad_down_lin_tau      = .true.        !< Linear-in-tau or layer-mean for downwelling radiances
 596          !logical(jplm) :: hydro_cfrac_tlad      = .true.        !< Switch for hydrometeor TL/AD sensitivity to effective cfrac
 597          !logical(jplm) :: zero_hydro_tlad       = .false.       !< Switch for hydrometeor TL/AD sensitivity in layers with zero
 598                                                                  !   hydrometeor concentration
 599        end if
 600        
 601
 602        errorStatus = errorStatus_success
 603        call utl_tmg_start(16,'----RttovSetup')
 604        write(*,*) ' sensorIndex,tvs_nchan(sensorIndex)',  sensorIndex,tvs_nchan(sensorIndex)
 605        if ( tvs_mpiTask0ReadCoeffs ) then
 606          call tvs_rttov_read_coefs(errorStatus, tvs_coefs(sensorIndex), tvs_opts(sensorIndex), & 
 607               tvs_ichan(1:tvs_nchan(sensorIndex),sensorIndex), tvs_listSensors(:,sensorIndex))
 608        else
 609          call rttov_read_coefs (                               &
 610               errorStatus,                                     &! out
 611               tvs_coefs(sensorIndex),                          &
 612               tvs_opts(sensorIndex),                           &
 613               instrument= tvs_listSensors(:,sensorIndex),      &! in
 614               channels=  tvs_ichan(1:tvs_nchan(sensorIndex),sensorIndex) )     ! in option
 615        end if
 616        if (errorStatus /= errorStatus_success) then
 617          write(*,*) 'rttov_read_coefs: fatal error reading coefficients',errorStatus,sensorIndex,tvs_listSensors(1:3,sensorIndex)
 618          call utl_abort('tvs_setupAlloc')
 619        end if
 620       
 621        if (runObsOperatorWithHydrometeors) then
 622          hydrotableFilename = 'hydrotable_' // trim(platform_name(tvs_platforms(sensorIndex))) // '_' // &
 623               trim(inst_name(tvs_instruments(sensorIndex))) // '.dat'
 624          call rttov_read_scattcoeffs(errorStatus, tvs_opts_scatt(sensorIndex), tvs_coefs(sensorIndex), &
 625               tvs_coef_scatt(sensorIndex), file_coef=hydrotableFilename)
 626          if (errorStatus /= errorStatus_success) then
 627            write(*,*) 'rttov_read_scattcoeffs: fatal error reading RTTOV-SCATT coefficients', hydrotableFilename
 628            call utl_abort('tvs_setupAlloc')
 629          end if
 630        end if
 631        call utl_tmg_stop(16)
 632
 633        tvs_opts(sensorIndex) % rt_all % ozone_data = ( tvs_coefs(sensorIndex) % coef % nozone > 0 ) ! profil d'ozone disponible
 634
 635        ! Ensure the options and coefficients are consistent
 636        call rttov_user_options_checkinput(errorStatus, tvs_opts(sensorIndex), tvs_coefs(sensorIndex))
 637        if (errorStatus /= errorStatus_success) then
 638          write(*,*) 'error in rttov options', errorStatus
 639          call utl_abort('tvs_setupAlloc')
 640        end if
 641       
 642      end do
 643
 644
 645      !   4. Memory allocations for radiative tranfer model variables
 646
 647      ! Radiance by profile
 648
 649      allocate( tvs_radiance(tvs_nobtov) ,stat= allocStatus(1))
 650
 651      call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_setupAlloc radiances 1')
 652  
 653      do tovsIndex = 1, tvs_nobtov
 654        sensorIndex = tvs_lsensor(tovsIndex)
 655        if (sensorIndex > -1) then
 656          ! allocate BT equivalent to total direct, tl and ad radiance output
 657          allocate( tvs_radiance(tovsIndex)  % bt  ( tvs_nchan(sensorIndex) ) ,stat= allocStatus(1))
 658          tvs_radiance(tovsIndex)  % bt  ( : ) = 0.d0
 659          call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_setupAlloc radiances 2')
 660          nullify (tvs_radiance(tovsIndex)  % clear )
 661        end if
 662      end do
 663
 664    end if
 665  
 666    write(*,*) 'Leaving tvs_setupAlloc'
 667
 668  end subroutine tvs_setupAlloc
 669
 670  !--------------------------------------------------------------------------
 671  ! tvs_getProfile
 672  !--------------------------------------------------------------------------
 673  subroutine tvs_getProfile(profiles, profileType, cld_profiles_opt)
 674    !
 675    !:Purpose: sets profiles as a pointer of type rttov_profile
 676    !           based on profileType equal to nl or tlad. 
 677    ! 
 678    implicit none
 679
 680    ! Arguments:
 681    type(rttov_profile),       pointer,           intent(inout) :: profiles(:)
 682    character(len=*),                             intent(in)    :: profileType
 683    type(rttov_profile_cloud), pointer, optional, intent(inout) :: cld_profiles_opt(:)
 684
 685    select case( trim( profileType) )
 686      case('nl')
 687        profiles => tvs_profiles_nl
 688        if (present(cld_profiles_opt)) cld_profiles_opt => tvs_cld_profiles_nl
 689      case('tlad')
 690        profiles => tvs_profiles_tlad
 691        if (present(cld_profiles_opt)) cld_profiles_opt => tvs_cld_profiles_tlad
 692      case default
 693        call utl_abort('tvs_getProfile: invalid profileType ' // profileType )
 694    end select
 695
 696  end subroutine tvs_getProfile
 697
 698  !--------------------------------------------------------------------------
 699  ! tvs_allocTransmission
 700  !--------------------------------------------------------------------------
 701  subroutine tvs_allocTransmission(nlevels)
 702    !
 703    !:Purpose: Allocate the global rttov transmission structure used
 704    !           when this is needed for some purpose (e.g. used in 
 705    !           LETKF to determine peak pressure level of each radiance
 706    !           channel for vertical localization).
 707    !
 708    implicit none
 709
 710    ! Arguments:
 711    integer, intent(in) :: nlevels 
 712
 713    ! Locals:
 714    integer :: allocStatus(2), jo, isens, nc
 715
 716    allocStatus(:) = 0
 717    allocate( tvs_transmission(tvs_nobtov), stat=allocStatus(1))
 718    call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_allocTransmission')
 719
 720    do jo = 1, tvs_nobtov
 721      isens = tvs_lsensor(jo)
 722      nc = tvs_nchan(isens)
 723      ! allocate transmittance from surface and from pressure levels
 724      allocate( tvs_transmission(jo) % tau_total(nc),     stat= allocStatus(1))
 725      allocate( tvs_transmission(jo) % tau_levels(nlevels,nc), stat= allocStatus(2))
 726      call utl_checkAllocationStatus(allocStatus, ' tvs_allocTransmission')
 727    end do
 728
 729  end subroutine tvs_allocTransmission
 730
 731
 732
 733  !--------------------------------------------------------------------------
 734  ! tvs_setup
 735  !--------------------------------------------------------------------------
 736  subroutine tvs_setup
 737    !
 738    !:Purpose: to read namelist NAMTOV, initialize the observation error covariance and setup RTTOV-12.
 739    !
 740    implicit none
 741
 742    ! Locals:
 743    integer  sensorIndex, ierr, nulnam
 744    integer, external :: fclos, fnom
 745    integer :: instrumentIndex, numMWInstrumToUseCLW, numMWInstrumToUseHydrometeors
 746
 747    ! Namelist variables: (local)
 748    character(len=8)  :: crtmodl ! For now, must equal 'RTTOV'
 749    integer :: nsensors ! MUST NOT BE INCLUDED IN NAMELIST!
 750    character(len=15) :: csatid(tvs_maxNumberOfSensors)        ! List of satellite names
 751    character(len=15) :: cinstrumentid(tvs_maxNumberOfSensors) ! List of incstrument names
 752    logical :: ldbgtov  ! Choose to print simulated and observed Tb to listing
 753    logical :: useO3Climatology ! Choose to use ozone climatology (otherwise model field)
 754    logical :: regLimitExtrap ! Choose to use RTTOV reg_limit_extrap option
 755    logical :: doAzimuthCorrection(tvs_maxNumberOfSensors) ! Choose to apply correction to azimuth angle
 756    logical :: isAzimuthValid(tvs_maxNumberOfSensors) ! Indicate if azimuth angle is valid
 757    logical :: userDefinedDoAzimuthCorrection ! Indicate if user defined azimuth correction is to be used
 758    logical :: userDefinedIsAzimuthValid ! Indicate if user defined azimuth angle is valid
 759    logical :: mpiTask0ReadCoeffs ! Choose to read coeffs only on task 0 and broadcast
 760    logical :: mwInstrumUsingCLW_tl ! Choose to use CLW increment in TL/AD if exists as state variable
 761    logical :: mwInstrumUsingHydrometeors_tl ! Choose to all hydomet variables in TL/AD if exist as state variables
 762    real(8) :: cloudScaleFactor  ! Scale factor applied to model produced clouds to account for bias
 763    character(len=15) :: instrumentNamesUsingCLW(tvs_maxNumberOfSensors) ! List of inst names using CLW
 764    character(len=15) :: instrumentNamesUsingHydrometeors(tvs_maxNumberOfSensors) ! List of inst name using full set of hydromet variables
 765    logical :: mwAllskyAssim ! High-level key to activate all-sky treatment of MW radiances
 766
 767    namelist /NAMTOV/ nsensors, csatid, cinstrumentid
 768    namelist /NAMTOV/ ldbgtov,useO3Climatology
 769    namelist /NAMTOV/ useUofWIREmiss, crtmodl
 770    namelist /NAMTOV/ useMWEmissivityAtlas, mWAtlasId
 771    namelist /NAMTOV/ mwInstrumUsingCLW_tl, instrumentNamesUsingCLW
 772    namelist /NAMTOV/ mwInstrumUsingHydrometeors_tl, instrumentNamesUsingHydrometeors
 773    namelist /NAMTOV/ regLimitExtrap, doAzimuthCorrection, userDefinedDoAzimuthCorrection
 774    namelist /NAMTOV/ isAzimuthValid, userDefinedIsAzimuthValid, cloudScaleFactor 
 775    namelist /NAMTOV/ mwAllskyAssim, mpiTask0ReadCoeffs
 776
 777    ! return if the NAMTOV does not exist
 778    if ( .not. utl_isNamelistPresent('NAMTOV','./flnml') ) then
 779      write(*,*)
 780      write(*,*) 'tvs_setup: Namelist block NAMTOV is missing in the namelist.'
 781      write(*,*) '           Skipping tvs_setup.'
 782      return
 783    end if
 784 
 785    !   1.1 Default values for namelist variables
 786
 787    nsensors = MPC_missingValue_INT
 788    csatid(:) = '***UNDEFINED***'
 789    cinstrumentid(:) = '***UNDEFINED***'
 790    doAzimuthCorrection(:) = .false.
 791    isAzimuthValid(:) = .false.
 792    ldbgtov = .false.
 793    useO3Climatology = .true.
 794    userDefinedDoAzimuthCorrection = .false.
 795    userDefinedIsAzimuthValid = .false.
 796    crtmodl = 'RTTOV'
 797    useUofWIREmiss = .false.
 798    useMWEmissivityAtlas = .false.
 799    mWAtlasId = 1 !Default to TELSEM-2
 800    mwInstrumUsingCLW_tl = .false.
 801    mwInstrumUsingHydrometeors_tl = .false.
 802    instrumentNamesUsingCLW(:) = '***UNDEFINED***'
 803    instrumentNamesUsingHydrometeors(:) = '***UNDEFINED***'
 804    regLimitExtrap = .true.
 805    cloudScaleFactor = 0.5D0
 806    mwAllskyAssim = .false.
 807    mpiTask0ReadCoeffs = .true.
 808
 809    !   1.2 Read the NAMELIST NAMTOV to modify them
 810 
 811    nulnam = 0
 812    ierr = fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
 813    read(nulnam, nml=namtov, iostat=ierr)
 814    if (ierr /= 0) call utl_abort('tvs_setup: Error reading namelist NAMTOV')
 815
 816    if (mmpi_myid == 0) write(*,nml=namtov)
 817    ierr = fclos(nulnam)
 818
 819    !  1.3 Transfer namelist variables to module variables
 820    if (nsensors /= MPC_missingValue_INT) then
 821      call utl_abort('tvs_setup: check namelist section NAMTOV; nsensors should be removed as it is' // &
 822          ' now computed by Midas from cinstrumentid and csatid arrays')
 823    end if
 824    
 825    tvs_nsensors = 0
 826    sensor_loop:do sensorIndex = 1, tvs_maxNumberOfSensors
 827      if (cinstrumentid(sensorIndex) /= "***UNDEFINED***" .and. &
 828          csatid(sensorIndex) /= "***UNDEFINED***" ) then
 829        tvs_nsensors = tvs_nsensors + 1
 830      else
 831        exit sensor_loop
 832      end if
 833    end do sensor_loop
 834    
 835    tvs_debug = ldbgtov
 836    radiativeTransferCode = crtmodl
 837    tvs_useO3Climatology = useO3Climatology
 838    tvs_instrumentName(:) = cinstrumentid(:)
 839    tvs_satelliteName(:) = csatid(:)
 840    tvs_mwInstrumUsingCLW_tl = mwInstrumUsingCLW_tl
 841    tvs_regLimitExtrap = regLimitExtrap
 842    tvs_userDefinedDoAzimuthCorrection = userDefinedDoAzimuthCorrection
 843    tvs_userDefinedIsAzimuthValid = userDefinedIsAzimuthValid
 844    tvs_doAzimuthCorrection(:) =  doAzimuthCorrection(:)
 845    tvs_isAzimuthValid(:) =  isAzimuthValid(:)
 846    tvs_cloudScaleFactor = cloudScaleFactor 
 847    tvs_mwAllskyAssim = mwAllskyAssim
 848    tvs_mpiTask0ReadCoeffs = mpiTask0ReadCoeffs
 849
 850    !  1.4 Validate namelist values
 851    
 852    if ( tvs_nsensors == 0 ) then
 853      if(mmpi_myid==0) then 
 854        write(*,*) ' ====================================================='
 855        write(*,*) ' tvs_setup: Number of sensors is zero, skipping setup'
 856        write(*,*) ' ====================================================='
 857      end if
 858      return
 859    end if
 860
 861    if ( radiativeTransferCode /= 'RTTOV' ) then
 862      write(*,'(A)') ' Invalid radiation model name'
 863      call utl_abort('tvs_setup')
 864    end if
 865
 866    if ( tvs_nsensors > tvs_maxNumberOfSensors ) then
 867      write(*,'(A)') ' Number of sensors (tvs_nsensors) is greater than maximum allowed (tvs_maxNumberOfSensors)'
 868      call utl_abort('tvs_setup')
 869    end if
 870
 871    !  1.5 Print the content of this NAMELIST
 872
 873    if(mmpi_myid == 0) then
 874      write(*,'(A)') 
 875      write(*,'(3X,A)') '- Parameters used for TOVS processing (read in NAMTOV)'
 876      write(*,'(3X,A)') '  ----------------------------------------------------'
 877      write(*,'(6X,A,2X,L1)') 'TOVS debug                           : ', tvs_debug
 878      write(*,'(6X,A,2X,L1)') 'Use of UW IR land emissivity atlases : ', useUofWIREmiss
 879      write(*,'(6X,A,2X,L1)') 'Use of MW land emissivity atlases    : ', useMWEmissivityAtlas
 880      if (useMWEmissivityAtlas) then
 881        write(*,'(6X,A,2X,I1)') 'MW atlas Id                          : ', mWAtlasId
 882      end if
 883      write(*,'(6X,A,2X,L1)') 'Use of reg_limit_extrap              : ', regLimitExtrap
 884      write(*,'(6X,A,2X,A)')  'Radiative transfer model             : ', radiativeTransferCode
 885      write(*,'(6X,A,2X,I3)') 'Number of sensors                    : ', tvs_nsensors
 886      write(*,"(6X,'Satellite ids          : ',10A10)") (tvs_satelliteName(sensorIndex), sensorIndex=1,tvs_nsensors)
 887      write(*,"(6X,'Instrument ids         : ',10A10)") (tvs_instrumentName(sensorIndex), sensorIndex=1,tvs_nsensors)
 888      write(*,'(A)') 
 889      write(*,'(A)') 
 890      write(*,'(A)') 
 891      write(*,'(3X,A)') '- Reading and initialization in preparation to the TOVS processing'
 892      write(*,'(5X,A)') '----------------------------------------------------------------'
 893    end if
 894
 895    !  1.6 Set up platform, satellite, instrument and channel mapping
 896
 897    call sensors()
 898
 899    ! Get the name and number of instruments to use CLW
 900    instrumentIdsUsingCLW(:) = -1
 901    do instrumentIndex = 1, tvs_nsensors
 902      instrumentIdsUsingCLW(instrumentIndex) = tvs_getInstrumentId(instrumentNamesUsingCLW(instrumentIndex))
 903      if ( instrumentNamesUsingCLW(instrumentIndex) /= '***UNDEFINED***' ) then
 904        if ( instrumentIdsUsingCLW(instrumentIndex) == -1 ) then
 905          write(*,*) instrumentIndex, instrumentNamesUsingCLW(instrumentIndex)
 906          call utl_abort('tvs_setup: Unknown instrument name to use CLW')
 907        end if
 908      else
 909        numMWInstrumToUseCLW = instrumentIndex - 1
 910        exit
 911      end if
 912    end do
 913
 914    ! Get the name and number of instruments to use hydrometeors
 915    instrumentIdsUsingHydrometeors(:) = -1
 916    do instrumentIndex = 1, tvs_nsensors
 917      instrumentIdsUsingHydrometeors(instrumentIndex) = &
 918                  tvs_getInstrumentId(instrumentNamesUsingHydrometeors(instrumentIndex))
 919      if ( instrumentNamesUsingHydrometeors(instrumentIndex) /= '***UNDEFINED***' ) then
 920        if ( instrumentIdsUsingHydrometeors(instrumentIndex) == -1 ) then
 921          write(*,*) instrumentIndex, instrumentNamesUsingHydrometeors(instrumentIndex)
 922          call utl_abort('tvs_setup: Unknown instrument name to use hydrometeors')
 923        end if
 924      else
 925        numMWInstrumToUseHydrometeors = instrumentIndex - 1
 926        exit
 927      end if
 928    end do
 929
 930    ! check instrument is either using CLW or hydrometeors for non-ATMS instruments
 931    do instrumentIndex = 1, numMWInstrumToUseHydrometeors
 932      if (numMWInstrumToUseCLW == 0) exit
 933
 934      if (any(instrumentIdsUsingCLW(1:numMWInstrumToUseCLW) == &
 935              instrumentIdsUsingHydrometeors(instrumentIndex))) then
 936        write(*,*) instrumentIndex, instrumentNamesUsingHydrometeors(instrumentIndex)
 937        call utl_abort('tvs_setup: all-sky TtHu for this intrument is not assimilated yet')
 938      end if
 939    end do
 940
 941    tvs_numMWInstrumUsingCLW = numMWInstrumToUseCLW
 942    tvs_numMWInstrumUsingHydrometeors = numMWInstrumToUsehydrometeors
 943
 944    if ( mmpi_myid == 0 ) then
 945      write(*,*) 'tvs_setup: Instrument IDs to use CLW: ', instrumentIdsUsingCLW(1:numMWInstrumToUseCLW)
 946      write(*,*) 'tvs_setup: Number of instruments to use CLW: ', numMWInstrumToUseCLW
 947
 948      write(*,*) 'tvs_setup: Instrument IDs to use hydrometeors: ', &
 949                             instrumentIdsUsingHydrometeors(1:numMWInstrumToUseHydrometeors)
 950      write(*,*) 'tvs_setup: Number of instruments to use hydrometeors: ', &
 951                             numMWInstrumToUseHydrometeors
 952    end if
 953
 954  end subroutine tvs_setup
 955
 956  !--------------------------------------------------------------------------
 957  ! tvs_cleanup
 958  !--------------------------------------------------------------------------
 959  subroutine tvs_cleanup
 960    !
 961    !:Purpose: release memory used by RTTOV-12.
 962    !
 963    implicit none
 964
 965    ! Locals:
 966    integer :: allocStatus(8)
 967    integer :: iSensor,iObs,nChans,nl
 968
 969    Write(*,*) 'tvs_cleanup: Starting'
 970
 971    allocStatus(:) = 0
 972
 973    if ( radiativeTransferCode == 'RTTOV' ) then
 974
 975      !___ radiance by profile
 976
 977      do iObs = 1, tvs_nobtov
 978        iSensor = tvs_lsensor(iObs)
 979        nchans = tvs_nchan(isensor)
 980        ! deallocate BT equivalent to total direct, tl and ad radiance output
 981        deallocate( tvs_radiance(iObs)  % bt ,stat= allocStatus(1))
 982        call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_cleanup radiances 1',.false.)
 983      end do
 984
 985      deallocate( tvs_radiance ,stat= allocStatus(1))
 986      call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_cleanup radiances 2')
 987
 988      do iObs = 1, tvs_nobtov
 989        iSensor = tvs_lsensor(iObs)
 990        nl = tvs_coefs(iSensor) % coef % nlevels
 991        ! deallocate model profiles atmospheric arrays with RTTOV levels dimension
 992        call rttov_alloc_prof(allocStatus(1),1,tvs_profiles_nl(iObs),nl, &    ! 1 = nprofiles un profil a la fois
 993             tvs_opts(iSensor),asw=0,coefs=tvs_coefs(iSensor),init=.false. ) ! asw =0 deallocation
 994        call rttov_alloc_prof(allocStatus(2),1,tvs_profiles_tlad(iObs),nl, &    ! 1 = nprofiles un profil a la fois
 995             tvs_opts(iSensor),asw=0,coefs=tvs_coefs(iSensor),init=.false. ) ! asw =0 deallocation
 996        call utl_checkAllocationStatus(allocStatus(1:2), 'profiles deallocation in tvs_cleanup',.false.)
 997      end do
 998
 999      deallocate(tvs_profiles_nl,   stat=allocStatus(1) )
1000      deallocate(tvs_profiles_tlad, stat=allocStatus(2) )
1001      call utl_checkAllocationStatus(allocStatus(1:2), ' tvs_setupAlloc tvs_profiles_nl/tlad')
1002
1003      do iSensor = tvs_nsensors,1,-1
1004        call rttov_dealloc_coefs(allocStatus(1),  tvs_coefs(iSensor) )
1005        Write(*,*) 'Deallocating coefficient structure for instrument', iSensor
1006        call utl_checkAllocationStatus(allocStatus(1:1), ' rttov_dealloc_coefs in tvs_cleanup', .false.)
1007      end do
1008
1009      deallocate (tvs_coefs       ,stat= allocStatus(1))
1010      deallocate (tvs_listSensors ,stat= allocStatus(2))
1011      deallocate (tvs_opts        ,stat= allocStatus(3))
1012
1013      call utl_checkAllocationStatus(allocStatus(1:3), ' tvs_cleanup', .false.)
1014
1015    end if
1016
1017    deallocate (tvs_nchan,          stat= allocStatus(1))
1018    deallocate (tvs_ichan,          stat= allocStatus(2))
1019    deallocate (tvs_lsensor,        stat= allocStatus(3))
1020    deallocate (tvs_headerIndex,    stat= allocStatus(4))
1021    deallocate (tvs_tovsIndex,      stat= allocStatus(5))
1022    deallocate (tvs_isReallyPresent,stat= allocStatus(6))
1023    deallocate (tvs_nchanMpiGlobal, stat= allocStatus(7))
1024    deallocate (tvs_ichanMpiGlobal, stat= allocStatus(8))
1025
1026    call utl_checkAllocationStatus(allocStatus, ' tvs_cleanup', .false.)
1027
1028    Write(*,*) 'tvs_cleanup: Finished'
1029
1030  end subroutine tvs_cleanup
1031
1032  !--------------------------------------------------------------------------
1033  ! tvs_deallocateProfilesNlTlAd
1034  !--------------------------------------------------------------------------
1035  subroutine tvs_deallocateProfilesNlTlAd
1036    !
1037    !:Purpose: release memory used by RTTOV-12.
1038    !
1039    implicit none
1040
1041    ! Locals:
1042    integer :: allocStatus(8)
1043
1044    Write(*,*) 'tvs_deallocateProfilesNlTlAd: Starting'
1045
1046    allocStatus(:) = 0
1047
1048    if ( radiativeTransferCode == 'RTTOV' ) then
1049      if ( allocated(tvs_profiles_nl) ) deallocate(tvs_profiles_nl, stat=allocStatus(1))
1050      if ( allocated(tvs_profiles_tlad) ) deallocate(tvs_profiles_tlad, stat=allocStatus(2))
1051      call utl_checkAllocationStatus(allocStatus(1:2), ' tvs_profiles_nl tvs_profiles_tlad', .false.)
1052    end if
1053
1054    Write(*,*) 'tvs_deallocateProfilesNlTlAd: Finished'
1055
1056  end subroutine tvs_deallocateProfilesNlTlAd
1057
1058  !--------------------------------------------------------------------------
1059  ! sensors
1060  !--------------------------------------------------------------------------
1061  subroutine sensors
1062    !
1063    !:Purpose: Initialisation of the RTTOV-10 platform, satellite
1064    !          and instrument ID's. Also set burp to RTTOV channel
1065    !          mapping offset.
1066    !          To verify and transfom the sensor information contained in the
1067    !          NAMTOV namelist into the variables required by RTTTOV-7:
1068    !          platform, satellite and instrument ID's.
1069    !
1070    implicit none
1071
1072    ! Locals:
1073    integer sensorIndex, instrumentIndex, platformIndex
1074    integer ipos1, ipos2
1075    integer numerosat, ierr, kindex, nulnam
1076    character(len=15) :: tempocsatid
1077    logical, save :: first=.true.
1078    integer, save :: ioffset1b(0:ninst-1)
1079    character(len=15) :: tempo_inst
1080    integer, external :: fnom, fclos
1081
1082    ! Namelist variables:
1083    character(len=8) :: listinstrum(0:ninst-1) ! List of instrument names
1084    integer          :: listoffset(0:ninst-1)  ! Corresponding list of channel offset values
1085    namelist /NAMCHANOFFSET/ listoffset, listinstrum
1086
1087    !  1.0 Go through sensors and set RTTOV-10 variables
1088
1089    do sensorIndex=1, tvs_nsensors
1090      tvs_platforms  (sensorIndex) = -1
1091      tvs_satellites (sensorIndex) = -1
1092      tvs_instruments(sensorIndex) = -1
1093      tvs_channelOffset(sensorIndex) = -1
1094    end do
1095
1096    if (first) then
1097      if ( utl_isNamelistPresent('NAMCHANOFFSET', './flnml') ) then
1098        call utl_abort('sensors: NAMCHANOFFSET namelist section should be now in flnml_static !')
1099      end if
1100      ! read the namelist
1101      nulnam = 0
1102      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1103      if (ierr /= 0) then
1104        write(*,*) 'Error while opening flnml_static namelist file !'
1105        call utl_abort('sensors')
1106      end if
1107      listoffset(:) = 0
1108      listinstrum(:) = 'XXXXXXXX'
1109      read(nulnam,NAMCHANOFFSET, iostat=ierr)
1110      if (ierr /= 0) then
1111        write(*,*) 'Error while reading NAMCHANOFFSET namelist section in flnml_static file !'
1112        call utl_abort('sensors')
1113      end if
1114      do instrumentIndex=0, ninst - 1
1115        if ( listinstrum(instrumentIndex) /= 'XXXXXXXX' ) then
1116          ioffset1b( tvs_getInstrumentId( listinstrum(instrumentIndex) ) )  = listoffset(instrumentIndex)
1117        end if
1118      end do
1119      ierr = fclos(nulnam)
1120      first = .false.
1121    end if
1122
1123    !  1.1 Set platforms and satellites
1124
1125    ! N.B.: Special cases for satellites TERRA and AQUA.
1126    !       For consistency with the RTTOV-10 nomenclature, rename:
1127    !       TERRA  to  eos1
1128    !       AQUA   to  eos2
1129    !       NPP    to  jpss0
1130    !       JPSS    to  jpss0
1131    !       HMWARI    to  himawari
1132    !       FY-3C    to  FY3-3
1133    do sensorIndex = 1, tvs_nsensors
1134      if    ( tvs_satelliteName(sensorIndex) == 'TERRA' ) then
1135        tempocsatid = 'eos1'
1136      else if ( tvs_satelliteName(sensorIndex) == 'AQUA'  ) then
1137        tempocsatid = 'eos2'
1138      else if ( tvs_satelliteName(sensorIndex) == 'NPP'  ) then
1139        tempocsatid = 'jpss0'
1140      else if ( tvs_satelliteName(sensorIndex) == 'JPSS'  ) then
1141        tempocsatid = 'jpss0'
1142      else if ( tvs_satelliteName(sensorIndex)(1:6) == 'HMWARI'  ) then
1143        tempocsatid = 'himawari' // trim(tvs_satelliteName(sensorIndex) (7:15))
1144      else if ( tvs_satelliteName(sensorIndex) == 'FY-3C'  ) then
1145        TEMPOCSATID = 'FY3-3'
1146      else
1147        call up2low(tvs_satelliteName(sensorIndex),tempocsatid)
1148      end if
1149      do platformIndex = 1, nplatforms
1150        ipos1 = len_trim(platform_name(platformIndex))
1151        ipos2 = index(tempocsatid,platform_name(platformIndex)(1:ipos1))
1152        if ( ipos2 == 1 ) then
1153          tvs_platforms(sensorIndex) = platformIndex
1154          kindex = platformIndex
1155        end if
1156      end do
1157      if ( tvs_platforms(sensorIndex) < 0 ) then
1158        write(*,'(A)') ' Satellite ' // trim(tempocsatid) // ' not supported.'
1159        call utl_abort('SENSORS')
1160      else
1161        ipos1 = len_trim(platform_name(kindex))
1162        ipos2 = len_trim(tempocsatid)
1163        read(tempocsatid(ipos1+1:ipos2),*,IOSTAT=ierr) numerosat
1164        numerosat = abs ( numerosat )
1165        if ( ierr /= 0) then
1166          write(*,'(A,1x,i6,1x,i3,1x,i3,1x,A15)') 'Problem while reading satellite number', &
1167               ierr, ipos1, ipos2, tempocsatid
1168          call utl_abort('SENSORS')
1169        else
1170          tvs_satellites(sensorIndex) = numerosat
1171        end if
1172      end if
1173    end do
1174
1175    !   1.2 Set instruments,
1176    !     also set channel offset, which is in fact a channel mapping between
1177    !     the channel number in BURP files and the channel number used in
1178    !     RTTOV-10.
1179
1180    do sensorIndex = 1, tvs_nsensors
1181      if ( tvs_instrumentName(sensorIndex)(1:10) == 'GOESIMAGER') then !cas particulier
1182        tvs_instruments(sensorIndex) = inst_id_goesim
1183      else if ( tvs_satelliteName(sensorIndex)(1:5) == 'MTSAT') then !autre cas particulier
1184        tvs_instruments(sensorIndex) = inst_id_gmsim
1185      else 
1186        call up2low(tvs_instrumentName(sensorIndex),tempo_inst)
1187        do instrumentIndex = 0, ninst -1 
1188          if ( trim(tempo_inst) == trim(inst_name(instrumentIndex))) then
1189            tvs_instruments(sensorIndex) = instrumentIndex
1190          end if
1191        end do
1192      end if
1193      if ( tvs_instruments(sensorIndex) < 0 ) then
1194        write(*,'(A)') ' INSTRUMENT '// trim( tvs_instrumentName(sensorIndex)) // ' not supported.'
1195        call utl_abort('SENSORS')
1196      end if
1197      tvs_channelOffset(sensorIndex) = ioffset1b(tvs_instruments(sensorIndex))
1198    end do
1199
1200    !    1.3 Print the RTTOV-12 related variables
1201
1202    if (mmpi_myid == 0) then
1203      write(*,*)
1204      write(*,'(3X,A)') '- SENSORS. Variables prepared for RTTOV-12:'
1205      write(*,'(3X,A)') '  ----------------------------------------'
1206      write(*,*)
1207      write(*,'(6X,A,I3)')   'Number of sensors       : ', tvs_nsensors
1208      write(*,"('Platform numbers        : ',6X,10I3)")  (tvs_platforms(sensorIndex), sensorIndex=1,tvs_nsensors)
1209      write(*,"('Satellite numbers       : ',6X,10I3)")  (tvs_satellites(sensorIndex), sensorIndex=1,tvs_nsensors)
1210      write(*,"('Instrument numbers      : ',6X,10I3)")  (tvs_instruments(sensorIndex), sensorIndex=1,tvs_nsensors)
1211      write(*,"('Channel mapping offsets : ',6X,10I3)")  (tvs_channelOffset(sensorIndex), sensorIndex=1,tvs_nsensors)
1212    end if
1213
1214  end subroutine sensors
1215
1216
1217  !--------------------------------------------------------------------------
1218  !  tvs_getAllIdBurpTovs
1219  !--------------------------------------------------------------------------
1220  subroutine tvs_getAllIdBurpTovs(idatypListSize, idatypList)
1221    !
1222    !:Purpose: Function to return a list of all idatyp (a.k.a. codtyp) values
1223    !           for all possible radiance observations (according to the namelist)
1224    !
1225    implicit none
1226
1227    ! Argument:
1228    integer, intent(out) :: idatypListSize
1229    integer, intent(out) :: idatypList(:)
1230    
1231    ! Locals:
1232    logical, save :: first=.true.
1233    integer, save :: ninst_tovs
1234    integer :: nulnam, ierr, instrumentIndex 
1235    integer, external :: fnom, fclos
1236    integer, save :: list_inst(ninst)
1237
1238    ! Namelist variables:
1239    character(len=22) :: inst_names(ninst) ! List of instrument names for all radiance types
1240    namelist /namtovsinst/ inst_names
1241
1242    if (tvs_nsensors == 0) then
1243      ! no tovs data will be read, therefore false
1244      idatypList(:) = MPC_missingValue_int
1245      idatypListSize = 0      
1246      return
1247    end if
1248
1249    if (first) then
1250      if ( utl_isNamelistPresent('NAMTOVSINST', './flnml') ) then
1251        call utl_abort('tvs_getAllIdBurpTovs: NAMTOVSINST namelist section should be now in flnml_static !')
1252      end if
1253      nulnam = 0
1254      ninst_tovs = 0
1255      list_inst(:) = -1
1256      inst_names(:) = 'XXXXXX'
1257      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1258      read(nulnam, nml=namtovsinst, iostat=ierr)
1259      if (ierr /= 0) call utl_abort('tvs_getAllIdBurpTovs: Error reading NAMTOVSINST namelist section in flnml_static file')
1260      if (mmpi_myid == 0) write(*,nml=namtovsinst)
1261      ierr = fclos(nulnam)
1262      do instrumentIndex=1, ninst
1263        if (inst_names(instrumentIndex) == 'XXXXXX' ) then
1264          ninst_tovs = instrumentIndex - 1
1265          exit
1266        else
1267          list_inst(instrumentIndex) = codtyp_get_codtyp( inst_names(instrumentIndex) )
1268          if (list_inst(instrumentIndex) < 0) then
1269            write(*,*) inst_names(instrumentIndex)
1270            call utl_abort('tvs_isIdBurpTovs: unknown instrument in namtovsinst namelist')
1271          end if
1272        end if
1273      end do
1274      if ( ninst_tovs == 0 ) call utl_abort('tvs_getAllIdBurpTovs: Empty namtovsinst namelist')
1275      first = .false.
1276    end if
1277
1278    idatypList(:) = MPC_missingValue_int
1279    idatypList(1:ninst_tovs) = list_inst(1:ninst_tovs)
1280    idatypListSize = ninst_tovs
1281
1282  end subroutine tvs_getAllIdBurpTovs
1283
1284  !--------------------------------------------------------------------------
1285  !  tvs_isIdBurpTovs
1286  !--------------------------------------------------------------------------
1287  logical function tvs_isIdBurpTovs(idatyp)
1288    !
1289    !:Purpose: Function to check if the given idatyp (a.k.a. codtyp) 
1290    !           corresponds to a radiance
1291    !
1292    implicit none
1293
1294    ! Arguments:
1295    integer, intent(in) :: idatyp
1296    
1297    ! Locals:
1298    logical, save :: first=.true.
1299    integer, save :: ninst_tovs
1300    integer :: nulnam, ierr, instrumentIndex 
1301    integer, external :: fnom, fclos
1302    integer, save :: list_inst(ninst)
1303
1304    ! Namelist variables:
1305    character(len=22) :: inst_names(ninst) ! List of instrument names for all radiance types
1306    namelist /namtovsinst/ inst_names
1307
1308    if (tvs_nsensors == 0) then
1309      ! no tovs data will be read, therefore false
1310      tvs_isIdBurpTovs = .false.
1311      return
1312    end if
1313
1314    if (first) then
1315       if ( utl_isNamelistPresent('NAMTOVSINST', './flnml') ) then
1316        call utl_abort('tvs_isIdBurpTovs: NAMTOVSINST namelist section should be now in flnml_static !')
1317      end if
1318      nulnam = 0
1319      ninst_tovs = 0
1320      list_inst(:) = -1
1321      inst_names(:) = 'XXXXXX'
1322      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1323      read(nulnam, nml=namtovsinst, iostat=ierr)
1324      if (ierr /= 0) call utl_abort('tvs_isIdBurpTovs: Error reading NAMTOVSINST namelist section in flnml_static file')
1325      if (mmpi_myid == 0) write(*,nml=namtovsinst)
1326      ierr = fclos(nulnam)
1327      do instrumentIndex=1, ninst
1328        if (inst_names(instrumentIndex) == 'XXXXXX' ) then
1329          ninst_tovs= instrumentIndex - 1
1330          exit
1331        else
1332          list_inst(instrumentIndex) = codtyp_get_codtyp( inst_names(instrumentIndex) )
1333          if (list_inst(instrumentIndex) < 0) then
1334            write(*,*) inst_names(instrumentIndex)
1335            call utl_abort('tvs_isIdBurpTovs: unknown instrument in namtovsinst namelist')
1336          end if
1337        end if
1338      end do
1339      if ( ninst_tovs == 0 ) call utl_abort('tvs_isIdBurpTovs: Empty namtovsinst namelist')
1340      first = .false.
1341    end if
1342
1343    tvs_isIdBurpTovs = .false.
1344
1345    do instrumentIndex = 1, ninst_tovs
1346      if (idatyp == list_inst(instrumentIndex) ) then
1347        tvs_isIdBurpTovs = .true.
1348        exit
1349      end if
1350    end do
1351
1352  end function tvs_isIdBurpTovs
1353
1354  !--------------------------------------------------------------------------
1355  !  tvs_isIdBurpHyperSpectral
1356  !--------------------------------------------------------------------------
1357  logical function tvs_isIdBurpHyperSpectral(idatyp)
1358    !
1359    !:Purpose: Function to check if the given idatyp (a.k.a. codtyp) 
1360    !           corresponds to a hyper-spectral infrared radiance
1361    !
1362    implicit none
1363
1364    ! Argument:
1365    integer, intent(in) :: idatyp
1366    
1367    ! Locals:
1368    logical, save :: first=.true.
1369    integer, save :: ninst_hyper
1370    integer :: nulnam, ierr, instrumentIndex 
1371    integer, external :: fnom, fclos
1372    integer, save :: list_inst(ninst)
1373
1374    ! Namelist variables:
1375    character(len=22) :: name_inst(ninst) ! List of instrument names for hyperspectral IR
1376    namelist /namhyper/ name_inst
1377
1378    if (tvs_nsensors == 0) then
1379      ! no tovs data will be read, therefore false
1380      tvs_isIdBurpHyperSpectral = .false.
1381      return
1382    end if
1383
1384    if (first) then
1385      if ( utl_isNamelistPresent('NAMHYPER', './flnml') ) then
1386        call utl_abort('tvs_isIdBurpHyperSpectral: NAMHYPER namelist section should be now in flnml_static !')
1387      end if
1388      nulnam = 0
1389      ninst_hyper = 0
1390      list_inst(:) = -1
1391      name_inst(:) = 'XXXXXX'
1392      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1393      read(nulnam, nml=namhyper, iostat=ierr)
1394      if (ierr /= 0) call utl_abort('tvs_isIdBurpHyperSpectral: Error reading NAMHYPER namelist section in flnml_static file')
1395      if (mmpi_myid == 0) write(*,nml=namhyper)
1396      ierr = fclos(nulnam)
1397      do instrumentIndex=1, ninst
1398        if (name_inst(instrumentIndex) == 'XXXXXX' ) then
1399          ninst_hyper = instrumentIndex - 1
1400          exit
1401        else
1402          list_inst(instrumentIndex) = codtyp_get_codtyp( name_inst(instrumentIndex) )
1403          if (list_inst(instrumentIndex) < 0) then
1404            write(*,*) name_inst(instrumentIndex)
1405            call utl_abort('tvs_isIdBurpHyperSpectral: unknown instrument in namhyper namelist')
1406          end if
1407        end if
1408      end do
1409      if ( ninst_hyper == 0 ) call utl_abort('tvs_isIdBurpHyperSpectral: Empty namhyper namelist')
1410      first = .false.
1411    end if
1412
1413    tvs_isIdBurpHyperSpectral = .false.
1414
1415    do instrumentIndex = 1, ninst_hyper
1416      if (idatyp == list_inst(instrumentIndex) ) then
1417        tvs_isIdBurpHyperSpectral = .true.
1418        exit
1419      end if
1420    end do
1421
1422  end function tvs_isIdBurpHyperSpectral
1423
1424  !--------------------------------------------------------------------------
1425  !  tvs_isIdBurpInst
1426  !--------------------------------------------------------------------------
1427  logical function tvs_isIdBurpInst(idburp,cinst)
1428    !
1429    !:Purpose: function to check if the provided idburp (a.k.a. codtyp) corresponds to instrument cinst
1430    !
1431    implicit none
1432
1433    ! Arguments:
1434    integer,          intent(in) :: idburp ! Input codtyp
1435    character(len=*), intent(in) :: cinst  ! Input instrument name
1436
1437    if (tvs_nsensors == 0) then
1438      ! no tovs data will be read, therefore false
1439      tvs_isIdBurpInst = .false.
1440      return
1441    end if
1442
1443    tvs_isIdBurpInst = ( idburp == codtyp_get_codtyp(cinst) )
1444
1445  end function tvs_isIdBurpInst
1446
1447  !--------------------------------------------------------------------------
1448  !  tvs_getPlatformId
1449  !--------------------------------------------------------------------------
1450  integer function tvs_getPlatformId(name)
1451    !
1452    !:Purpose: return RTTOV platform id (>0) from platform name.
1453    !           -1 if not found
1454    !
1455    implicit none
1456
1457    ! Arguments:
1458    character(len=*), intent(in) :: name ! Platform name
1459
1460    ! Locals:
1461    integer           :: platformIndex, length, ipos
1462    character(len=64) :: tempo_name
1463
1464    tvs_getPlatformId = -1
1465    length = len_trim(name)
1466    call up2low(name(1:length),tempo_name(1:length))
1467
1468    if ( index(tempo_name(1:length),'npp') /= 0 ) then
1469      tvs_getPlatformId = platform_id_jpss
1470    else if ( index(tempo_name(1:length),'hmwari') /= 0 ) then
1471      tvs_getPlatformId = platform_id_himawari
1472    else
1473      do platformIndex = 1, nplatforms
1474        ipos = index(tempo_name(1:length),trim(platform_name(platformIndex)))
1475        if (ipos == 1) then
1476          tvs_getPlatformId = platformIndex
1477          exit
1478        end if
1479      end do
1480    end if
1481
1482  end function tvs_getPlatformId
1483
1484  !--------------------------------------------------------------------------
1485  !  tvs_getInstrumentId
1486  !--------------------------------------------------------------------------
1487  integer function tvs_getInstrumentId(name)
1488    !
1489    !:Purpose: return RTTOV instrument id from intrument name. 0 is a valid answer.
1490    !           -1 if not found
1491    !
1492    implicit none
1493
1494    ! Arguments:
1495    character(len=*), intent(in) :: name ! Instrument name
1496
1497    ! Locals:
1498    integer           :: instrumentIndex, length
1499    character(len=64) :: tempo_name
1500
1501    tvs_getInstrumentId = -1
1502    length = len_trim(name)
1503    call up2low(name(1:length),tempo_name(1:length))
1504    if ( trim(tempo_name(1:length)) == 'goesim' ) then
1505      tvs_getInstrumentId = inst_id_goesim
1506    else if ( trim(tempo_name(1:length)) == 'gmsim' ) then
1507      tvs_getInstrumentId = inst_id_gmsim
1508    else if ( trim(tempo_name(1:length)) == 'mtsatim' ) then
1509      tvs_getInstrumentId = inst_id_mtsatim
1510    else
1511      do instrumentIndex = 0, ninst - 1
1512        if (trim(inst_name(instrumentIndex)) == tempo_name(1:length) ) then
1513          tvs_getInstrumentId = instrumentIndex
1514          exit
1515        end if
1516      end do
1517    end if
1518  end function tvs_getInstrumentId
1519
1520  !--------------------------------------------------------------------------
1521  !  tvs_isInstrumHyperSpectral
1522  !--------------------------------------------------------------------------
1523  logical function tvs_isInstrumHyperSpectral(instrum)
1524    !
1525    !:Purpose: given an RTTOV instrument code return if it is an hyperspectral one
1526    !           information from namelist NAMHYPER
1527    !
1528    implicit none
1529
1530    ! Arguments:
1531    integer, intent(in) :: instrum     ! input Rttov instrument code
1532
1533    ! Locals:
1534    integer, parameter :: maxsize = 100
1535    integer :: nulnam, ierr, instrumentIndex 
1536    integer, save :: list_inst(maxsize), ninst_hir
1537    logical, save :: first = .true.
1538    integer, external :: fclos, fnom
1539
1540    ! Namelist variables:
1541    character (len=8) :: name_inst(maxsize) ! List of instrument names for hyperspectral IR
1542    namelist /NAMHYPER/ name_inst
1543    
1544    if (first) then
1545      if ( utl_isNamelistPresent('NAMHYPER', './flnml') ) then
1546        call utl_abort('tvs_isInstrumHyperSpectral: NAMHYPER namelist section should be now in flnml_static !')
1547      end if
1548      nulnam = 0
1549      ninst_hir = 0
1550      name_inst(:) = 'XXXXXXX'
1551      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1552      read(nulnam,nml=namhyper, iostat=ierr)
1553      if (ierr /= 0) call utl_abort('tvs_isInstrumHyperSpectral: Error reading namelist section NAMHYPER in flnm_static file')
1554      if (mmpi_myid == 0) write(*,nml=namhyper)
1555      ierr = fclos(nulnam)
1556      list_inst(:) = -1
1557      do instrumentIndex=1, maxsize
1558        list_inst(instrumentIndex) = tvs_getInstrumentId( name_inst(instrumentIndex) )
1559        if (name_inst(instrumentIndex) /= 'XXXXXXX') then
1560          if (list_inst(instrumentIndex) == -1) then
1561            write(*,*) instrumentIndex,name_inst(instrumentIndex)
1562            call utl_abort('tvs_isInstrumHyperSpectral: Unknown instrument name')
1563          end if
1564        else
1565          ninst_hir = instrumentIndex - 1
1566          exit
1567        end if
1568      end do
1569      first = .false.
1570      if (ninst_hir == 0) then
1571        write(*,*) 'tvs_isInstrumHyperSpectral: Warning : empty namhyper namelist !'
1572      end if
1573    end if
1574    tvs_isInstrumHyperSpectral = .false.
1575    do instrumentIndex =1, ninst_hir
1576      if ( instrum == list_inst(instrumentIndex)) then
1577        tvs_isInstrumHyperSpectral = .true.
1578        exit
1579      end if
1580    end do
1581
1582  end function tvs_isInstrumHyperSpectral
1583
1584  !--------------------------------------------------------------------------
1585  !  tvs_isNameHyperSpectral
1586  !--------------------------------------------------------------------------
1587  logical function tvs_isNameHyperSpectral(cinstrum)
1588    !
1589    !:Purpose: given an instrument name
1590    !           returns if it is an hyperspectral one
1591    !           (information from namelist NAMHYPER)
1592    !
1593    implicit none
1594
1595    ! Arguments:
1596    character(len=*), intent(in) :: cinstrum
1597
1598    ! Locals:
1599    integer, parameter :: maxsize = 20
1600    integer :: nulnam, ierr, i 
1601    integer, save :: ninst_hir
1602    logical, save :: lfirst = .true.
1603    integer, external :: fclos, fnom
1604    character (len=8) :: name2
1605
1606    ! Namelist variables:
1607    character (len=8),save  :: name_inst(maxsize) ! List of instrument names for hyperspectral IR
1608    namelist /NAMHYPER/ name_inst
1609
1610    if (lfirst) then
1611      nulnam = 0
1612      ninst_hir = 0
1613      name_inst(:) = 'XXXXXXX'
1614      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1615      read(nulnam,nml=namhyper, iostat=ierr)
1616      if (ierr /= 0) call utl_abort('tvs_isNameHyperSpectral: Error reading NAMHYPER namelist section in flnml_static file')
1617      if (mmpi_myid == 0) write(*,nml=namhyper)
1618      ierr = fclos(nulnam)
1619      do i=1, maxsize
1620        if (name_inst(i) == 'XXXXXXX') then
1621          ninst_hir = i -1
1622          exit
1623        end if
1624      end do
1625      lfirst = .false.
1626      if (ninst_hir == 0) then
1627        write(*,*) 'tvs_isNameHyperSpectral: Warning : empty namhyper namelist !'
1628      end if
1629    end if
1630
1631    tvs_isNameHyperSpectral = .false.
1632
1633    call up2low(cinstrum, name2)
1634
1635    do i=1, ninst_hir
1636      if ( trim(name2) == name_inst(i)) then
1637        tvs_isNameHyperSpectral = .true.
1638        exit
1639      end if
1640    end do
1641
1642  end function tvs_isNameHyperSpectral
1643
1644  !--------------------------------------------------------------------------
1645  !  tvs_isInstrumGeostationary
1646  !--------------------------------------------------------------------------
1647  logical function tvs_isInstrumGeostationary(instrum)
1648    !
1649    !:Purpose: given an RTTOV instrument code return if it is a Geostationnary Imager
1650    !           information from namelist NAMGEO
1651    !
1652    implicit none
1653
1654    ! Arguments:
1655    integer, intent(in) :: instrum ! input Rttov instrument code
1656
1657    ! Locals:
1658    integer, parameter :: maxsize = 100
1659    integer :: nulnam, ierr, instrumentIndex 
1660    integer, save :: list_inst(maxsize), ninst_geo
1661    logical, save :: first = .true.
1662    integer, external :: fnom, fclos
1663
1664    ! Namelist variables:
1665    character(len=8) :: name_inst(maxsize) ! List of instrument names for geostationary
1666    namelist /NAMGEO/ name_inst
1667
1668    if (first) then
1669      if ( utl_isNamelistPresent('NAMGEO', './flnml') ) then
1670        call utl_abort('tvs_isInstrumGeostationary: NAMGEO namelist section should be now in flnml_static !')
1671      end if
1672      nulnam = 0
1673      ninst_geo = 0
1674      name_inst(:) = 'XXXXXX'
1675      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1676      read(nulnam,nml=namgeo, iostat=ierr)
1677      if (ierr /= 0) call utl_abort('tvs_isInstrumGeostationary: Error reading namelist section NAMGEO in flnml_static file')
1678      if (mmpi_myid == 0) write(*,nml=namgeo)
1679      ierr = fclos(nulnam)
1680      list_inst(:) = -1
1681      do instrumentIndex=1, maxsize
1682        list_inst(instrumentIndex) = tvs_getInstrumentId( name_inst(instrumentIndex) )
1683        if (name_inst(instrumentIndex) /= 'XXXXXX') then
1684          if (list_inst(instrumentIndex) == -1) then
1685            write(*,*) instrumentIndex,name_inst(instrumentIndex)
1686            call utl_abort('tvs_isInstrumGeostationary: Unknown instrument name')
1687          end if
1688        else
1689          ninst_geo = instrumentIndex - 1
1690          exit
1691        end if
1692      end do
1693      first = .false.
1694      if (ninst_geo == 0) then
1695        write(*,*) 'tvs_isInstrumGeostationary: Warning : empty namgeo namelist !'
1696      end if
1697    end if
1698    tvs_isInstrumGeostationary = .false.
1699    do instrumentIndex=1, ninst_geo
1700      if ( instrum == list_inst(instrumentIndex)) then
1701        tvs_isInstrumGeostationary = .true.
1702        exit
1703      end if
1704    end do
1705    
1706  end function tvs_isInstrumGeostationary
1707
1708  !--------------------------------------------------------------------------
1709  !  tvs_isInstrumUsingCLW
1710  !--------------------------------------------------------------------------
1711  function tvs_isInstrumUsingCLW(instrumId) result(idExist)
1712    !
1713    !:Purpose: given an RTTOV instrument code return if it is in the list to use CLW
1714    !
1715    implicit none
1716
1717    ! Arguments:
1718    integer, intent(in) :: instrumId     ! input Rttov instrument code
1719    ! Result:
1720    logical             :: idExist
1721
1722    ! Locals:
1723    integer :: instrumentIndex 
1724
1725    idExist = .false.
1726    do instrumentIndex = 1, tvs_numMWInstrumUsingCLW
1727      if ( instrumId == instrumentIdsUsingCLW(instrumentIndex) ) then
1728        idExist = .true.
1729        exit
1730      end if
1731    end do
1732
1733  end function tvs_isInstrumUsingCLW
1734
1735  !--------------------------------------------------------------------------
1736  !  tvs_isInstrumUsingHydrometeors
1737  !--------------------------------------------------------------------------
1738  function tvs_isInstrumUsingHydrometeors(instrumId) result(idExist)
1739    !
1740    !:Purpose: given an RTTOV instrument code return if it is in the list to use Hydrometeors
1741    !
1742    implicit none
1743
1744    ! Arguments:
1745    integer, intent(in) :: instrumId     ! input Rttov instrument code
1746    ! Result:
1747    logical             :: idExist
1748
1749    ! Locals:
1750    integer :: instrumentIndex 
1751
1752    idExist = .false.
1753    do instrumentIndex = 1, tvs_numMWInstrumUsingHydrometeors
1754      if ( instrumId == instrumentIdsUsingHydrometeors(instrumentIndex) ) then
1755        idExist = .true.
1756        exit
1757      end if
1758    end do
1759
1760  end function tvs_isInstrumUsingHydrometeors
1761
1762  !--------------------------------------------------------------------------
1763  !  tvs_isInstrumAllskyTtAssim
1764  !--------------------------------------------------------------------------
1765  function tvs_isInstrumAllskyTtAssim(instrumId) result(allskyTtAssim)
1766    !
1767    !:Purpose: determine if all-sky temperature-channel assimilation is asked for the instrument.
1768    !
1769    implicit none
1770
1771    ! Arguments:
1772    integer, intent(in) :: instrumId     ! input Rttov instrument code
1773    ! Result:
1774    logical             :: allskyTtAssim
1775
1776    allskyTtAssim = (tvs_mwAllskyAssim .and. tvs_isInstrumUsingCLW(instrumId))
1777
1778  end function tvs_isInstrumAllskyTtAssim
1779
1780  !--------------------------------------------------------------------------
1781  !  tvs_isInstrumAllskyHuAssim
1782  !--------------------------------------------------------------------------
1783  function tvs_isInstrumAllskyHuAssim(instrumId) result(allskyHuAssim)
1784    !
1785    !:Purpose: determine if all-sky humidity-channel assimilation is asked for the instrument.
1786    !
1787    implicit none
1788
1789    ! Arguments:
1790    integer, intent(in) :: instrumId     ! input Rttov instrument code
1791    ! Result:
1792    logical             :: allskyHuAssim
1793
1794    allskyHuAssim = (tvs_mwAllskyAssim .and. tvs_isInstrumUsingHydrometeors(instrumId))
1795
1796  end function tvs_isInstrumAllskyHuAssim
1797
1798  !--------------------------------------------------------------------------
1799  !  tvs_mapInstrum
1800  !--------------------------------------------------------------------------
1801  subroutine tvs_mapInstrum(instrumburp,instrum)
1802    !
1803    !:Purpose:  Map burp satellite instrument (element #2019) to RTTOV-7 instrument.
1804    !            A negative value is returned, if no match in found.
1805    !
1806    !:Table of  RTTOV-7 instrument identifier:
1807    !
1808    ! ==================  =====================  ==================
1809    ! Instrument          Instrument identifier  Sensor type
1810    ! ==================  =====================  ==================
1811    !               HIRS               0                     ir
1812    !                MSU               1                     mw
1813    !                SSU               2                     ir
1814    !              AMSUA               3                     mw
1815    !              AMSUB               4                     mw
1816    !              AVHRR               5                     ir
1817    !               SSMI               6                     mw
1818    !              VTPR1               7                     ir
1819    !              VTPR2               8                     ir
1820    !                TMI               9                     mw
1821    !              SSMIS              10                     mw
1822    !               AIRS              11                     ir
1823    !              MODIS              13                     ir
1824    !               ATSR              14                     ir
1825    !                MHS              15                     mw
1826    !               ATMS              19                     mw
1827    !              MVIRI              20                     ir
1828    !             SEVIRI              21                     ir
1829    !         GOESIMAGER              22                     ir
1830    !        GOESSOUNDER              23                     ir
1831    !   GMS/MTSAT IMAGER              24                     ir
1832    !          FY2-VISSR              25                     ir
1833    !          FY1-MVISR              26                     ir
1834    !                AHI              56                     ir
1835    ! ==================  =====================  ==================
1836    !
1837    implicit none
1838
1839    ! Arguments:
1840    integer, intent(in)  :: instrumburp  ! burp satellite instrument (element #2019)
1841    integer, intent(out) :: instrum      ! RTTOV-7 instrument ID numbers (e.g. 3 for  AMSUA)
1842  
1843    ! Locals:  
1844    integer instrumentIndex, numinstburp
1845    integer, parameter :: mxinstrumburp   = 100
1846    logical, save :: first = .true.
1847    integer :: nulnam, ier
1848    integer, external :: fnom, fclos
1849
1850    ! Namelist variables:
1851    integer, save ::   listburp(mxinstrumburp)           ! List of instrument ID values from obs file
1852    character(len=8), save :: listinstrum(mxinstrumburp) ! List of instrument names
1853    namelist /NAMINST/ listburp, listinstrum
1854
1855    !      Table of BURP satellite sensor identifier element #002019
1856
1857    !   1.0 Find instrument
1858
1859    if (first) then
1860      if ( utl_isNamelistPresent('NAMINST', './flnml') ) then
1861        call utl_abort('tvs_mapInstrum: NAMINST namelist section should be now in flnml_static !')
1862      end if
1863      
1864      ! set the default values
1865      listburp(:) = -1
1866      listinstrum(:) = 'XXXXXXXX'
1867
1868      ! read the namelist
1869      nulnam = 0
1870      ier = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1871      if (ier /= 0) then
1872        write(*,*) 'Error while opening flnml_static namelist file !'
1873        call utl_abort('tvs_mapInstrum')
1874      end if
1875      read(nulnam,NAMINST,iostat=ier)
1876      if (ier /= 0) then
1877        write(*,*) 'Error while reading NAMINST namelist section in flnml_static file !'
1878        call utl_abort('tvs_mapInstrum')
1879      end if
1880      ier = fclos(nulnam)
1881
1882      ! figure out how many valid elements in the lists
1883      do instrumentIndex=1, mxinstrumburp
1884        if(listburp(instrumentIndex) == -1) then
1885          numinstburp = instrumentIndex - 1
1886          exit
1887        end if
1888      end do
1889      if (numinstburp > mxinstrumburp) then
1890        call utl_abort('tvs_mapInstrum: exceeded maximum number of platforms')
1891      end if
1892      write(*,*) 'tvs_mapInstrum: number of satellites found in namelist = ',numinstburp
1893      write(*,*) 'tvs_mapInstrum: listburp   = ',listburp(1:numinstburp)
1894      write(*,*) 'tvs_mapInstrum: listinstrum    = ',listinstrum(1:numinstburp)
1895      first=.false.
1896    end if
1897
1898    instrum = -1
1899    do instrumentIndex=1, mxinstrumburp
1900      if ( instrumburp == listburp(instrumentIndex) ) then
1901        instrum = tvs_getInstrumentId( listinstrum(instrumentIndex) )
1902        exit
1903      end if
1904    end do
1905
1906  end subroutine tvs_mapInstrum
1907
1908  !--------------------------------------------------------------------------
1909  !  tvs_isNameGeostationary
1910  !--------------------------------------------------------------------------
1911  logical function tvs_isNameGeostationary(cinstrum)
1912    !
1913    !:Purpose: given an instrument name following BUFR convention
1914    !           returns if it is a Geostationnary Imager
1915    !           (information from namelist NAMGEOBUFR)
1916    !
1917    implicit none
1918
1919    ! Arguments:
1920    character(len=*), intent(in) :: cinstrum
1921
1922    ! Locals:
1923    integer, parameter :: maxsize = 100
1924    integer :: nulnam, ierr, i 
1925    integer, save :: ninst_geo
1926    logical, save :: lfirst = .true.
1927    integer, external :: fnom, fclos
1928
1929    ! Namelist variables:
1930    character (len=8),save :: name_inst(maxsize) ! List of instrument names for geostationary
1931    namelist /NAMGEOBUFR/ name_inst
1932
1933    if (lfirst) then
1934      if ( utl_isNamelistPresent('NAMGEOBUFR', './flnml') ) then
1935        call utl_abort('tvs_isNameGeostationary: NAMGEOBUFR namelist section should be now in flnml_static !')
1936      end if
1937      nulnam = 0
1938      ninst_geo = 0
1939      name_inst(:) = 'XXXXXXXX'
1940      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
1941      read(nulnam,nml=namgeobufr, iostat=ierr)
1942      if (ierr /= 0) call utl_abort('tvs_isNameGeostationary: Error reading namelist section NAMGEOBUFR in flnml_static_file')
1943      if (mmpi_myid == 0) write(*,nml=namgeobufr)
1944      ierr = fclos(nulnam)
1945      do i=1, maxsize
1946        if (name_inst(i) == 'XXXXXXXX') then
1947          ninst_geo = i - 1
1948          exit
1949        end if
1950      end do
1951      lfirst = .false.
1952      if (ninst_geo == 0) then
1953        write(*,*) 'tvs_isNameGeostationary: Warning : empty namgeobufr namelist !' 
1954      end if
1955    end if
1956    
1957    tvs_isNameGeostationary = .false.
1958    do i=1, ninst_geo
1959      if ( trim(cinstrum) == trim(name_inst(i)) ) then
1960        tvs_isNameGeostationary= .true.
1961        exit
1962      end if
1963    end do
1964    
1965  end function tvs_isNameGeostationary
1966
1967  !--------------------------------------------------------------------------
1968  !  tvs_mapSat
1969  !--------------------------------------------------------------------------
1970  subroutine tvs_mapSat(isatBURP,iplatform,isat)
1971    !
1972    !:Purpose:  Map burp satellite identifier (element #1007)
1973    !            to RTTOV-7 platform and satellite.
1974    !            Negative values are returned, if no match in found.
1975    !
1976    !:Table of  RTTOV-7 platform identifier:
1977    !
1978    ! ========          ===========================
1979    ! Platform          RTTOV-7 platform identifier
1980    ! ========          ===========================
1981    !     NOAA               1
1982    !     DMSP               2
1983    ! METEOSAT               3
1984    !     GOES               4
1985    !      GMS               5
1986    !      FY2               6
1987    !     TRMM               7
1988    !      ERS               8
1989    !      EOS               9
1990    !    METOP              10
1991    !  ENVISAT              11
1992    !      MSG              12
1993    !      FY1              13
1994    !    ADEOS              14
1995    !    MTSAT              15
1996    ! CORIOLIS              16
1997    !      NPP              17
1998    ! ========          ===========================
1999    !
2000    !:Example: 
2001    !          NOAA15, which has a burp satellite identifier value of 206,
2002    !          is mapped into the following:
2003    !          RTTOV-7 platform  =  1,
2004    !          RTTOV-7 satellite = 15.
2005    !
2006    !:Arguments:
2007    !     :isatBURP: BURP satellite identifier
2008    !     :iplatform: RTTOV-7 platform ID numbers (e.g. 1 for  NOAA)
2009    !     :isat: RTTOV-7 satellite ID numbers (e.g. 15)
2010    !
2011    implicit none
2012    
2013    ! Arguments:
2014    integer, intent(in)  :: isatburp   ! BURP satellite identifier
2015    integer, intent(out) :: iplatform  ! RTTOV-7 platform ID numbers (e.g. 1 for  NOAA)
2016    integer, intent(out) :: isat       ! RTTOV-7 satellite ID numbers (e.g. 15)
2017
2018    ! Locals:
2019    integer           :: satelliteIndex, ierr, nulnam
2020    logical, save     :: first=.true.
2021    integer, external :: fnom, fclos
2022    integer, parameter:: mxsatburp = 100
2023    integer, save     :: numsatburp
2024
2025    ! Namelist variables:
2026    integer, save          :: listburp(mxsatburp) ! Table of BURP satellite identifier element #001007
2027    character(len=8), save :: listplat(mxsatburp) ! Table of RTTOV platform identifier
2028    integer, save          :: listsat (mxsatburp) ! Table of RTTOV satellite identifier
2029
2030    namelist /NAMSAT/ listburp, listplat, listsat
2031
2032    !     Fill tables from namelist at the first call 
2033    if (first) then
2034      if ( utl_isNamelistPresent('NAMSAT', './flnml') ) then
2035        call utl_abort('tvs_mapSat: NAMSAT namelist section should be now in flnml_static !')
2036      end if
2037      ! set the default values
2038      listburp(:) = -1
2039      listsat(:) = -1
2040      listplat(:) = 'XXXXXXXX'
2041      ! read the namelist
2042      nulnam = 0
2043      ierr = fnom(nulnam,'./flnml_static','FTN+SEQ+R/O',0)
2044      if (ierr /= 0) then
2045        write(*,*) 'Error while opening namelist flnml_static file !'
2046        call utl_abort('tvs_mapSat')
2047      end if
2048      read(nulnam, NAMSAT, iostat = ierr)
2049      if (ierr /= 0) then
2050        write(*,*) 'Error while reading NAMSAT namelist section in flnml_static file !'
2051        call utl_abort('tvs_mapSat')
2052      end if
2053      ierr = fclos(nulnam)
2054
2055      !  Figure out how many valid elements in the lists
2056      do satelliteIndex=1, mxsatburp
2057        if(listburp(satelliteIndex) == -1) then
2058          numsatburp = satelliteIndex - 1
2059          exit
2060        end if
2061      end do
2062      if(numsatburp >= mxsatburp) then
2063        call utl_abort('tvs_mapSat: exceeded maximum number of platforms')
2064      end if
2065      write(*,*) 'tvs_mapSat: number of satellites found in namelist = ',numsatburp
2066      write(*,*) 'tvs_mapSat: listburp   = ',listburp(1:numsatburp)
2067      write(*,*) 'tvs_mapSat: listsat    = ',listsat(1:numsatburp)
2068      write(*,*) 'tvs_mapSat: listplat   = ',listplat(1:numsatburp)
2069      first = .false.
2070    end if
2071
2072    !   Find platform and satellite
2073
2074    iplatform = -1
2075    isat      = -1
2076    do satelliteIndex=1, numsatburp
2077      if ( isatburp == listburp(satelliteIndex) ) then
2078        iplatform = tvs_getPlatformId( listplat(satelliteIndex) )
2079        isat = listsat (satelliteIndex)
2080        exit
2081      end if
2082    end do
2083
2084  end subroutine tvs_mapSat
2085
2086  !--------------------------------------------------------------------------
2087  !  tvs_getChanProf
2088  !--------------------------------------------------------------------------
2089  subroutine tvs_getChanprof(sensorTovsIndexes, obsSpaceData, chanprof, lchannel_subset_opt, iptobs_cma_opt)
2090    ! 
2091    !:Purpose: subroutine to initialize the chanprof structure used by RTTOV
2092    !
2093    implicit none
2094
2095    ! Arguments:
2096    integer,              intent(in)  :: sensorTovsIndexes(:)
2097    type(struct_obs),     intent(in)  :: obsSpaceData
2098    type(rttov_chanprof), intent(out) :: chanprof(:)
2099    logical,    optional, intent(out) :: lchannel_subset_opt(:,:)
2100    integer,    optional, intent(out) :: iptobs_cma_opt(:)
2101
2102    ! Locals:
2103    integer :: count, profileIndex, headerIndex, istart, iend, bodyIndex, channelNumber, iobs
2104    integer :: ChannelIndex
2105
2106    ! Build the list of channels/profiles indices
2107    count = 0
2108    if (present( lchannel_subset_opt )) lchannel_subset_opt(:,:) = .false.
2109         
2110    do profileIndex = 1, size(sensorTovsIndexes)
2111      iobs = sensorTovsIndexes(profileIndex)
2112      headerIndex = tvs_headerIndex(iobs)
2113      if (headerIndex > 0) then
2114        istart = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2115        iend= obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex) + istart - 1
2116        do bodyIndex = istart, iend
2117          if (obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated) then
2118            call tvs_getChannelNumIndexFromPPP( obsSpaceData, headerIndex, bodyIndex, &
2119                                                channelNumber, channelIndex )
2120            if (channelIndex >0) then
2121              count =  count + 1
2122              chanprof(count)%prof = profileIndex
2123              chanprof(count)%chan = channelIndex
2124              if (present(iptobs_cma_opt)) iptobs_cma_opt(count) = bodyIndex
2125              if (present( lchannel_subset_opt )) lchannel_subset_opt(profileIndex,channelIndex) = .true.
2126            else
2127              write(*,*) 'tvs_getChanProf: strange channel number',channelNumber
2128            end if
2129          end if
2130        end do
2131      end if
2132    end do
2133  
2134  end subroutine tvs_getChanprof
2135
2136  !--------------------------------------------------------------------------
2137  !  tvs_countRadiances
2138  !--------------------------------------------------------------------------
2139  integer function tvs_countRadiances(sensorTovsIndexes, obsSpaceData, assim_flag_val_opt)
2140    !
2141    !:Purpose: to count radiances selected for assimilation
2142    !
2143    implicit none
2144
2145    ! Arguments:
2146    integer,           intent(in) :: sensorTovsIndexes(:)
2147    type(struct_obs),  intent(in) :: obsSpaceData
2148    integer, optional, intent(in) :: assim_flag_val_opt
2149    
2150    ! Locals:
2151    integer :: profileIndex, headerIndex, istart, iend, bodyIndex, iobs, assim_flag_val
2152
2153    if (present(assim_flag_val_opt)) then
2154      assim_flag_val = assim_flag_val_opt
2155    else
2156      assim_flag_val = 1
2157    end if
2158
2159    tvs_countRadiances = 0
2160    do profileIndex = 1, size(sensorTovsIndexes)
2161      iobs = sensorTovsIndexes(profileIndex)
2162      headerIndex = tvs_headerIndex(iobs)
2163      if (headerIndex > 0) then
2164        istart = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2165        iend = obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex) + istart - 1
2166        do bodyIndex = istart, iend
2167          if(obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated) tvs_countRadiances  = tvs_countRadiances + 1
2168        end do
2169      end if
2170    end do
2171
2172  end function tvs_countRadiances
2173
2174  !--------------------------------------------------------------------------
2175  !  tvs_ChangedStypValue(obsspacedata, headerIndex)
2176  !--------------------------------------------------------------------------
2177  integer function tvs_ChangedStypValue(obsSpaceData, headerIndex)
2178    !
2179    !:Purpose: to obtain new STYP value given observed STYP and TTYP value
2180    !
2181    implicit none
2182
2183    ! Arguments:
2184    integer,          intent(in) :: headerIndex
2185    type(struct_obs), intent(in) :: obsSpaceData
2186    
2187    ! Locals:
2188    integer :: terrainType
2189    integer :: landSea 
2190
2191    terrainType = obs_headElem_i(obsSpaceData,OBS_TTYP,headerIndex)
2192    landSea     = obs_headElem_i(obsSpaceData,OBS_STYP,headerIndex)
2193
2194    if ( terrainType ==  0 ) then
2195      tvs_ChangedStypValue = surftype_seaice
2196    else
2197      tvs_ChangedStypValue = landSea
2198    end if
2199
2200  end function tvs_ChangedStypValue
2201
2202  !--------------------------------------------------------------------------
2203  !  tvs_getHIREmissivities
2204  !--------------------------------------------------------------------------
2205  subroutine tvs_getHIREmissivities(sensorTovsIndexes, obsSpaceData, surfem)
2206    !
2207    !:Purpose: to get emissivity for Hyperspectral Infrared Sounders (AIRS, IASI, CrIS, ...)
2208    !
2209    implicit none
2210
2211    ! Arguments:
2212    integer,          intent(in)  :: sensorTovsIndexes(:)
2213    type(struct_obs), intent(in)  :: obsSpaceData
2214    real(8),          intent(out) :: surfem(:)
2215
2216    ! Locals:
2217    integer :: count, profileIndex, iobs, istart, iend, bodyIndex, headerIndex
2218
2219    count = 0 
2220    surfem(:) = 0.98d0
2221    do profileIndex = 1, size(sensorTovsIndexes)
2222      iobs = sensorTovsIndexes(profileIndex)
2223      headerIndex = tvs_headerIndex(iobs)
2224      if (headerIndex > 0 ) then
2225        istart = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2226        iend = obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex) + istart - 1
2227        do bodyIndex = istart, iend
2228          if(obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated) then
2229            count = count + 1
2230            surfem ( count ) = obs_bodyElem_r(obsSpaceData,OBS_SEM,bodyIndex)
2231          end if
2232        end do
2233      end if
2234    end do
2235
2236  end subroutine tvs_getHIREmissivities
2237
2238  !--------------------------------------------------------------------------
2239  !  tvs_getOtherEmissivities
2240  !--------------------------------------------------------------------------
2241  subroutine tvs_getOtherEmissivities(chanprof, sensorTovsIndexes, sensorType, instrument, surfem, calcemis)
2242    !
2243    !:Purpose: to get emissivity for microwave sounders and infrared geostationary imagers
2244    !
2245    implicit none
2246
2247    ! Arguments:
2248    type(rttov_chanprof), intent(in)  :: chanprof(:)
2249    integer,              intent(in)  :: sensorTovsIndexes(:)
2250    integer,              intent(in)  :: sensorType
2251    integer,              intent(in)  :: instrument
2252    real(8),              intent(out) :: surfem(:)
2253    logical,              intent(out) :: calcemis(:)
2254    
2255    ! Locals:
2256    integer :: radiance_index, profileIndex, iobs, surfaceType
2257
2258    do radiance_index = 1, size(chanprof)
2259      profileIndex = chanprof(radiance_index)%prof
2260      iobs = sensorTovsIndexes(profileIndex)
2261      surfaceType = tvs_profiles_nl(iobs) % skin % surftype
2262      if ( sensorType == sensor_id_mw ) then
2263        if ( surfaceType == surftype_land .or. &
2264             surfaceType == surftype_seaice     ) then
2265          calcemis(radiance_index) = .false.
2266          surfem (radiance_index) = 0.75d0
2267        else
2268          calcemis(radiance_index) = .true.
2269          surfem (radiance_index) = 0.d0
2270        end if
2271      else if ( tvs_isInstrumHyperSpectral(instrument) ) then
2272        calcemis(radiance_index) = .false. 
2273      else if ( tvs_isInstrumGeostationary(instrument) ) then
2274        calcemis(radiance_index) = .true.
2275        surfem (radiance_index) = 0.d0
2276      else
2277        write(*,*) sensorType,instrument
2278        call utl_abort('tvs_getOtherEmissivities. invalid sensor type or unknown IR instrument')
2279      end if
2280    end do
2281   
2282  end subroutine tvs_getOtherEmissivities
2283  
2284  !--------------------------------------------------------------------------
2285  !  tvs_fillProfiles
2286  !--------------------------------------------------------------------------
2287  subroutine tvs_fillProfiles(columnTrl, obsSpaceData, datestamp, profileType, beSilent)
2288    !
2289    !:Purpose:  to fill in tvs_profiles_nl structure before call to non-linear, 
2290    !            tangent-linear or adjoint of RTTOV
2291    !
2292    implicit none
2293
2294    ! Arguments:
2295    type(struct_columnData), intent(in)    :: columnTrl    ! Column structure
2296    type(struct_obs),        intent(inout) :: obsSpaceData ! obsSpaceData structure
2297    integer,                 intent(in)    :: datestamp    ! CMC date stamp
2298    character(len=*),        intent(in)    :: profileType
2299    logical,                 intent(in)    :: beSilent     ! To control verbosity
2300
2301    ! Locals:
2302    integer :: instrum, iplatform
2303    integer :: nobmax
2304    integer :: sensorIndex, tovsIndex
2305    integer :: profileCount, headerIndex
2306    integer :: profileIndex, levelIndex
2307    integer :: ilowlvl_M,ilowlvl_T,nlv_M,nlv_T
2308    integer :: Vcode
2309    integer :: ierr,day,month,year,ijour,itime
2310    integer :: allocStatus(13)    
2311    integer,external ::  omp_get_num_threads
2312    integer,external ::  newdate
2313    integer, allocatable :: sensorTovsIndexes(:)
2314    integer, allocatable :: sensorHeaderIndexes(:)  
2315    type(struct_vco), pointer :: vco
2316    real(8), allocatable :: pressure (:,:)
2317    real(8), allocatable :: latitudes(:)
2318    real(8), allocatable :: ozone(:,:)
2319    character(len=4)     :: ozoneVarName
2320    real(8), allocatable :: clw   (:,:)
2321    real(8), allocatable :: ciw   (:,:)
2322    real(8), allocatable :: rainflux  (:,:)
2323    real(8), allocatable :: snowflux  (:,:)
2324    real(8), allocatable :: cloudFraction(:,:)
2325    logical, allocatable :: surfTypeIsWater(:)
2326    logical :: runObsOperatorWithClw
2327    logical :: runObsOperatorWithHydrometeors
2328    type(rttov_profile), pointer :: profiles(:)
2329    type(rttov_profile_cloud), pointer :: cld_profiles(:)
2330    real(8), pointer :: column_ptr(:)
2331    real(8) :: zmax, wind
2332
2333    if ( .not. beSilent ) write(*,*) 'tvs_fillProfiles: Starting'
2334  
2335    if (tvs_nobtov == 0) return    ! exit if there are no tovs data
2336
2337    if ( tvs_numMWInstrumUsingCLW > 0 .and. .not. col_varExist(columnTrl,'LWCR') ) then
2338      call utl_abort('tvs_fillProfiles: if number of instrument to use CLW greater than zero, ' // &
2339                     'the LWCR variable must be included as an analysis variable in NAMSTATE. ')
2340    end if
2341    if (tvs_numMWInstrumUsingHydrometeors > 0) then
2342      if (.not. (col_varExist(columnTrl,'LWCR') .and. col_varExist(columnTrl,'IWCR'))) then
2343        call utl_abort('tvs_fillProfiles: if number of instrument to use hydrometeors greater than zero, ' // &
2344                       'the LWCR/IWCR variables must be included as an analysis variable in NAMSTATE. ')
2345      end if
2346      if (.not. beSilent .and. .not. (col_varExist(columnTrl,'RF') .and. col_varExist(columnTrl,'SF') .and. &
2347          col_varExist(columnTrl,'CLDR'))) then
2348        write(*,*) 'tvs_fillProfiles: one of RF/SF/CLDR does not exist in NAMSTATE'
2349      end if
2350    end if
2351
2352    if ( (tvs_numMWInstrumUsingCLW == 0 .and. tvs_numMWInstrumUsingHydrometeors == 0 .and. &
2353            tvs_mwAllskyAssim) .or. &
2354         (tvs_numMWInstrumUsingCLW  > 0 .and. tvs_numMWInstrumUsingHydrometeors == 0 .and. &
2355            .not. tvs_mwAllskyAssim) .or. &
2356         (tvs_numMWInstrumUsingCLW == 0 .and. tvs_numMWInstrumUsingHydrometeors  > 0 .and. &
2357            .not. tvs_mwAllskyAssim) ) then
2358      call utl_abort('tvs_fillProfiles: number of instrument to use CLW/hydrometeors do not match ' // &
2359                     'all-sky namelist variable.')
2360    end if
2361
2362    if (.not. tvs_useO3Climatology .and. .not. col_varExist(columnTrl,'TO3') .and. &
2363        .not. col_varExist(columnTrl,'O3L') ) then
2364      call utl_abort('tvs_fillProfiles: if tvs_useO3Climatology is set to .false. the ozone variable ' // &
2365                     'must be included as an analysis variable in NAMSTATE. ')
2366    else if (.not.tvs_useO3Climatology) then 
2367      if (col_varExist(columnTrl,'TO3') ) then
2368        ozoneVarName = 'TO3'
2369      else
2370        ozoneVarName = 'O3L'
2371      end if
2372    end if
2373
2374    allocStatus(:) = 0
2375
2376    if ( profileType == 'nl' ) then
2377      if ( .not. allocated( tvs_profiles_nl) ) then
2378        allocate(tvs_profiles_nl(tvs_nobtov) , stat=allocStatus(1) )
2379        if (tvs_numMWInstrumUsingHydrometeors  > 0) then
2380          allocate(tvs_cld_profiles_nl(tvs_nobtov) , stat=allocStatus(2))
2381        end if
2382        call utl_checkAllocationStatus(allocStatus(1:2), ' tvs_fillProfiles tvs_profiles_nl')
2383      end if
2384    else if ( profileType == 'tlad' ) then
2385      if ( .not. allocated( tvs_profiles_tlad) ) then
2386        allocate(tvs_profiles_tlad(tvs_nobtov) , stat=allocStatus(1) )
2387        if (tvs_numMWInstrumUsingHydrometeors  > 0) then
2388          allocate(tvs_cld_profiles_tlad(tvs_nobtov) , stat=allocStatus(2))
2389        end if
2390        call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_fillProfiles tvs_profiles_tlad')
2391      else
2392        return
2393      end if
2394    else
2395      write(*,*) 'Invalid  profileType ', profileType
2396      call utl_abort('tvs_fillProfiles')
2397    end if
2398
2399    if ( .not. beSilent ) write(*,*) 'tvs_fillProfiles: profileType is ', profileType
2400
2401    call tvs_getProfile(profiles, profileType, cld_profiles)
2402
2403!
2404!     1.    Set index for model's lowest level and model top
2405!     .     ------------------------------------------------
2406    
2407    nlv_M = col_getNumLev(columnTrl,'MM')
2408    nlv_T = col_getNumLev(columnTrl,'TH')
2409
2410    if (  col_getPressure(columnTrl,1,1,'TH') < col_getPressure(columnTrl,nlv_T,1,'TH') ) then
2411      ilowlvl_M = nlv_M
2412      ilowlvl_T = nlv_T
2413    else
2414      ilowlvl_M = 1
2415      ilowlvl_T = 1
2416    end if
2417
2418    vco => col_getVco(columnTrl)
2419    Vcode = vco%Vcode
2420
2421    ierr = newdate(datestamp,ijour,itime,-3)
2422    if (ierr < 0) then
2423      write(*,*) 'Invalid datestamp ',datestamp,ijour,itime,ierr
2424      call utl_abort('tvs_fillProfiles')
2425    end if
2426    year= ijour / 10000
2427    month = mod(ijour / 100,100)
2428    day = mod(ijour,100)
2429
2430    !  1.2   Read ozone climatology
2431
2432    if (tvs_useO3Climatology) call ozo_read_climatology(datestamp)
2433
2434    !     2.  Fill profiles structure
2435    
2436    ! loop over all instruments
2437    sensor_loop: do sensorIndex=1, tvs_nsensors
2438
2439      runObsOperatorWithClw = (col_varExist(columnTrl,'LWCR') .and. tvs_numMWInstrumUsingCLW /= 0 .and. & 
2440                               tvs_isInstrumUsingCLW(tvs_instruments(sensorIndex)))
2441
2442      runObsOperatorWithHydrometeors = (col_varExist(columnTrl,'LWCR') .and. col_varExist(columnTrl,'IWCR') .and. &
2443                                        tvs_isInstrumUsingHydrometeors(tvs_instruments(sensorIndex)))
2444
2445      if (runObsOperatorWithClw .and. runObsOperatorWithHydrometeors) then
2446        call utl_abort('tvs_fillProfiles: this instrument is mentioned in using CLW and hydrometeors.')
2447      end if
2448
2449      ! first loop over all obs.
2450      profileCount = 0
2451      bobs1: do tovsIndex = 1, tvs_nobtov
2452        if (tvs_lsensor(tovsIndex) == sensorIndex) then
2453          profileCount = profileCount + 1
2454          NOBMAX = tovsIndex
2455        end if
2456      end do bobs1
2457
2458      if (profileCount == 0) cycle sensor_loop
2459
2460      if (tvs_coefs(sensorIndex)%coef%fmv_model_ver >= 9) then
2461        zmax = zenmaxv9
2462      else
2463        zmax = zenmax
2464      end if
2465      
2466      allocStatus(:) = 0
2467      allocate (sensorTovsIndexes(profileCount),                     stat = allocStatus(1) )
2468      allocate (sensorHeaderIndexes(profileCount),                   stat = allocStatus(2) )
2469      allocate (latitudes(profileCount),                             stat = allocStatus(3) )
2470      allocate (ozone(nlv_T,profileCount),                           stat = allocStatus(4) ) 
2471      allocate (pressure(nlv_T,profileCount),                        stat = allocStatus(5) )
2472      if (runObsOperatorWithClw .or. runObsOperatorWithHydrometeors) then
2473        allocate (clw       (nlv_T,profileCount),stat= allocStatus(6))
2474        clw(:,:) = qlim_getMinValueCloud('LWCR')
2475      end if
2476      if (runObsOperatorWithHydrometeors) then
2477        allocate (ciw       (nlv_T,profileCount),stat= allocStatus(7))
2478        allocate (rainFlux  (nlv_T,profileCount),stat= allocStatus(8))
2479        allocate (snowFlux  (nlv_T,profileCount),stat= allocStatus(9))
2480        allocate (cloudFraction(nlv_T,profileCount),stat= allocStatus(10))
2481        ciw(:,:) = qlim_getMinValueCloud('IWCR')
2482        rainFlux(:,:) = qlim_getMinValueCloud('RF')
2483        snowFlux(:,:) = qlim_getMinValueCloud('SF')
2484        cloudFraction(:,:) = qlim_getMinValueCloud('CLDR')
2485      end if
2486      allocate (surfTypeIsWater(profileCount),stat= allocStatus(11)) 
2487      surfTypeIsWater(:) = .false.
2488
2489      call utl_checkAllocationStatus(allocStatus, ' tvs_fillProfiles')
2490
2491      profileCount = 0
2492
2493      ! second loop over all obs.
2494      bobs2: do tovsIndex = 1, NOBMAX
2495        if (tvs_lsensor(tovsIndex) /= sensorIndex) cycle bobs2
2496        profileCount = profileCount + 1
2497        sensorTovsIndexes(profileCount) = tovsIndex
2498        headerIndex = tvs_headerIndex(tovsIndex)
2499        sensorHeaderIndexes(profileCount) = headerIndex
2500
2501        call rttov_alloc_prof(                 &
2502             allocStatus(1),                   &
2503             1,                                & ! 1 = nprofiles un profil a la fois
2504             profiles(tovsIndex:tovsIndex),    &
2505             nlv_T,                            & 
2506             tvs_opts(sensorIndex),            &
2507             asw=1,                            & ! asw =1 allocation
2508             coefs=tvs_coefs(sensorIndex),     &
2509             init=.true. )                       
2510        if (runObsOperatorWithHydrometeors) then
2511          call rttov_alloc_scatt_prof(            &   
2512               allocstatus(2),                    &
2513               1,                                 &
2514               cld_profiles(tovsIndex:tovsIndex), &
2515               nlv_T,                             &
2516               nhydro=5,                          & ! depending on what is defined in the Mie tables
2517               nhydro_frac=1,                     & ! 1 cloud fraction for all variable or nhydro 1 cloud fraction for each variable
2518               asw=1_jpim,                        & ! 1 => allocate
2519               init=.true.,                       & ! initialize profiles to zero
2520               flux_conversion=[1,2,0,0,0] )        !flux_conversion  input units: 0 (default) => kg/kg,
2521                                                    ! 1,2 => kg/m2/s, optional for rain, snow
2522        end if
2523        call utl_checkAllocationStatus(allocStatus(1:2), ' tvs_setupAlloc tvs_fillProfiles')
2524
2525        !    extract land/sea/sea-ice flag (0=land, 1=sea, 2=sea-ice)
2526        profiles(tovsIndex) % skin % surftype = tvs_ChangedStypValue(obsSpaceData,headerIndex)
2527
2528        !    extract satellite zenith and azimuth angle, 
2529        !    sun zenith angle, cloud fraction, latitude and longitude
2530        profiles(tovsIndex) % zenangle   = obs_headElem_r(obsSpaceData,OBS_SZA,headerIndex)
2531
2532        call validateRttovVariable(profiles(tovsIndex) % zenangle, "satellite zenith angle", &
2533            obsSpaceData, headerIndex, 0.d0, zmax)
2534 
2535        profiles(tovsIndex) % azangle = tvs_getCorrectedSatelliteAzimuth(obsSpaceData, headerIndex)
2536        profiles(tovsIndex) % sunazangle  = obs_headElem_r(obsSpaceData,OBS_SAZ,headerIndex) ! necessaire pour radiation solaire
2537        iplatform = tvs_coefs(sensorIndex) % coef % id_platform
2538        instrum = tvs_coefs(sensorIndex) % coef % id_inst
2539        profiles(tovsIndex) % sunzenangle = obs_headElem_r(obsSpaceData,OBS_SUN,headerIndex)
2540        if (tvs_opts(sensorIndex)%rt_ir%addsolar) then
2541          call validateRttovVariable(profiles(tovsIndex) % sunzenangle, "sun zenith angle", &
2542              obsSpaceData, headerIndex, 0.d0)
2543        end if
2544        latitudes(profileCount) = obs_headElem_r(obsSpaceData,OBS_LAT,headerIndex) * MPC_DEGREES_PER_RADIAN_R8
2545        !1d-5 was chosen as a threshold because it is the high precision for latitudes in BUFR/BURP files
2546        if (latitudes(profileCount) > 90.d0 .and. (latitudes(profileCount)-90.d0) < 1.d-5) latitudes(profileCount) = 90.d0
2547        if (latitudes(profileCount) < -90.d0 .and. (-latitudes(profileCount)-90.d0) < 1.d-5) latitudes(profileCount) = -90.d0
2548        call validateRttovVariable(latitudes(profileCount), 'latitude', obsSpaceData, headerIndex, -90.d0, 90.d0) 
2549        
2550        profiles(tovsIndex) % longitude = obs_headElem_r(obsSpaceData,OBS_LON,headerIndex) * MPC_DEGREES_PER_RADIAN_R8
2551
2552        surfTypeIsWater(profileCount) = ( tvs_ChangedStypValue(obsSpaceData,headerIndex) == surftype_sea )
2553
2554        do levelIndex = 1, nlv_T
2555          pressure(levelIndex,profileCount) = col_getPressure(columnTrl,levelIndex,headerIndex,'TH') * MPC_MBAR_PER_PA_R8
2556          if ((runObsOperatorWithClw .and. surfTypeIsWater(profileCount)) .or. &
2557              (runObsOperatorWithHydrometeors .and. surfTypeIsWater(profileCount))) then
2558
2559            ! cloud liquid water content
2560            clw(levelIndex,profileCount) = col_getElem(columnTrl,levelIndex,headerIndex,'LWCR')
2561            if (clw(levelIndex,profileCount) < qlim_getMinValueCloud('LWCR') .or. &
2562                clw(levelIndex,profileCount) > qlim_getMaxValueCloud('LWCR')) then
2563              write(*,*) 'tvs_fillProfiles: clw=' , clw(:,profileCount) 
2564              call utl_abort('tvs_fillProfiles: columnTrl has clw outside RTTOV bounds')
2565            end if
2566
2567            clw(levelIndex,profileCount) = clw(levelIndex,profileCount) * tvs_cloudScaleFactor
2568          end if
2569          if (runObsOperatorWithHydrometeors .and. surfTypeIsWater(profileCount)) then
2570            ! cloud ice water content
2571            ciw(levelIndex,profileCount) = col_getElem(columnTrl,levelIndex,headerIndex,'IWCR')
2572            if (ciw(levelIndex,profileCount) < qlim_getMinValueCloud('IWCR') .or. &
2573                ciw(levelIndex,profileCount) > qlim_getMaxValueCloud('IWCR')) then
2574              write(*,*) 'tvs_fillProfiles: ciw=' , ciw(:,profileCount) 
2575              call utl_abort('tvs_fillProfiles: columnTrl has ciw outside RTTOV bounds')
2576            end if
2577
2578            ! rain flux (zero, if not part of control variables)
2579            if (col_varExist(columnTrl,'RF')) then
2580              rainFlux(levelIndex,profileCount) = col_getElem(columnTrl,levelIndex,headerIndex,'RF')
2581            end if
2582            if (rainFlux(levelIndex,profileCount) < qlim_getMinValueCloud('RF') .or. &
2583                rainFlux(levelIndex,profileCount) > qlim_getMaxValueCloud('RF')) then
2584              write(*,*) 'tvs_fillProfiles: rainFlux=' , rainFlux(:,profileCount) 
2585              call utl_abort('tvs_fillProfiles: columnTrl has rain flux outside RTTOV bounds')
2586            end if
2587
2588            ! snow flux (zero, if not part of control variables)
2589            if (col_varExist(columnTrl,'SF')) then
2590              snowFlux(levelIndex,profileCount) = col_getElem(columnTrl,levelIndex,headerIndex,'SF')
2591            end if
2592            if (snowFlux(levelIndex,profileCount) < qlim_getMinValueCloud('SF') .or. &
2593                snowFlux(levelIndex,profileCount) > qlim_getMaxValueCloud('SF')) then
2594              write(*,*) 'tvs_fillProfiles: snowFlux=' , snowFlux(:,profileCount) 
2595              call utl_abort('tvs_fillProfiles: columnTrl has snow flux outside RTTOV bounds')
2596            end if
2597
2598            ! cloud fraction (zero, if not part of control variables)
2599            if (col_varExist(columnTrl,'CLDR')) then
2600              cloudFraction(levelIndex,profileCount) = col_getElem(columnTrl,levelIndex,headerIndex,'CLDR')
2601            end if
2602            if (cloudFraction(levelIndex,profileCount) < qlim_getMinValueCloud('CLDR') .or. &
2603                cloudFraction(levelIndex,profileCount) > qlim_getMaxValueCloud('CLDR')) then
2604              write(*,*) 'tvs_fillProfiles: cloudFraction=' , cloudFraction(:,profileCount) 
2605              call utl_abort('tvs_fillProfiles: columnTrl has cloud fraction outside RTTOV bounds')
2606            end if
2607
2608            ciw(levelIndex,profileCount) = ciw(levelIndex,profileCount) * tvs_cloudScaleFactor
2609            rainFlux(levelIndex,profileCount) = rainFlux(levelIndex,profileCount) * tvs_cloudScaleFactor
2610            snowFlux(levelIndex,profileCount) = snowFlux(levelIndex,profileCount) * tvs_cloudScaleFactor
2611
2612          end if ! runObsOperatorWithHydrometeors .and. surfTypeIsWater
2613        end do ! levelIndex
2614        
2615        if (tvs_coefs(sensorIndex) %coef % nozone > 0 .and. .not. tvs_useO3Climatology) then
2616          column_ptr => col_getColumn(columnTrl, headerIndex, trim(ozoneVarName) )
2617          ! Conversion from microgram/km to ppmv (to have the same units as climatology when tvs_useO3Climatology is .true.
2618          ! Conversion to kg/kg for use by RTTOV in done later
2619          ozone(:,profileCount) = column_ptr(:) * 1.0D-9 * o3Mixratio2ppmv
2620        end if
2621
2622      end do bobs2
2623
2624      !    2.5  Get ozone profiles (ppmv) from climatology if necessary
2625      if (tvs_coefs(sensorIndex) %coef % nozone > 0 .and. tvs_useO3Climatology) then
2626        call ozo_get_profile (ozone, latitudes, pressure, nlv_T, profileCount)
2627      end if
2628
2629      !   2.5  Fill profiles structure
2630
2631      do  profileIndex = 1 , profileCount 
2632        tovsIndex = sensorTovsIndexes(profileIndex)
2633        headerIndex = sensorHeaderIndexes(profileIndex)
2634        profiles(tovsIndex) % gas_units       = gas_unit_specconc ! all gas profiles are supposed to be provided in kg/kg (specific humidity, i.e. mass mixing ratio [kg/kg] over wet air)
2635        profiles(tovsIndex) % id              = '' ! profile id, up to 128 characters, to consider for use
2636        profiles(tovsIndex) % nlevels         = nlv_T
2637        profiles(tovsIndex) % nlayers         = nlv_T - 1
2638        profiles(tovsIndex) % date(1)         = year
2639        profiles(tovsIndex) % date(2)         = month
2640        profiles(tovsIndex) % date(3)         = day
2641        profiles(tovsIndex) % latitude        = latitudes(profileIndex)
2642        profiles(tovsIndex) % elevation       = 0.001d0 * col_getHeight(columnTrl,ilowlvl_T,headerIndex,'TH') ! unite km
2643        call validateRttovVariable(profiles(tovsIndex) % elevation, "elevation", obsSpaceData, headerIndex, maximum_opt=elevmax)
2644        profiles(tovsIndex) % skin % watertype = watertype_ocean_water !utilise pour calcul rayonnement solaire reflechi seulement
2645        profiles(tovsIndex) % skin % t         = col_getElem(columnTrl,1,headerIndex,'TG')
2646        call validateRttovVariable( profiles(tovsIndex) % skin % t, "skin temperature", obsSpaceData, headerIndex, tmin, tmax) 
2647        profiles(tovsIndex) % skin % salinity  = 35.d0 ! for FASTEM-4 only to revise (practical salinity units)
2648        profiles(tovsIndex) % skin % fastem(:) = 0.0d0
2649        profiles(tovsIndex) % skin % snow_fraction  = 0.d0 ! Surface coverage snow fraction(0-1), used only by IR emissivity atlas
2650        profiles(tovsIndex) % skin % soil_moisture  = 0.d0 ! soil moisure (m**3/m**3) not yet used
2651        profiles(tovsIndex) % s2m % t          = col_getElem(columnTrl,ilowlvl_T,headerIndex,'TT')
2652        call validateRttovVariable(profiles(tovsIndex) % s2m % t, '2m air temperature', &
2653            obsSpaceData, headerIndex, tmin, tmax) 
2654        profiles(tovsIndex) % s2m % p         = col_getElem(columnTrl,1      ,headerIndex,'P0')*MPC_MBAR_PER_PA_R8
2655        call validateRttovVariable(profiles(tovsIndex) % s2m % p, 'surface pressure', &
2656            obsSpaceData, headerIndex, pmin, pmax) 
2657        profiles(tovsIndex) % s2m % u         = col_getElem(columnTrl,ilowlvl_M,headerIndex,'UU')
2658        profiles(tovsIndex) % s2m % v         = col_getElem(columnTrl,ilowlvl_M,headerIndex,'VV')
2659        wind = sqrt( profiles(tovsIndex) % s2m % u ** 2 + &
2660            profiles(tovsIndex) % s2m % v ** 2 )
2661        if ( wind > wmax ) then
2662          write(*,*) 'tvs_fillProfiles: !!! WARNING !!!'
2663          write(*,*) 'tvs_fillProfiles: INVALID 10m wind speed'
2664          write(*,*) 'tvs_fillProfiles: headerIndex ', headerIndex, " !"
2665          write(*,*) 'tvs_fillProfiles: modulus ', wind, ' larger than ', wmax, 'set to zero !'
2666          profiles(tovsIndex) % s2m % u = 0.d0
2667          profiles(tovsIndex) % s2m % v = 0.d0
2668          call rejectObs(obsSpaceData, headerIndex)
2669        end if
2670        profiles(tovsIndex) % s2m % o         = 0.0d0 !surface ozone never used
2671        profiles(tovsIndex) % s2m % wfetc     = 100000.0d0 ! Wind fetch (in meter for rttov10 ?) used to calculate reflection of solar radiation by sea surface
2672        profiles(tovsIndex) % icede_param     = 0
2673        profiles(tovsIndex) % Be              = 0.4d0 ! earth magnetic field strength (gauss) (must be non zero)
2674        profiles(tovsIndex) % cosbk           = 0.0d0 ! cosine of the angle between the earth magnetic field and wave propagation direction
2675        profiles(tovsIndex) % p(:)            = pressure(:,profileIndex)
2676        call validateRttovVariable(profiles(tovsIndex) % p(nlv_T), "pressure profile near surface", obsSpaceData, headerIndex, maximum_opt=2000.d0)
2677        call validateRttovVariable(profiles(tovsIndex) % p(1), "pressure profile near top", obsSpaceData, headerIndex, 0.d0) 
2678        !RTTOV scatt needs half pressure levels (see figure 5 of RTTOV 12 User's Guide)
2679        if (runObsOperatorWithHydrometeors) then
2680          cld_profiles(tovsIndex) % ph (1) = 0.d0
2681          cld_profiles(tovsIndex) % cfrac = 0.d0
2682          do levelIndex = 1, nlv_T - 1
2683            cld_profiles(tovsIndex) % ph (levelIndex+1) = 0.5d0 * (profiles(tovsIndex) % p(levelIndex) + &
2684                                                                   profiles(tovsIndex) % p(levelIndex+1))
2685          end do
2686          cld_profiles(tovsIndex) % ph (nlv_T+1) = profiles(tovsIndex) % s2m % p
2687        end if
2688        column_ptr => col_getColumn(columnTrl, headerIndex,'TT' )
2689        profiles(tovsIndex) % t(:)   = column_ptr(:)
2690        call validateRttovProfile(profiles(tovsIndex) % t, 'temparature', tmin, tmax, obsSpaceData, headerIndex) 
2691        if (tvs_coefs(sensorIndex) %coef %nozone > 0) then
2692          profiles(tovsIndex) % o3(:) = ozone(:,profileIndex) * o3ppmv2Mixratio ! Climatology output is ppmv over dry air                                                                                                            ! because atmosphere is very dry where there is significant absorption by ozone)
2693          if (.not. tvs_useO3Climatology)  then
2694            profiles(tovsIndex) % s2m % o  = col_getElem(columnTrl,ilowlvl_T,headerIndex,trim(ozoneVarName)) * 1.0d-9 ! Assumes model ozone in ug/kg
2695          end if
2696          call validateRttovProfile(profiles(tovsIndex) % o3, 'ozone', o3min, o3max, obsSpaceData, headerIndex)
2697        end if
2698
2699        column_ptr => col_getColumn(columnTrl, headerIndex,'HU' )
2700        profiles(tovsIndex) % q(:)            =  column_ptr(:)
2701        call validateRttovProfile(profiles(tovsIndex) % q, 'water vapor', qmin, qmax, obsSpaceData, headerIndex)
2702        profiles(tovsIndex) % ctp = 1013.25d0
2703        profiles(tovsIndex) % cfraction = 0.d0
2704        if (runObsOperatorWithClw) then
2705          profiles(tovsIndex) % clw(:) = clw(:,profileIndex)
2706        else if (runObsOperatorWithHydrometeors) then
2707          cld_profiles(tovsIndex) % hydro(:,1) = rainFlux(:,profileIndex)
2708          cld_profiles(tovsIndex) % hydro(:,2) = snowFlux(:,profileIndex)
2709          cld_profiles(tovsIndex) % hydro(:,4) = clw(:,profileIndex)
2710          cld_profiles(tovsIndex) % hydro(:,5) = ciw(:,profileIndex)
2711
2712          do levelIndex = 1, nlv_T
2713            if (cld_profiles(tovsIndex) % hydro(levelIndex,1) > qlim_getMinValueCloud('RF') .or. &
2714                cld_profiles(tovsIndex) % hydro(levelIndex,2) > qlim_getMinValueCloud('SF') .or. &
2715                cld_profiles(tovsIndex) % hydro(levelIndex,4) > qlim_getMinValueCloud('LWCR') .or. &
2716                cld_profiles(tovsIndex) % hydro(levelIndex,5) > qlim_getMinValueCloud('IWCR')) then
2717              
2718              ! set to overcast cloud, if CLDR not part of control variables
2719              if (col_varExist(columnTrl,'CLDR')) then
2720                cld_profiles(tovsIndex) % hydro_frac(levelIndex,1) = cloudFraction(levelIndex,profileIndex)
2721              else
2722                cld_profiles(tovsIndex) % hydro_frac(levelIndex,1) = 1.0d0
2723              end if
2724            else
2725              cld_profiles(tovsIndex) % hydro_frac(levelIndex,1) = qlim_getMinValueCloud('CLDR')  
2726            end if
2727
2728          end do ! levelIndex
2729        end if  ! runObsOperatorWithClw
2730      end do ! profileIndex
2731
2732      deallocate (pressure,            stat = allocStatus(2))
2733      deallocate (ozone,               stat = allocStatus(3))
2734      deallocate (latitudes,           stat = allocStatus(4))
2735      deallocate (sensorHeaderIndexes, stat = allocStatus(5))
2736      deallocate (sensorTovsIndexes,   stat = allocStatus(6))
2737      if (tvs_coefs(sensorIndex) %coef %nozone > 0 .and. .not.tvs_useO3Climatology) then
2738        deallocate (ozone,             stat = allocStatus(7))
2739      end if
2740      if ( allocated(clw) ) then
2741        deallocate (clw,      stat= allocStatus(8))
2742      end if
2743      if ( allocated(ciw) ) then
2744        deallocate (ciw,      stat= allocStatus(9))
2745        deallocate (rainFlux, stat= allocStatus(10))
2746        deallocate (snowFlux, stat= allocStatus(11))
2747        deallocate (cloudFraction, stat= allocStatus(12))
2748      end if
2749      deallocate (surfTypeIsWater,stat= allocStatus(13))
2750
2751      call utl_checkAllocationStatus(allocStatus, ' tvs_fillProfiles', .false.)
2752     
2753    end do sensor_loop
2754
2755  end subroutine tvs_fillProfiles
2756
2757  !--------------------------------------------------------------------------
2758  !  tvs_getCorrectedSatelliteAzimuth
2759  !--------------------------------------------------------------------------
2760  function tvs_getCorrectedSatelliteAzimuth(obsSpaceData, headerIndex) result(correctedAzimuth)
2761    !
2762    !:Purpose: get properly corrected satellite Azimuth Angle from obsSpaceData header
2763    !
2764    implicit none
2765
2766    ! Arguments:
2767    type(struct_obs), intent(in) :: obsSpaceData     ! obsSpaceData structure
2768    integer,          intent(in) :: headerIndex      ! location in header
2769    ! Result:
2770    real(8)                      :: correctedAzimuth ! corrected azimuth (function result)
2771
2772    ! Locals:
2773    integer :: sensorNo, tovsIndex
2774
2775    correctedAzimuth = obs_headElem_r(obsSpaceData,OBS_AZA,headerIndex)
2776
2777    tovsIndex = tvs_tovsIndex (headerIndex)
2778    if ( tovsIndex < 0) return
2779
2780    sensorNo  = tvs_lsensor(tovsIndex)
2781
2782    if ( .not. tvs_isAzimuthValid(sensorNo) ) then
2783      correctedAzimuth = obs_missingValue_R
2784      return
2785    end if
2786
2787    if ( tvs_doAzimuthCorrection(sensorNo) ) then
2788      ! Correction sur la definition de l'angle.
2789      correctedAzimuth = obs_headElem_r(obsSpaceData,OBS_SAZ,headerIndex) + correctedAzimuth
2790      if ( correctedAzimuth > 360.d0 ) correctedAzimuth = correctedAzimuth - 360.d0
2791    end if
2792
2793  end function tvs_getCorrectedSatelliteAzimuth
2794
2795
2796  !--------------------------------------------------------------------------
2797  !  tvs_rttov
2798  !--------------------------------------------------------------------------
2799  subroutine tvs_rttov(obsSpaceData, bgckMode, beSilent)
2800    !
2801    !:Purpose: Interface for RTTOV non linear operator
2802    !           tvs_fillProfiles should be called before
2803    !
2804    implicit none
2805
2806    ! Arguments:
2807    type(struct_obs), intent(inout) :: obsSpaceData  ! obsSpaceData structure
2808    logical,          intent(in)    :: bgckMode      ! flag to transfer transmittances and cloudy overcast radiances in bgck mode 
2809    logical,          intent(in)    :: beSilent      ! flag to control verbosity
2810
2811    ! Locals:
2812    integer :: nlv_T
2813    integer :: btCount
2814    integer :: allocStatus(4)
2815    integer :: rttov_err_stat ! rttov error return code
2816    integer, external :: omp_get_num_threads
2817    integer :: nthreads,max_nthreads
2818    integer :: sensorId, tovsIndex
2819    integer :: channelIndex, channelIndexFound, channelNumber
2820    integer :: profileCount
2821    integer :: profileIndex, levelIndex, jj, btIndex
2822    integer :: instrum
2823    integer :: sensorType        ! sensor type (1=infrared; 2=microwave; 3=high resolution,4=polarimetric)
2824    integer, allocatable:: sensorTovsIndexes(:)
2825    type (rttov_emissivity), pointer :: emissivity_local(:)    ! emissivity structure with input and output
2826    type (rttov_chanprof), pointer :: chanprof(:)
2827    type (rttov_chanprof), allocatable :: chanprof1(:)
2828    type (rttov_radiance) :: radiancedata_d, radiancedata_d1
2829    type (rttov_transmission) :: transmission, transmission1
2830    integer              :: asw
2831    logical, pointer :: calcemis(:)
2832    real(8), allocatable  :: surfem1(:)
2833    integer, allocatable  :: frequencies(:)
2834    real(8), allocatable  :: uOfWLandWSurfaceEmissivity(:)
2835    logical, allocatable  :: lchannel_subset(:,:)
2836    integer               :: profileIndex2, tb1, tb2
2837    integer :: istart, iend, bodyIndex, headerIndex
2838    real(8) :: clearMwRadiance
2839    logical :: ifBodyIndexFound
2840    logical :: runObsOperatorWithClw
2841    logical :: runObsOperatorWithHydrometeors
2842
2843    if ( .not. beSilent ) write(*,*) 'tvs_rttov: Starting'
2844    if ( .not. beSilent ) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
2845
2846    if (tvs_nobtov == 0) return                  ! exit if there are not tovs data
2847
2848    !   1.  Get number of threads available and allocate memory for some variables
2849    !$omp parallel
2850    max_nthreads = omp_get_num_threads()
2851    !$omp end parallel
2852    allocStatus(:) = 0
2853    allocate(sensorTovsIndexes(tvs_nobtov),stat=allocStatus(1))
2854    call utl_checkAllocationStatus(allocStatus(1:1), ' tvs_rttov sensorTovsIndexes')
2855    
2856    
2857    !   1.1   Read surface information
2858    if ( bgckMode ) call EMIS_READ_CLIMATOLOGY
2859
2860    !   2.  Computation of hx for tovs data only
2861
2862    ! Loop over all sensors specified by user
2863    sensor_loop:do sensorId = 1, tvs_nsensors
2864   
2865      sensorType = tvs_coefs(sensorId) % coef % id_sensor
2866      instrum = tvs_coefs(sensorId) % coef % id_inst
2867
2868      runObsOperatorWithClw = (tvs_numMWInstrumUsingCLW /= 0 .and. &
2869                               tvs_isInstrumUsingCLW(tvs_instruments(sensorId)))
2870      runObsOperatorWithHydrometeors = (tvs_numMWInstrumUsingHydrometeors /= 0 .and. &
2871                                        tvs_isInstrumUsingHydrometeors(tvs_instruments(sensorId)))
2872                                        
2873      if (runObsOperatorWithClw .and. runObsOperatorWithHydrometeors) then
2874        call utl_abort('tvs_rttov: this instrument is mentioned in using CLW and hydrometeors.')
2875      end if
2876    
2877      !  loop over all obs.
2878      profileCount = 0
2879      obs_loop: do tovsIndex = 1, tvs_nobtov
2880        
2881        !    Currently processed sensor?
2882        if ( tvs_lsensor(tovsIndex) == sensorId ) then
2883          profileCount = profileCount + 1
2884          sensorTovsIndexes(profileCount) = tovsIndex
2885          nlv_T = tvs_profiles_nl(tovsIndex) % nlevels
2886        end if
2887      end do obs_loop
2888      
2889      if (profileCount == 0) cycle sensor_loop
2890      
2891      !    2.1  Calculate the actual number of threads which will be used.
2892      
2893      nthreads = min(max_nthreads, profileCount )  
2894      
2895      !    2.2  Prepare all input variables required by rttov.
2896      
2897      if ( bgckMode .and. tvs_isInstrumHyperSpectral(instrum) ) then
2898        btCount = profileCount * tvs_nchan(sensorId)
2899      else
2900        btCount = tvs_countRadiances(sensorTovsIndexes(1:profileCount), obsSpaceData)
2901      end if
2902      
2903      if (allocated(tvs_bodyIndexFromBtIndex)) deallocate(tvs_bodyIndexFromBtIndex)
2904      allocate(tvs_bodyIndexFromBtIndex(btCount))
2905
2906      if ( btCount == 0 ) cycle sensor_loop
2907      tvs_bodyIndexFromBtIndex(:) = -1      
2908      allocate ( surfem1          (btCount) ,stat=allocStatus(1))
2909
2910      asw = 1 ! Allocation
2911      call rttov_alloc_direct(            &
2912              allocStatus(2),             &
2913              asw,                        &
2914              nprofiles=profileCount,     & ! (not used)
2915              nchanprof=btCount,          &
2916              nlevels=nlv_T,              &
2917              chanprof=chanprof,          &
2918              opts=tvs_opts(sensorId),    &
2919              coefs=tvs_coefs(sensorId),  &
2920              transmission=transmission,  &
2921              radiance=radiancedata_d,    &
2922              calcemis=calcemis,          &
2923              emissivity=emissivity_local,&
2924              init=.true.)
2925
2926      if (runObsOperatorWithHydrometeors) then
2927        allocate ( frequencies(btCount), stat=allocStatus(3))
2928      end if
2929
2930      if (useUofWIREmiss) then
2931        allocate ( uOfWLandWSurfaceEmissivity(btCount), stat=allocStatus(4) )
2932      end if
2933      call utl_checkAllocationStatus(allocStatus, ' tvs_rttov')
2934      
2935      !     get Hyperspectral IR emissivities
2936      if ( tvs_isInstrumHyperSpectral(instrum) ) then
2937        surfem1(:) = 0.
2938        if ( bgckMode ) then
2939          call emis_getIrEmissivity (surfem1,tvs_nchan(sensorId),sensorId,profileCount,btCount,sensorTovsIndexes)
2940        else
2941          call tvs_getHIREmissivities(sensorTovsIndexes(1:profileCount), obsSpaceData, surfem1)
2942        end if
2943      end if
2944      
2945      if ( bgckMode .and. tvs_isInstrumHyperSpectral(instrum) ) then
2946        btIndex = 0
2947        do profileIndex = 1 , profileCount
2948          do  channelIndex = 1,tvs_nchan(sensorId)
2949            btIndex = btIndex + 1
2950            chanprof(btIndex)%prof = profileIndex
2951            chanprof(btIndex)%chan = channelIndex
2952          end do
2953        end do
2954        
2955        do profileIndex = 1, profileCount
2956          headerIndex = tvs_headerIndex(sensorTovsIndexes(profileIndex))
2957          if (headerIndex > 0) then
2958            istart = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2959            iend = obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex) + istart - 1
2960            do bodyIndex = istart, iend
2961              call tvs_getChannelNumIndexFromPPP( obsSpaceData, headerIndex, bodyIndex, &
2962                  channelNumber, channelIndex )
2963              if (channelIndex > 0) then
2964                tvs_bodyIndexFromBtIndex((profileIndex-1)*tvs_nchan(sensorId)+channelIndex) = bodyIndex
2965              else
2966                write(*,*) 'tvs_rttov: strange channel number',channelNumber
2967              end if
2968            end do
2969          end if
2970        end do
2971        
2972      else
2973        allocate( lchannel_subset(profileCount,tvs_nchan(sensorId)) )
2974        call tvs_getChanprof(sensorTovsIndexes(1:profileCount), obsSpaceData, chanprof, lchannel_subset_opt = lchannel_subset, iptobs_cma_opt = tvs_bodyIndexFromBtIndex)
2975        if (runObsOperatorWithHydrometeors) then
2976          call rttov_scatt_setupindex (  &
2977               rttov_err_stat,           &
2978               profileCount,             &  ! number of profiles
2979               tvs_nchan(sensorId),      &  ! number of channels 
2980               tvs_coefs(sensorId),      &  ! coef structure read in from rttov coef file
2981               tvs_coef_scatt(sensorId), &  ! 
2982               btcount,                  &  ! number of calculated channels
2983               chanprof,                 &  ! channels and profile numbers
2984               frequencies,              &  ! array, frequency number for each channel
2985               lchannel_subset )            ! OPTIONAL array of logical flags to indicate a subset of channels
2986        end if
2987        deallocate( lchannel_subset )
2988      end if
2989                 
2990      call tvs_getOtherEmissivities(chanprof, sensorTovsIndexes, sensorType, instrum, surfem1, calcemis)
2991      
2992      if (useUofWIREmiss .and. tvs_isInstrumHyperSpectral(instrum) .and. bgckMode) then
2993        if (.not. allocated (tvs_atlas)) allocate(tvs_atlas(tvs_nsensors))
2994        if ( .not. tvs_atlas(sensorId)%init) then
2995          call rttov_setup_emis_atlas( rttov_err_stat,  &! out
2996               tvs_opts(sensorId),                      &! in
2997               tvs_profiles_nl(1)%date(2) ,             &! in
2998               atlas_type_ir,                           &! in
2999               tvs_atlas(sensorId),                     &! in
3000               ir_atlas_ang_corr = .false.,             &! in
3001               ir_atlas_read_std = .false.,             &! in
3002               coefs = tvs_coefs(sensorId)  )
3003          if (rttov_err_stat/=0) then
3004            write(*,*) 'Error in rttov_atlas_setup IR',rttov_err_stat
3005            call utl_abort('tvs_rttov')
3006          end if
3007        end if
3008          
3009        call rttov_get_emis( rttov_err_stat,                  & ! out
3010             tvs_opts(sensorId),                              & ! in
3011             chanprof(1:btCount),                             & ! in
3012             tvs_profiles_nl(sensorTovsIndexes(1:profileCount)), & ! in
3013             tvs_coefs(sensorId),                             & ! in
3014             tvs_atlas(sensorId),                             & ! inout
3015             uOfWLandWSurfaceEmissivity(1:btCount) )            ! out
3016
3017        if (rttov_err_stat /= 0) then
3018          write(*,*) 'Error in rttov_get_emis IR', rttov_err_stat
3019          call utl_abort('tvs_rttov')
3020        end if
3021              
3022        do profileIndex=1, profileCount !loop on profiles
3023          jj = sensorTovsIndexes(profileIndex)
3024          do btIndex=1, btCount !loop on channels
3025            if (chanprof(btIndex)%prof==profileIndex) then
3026              ! surftype: 0 land, 1 sea, 2 sea-ice
3027              ! this logic is primitive and could be improved for example using
3028              ! additional criteria based on emissivity_std and emissivity_flg
3029              !Definition of emis_flag:
3030              ! emis_flag:Flag_0 = '0 = sea, no MOD11 data' ;
3031              ! emis_flag:Flag_1 = '1 = land where BF method was applied' ;
3032              ! emis_flag:Flag_2 = '2 = land where data was filled with average (original UWiremis bfemis_flag=2 or 3 or 4' ;
3033              ! emis_flag:Flag_3 = '3 = contains inland water or coastline by the sea/land mask where the BF method was used' ;
3034              ! emis_flag:Flag_4 = '4 = contains inland water or coastline by the sea/land mask where data was filled with average original UWiremis bfemis_flag=2 or 3 or 4' ;
3035              ! emis_flag:Flag_5 = '5 = contains coastline by land fraction where the BF method was used' ;
3036              ! emis_flag:Flag_6 = '6 = contains coastline by land fraction where data was filled with average (original UWiremis bfemis_flag=2 or 3 or 4' ;
3037              ! other information that could be useful for quality control can be found in the in the profile_qc structure
3038              ! Now we have the 'traditionnal' emissivity in surfem1(:)
3039              ! and University of Wisconsin emissivity in uOfWLandWSurfaceEmissivity(:)
3040              if (tvs_profiles_nl(jj)% skin % surftype == surftype_land .and. &
3041                   uOfWLandWSurfaceEmissivity(btIndex) > 0.5 ) then
3042                emissivity_local(btIndex)%emis_in = uOfWLandWSurfaceEmissivity(btIndex)
3043              else
3044                emissivity_local(btIndex)%emis_in = surfem1(btIndex)
3045              end if
3046            end if
3047          end do
3048        end do
3049
3050      else if (sensorType == sensor_id_mw) then
3051        call tvs_getMWemissivityFromAtlas(surfem1(1:btcount), emissivity_local, sensorId, chanprof, &
3052             sensorTovsIndexes(1:profileCount))
3053      else
3054        emissivity_local(:)%emis_in = surfem1(:)
3055      end if
3056
3057      !   2.3  Compute radiance with rttov_direct
3058
3059      rttov_err_stat = 0 
3060
3061      if( bgckMode .and. tvs_isInstrumHyperSpectral(instrum) ) then
3062        write(*,*) 'for bgck IR: call rttov_parallel_direct for each profile...'
3063
3064        asw = 1 ! 1 to allocate,0 to deallocate
3065        ! allocate transmitance structure for 1 profile
3066        call rttov_alloc_transmission(allocStatus(1), transmission1, nlevels=nlv_T, &
3067             nchanprof=tvs_nchan(sensorId), asw=asw, init=.true.)
3068        ! allocate radiance structure for 1 profile
3069        call rttov_alloc_rad (allocStatus(2),tvs_nchan(sensorId), radiancedata_d1,nlv_T,asw,init=.true.)
3070        ! allocate chanprof for 1 profile
3071        allocate(chanprof1(tvs_nchan(sensorId)))
3072        do  channelIndex = 1,tvs_nchan(sensorId)
3073          chanprof1(channelIndex)%prof = 1
3074          chanprof1(channelIndex)%chan = channelIndex
3075        end do
3076
3077        do profileIndex2 = 1, profileCount
3078          tb1 = 1 + (profileIndex2-1) * tvs_nchan(sensorId) 
3079          tb2 = profileIndex2 * tvs_nchan(sensorId)
3080
3081          call rttov_parallel_direct(                                                              &
3082               rttov_err_stat,                                                                     & ! out
3083               chanprof1,                                                                          & ! in
3084               tvs_opts(sensorId),                                                                 & ! in
3085               tvs_profiles_nl(sensorTovsIndexes(profileIndex2):sensorTovsIndexes(profileIndex2)), & ! in
3086               tvs_coefs(sensorId),                                                                & ! in
3087               transmission1,                                                                      & ! inout
3088               radiancedata_d1,                                                                    & ! inout
3089               calcemis=calcemis(tb1:tb2),                                                         & ! in
3090               emissivity=emissivity_local(tb1:tb2),                                               & ! inout
3091               nthreads=nthreads )   
3092
3093          ! copy contents of single profile structures into complete structures
3094          transmission%tau_total(tb1:tb2)             = transmission1%tau_total(:)
3095          transmission%tau_levels(:,tb1:tb2)          = transmission1%tau_levels(:,:)
3096          transmission%tausun_levels_path1(:,tb1:tb2) = transmission1%tausun_levels_path1(:,:)
3097          transmission%tausun_levels_path2(:,tb1:tb2) = transmission1%tausun_levels_path2(:,:)
3098          transmission%tausun_total_path1(tb1:tb2)    = transmission1%tausun_total_path1(:)
3099          transmission%tausun_total_path2(tb1:tb2)    = transmission1%tausun_total_path2(:)
3100          radiancedata_d%clear(tb1:tb2)      = radiancedata_d1%clear(:)
3101          radiancedata_d%total(tb1:tb2)      = radiancedata_d1%total(:)
3102          radiancedata_d%bt_clear(tb1:tb2)   = radiancedata_d1%bt_clear(:)
3103          radiancedata_d%bt(tb1:tb2)         = radiancedata_d1%bt(:)
3104          radiancedata_d%refl_clear(tb1:tb2) = radiancedata_d1%refl_clear(:)
3105          radiancedata_d%refl(tb1:tb2)       = radiancedata_d1%refl(:)
3106          radiancedata_d%overcast(:,tb1:tb2) = radiancedata_d1%overcast(:,:)
3107          radiancedata_d%cloudy(tb1:tb2)     = radiancedata_d1%cloudy(:)
3108
3109        end do
3110
3111        ! transmittance deallocation for 1 profile
3112        deallocate(chanprof1)
3113        asw = 0 ! 1 to allocate,0 to deallocate
3114        ! transmittance deallocation for 1 profile
3115        call rttov_alloc_transmission(allocStatus(1),transmission1,nlevels=nlv_T,  &
3116             nchanprof=tvs_nchan(sensorId), asw=asw )
3117        ! radiance deallocation for 1 profile
3118        call rttov_alloc_rad (allocStatus(2), tvs_nchan(sensorId), radiancedata_d1, nlv_T, asw)
3119
3120      else
3121
3122        ! run clear-sky RTTOV, save the radiances in OBS_BTCL of obsSpaceData 
3123        if ((runObsOperatorWithClw .or. runObsOperatorWithHydrometeors) .and. &
3124            obs_columnActive_RB(obsSpaceData, OBS_BTCL)) then
3125
3126          ! run rttovScatt
3127          if (runObsOperatorWithHydrometeors) then
3128            ! set the cloud profile in tvs_cld_profiles_nl to zero
3129            call updateCloudInTovsCloudProfile(sensorTovsIndexes(1:profileCount), &
3130                                          nlv_T,                      &
3131                                          mode='save',                &
3132                                          beSilent=.true.)
3133            call rttov_scatt(                                         &
3134                 rttov_err_stat,                                      &! out
3135                 tvs_opts_scatt(sensorId),                            &! in
3136                 nlv_T,                                               &! in
3137                 chanprof,                                            &! in
3138                 frequencies,                                         &! in
3139                 tvs_profiles_nl(sensorTovsIndexes(1:profileCount)),  &! in
3140                 tvs_cld_profiles_nl(sensorTovsIndexes(1:profileCount)), &! in
3141                 tvs_coefs(sensorId),                                 &! in
3142                 tvs_coef_scatt(sensorId),                            &! in
3143                 calcemis,                                            &! in
3144                 emissivity_local,                                    &! inout
3145                 radiancedata_d) 
3146          else
3147            ! set the cloud profile in tvs_profiles_nl to zero
3148            call updateCloudInTovsProfile(sensorTovsIndexes(1:profileCount), &
3149                                          nlv_T,                      &
3150                                          mode='save',                &
3151                                          beSilent=.true.)
3152            call rttov_parallel_direct(                               &
3153                 rttov_err_stat,                                      & ! out
3154                 chanprof,                                            & ! in
3155                 tvs_opts(sensorId),                                  & ! in
3156                 tvs_profiles_nl(sensorTovsIndexes(1:profileCount)),  & ! in
3157                 tvs_coefs(sensorId),                                 & ! in
3158                 transmission,                                        & ! inout
3159                 radiancedata_d,                                      & ! inout
3160                 calcemis=calcemis,                                   & ! in
3161                 emissivity=emissivity_local,                         & ! inout
3162                 nthreads=nthreads      )   
3163          end if ! run rttovScatt
3164
3165          ! save in obsSpaceData
3166          loopClearSky1: do btIndex = 1, btCount
3167            profileIndex = chanprof(btIndex)%prof
3168            channelIndex = chanprof(btIndex)%chan
3169            tovsIndex = sensorTovsIndexes(profileIndex)
3170
3171            clearMwRadiance = radiancedata_d % bt(btIndex)
3172
3173            headerIndex = tvs_headerIndex(tovsIndex)
3174            if ( headerIndex < 1 ) cycle loopClearSky1
3175            istart = obs_headElem_i(obsSpaceData, OBS_RLN, headerIndex)
3176            iend = obs_headElem_i(obsSpaceData, OBS_NLV, headerIndex) + istart - 1
3177
3178            ifBodyIndexFound = .false.
3179            loopClearSky2: do bodyIndex = istart, iend
3180              call tvs_getChannelNumIndexFromPPP( obsSpaceData, headerIndex, bodyIndex, &
3181                                                  channelNumber, channelIndexFound )
3182              if ( channelIndex == channelIndexFound ) then
3183                ifBodyIndexFound = .true.
3184                exit loopClearSky2
3185              end if
3186            end do loopClearSky2
3187
3188            if ( .not. ifBodyIndexFound ) call utl_abort('tvs_rttov: bodyIndex not found.')
3189
3190            if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) == obs_assimilated) then
3191              call obs_bodySet_r(obsSpaceData, OBS_BTCL, bodyIndex, clearMwRadiance)
3192            end if
3193          end do loopClearSky1
3194
3195          ! restore the cloud profiles in ...
3196          if (runObsOperatorWithHydrometeors) then
3197            ! tvs_cld_profiles_nl
3198            call updateCloudInTovsCloudProfile(sensorTovsIndexes(1:profileCount), &
3199                                          nlv_T,                             &
3200                                          mode='restore',                    &
3201                                          beSilent=.true.)
3202          else
3203            ! tvs_profiles_nl
3204            call updateCloudInTovsProfile(sensorTovsIndexes(1:profileCount), &
3205                                          nlv_T,                             &
3206                                          mode='restore',                    &
3207                                          beSilent=.true.)
3208          end if
3209        end if ! run clear-sky RTTOV
3210
3211        if (runObsOperatorWithHydrometeors) then
3212          if (.not. beSilent) write(*,*) 'before rttov_scatt...', sensorID, profileCount
3213          call rttov_scatt(                                         &
3214               rttov_err_stat,                                      &! out
3215               tvs_opts_scatt(sensorId),                            &! in
3216               nlv_T,                                               &! in
3217               chanprof,                                            &! in
3218               frequencies,                                         &! in
3219               tvs_profiles_nl(sensorTovsIndexes(1:profileCount)),  &! in
3220               tvs_cld_profiles_nl(sensorTovsIndexes(1:profileCount)), &! in
3221               tvs_coefs(sensorId),                                 &! in
3222               tvs_coef_scatt(sensorId),                            &! in
3223               calcemis,                                            &! in
3224               emissivity_local,                                    &! inout
3225               radiancedata_d) 
3226          if ( .not. beSilent ) write(*,*) 'after rttov_scatt...'
3227        else
3228          if (.not. beSilent) write(*,*) 'before rttov_parallel_direct...', sensorID, profileCount
3229          
3230          call rttov_parallel_direct(                               &
3231               rttov_err_stat,                                      & ! out
3232               chanprof,                                            & ! in
3233               tvs_opts(sensorId),                                  & ! in
3234               tvs_profiles_nl(sensorTovsIndexes(1:profileCount)),  & ! in
3235               tvs_coefs(sensorId),                                 & ! in
3236               transmission,                                        & ! inout
3237               radiancedata_d,                                      & ! inout
3238               calcemis=calcemis,                                   & ! in
3239               emissivity=emissivity_local,                         & ! inout
3240               nthreads=nthreads      )
3241          if ( .not. beSilent ) write(*,*) 'after rttov_parallel_direct...'
3242          
3243        end if
3244
3245      end if ! if (bgckMode .and. tvs_isInstrumHyperSpectral(instrum))
3246
3247      if ( .not. beSilent ) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'     
3248
3249      if (rttov_err_stat /= 0) then
3250        write(*,*) 'Error in rttov_parallel_direct',rttov_err_stat
3251        call utl_abort('tvs_rttov')
3252      end if
3253                                        
3254      !    2.4  Store hx in the structure tvs_radiance
3255
3256      do btIndex = 1, btCount
3257        profileIndex = chanprof(btIndex)%prof
3258        channelIndex = chanprof(btIndex)%chan
3259        tovsIndex = sensorTovsIndexes(profileIndex)
3260        tvs_radiance(tovsIndex) % bt(channelIndex) = radiancedata_d % bt(btIndex)
3261
3262        if ( bgckMode ) then
3263          if ( .not. associated(tvs_radiance(tovsIndex)  % clear)) then 
3264            allocStatus = 0
3265            allocate( tvs_radiance(tovsIndex)  % clear  ( tvs_nchan(sensorId)  ), stat= allocStatus(1) )
3266            !  allocate overcast black cloud sky radiance output
3267            allocate( tvs_radiance(tovsIndex)  % overcast  (nlv_T - 1, tvs_nchan(sensorId) ), stat=allocStatus(2))
3268            call utl_checkAllocationStatus(allocStatus(1:2), ' tvs_rttov')
3269          end if
3270          tvs_radiance(tovsIndex) % clear(channelIndex) =  &
3271               radiancedata_d %clear(btIndex)
3272          do levelIndex = 1, nlv_T - 1
3273            tvs_radiance(tovsIndex) % overcast(levelIndex,channelIndex) =   &
3274                 radiancedata_d % overcast(levelIndex,btIndex)
3275          end do
3276          if (.not. allocated(tvs_transmission)) call tvs_allocTransmission(nlv_T)
3277        end if
3278
3279        if ( allocated( tvs_transmission) ) then
3280          do levelIndex = 1, nlv_T
3281            tvs_transmission(tovsIndex) % tau_levels(levelIndex,channelIndex) = &
3282                 transmission % tau_levels(levelIndex,btIndex)
3283          end do
3284          
3285          tvs_transmission(tovsIndex) % tau_total(channelIndex) = &
3286               transmission % tau_total(btIndex)
3287        end if
3288
3289        if ( allocated(tvs_emissivity) ) then
3290          tvs_emissivity(channelIndex,tovsIndex) = emissivity_local(btIndex)%emis_out
3291        end if
3292          
3293      end do
3294
3295      ! Append Surface Emissivity into ObsSpaceData
3296      do btIndex = 1, btCount
3297        bodyIndex = tvs_bodyIndexFromBtIndex(btIndex)
3298        if (bodyIndex > 0) call obs_bodySet_r(obsSpaceData, OBS_SEM, bodyIndex, emissivity_local(btIndex)%emis_out)
3299      end do
3300
3301      !    Deallocate memory
3302      asw = 0 ! 0 to deallocate
3303      call rttov_alloc_direct(         &
3304           allocStatus(1),             &
3305           asw,                        &
3306           nprofiles=profileCount,     & ! (not used)
3307           nchanprof=btCount,          &
3308           nlevels=nlv_T,              &
3309           chanprof=chanprof,          &
3310           opts=tvs_opts(sensorId),    &
3311           coefs=tvs_coefs(sensorId),  &
3312           transmission=transmission,  &
3313           radiance=radiancedata_d,    &
3314           calcemis=calcemis,          &
3315           emissivity=emissivity_local,&
3316           init=.true.)
3317
3318 
3319      if (useUofWIREmiss) then
3320        deallocate ( uOfWLandWSurfaceEmissivity  ,stat=allocStatus(2) )
3321      end if
3322      deallocate ( surfem1    ,stat=allocStatus(3) )
3323      if (allocated(frequencies)) deallocate (frequencies, stat=allocStatus(4))
3324      call utl_checkAllocationStatus(allocStatus, ' tvs_rttov', .false.)
3325      
3326    end do sensor_loop
3327    
3328    deallocate(sensorTovsIndexes)
3329
3330  end subroutine tvs_rttov
3331
3332  !--------------------------------------------------------------------------
3333  !  tvs_getMWemissivityFromAtlas
3334  !--------------------------------------------------------------------------
3335  subroutine tvs_getMWemissivityFromAtlas(originalEmissivity, updatedEmissivity, sensorId, chanprof, sensorTovsIndexes)
3336    implicit none
3337
3338    ! Arguments:
3339    real(8),                 intent(in)  :: originalEmissivity(:)
3340    type(rttov_emissivity),  intent(out) :: updatedEmissivity(:)
3341    integer,                 intent(in)  :: sensorId
3342    type(rttov_chanprof),    intent(in)  :: chanprof(:)
3343    integer,                 intent(in)  :: sensorTovsIndexes(:)
3344
3345    ! Locals:
3346    integer :: returnCode
3347    real(8) :: mWAtlasSurfaceEmissivity(size(originalEmissivity))
3348    integer :: btCount, profileCount
3349    integer :: profileIndex, btIndex, sensorIndex
3350    
3351    btCount = size( originalEmissivity )
3352    if (useMWEmissivityAtlas) then
3353
3354      if (.not. allocated (tvs_atlas)) allocate(tvs_atlas(tvs_nsensors))
3355      if ( .not. tvs_atlas(sensorId)%init) then
3356        call rttov_setup_emis_atlas( returnCode, &! out
3357             tvs_opts(sensorId),                 &! in
3358             tvs_profiles_nl(1)%date(2),         &! in
3359             atlas_type_mw,                      &! in
3360             tvs_atlas(sensorId),                &! inout
3361             atlas_id = mWAtlasId,               &! in ! 1 TELSEM2, 2 CNRM
3362             coefs = tvs_coefs(sensorId)  )
3363        if (returnCode /= 0) then
3364          write(*,*) 'Error in rttov_atlas_setup MW',returnCode
3365          call utl_abort('tvs_getMWemissivityFromAtlas')
3366        end if
3367      end if
3368   
3369      call rttov_get_emis( returnCode,            & ! out
3370           tvs_opts(sensorId),                    & ! in
3371           chanprof,                              & ! in
3372           tvs_profiles_nl(sensorTovsIndexes(:)), & ! in
3373           tvs_coefs(sensorId),                   & ! in
3374           tvs_atlas(sensorId),                   & ! in
3375           mWAtlasSurfaceEmissivity)                ! out
3376    
3377      if (returnCode /= 0) then
3378        write(*,*) 'Error in rttov_get_emis MW', returnCode
3379        call utl_abort('tvs_getMWemissivityFromAtlas')
3380      end if
3381
3382      profileCount = size( sensorTovsIndexes )
3383
3384      do profileIndex=1, profileCount !loop on profiles
3385        sensorIndex = sensorTovsIndexes(profileIndex)
3386  
3387        do btIndex=1, btCount !loop on channels
3388          if (chanprof(btIndex)%prof==profileIndex) then
3389            ! Now we have 0.75 in originalEmissivity(:) for land and sea ice
3390            ! and the MW atlas emissivity in mWAtlasSurfaceEmissivity(:)
3391
3392            if ( tvs_profiles_nl(sensorIndex)% skin % surftype == surftype_land .and. &
3393                 mWAtlasSurfaceEmissivity(btIndex) > 0.d0 .and. &
3394                 mWAtlasSurfaceEmissivity(btIndex) <= 1.d0 ) then ! check for missing values
3395              updatedEmissivity(btIndex)%emis_in = mWAtlasSurfaceEmissivity(btIndex)
3396
3397            else
3398              updatedEmissivity(btIndex)%emis_in = originalEmissivity(btIndex)
3399            end if
3400            ! Note that emissivity above sea-ice is not modified
3401          end if
3402        end do
3403      end do
3404    else
3405      updatedEmissivity(:)%emis_in = originalEmissivity(:)
3406    end if
3407  end subroutine tvs_getMWemissivityFromAtlas
3408
3409  !--------------------------------------------------------------------------
3410  !  comp_ir_emiss
3411  !--------------------------------------------------------------------------
3412  subroutine comp_ir_emiss (emiss, wind, angle, nchn, np, mchannel)
3413    !
3414    !:Purpose: Computes water infrared emissivity for a specific set of
3415    !           channel indices, wind speed and zenith angle.
3416    !
3417    implicit none
3418
3419    ! Arguments:
3420    real(8), intent(out) :: emiss(nchn,np) ! emissivities (0.-1.)
3421    real(8), intent(in)  :: wind(np) ! wind: surface wind speed (m/s)
3422    real(8), intent(in)  :: angle(np) ! angle: viewing angle (deg)
3423    integer, intent(in)  :: nchn ! number of channels to process
3424    integer, intent(in)  :: np     !number of locations
3425    integer, intent(in)  :: mchannel(nchn) ! vector of channel indices to process
3426
3427    ! Locals:
3428    integer, parameter :: MaxWn = 19
3429    integer, parameter :: Nparm=3
3430    integer, parameter :: MaxChan=19
3431
3432    real (8),parameter :: Theta(Nparm,MaxWn) = (/ &
3433         1700.381d0, 25.28534d0, 144.1023d0,      &
3434         1738.149d0, 25.67787d0, 146.6139d0,      & 
3435         1769.553d0, 26.05250d0, 148.6586d0,      &
3436         1778.610d0, 26.12333d0, 149.5127d0,      &
3437         1794.245d0, 26.18523d0, 150.5874d0,      &
3438         1791.904d0, 26.19991d0, 150.7076d0,      &
3439         1806.872d0, 26.37132d0, 151.7191d0,      &
3440         1926.078d0, 27.63825d0, 160.7103d0,      &
3441         1969.155d0, 28.02767d0, 163.6069d0,      &
3442         1975.549d0, 27.86465d0, 164.6228d0,      &
3443         1991.288d0, 27.94312d0, 166.2924d0,      &
3444         2082.691d0, 28.93558d0, 172.4025d0,      &
3445         2182.872d0, 29.89974d0, 179.5839d0,      &
3446         2338.510d0, 31.27507d0, 191.2063d0,      &
3447         2164.615d0, 28.97152d0, 182.6279d0,      &
3448         2099.714d0, 29.91868d0, 178.4015d0,      &
3449         1857.644d0, 29.13640d0, 160.9822d0,      &
3450         1610.696d0, 26.48602d0, 142.2768d0,      &
3451         1503.969d0, 24.97931d0, 133.4392d0 /)
3452
3453    real (8),parameter ::  C(Nparm,2,MaxWn) = (/                                 &  
3454         0.9715104043561414d0,-1.2034233230944147D-06, -5.8742655960993913D-07,  &
3455         0.9263932848727608d0,-9.4908630939690859D-04, 2.2831134823358876D-05,   &
3456         0.9732503924722753d0,-1.2007007329295099D-06, -5.8767355551283423D-07,  &
3457         0.9290947860585505d0,-9.5233413988900161D-04, 2.2640835623043761D-05,   &
3458         0.9745005204317289d0, 1.2857517639804244D-06, -7.1356127087301190D-07,  &
3459         0.9310852809117095d0,-9.5453509182819095D-04, 2.2562638663187251D-05,   &
3460         0.9756204829761132d0, 1.2979181109743976D-06, -7.1406809362820139D-07,  &
3461         0.9329073568177888d0,-9.5627536945214183D-04, 2.2442358508999558D-05,   &
3462         0.9764012672766408d0,-2.0826654381361387D-06, -4.9103920569405721D-07,  &
3463         0.9341937281933334d0,-9.5764423928102976D-04, 2.2326701573603621D-05,   &
3464         0.9770513558720460d0, 4.1867599593267133D-07, -6.1768073971231931D-07,  &
3465         0.9352981872014672d0,-9.5833614545300181D-04, 2.2261996883974513D-05,   &
3466         0.9775970810179080d0,-1.2289690625562906D-06, -5.2953762169985775D-07,  &
3467         0.9362188153954743d0,-9.5950872922696905D-04, 2.2251301675423482D-05,   &
3468         0.9830610391451819d0, 2.7693589475690676D-07, -5.1580217018207558D-07,  &
3469         0.9461121192685766d0,-9.5718115604053031D-04, 2.1087308573177295D-05,   &
3470         0.9840097930773377d0,-1.4987900189155091D-06, -3.8281408128977038D-07,  &
3471         0.9479758694804105d0,-9.5451252460440695D-04, 2.0800627740862229D-05,   &
3472         0.9851056150728580d0,-6.5768237152417477D-07, -4.2053769829400935D-07,  &
3473         0.9502084544618980d0,-9.4965534997704157D-04,  2.0326602209199427D-05,  &
3474         0.9862706396188835d0,-2.3713068057993353D-06, -2.8671134918457728D-07,  &
3475         0.9526580467595886d0,-9.4614505430749598D-04,  2.0001856872595840D-05,  &
3476         0.9875307221489201d0, 1.3003462826947714D-07, -4.1335288320283954D-07,  &
3477         0.9554195617948236d0,-9.3806678196435643D-04,  1.9407754748128057D-05,  &
3478         0.9891153260567763d0,-8.0730206675976713D-07, -3.1811320626834656D-07,  &
3479         0.9590558393678170d0,-9.2716287670223167D-04, 1.8690586764925213D-05,   &
3480         0.9913304557147524d0,-2.1153391229093421D-08, -3.1094269595901165D-07,  &
3481         0.9644162604969492d0,-9.0342753739935612D-04, 1.7274993357160937D-05,   &
3482         0.9925188366950193d0,-4.6365959315123653D-07, -2.7020120347068712D-07,  &
3483         0.9667877170960085d0,-9.0665804037922043D-04, 1.7083616616646458D-05,   &
3484         0.9919408379810360d0,-2.0563508815953840D-06, -1.8066722718403761D-07,  &
3485         0.9627535343397309d0,-9.7537134133678965D-04,  1.9698263973541952D-05,  &
3486         0.9889406296815972d0,-2.3713068057993353D-06, -2.8671134918457728D-07,  &
3487         0.9506051906192242d0,-1.0642902225813857D-03,  2.4235485973033298D-05,  &
3488         0.9828819693848310d0,-7.4086701870172759D-07, -6.2949258820534062D-07,  &
3489         0.9329616683158125d0,-1.0728027288012200D-03, 2.7209071863380586D-05,   &
3490         0.9767410313266288d0,-9.1750038410238915D-07, -7.9177921107781349D-07,  &
3491         0.9192775350344998d0,-1.0369254272157462D-03, 2.8000594542037504D-05 /)
3492
3493    real (8) a(MaxChan),b(MaxChan),cc(MaxChan)  ! local variable
3494    real (8) ww
3495    integer Index,Ichan,IP
3496
3497    do Ichan = 1 , Nchn
3498
3499      Index = Mchannel(Ichan)
3500
3501      do IP=1,NP
3502
3503        ww = wind(IP)
3504        a(Ichan) = c(1,1,Index) + c(2,1,Index) * ww    &  
3505             + c(3,1,Index) * ww * ww
3506        b(Ichan) = c(1,2,Index) + c(2,2,Index) * ww    &
3507             + c(3,2,Index)* ww * ww
3508
3509        cc(Ichan) = Theta(1,Index) + Theta(2,Index) * ww
3510
3511        emiss(Ichan,IP) = a(Ichan) + (b(Ichan) - a(Ichan)) *   & 
3512             exp(( (theta(3,Index) - 60.d0)**2.d0              &
3513             - (angle(IP) - theta(3,Index))**2.d0 ) / CC(Ichan))
3514       
3515      end do
3516      
3517    end do
3518
3519  end subroutine comp_ir_emiss
3520
3521  !--------------------------------------------------------------------------
3522  !  pcnt_box
3523  !--------------------------------------------------------------------------
3524  subroutine pcnt_box(f_low, f_high, nprf, ilat, ilon, klat, klon, ireduc)
3525    !
3526    !:Purpose: Computes a low resolution feature form a high
3527    !           resolution one by averaging.
3528    !           example: use for percentage of water
3529    !
3530    implicit none
3531
3532    ! Arguments:
3533    real(8), intent(out)  :: f_low(nprf)       ! Low resolution field
3534    real(8), intent(in)   :: f_high(klon, klat)! High resolution field 
3535    integer, intent(in)   :: nprf              ! Number of profiles
3536    integer, intent(in)   :: ilat(nprf)        ! Y-coordinate of profile
3537    integer, intent(in)   :: ilon(nprf)        ! X-coordinate of profile
3538    integer, intent(in)   :: klon              ! Max value of latitude indices
3539    integer, intent(in)   :: klat              ! Max value of longitude indices
3540    integer, intent(in)   :: ireduc            ! Means a 2xireduc+1 by 2xireduc+1 averaging
3541
3542    ! Locals
3543    integer :: nplon, jdlo1, jdlo2, jlon1, jlon2
3544    integer :: nx, ilat1, ilat2, ilon1, ilon2, jn, ii, jj
3545   
3546    profiles : do jn = 1,nprf
3547
3548      nplon = 0
3549
3550      ! normal limits
3551
3552      ilat1=max(ilat(jn)-ireduc,1)
3553      ilat2=min(ilat(jn)+ireduc,klat)
3554      ilon1=max(ilon(jn)-ireduc,1)
3555      ilon2=min(ilon(jn)+ireduc,klon)
3556
3557      if (ilon1 == 1 .or. ilon2 == klon) then
3558        ! border cases for longitudes
3559        jdlo1 = ilon(jn)-ireduc
3560        jdlo2 = ilon(jn)+ireduc
3561
3562        if ( jdlo1 <= 0 ) then
3563          nplon = 1
3564          jlon1 = klon + jdlo1
3565          jlon2 = klon
3566        else if ( jdlo2 > klon ) then
3567          nplon = 1
3568          jlon1 = 1
3569          jlon2 = jdlo2 - klon
3570        end if
3571      end if
3572
3573      nx = 0
3574      f_low(jn) = 0.d0
3575     
3576      do jj = ilat1, ilat2
3577
3578        do ii = ilon1, ilon2
3579          nx = nx + 1
3580          f_low(jn) = f_low(jn) + f_high(ii,jj)         
3581        end do
3582        
3583        if (nplon == 1) then
3584          ! additional cases at border 1-klon
3585          do ii = jlon1, jlon2
3586            nx = nx + 1
3587            f_low(jn) = f_low(jn) + f_high(ii,jj)         
3588          end do
3589        end if
3590
3591      end do
3592      
3593      f_low(jn) = f_low(jn) / dble(nx)
3594
3595    end do profiles
3596
3597  end subroutine pcnt_box
3598
3599  !--------------------------------------------------------------------------
3600  !  emis_read_climatology
3601  !--------------------------------------------------------------------------
3602  subroutine emis_read_climatology
3603    !
3604    !:Purpose: Read information about ceres surface type and water fraction.
3605    !
3606    implicit none
3607    
3608    ! Locals:
3609    integer            :: nisf,njsf,nksf
3610    integer            :: niwa,njwa,nkwa
3611    character(len=20)  :: ceresFile
3612    integer, external  :: fnom,fstouv,fstfrm,fclos,fstlir
3613    integer            :: isftest
3614    integer            :: iv1,iv2,iv3,iv4,iv5,iv6
3615
3616    isftest = 0
3617
3618    !* get surface type and water fraction
3619    ceresFile = 'ceres_global.std'
3620    iv1 = fnom(isftest,ceresFile,'RND+R/O',0)
3621    iv2 = fstouv(isftest,'RND')
3622    iv3 = fstlir(surfaceType,isftest,nisf,njsf,nksf,-1,'SFC-TYPE',-1,-1,-1,'','TY')
3623    iv4 = utl_fstlir(waterFraction,isftest,niwa,njwa,nkwa,-1,'WATER_FR',-1,-1,-1,'','W%')
3624    iv5 = fstfrm(isftest)
3625    iv6 = fclos(isftest)
3626
3627    if (iv1 < 0 .or. iv2 < 0 .or. iv3 < 0 .or. iv4 < 0 .or. iv5 < 0 .or. iv6 < 0) then
3628      write(*,*) 'LES iv DE CERES ',iv1,iv2,iv3,iv4,iv5,iv6
3629      write(*,*) 'THESE NUMBER SHOULD NOT BE NEGATIVE WHEN DOING AIRS BACKGROUND CHECK'
3630      call utl_abort('Problem with file ceres_global.std in emis_read_climatology ')
3631    end if
3632   
3633  end subroutine emis_read_climatology
3634
3635  !--------------------------------------------------------------------------
3636  !  emis_getIrEmissivity
3637  !--------------------------------------------------------------------------
3638  subroutine emis_getIrEmissivity (surfem1, nchn, sensorIndex, nprf, nchannels_max, sensorTovsIndexes)
3639    !
3640    !:Purpose: Assign new ir surface emissivities based on
3641    !           cmc analysis surface albedo, sea ice fraction and snow mask
3642    !           in addition to ceres surface type and water fraction. 
3643    !           This is a subroutine that can apply to any instrument.
3644    !
3645    implicit none
3646   
3647    ! Arguments:
3648    real(8), intent(out) :: surfem1(nchannels_max) ! IR surface emissivity estimate (0-1)
3649    integer, intent(in)  :: nchn                   ! Number of channels
3650    integer, intent(in)  :: sensorindex            ! Sensor number
3651    integer, intent(in)  :: nprf                   ! Number of profiles
3652    integer, intent(in)  :: nchannels_max          ! Total number of observations treated
3653    integer, intent(in)  :: sensorTovsIndexes( nprf )         ! Profile position number
3654
3655    ! Locals:
3656    integer :: jc,jn
3657    integer :: ilat(nprf), ilon(nprf)
3658    real(8) :: latitudes(nprf), longitudes(nprf), satzang(nprf)
3659    real(8) :: wind_sfc(nprf), f_low(nprf), waven(nchn), em_oc(nchn,nprf), emi_mat(nchn,20)
3660
3661    ! Information to extract (transvidage)
3662    ! latitudes(nprf) -- latitude (-90 to 90)
3663    ! longitudes(nprf) -- longitude (0 to 360)
3664    ! satzang(nprf) -- satellite zenith angle (deg)
3665
3666    do jn = 1, nprf
3667      latitudes(jn)  = tvs_profiles_nl(sensorTovsIndexes(jn)) % latitude
3668      longitudes(jn) = tvs_profiles_nl(sensorTovsIndexes(jn)) % longitude
3669      satzang(jn)    = tvs_profiles_nl(sensorTovsIndexes(jn)) % zenangle
3670    end do
3671
3672    !  Assign surface properties from grid to profiles
3673    call interp_sfc(ilat,ilon, nprf,latitudes,longitudes,sensorTovsIndexes)
3674
3675
3676    !  Find the sensor bands (central) wavenumbers
3677    do jc = 1, nchn      
3678      waven(jc) = tvs_coefs(sensorIndex) % coef % ff_cwn(jc)
3679    end do
3680
3681
3682    !  Get the CERES emissivity matrix for all sensor wavenumbers and surface types
3683    call ceres_ematrix(emi_mat, waven,nchn)
3684
3685
3686    ! Refine water emissivities
3687
3688    do jn = 1, nprf
3689      !       find surface wind
3690      wind_sfc(jn) = min(sqrt(tvs_profiles_nl(sensorTovsIndexes(jn)) % s2m %u**2 + tvs_profiles_nl(sensorTovsIndexes(jn)) % s2m % v**2 + 1.d-12),15.d0)
3691    end do
3692
3693    !     find new ocean emissivities     
3694
3695    do jc = 1, nchn
3696      em_oc(jc,:)= emi_mat(jc,17)
3697    end do
3698    
3699    call emi_sea (em_oc, waven,satzang,wind_sfc,nprf,nchn)
3700    
3701
3702    ! Get surface emissivities
3703
3704    do jn = 1, nprf
3705      !       set albedo to 0.6 where snow is present
3706      if ( tvs_profiles_nl(sensorTovsIndexes(jn)) % skin % surftype == surftype_land .and. tvs_surfaceParameters(sensorTovsIndexes(jn)) % snow > 0.999 ) tvs_surfaceParameters(sensorTovsIndexes(jn)) % albedo = 0.6
3707      !       if albedo too high no water
3708      if ( tvs_surfaceParameters(sensorTovsIndexes(jn)) % albedo >= 0.55 ) tvs_surfaceParameters(sensorTovsIndexes(jn)) % pcnt_wat = 0.
3709      !       if water and CMC ice present then sea ice
3710      if ( tvs_profiles_nl(sensorTovsIndexes(jn)) % skin % surftype == surftype_sea .and. tvs_surfaceParameters(sensorTovsIndexes(jn)) % ice > 0.001 ) tvs_surfaceParameters(sensorTovsIndexes(jn)) % ltype = 20
3711      !       if land and CMC snow present then snow
3712      if ( tvs_profiles_nl(sensorTovsIndexes(jn)) % skin % surftype == surftype_land .and. tvs_surfaceParameters(sensorTovsIndexes(jn)) % snow > 0.999 ) tvs_surfaceParameters(sensorTovsIndexes(jn)) % ltype = 15
3713      do jc=1,nchn
3714        surfem1((jn-1)*nchn+jc) =  tvs_surfaceParameters(sensorTovsIndexes(jn)) % pcnt_wat * em_oc(jc,jn)  +   &
3715             ( 1.d0 - tvs_surfaceParameters(sensorTovsIndexes(jn)) % pcnt_wat ) * emi_mat(jc,tvs_surfaceParameters(sensorTovsIndexes(jn)) % ltype)
3716      end do
3717    end do
3718
3719    ! Find the regional water fraction (here in a 15x15 pixel box centered on profile)
3720    call pcnt_box (f_low, waterFraction,nprf,ilat,ilon,kslat,kslon,7)
3721
3722    do jn = 1, nprf
3723      tvs_surfaceParameters(sensorTovsIndexes(jn)) % pcnt_reg = f_low(jn)
3724    end do
3725
3726  end subroutine emis_getIrEmissivity
3727
3728  !--------------------------------------------------------------------------
3729  !  interp_sfc
3730  !--------------------------------------------------------------------------
3731  subroutine interp_sfc (ilat, ilon, nprf, latitudes, longitudes, sensorTovsIndexes)
3732    !
3733    !:Purpose: Associate surface albedo, ice fraction, snow depth 
3734    !           and ceres surface type and water fraction to observations profiles.
3735    !
3736    implicit none
3737
3738    ! Arguments:
3739    integer, intent(out) :: ilat(nprf)   ! y-coordinate of profile
3740    integer, intent(out) :: ilon(nprf)   ! x-coordinate of profile 
3741    integer, intent(in)  :: nprf         ! number of profiles
3742    real(8), intent(in)  :: latitudes(nprf)   ! latitude (-90s to 90n)
3743    real(8), intent(in)  :: longitudes(nprf)   ! longitude (0 to 360)
3744    integer, intent(in)  :: sensorTovsIndexes(nprf) ! observation index
3745
3746    ! Locals:
3747    character(len=20)  :: cfile3,cfile5
3748    integer            :: iun3,iun5
3749    integer            ::                        iv7
3750    integer            :: ix1,ix2,ix3,ix4,ix5,        ix8,ix9,ix10,ix11,ix12
3751    integer            ::         iy3,iy4,iy5,        iy8,iy9,iy10
3752    integer            :: iz1,iz2,iz3,iz4,iz5,        iz8,iz9,iz10,iz11,iz12
3753    integer            :: ni3,nj3,nk3
3754    integer            :: ni4,nj4,nk4
3755    integer            :: ni5,nj5,nk5
3756    integer            :: dateo,deet,npas,nbits,datyp
3757    integer            :: ip1,ip2,ip3
3758    integer            :: ig13,ig23,ig33,ig43
3759    integer            :: ig14,ig24,ig34,ig44
3760    integer            :: ig15,ig25,ig35,ig45
3761    integer            :: swa,lng,dltf,ubc,ex1,ex2,ex3
3762    integer            :: jn
3763    character(len=1)   :: typvar
3764    character(len=1)   :: grtyp3,grtyp4,grtyp5
3765    character(len=2)   :: nomvar, snowvar
3766    character(len=8)   :: etiket
3767    integer, external  :: fnom,fstouv,fstinf,fstprm,fstfrm,fclos
3768    integer, external  :: ezqkdef,ezdefset
3769    real(8)            :: zig1,zig2,zig3,zig4
3770    integer            :: ig1obs,ig2obs,ig3obs,ig4obs
3771    real (8)           :: alat, alon, zzlat, zzlon
3772    ! fields on input grid
3773    real(8), allocatable :: glace(:,:), neige(:,:), alb(:,:)
3774    ! fields on output grid
3775    real(8)              :: glace_intrpl(nprf,1), neige_intrpl(nprf,1), alb_intrpl(nprf,1)
3776
3777    ! printout header
3778    write(*,*) 
3779    write(*,*) 'SUBROUTINE interp_sfc'
3780    write(*,*) '---------------------'
3781    write(*,*) ' called multiple time by bunch of ',nprf,' profiles'
3782    write(*,*) ' <RETURN CODES> SHOULD NOT BE NEGATIVE'
3783    write(*,*) '---------------------------------------------------'
3784
3785
3786    ! --- FOR CERES VARIABLES -------------
3787    !  Get number of pixels per degree of lat or lon
3788
3789    alat = dble(kslat)/180.d0
3790    alon = dble(kslon)/360.d0
3791
3792    do jn=1, nprf
3793
3794      ! get lat and lon within limits if necessary
3795      zzlat = min(latitudes(jn),89.999d0)
3796      zzlat = max(Zzlat,-89.999d0)
3797      
3798      zzlon = min(longitudes(jn),359.999d0)
3799      zzlon = max(zzlon,0.d0)
3800
3801      !  Find in which surface field pixel is located the observation profile
3802
3803      ! Note : CERES grid at 1/6 resolution 
3804      !         N-S : starts at N pole and excludes S pole
3805      !         W-E : starts at longitude 0 and excludes longitude 360
3806
3807      ilat(jn) = max( nint((zzlat + 90.d0) * alat),1) 
3808      ilon(jn) = nint(zzlon * alon) + 1
3809      if (ilon(jn) > kslon) ilon(jn) = 1
3810
3811      !  Assign surface caracteristics to observation profiles
3812
3813      tvs_surfaceParameters(sensorTovsIndexes(jn)) % ltype    = surfaceType(ilon(jn),ilat(jn))
3814      tvs_surfaceParameters(sensorTovsIndexes(jn)) % pcnt_wat = waterFraction(ilon(jn),ilat(jn))
3815
3816    end do
3817
3818    !  For ice, snow and albedo variables -------------
3819
3820    iun3 = 0
3821    iun5 = 0
3822
3823    ! File names
3824    cfile3 = 'sfc4airs'          ! for ice fraction and snow cover
3825    cfile5 = 'sfc4airs_newalb'   ! for albedo
3826
3827
3828    ! fnom: make the connections with the external files name
3829    ! success = 0
3830    write(*,*) 
3831    ix1 = fnom(iun3,cfile3,'RND+R/O',0)
3832    write(*,*) 'file = sfc4airs         : fnom   : return = ', ix1
3833
3834    iz1 = fnom(iun5,cfile5,'RND+R/O',0)
3835    write(*,*) 'file = sfc4airs_newalb  : fnom   : return = ', iz1
3836
3837
3838    ! fstouv: open the standard files
3839    ! success = number of records found in the file
3840    write(*,*) 
3841    ix2 = fstouv(iun3,'RND')
3842    write(*,*) 'file = sfc4airs         : fstouv : return = ', ix2
3843    iz2 = fstouv(iun5,'RND')
3844    write(*,*) 'file = sfc4airs_newalb  : fstouv : return = ', iz2
3845
3846
3847    ! fstinf: locate the records that matches the search keys
3848    ! success = handle of the record found after the search
3849    ! desired output = handle
3850    write(*,*) 
3851    ix3 = fstinf(iun3,ni3,nj3,nk3,-1,'',-1,-1,-1,'','LG')
3852    write(*,*) 'variable = LG           : fstinf : return = ', ix3
3853
3854    snowvar='SD'
3855    iy3 = fstinf(iun3,ni4,nj4,nk4,-1,'',-1,-1,-1,'',snowvar)
3856    write(*,*) 'variable = ', snowvar, '           : fstinf : return = ', iy3
3857    if ( iy3  <  0 ) then
3858      write(*,*) 'did not find ''SD'' so look for ''NE'''
3859      snowvar='NE'
3860      iy3 = fstinf(iun3,ni4,nj4,nk4,-1,'',-1,-1,-1,'',snowvar)
3861      write(*,*) 'variable = ', snowvar, '           : fstinf : return = ', iy3
3862    end if
3863
3864    iz3 = fstinf(iun5,ni5,nj5,nk5,-1,'',-1,-1,-1,'','AL')
3865    write(*,*) 'variable = AL           : fstinf : return = ', iz3
3866
3867
3868    ! fstprm: get the description informations of the record given the key
3869    ! success = 0
3870    ! desired output = nix,njx,grtypx,igxx,ig1x,ig2x,ig3x,ig4x
3871
3872    write(*,*) 
3873    ix4 = fstprm(ix3, dateo,deet,npas,ni3,nj3,nk3,nbits,datyp, &
3874         ip1,ip2,ip3,typvar,nomvar,etiket,grtyp3,  &
3875         ig13,ig23,ig33,ig43,swa,lng,dltf,ubc,ex1,ex2,ex3)
3876    write(*,*) 'variable = LG           : fstprm : return = ', ix4
3877
3878    iy4 = fstprm(iy3, dateo,deet,npas,ni4,nj4,nk4,nbits,datyp, &
3879         ip1,ip2,ip3,typvar,nomvar,etiket,grtyp4,  &
3880         ig14,ig24,ig34,ig44,swa,lng,dltf,ubc,ex1,ex2,ex3)
3881    write(*,*) 'variable = ', snowvar, '           : fstprm : return = ', iy4
3882
3883    iz4 = fstprm(iz3, dateo,deet,npas,ni5,nj5,nk5,nbits,datyp, &
3884         ip1,ip2,ip3,typvar,nomvar,etiket,grtyp5,  &
3885         ig15,ig25,ig35,ig45,swa,lng,dltf,ubc,ex1,ex2,ex3)
3886    write(*,*) 'variable = AL           : fstprm : return = ', iz4
3887
3888
3889    ! allocation of the field on the grid
3890    allocate ( glace  (ni3,nj3) )
3891    allocate ( neige  (ni4,nj4) )
3892    allocate ( alb    (ni5,nj5) )
3893
3894
3895    ! utl_fstlir: read records data (field on the grid) given the key
3896    ! success = handle of the record
3897    ! desired output = FIELD
3898    write(*,*) 
3899
3900    ix5 = utl_fstlir(glace, iun3,ni3,nj3,nk3,-1,'',-1,-1,-1,'','LG')
3901    write(*,*) 'variable = LG           : utl_fstlir : return = ', ix5
3902    iy5 = utl_fstlir(neige, iun3,ni4,nj4,nk4,-1,'',-1,-1,-1,'',snowvar)
3903    write(*,*) 'variable = ', snowvar, '           : utl_fstlir : return = ', iy5
3904    iz5 = utl_fstlir(alb,   iun5,ni5,nj5,nk5,-1,'',-1,-1,-1,'','AL')
3905    write(*,*) 'variable = AL           : utl_fstlir : return = ', iz5
3906
3907    ! int_CXGAIG: define the grid descriptors (integer form) of the
3908    !          observation profile output grid
3909    ! desired output = ig1OBS, ig2OBS, ig3OBS, ig4OBS
3910    zig1 = 0.0d0
3911    zig2 = 0.0d0
3912    zig3 = 1.0d0
3913    zig4 = 1.0d0
3914
3915    call int_cxgaig('L',ig1OBS,ig2OBS,ig3OBS,ig4OBS,zig1,zig2,zig3,zig4)
3916
3917
3918    ! int_EZGDEF: define the grid of the observations profiles (output grid)
3919    ! of type Y containing the lat-lon of profiles
3920    ! success = token to identify the grid
3921    ! desired output = token
3922    write(*,*) 
3923    iv7 = int_ezgdef(nprf,1,'Y','L',ig1obs,ig2obs,ig3obs,ig4obs,longitudes,latitudes)
3924    write(*,*) 'apply to all variables  : int_EZGDEF : return = ', iv7
3925    
3926
3927    ! EZQKDEF: define the grid of the records data (input grid)
3928    ! success = token to identify the grid
3929    ! desired output = token
3930    ! EZDEFSET: interpolate from input grids to output grid
3931    ! success = key
3932    ! int_hInterpScalar: interpolation of the field on the input grid to observation profiles
3933    ! success = 0
3934    ! desired output = FIELD_intrpl
3935    write(*,*) 
3936    ix8 = ezqkdef(ni3,nj3,grtyp3,ig13,ig23,ig33,ig43,iun3)
3937    write(*,*) 'variable = LG           : ezqkdef  : return = ', ix8
3938    
3939    ix9 = ezdefset(iv7,ix8)
3940    write(*,*) 'variable = LG           : ezdefset : return = ', ix9
3941
3942    ix10 = int_hInterpScalar(glace_intrpl,glace,interpDegree='NEAREST')
3943    write(*,*) 'variable = LG           : int_hInterpScalar  : return = ', ix10
3944
3945    write(*,*) 
3946
3947    iy8 = ezqkdef(ni4,nj4,grtyp4,ig14,ig24,ig34,ig44,iun3)
3948    write(*,*) 'variable = ', snowvar, '           : ezqkdef  : return = ', iy8
3949
3950    iy9 = ezdefset(iv7,iy8)
3951    write(*,*) 'variable = ', snowvar, '           : ezdefset : return = ', iy9
3952
3953    iy10 = int_hInterpScalar(neige_intrpl,neige,interpDegree='NEAREST')
3954    write(*,*) 'variable = ', snowvar, '           : int_hInterpScalar  : return = ', iy10
3955
3956    write(*,*) 
3957
3958    iz8 = ezqkdef(ni5,nj5,grtyp5,ig15,ig25,ig35,ig45,iun5)
3959    write(*,*) 'variable = AL           : ezqkdef  : return = ', iz8
3960
3961    iz9 = ezdefset(iv7,iz8)
3962    write(*,*) 'variable = AL           : ezdefset : return = ', iz9
3963
3964    iz10 = int_hInterpScalar(alb_intrpl,alb,interpDegree='NEAREST')
3965    write(*,*) 'variable = AL           : int_hInterpScalar  : return = ', iz10
3966
3967
3968    ! fstfrm: close the standard files
3969    ! success = 0
3970    write(*,*) 
3971    ix11 = fstfrm(iun3)
3972    write(*,*) 'file = sfc4airs         : fstfrm : return = ', ix11
3973    
3974    iz11 = fstfrm(iun5)
3975    write(*,*) 'file = sfc4airs_newalb  : fstfrm : return = ', iz11
3976 
3977
3978    ! fclos: release the connections with the external files name
3979    ! success = 0
3980
3981    write(*,*) 
3982
3983    ix12 = fclos(iun3)
3984    write(*,*) 'file = sfc4airs         : fclos  : return = ', ix12
3985
3986    iz12 = fclos(iun5)
3987    write(*,*) 'file = sfc4airs_newalb  : fclos  : return = ', iz12
3988
3989    ! assign surface caracteristics to observation profiles
3990
3991    do jn=1, nprf
3992      tvs_surfaceParameters(sensorTovsIndexes(jn)) % ice    = glace_intrpl(jn,1)
3993      tvs_surfaceParameters(sensorTovsIndexes(jn)) % snow   = neige_intrpl(jn,1)
3994      tvs_surfaceParameters(sensorTovsIndexes(jn)) % albedo = alb_intrpl(jn,1)
3995    end do
3996
3997    deallocate(glace,neige,alb)
3998
3999  end subroutine interp_sfc
4000
4001  !--------------------------------------------------------------------------
4002  !  ceres_ematrix
4003  !--------------------------------------------------------------------------
4004  subroutine ceres_ematrix(emi_mat, waven, nchn)
4005    !
4006    !:Purpose: Set up emissivity versus fixed wavenumbers and surface types.
4007    !
4008    !:CERES:
4009    ! Emissivity data available at low spectral resolution: only 14 values 
4010    ! to cover the entire spectrum. Thus, this can be used as a nominal value.
4011    ! The error associated with this emissivity can roughly be estimated to
4012    ! increase with lower emissivity as : (1-EMI)*0.5 
4013    ! (i.e. as large as 0.10 for EMI=0.80 but better than 0.01 for EMI > 0.98)
4014    ! -No dependence on viewing angle is assumed.
4015    ! -Not to be used for oceans uncovered by ice.
4016    !
4017    !:Longwave Emmissivities in 12 original Fu bands + 2 extra to cover the range:
4018    !
4019    ! Longwave spectral intervals [cm-1] for the Fu & Liou code.
4020    !
4021    ! ====  ==========  ==========  ==========  ===========  ==========  ==========  =========  =========  =========  =========  =========  =============
4022    ! Band       1          2           3           4           5            6           7          8          9          10         11          12
4023    !       2200-1900   1900-1700   1700-1400   1400-1250    1250-1100   1100-980     980-800    800-670    670-540    540-400    400-280    280-0 
4024    ! ====  ==========  ==========  ==========  ===========  ==========  ==========  =========  =========  =========  =========  =========  =============
4025    !
4026    ! Two additional LW spectral intervals have been added in beyond 2200cm-1.
4027    !
4028    ! =====   ===========   ===========
4029    ! Band        13            14
4030    !          2500-2200     2850-2500
4031    ! =====   ===========   ===========
4032    !
4033    ! Emissivity ems(band(1))   from April data, Table2 of Chen et al
4034    ! 11th Conf Sat Met, Madison, WI, p 514
4035    ! here regoganized as 14 13 1 2 ... 12 above
4036    !
4037    !:20 surface types:
4038    !
4039    ! ===================  ===================  ===================  =====================
4040    !  1= evergreen nleaf   2= evergreen bleaf   3= deciduous nleaf   4= deciduous bleaf
4041    !  5= mixed forests     6= closed shrubs     7= open shrubs       8= woody savanna
4042    !  9= savanna          10= grasslands       11= perma wet        12= croplands
4043    ! 13= urban            14= mosaic           15= snow             16= barren (deserts)
4044    ! 17= water            18= toundra          19= fresh snow       20= sea ice
4045    ! ===================  ===================  ===================  =====================
4046    !
4047    implicit none
4048
4049    ! Arguments:
4050    integer, intent(in)  :: nchn              ! number of bands for which emissivity is needed
4051    real(8), intent(in)  :: waven(nchn)       ! wavenumbers (cm-1)
4052    real(8), intent(out) :: emi_mat(nchn, 20) ! emissivity (0.0-1.0)
4053
4054    ! Locals:
4055    integer          :: i, nc, nt
4056    real(8)          :: dum
4057
4058    ! CERES bands central wavenumber (covers 3.7 micron to 71.4 mic)
4059    integer, parameter :: nb=14
4060    real(8), parameter :: mid(nb) =(/                                             &
4061         2675.d0, 2350.d0, 2050.d0, 1800.d0, 1550.d0, 1325.d0, 1175.d0, 1040.d0,  &
4062         890.d0,  735.d0,  605.d0,  470.d0,  340.d0,  140.d0 /)
4063
4064    ! CERES emissivity per wavenumber and surface types
4065    real(8), parameter ::  emi_tab(nb,20)=(/                                      &
4066         0.951d0, 0.989d0, 0.989d0, 0.989d0, 0.990d0, 0.991d0, 0.991d0, 0.990d0,  &
4067         0.990d0, 0.995d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4068         0.956d0, 0.989d0, 0.989d0, 0.989d0, 0.990d0, 0.991d0, 0.991d0, 0.990d0,  &
4069         0.990d0, 0.995d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4070         0.929d0, 0.985d0, 0.985d0, 0.986d0, 0.984d0, 0.983d0, 0.979d0, 0.980d0,  &
4071         0.973d0, 0.987d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4072         0.943d0, 0.985d0, 0.985d0, 0.986d0, 0.984d0, 0.983d0, 0.979d0, 0.980d0,  &
4073         0.973d0, 0.987d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4074         0.945d0, 0.987d0, 0.987d0, 0.987d0, 0.987d0, 0.987d0, 0.985d0, 0.985d0,  &
4075         0.982d0, 0.991d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4076         0.933d0, 0.949d0, 0.949d0, 0.970d0, 0.974d0, 0.971d0, 0.947d0, 0.958d0,  &
4077         0.966d0, 0.975d0, 0.984d0, 0.984d0, 0.984d0, 0.984d0,                    &
4078         0.873d0, 0.873d0, 0.873d0, 0.934d0, 0.944d0, 0.939d0, 0.873d0, 0.904d0,  &
4079         0.936d0, 0.942d0, 0.951d0, 0.951d0, 0.951d0, 0.951d0,                    &
4080         0.930d0, 0.987d0, 0.987d0, 0.990d0, 0.992d0, 0.993d0, 0.983d0, 0.975d0,  &
4081         0.985d0, 0.993d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4082         0.926d0, 0.987d0, 0.987d0, 0.990d0, 0.992d0, 0.993d0, 0.983d0, 0.975d0,  &
4083         0.985d0, 0.993d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4084         0.899d0, 0.987d0, 0.987d0, 0.990d0, 0.992d0, 0.993d0, 0.983d0, 0.975d0,  &
4085         0.985d0, 0.993d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4086         0.951d0, 0.983d0, 0.983d0, 0.987d0, 0.987d0, 0.988d0, 0.983d0, 0.981d0,  &
4087         0.987d0, 0.982d0, 0.986d0, 0.986d0, 0.986d0, 0.986d0,                    &
4088         0.924d0, 0.987d0, 0.987d0, 0.990d0, 0.992d0, 0.993d0, 0.983d0, 0.975d0,  &
4089         0.985d0, 0.993d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4090         0.929d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,  &
4091         1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4092         0.926d0, 0.987d0, 0.987d0, 0.989d0, 0.989d0, 0.990d0, 0.984d0, 0.980d0,  &
4093         0.983d0, 0.992d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,                    &
4094         0.972d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0, 1.000d0,  &
4095         1.000d0, 0.999d0, 0.999d0, 0.999d0, 0.999d0, 0.999d0,                    &
4096         0.866d0, 0.835d0, 0.835d0, 0.916d0, 0.934d0, 0.923d0, 0.835d0, 0.877d0,  &
4097         0.921d0, 0.926d0, 0.934d0, 0.934d0, 0.934d0, 0.934d0,                    &
4098         0.973d0, 0.979d0, 0.979d0, 0.983d0, 0.982d0, 0.982d0, 0.984d0, 0.987d0,  &
4099         0.989d0, 0.972d0, 0.972d0, 0.972d0, 0.972d0, 0.972d0,                    &
4100         0.968d0, 0.947d0, 0.947d0, 0.967d0, 0.988d0, 0.979d0, 0.975d0, 0.977d0,  &
4101         0.992d0, 0.989d0, 0.989d0, 0.989d0, 0.989d0, 0.989d0,                    &
4102         0.984d0, 0.988d0, 0.988d0, 0.988d0, 0.988d0, 0.988d0, 0.988d0, 0.988d0,  &
4103         0.988d0, 0.988d0, 0.988d0, 0.988d0, 0.988d0, 0.988d0,                    &
4104         0.964d0, 0.979d0, 0.979d0, 0.979d0, 0.979d0, 0.979d0, 0.979d0, 0.979d0,  &
4105         0.979d0, 0.979d0, 0.979d0, 0.979d0, 0.979d0, 0.979d0  /)
4106
4107    do nt = 1, 20
4108      do nc = 1, nchn
4109        if ( waven(nc) > mid(1) ) then
4110          emi_mat(nc,nt) = emi_tab(1,nt)
4111        else if ( waven(nc) < mid(nb) ) then
4112          emi_mat(nc,nt) = emi_tab(nb,nt)
4113        else
4114          do i = 1, nb - 1
4115            if ( waven(nc) <= mid(i) .and. waven(nc) >= mid(i + 1) ) then
4116              dum = ( waven(nc) - mid(i) ) / ( mid(i + 1) - mid(i) )
4117              emi_mat(nc,nt) = emi_tab(i,nt) + ( emi_tab(i + 1,nt) - emi_tab(i,nt) ) * dum
4118              exit
4119            end if
4120          end do
4121        end if
4122      end do
4123    end do
4124
4125
4126  end subroutine ceres_ematrix
4127
4128  !--------------------------------------------------------------------------
4129  !  emi_sea
4130  !--------------------------------------------------------------------------
4131  subroutine emi_sea(em_oc, wnum, angle, wind, np, nc)
4132    !
4133    !:Purpose: GET OCEAN SURFACE EMISSIVITY
4134    !:Note:    IMEM(NC), set to zero initially, on next call IMEM will have the
4135    !           right boundary channel to save search time in interpolation.
4136    !           IOPT=1 means activate IMEM option (all calls ask for same channels)
4137    !
4138    !           To get surface ocean emissivity for a group of channels with
4139    !           wavenumbers WNUM (cm-1) looking at one point with surface
4140    !           wind speed wind from angle angle.
4141    !           Based on Masuda,1988, Remote Sens. of Envir, 313-329.
4142    !           Coded emissivity routine based on Masuda's data by Tom Kleespies
4143    !           Covers 650-2857 cm-1 or 3.1-15.4 microns
4144    !
4145    !:CAUTION: extrapolated values from 769-650 cm-1
4146    !           and interpolated values between 2439-1250 cm-1
4147    !
4148    implicit none
4149
4150    ! Arguments:
4151    real(8), intent(out)   :: em_oc(nc,np) ! Ocean emissivities (0.-1.)
4152    real(8), intent(in)    :: wnum(nc)     ! Channel wavenumbers (cm-1)
4153    real(8), intent(in)    :: angle(np)    ! Viewing angle (deg)
4154    real(8), intent(in)    :: wind(np)     ! Surface wind speed (m/s)
4155    integer, intent(in)    :: np           ! Number of profiles
4156    integer, intent(in)    :: nc           ! Number of channels
4157
4158    ! Locals:
4159    integer     :: i, k, l
4160    integer     :: imem(nc) 
4161    integer     :: mchan(2)
4162    real(8)     :: dum
4163    real(8)     :: emi2(2,np)
4164
4165    ! Masuda's 19 wavelengths converted to wavenumber
4166    real(8), parameter :: refw(19)=(/ 2857.1d0, 2777.7d0, 2702.7d0, 2631.6d0, 2564.1d0, &
4167         2500.0d0, 2439.0d0, 1250.0d0, 1190.5d0, 1136.3d0,                           &
4168         1087.0d0, 1041.7d0, 1000.0d0, 952.38d0, 909.09d0,                           &
4169         869.57d0, 833.33d0, 800.00d0, 769.23d0/)
4170
4171    ! imem options
4172    imem(:) = 0
4173
4174    do I = 1, nc
4175
4176      !  out of range
4177      if ( wnum(I) < 645.d0 .or. wnum(I) > refw(1) ) then
4178        write(*,'(A,1x,e12.4)') ' fatal: wavenumber out of range in emi_sea', wnum(I)
4179        stop
4180      else if ( wnum(I) <= refw(19) .and. wnum(I) > 645.d0 ) then
4181        !  extrapolated from 769 cm-1 to 645 cm-1: NOT FROM REAL DATA
4182        !  nevertheless thought to be much better than unity
4183        !  this is a region of relatively rapid emissivity change
4184        !  worst estimates for 700-645 cm-1, but these channels do not
4185        !  see the surface (strong co2 absorption).
4186        imem(I) = 18
4187      else
4188        !  CAUTION interpolation on large interval 1250-2439 cm-1
4189        !  where no data is available except that of ASTER. ASTER
4190        !  shows a relatively smooth variation with wavelength except
4191        !  for a sharp drop at 1600 cm-1 with highs at 1550 and 1650 cm-1
4192        !  with peak-to-peak variation of 1.5% in that narrow range.
4193        !  Worst estimates would be between 1400-1800 cm-1 in HIRS ch 12
4194        !  which only in very cold atmospheres sees the surface.
4195        do k = 1, 18
4196          if ( wnum(I) > refw(k + 1) .and. wnum(I) <= refw(k) ) then
4197            imem(I) = k
4198          end if
4199        end do
4200
4201      end if
4202   
4203      mchan(1)= imem(I)
4204      mchan(2)= imem(I) + 1
4205
4206      dum = ( wnum(I) - refw(mchan(1)) ) / ( refw(mchan(2)) - refw(mchan(1)) )
4207
4208      call COMP_IR_EMISS(emi2, wind,angle,2,np,mchan)
4209
4210      ! interpolation/extrapolation in wavenumber 
4211
4212      do L = 1, np
4213  
4214        em_oc(I,L) = emi2(1,L) + ( emi2(2,L) - emi2(1,L) ) * dum
4215          
4216      end do
4217
4218    end do
4219
4220
4221  end subroutine emi_sea
4222
4223
4224  !--------------------------------------------------------------------------
4225  !  tvs_getCommonChannelSet
4226  !--------------------------------------------------------------------------
4227  subroutine tvs_getCommonChannelSet(channels,countUniqueChannel, listAll)
4228    !
4229    !:Purpose: get common channels among all MPI tasks
4230    !
4231    implicit none
4232
4233    ! Arguments:
4234    integer, intent(in)  :: channels(:)
4235    integer, intent(out) :: countUniqueChannel
4236    integer, intent(out) :: listAll(:)
4237
4238    ! Locals:
4239    integer :: channelsb(tvs_maxChannelNumber)
4240    integer :: ierr, i, j
4241    integer, allocatable :: listGlobal(:)
4242    logical :: found
4243     
4244    if (size(channels) > tvs_maxChannelNumber) then
4245      write(*,*) 'You need to increase tvs_maxChannelNumber in tovsNL_mod !',size(channels), tvs_maxChannelNumber
4246      call utl_abort('tvs_getCommonChannelSet')
4247    end if
4248
4249    if (mmpi_myid ==0) then
4250      allocate(listGlobal(mmpi_nprocs*tvs_maxChannelNumber))
4251    else
4252      allocate(listGlobal(1))
4253    end if
4254
4255    listAll(:) = 0
4256    listGlobal(:) = 0
4257    channelsb(:) = 0
4258    channelsb(1:size(channels)) = channels(:)
4259
4260    call rpn_comm_barrier('GRID',ierr)
4261
4262    call rpn_comm_gather(channelsb, tvs_maxChannelNumber, 'MPI_INTEGER', listGlobal, &
4263         tvs_maxChannelNumber, 'MPI_INTEGER', 0, 'GRID', ierr) 
4264    countUniqueChannel = 0
4265    if ( mmpi_myid == 0 ) then
4266      call isort(listGlobal, mmpi_nprocs*tvs_maxChannelNumber)
4267      do i=1, mmpi_nprocs * tvs_maxChannelNumber
4268        if (listGlobal(i) > 0) then
4269          found = .false.
4270          LOOPJ: do j=countUniqueChannel,1,-1
4271            if (listGlobal(i) == listAll(j) ) then
4272              found =.true.
4273              exit LOOPJ
4274            end if
4275          end do LOOPJ
4276          if (.not.found) then
4277            countUniqueChannel = countUniqueChannel + 1
4278            listAll(countUniqueChannel) = listGlobal(i)
4279          end if
4280        end if
4281      end do
4282    end if
4283    
4284    call rpn_comm_bcast(countUniqueChannel, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4285    call rpn_comm_bcast(listAll(1:countUniqueChannel), countUniqueChannel, 'MPI_INTEGER', 0, 'GRID', ierr)
4286
4287    deallocate(listGlobal)
4288
4289  end subroutine tvs_getCommonChannelSet
4290
4291
4292  !--------------------------------------------------------------------------
4293  !  tvs_rttov_read_coefs
4294  !--------------------------------------------------------------------------
4295  subroutine tvs_rttov_read_coefs(errorStatus, coefs, opts, channels, instrument)
4296    !
4297    !:Purpose: MPI wrapper for rttov_read_coefs
4298    !           the coefficient files are read by MPI task 0
4299    !           and then broadcasted to the other tasks according to the selected
4300    !           channels. Argument channels is mandatory (it is optional in rttov_setup)
4301    !           optional argument channels_rec was removed (it is useful only in principal component mode)
4302    !           other optionnal arguments were removed :
4303    !                          *  form_coef, to specify format
4304    !                          *  form_scaer,        
4305    !                          *  form_sccld,        
4306    !                          *  form_pccoef,       
4307    !                          *  file_coef, to specify filename
4308    !                          *  file_scaer,        
4309    !                          *  file_sccld,        
4310    !                          *  file_pccoef,       
4311    !                          *  file_id_coef, to specify fortran unit number
4312    !                          *  file_id_scaer,     
4313    !                          *  file_id_sccld,     
4314    !                          *  file_id_pccoef,
4315    !                          *  path,  to specify the path to look for coefficient files
4316    !
4317    !           if necessary these arguments could be  added (ask S. Heilliette)
4318    !           also this subroutine will work only for clear sky radiance computations
4319    !           if somebody wants to do realistic cloud or aerosol affected radiance simulations
4320    !           some changes are needed. Ask me in that case. (S. Heilliette) 
4321    !           It is implicitely assumed that the options are the same for all MPI tasks for a given instrument
4322    !           No check will be done (options for task 0 will be used for all tasks). 
4323    !           Only differences in channel lists are accounted for.
4324    !
4325    implicit none
4326
4327    ! Arguments:
4328    integer(kind=jpim),  intent(out) :: errorStatus   ! Error status
4329    type(rttov_coefs),   intent(out) :: coefs         ! Rttov coefficient structure
4330    type(rttov_options), intent(in)  :: opts          ! Rttov option structure
4331    integer(kind=jpim),  intent(in)  :: channels(:)   ! Channel list
4332    integer(kind=jpim),  intent(in)  :: instrument(3) ! Instrument vector
4333
4334    ! Locals:
4335    real(8), allocatable :: bigArray(:,:,:,:)
4336    integer :: i, j, ichan, ierr, countUniqueChannel, indexchan(size(channels)), listAll(tvs_maxChannelNumber)
4337    logical :: associated0
4338    integer :: nlte_count, nlte_start,isol,isat,nlte_file_nchan
4339    integer, allocatable :: nlte_chans(:) 
4340
4341    write(*,*) 'tvs_rttov_read_coefs: Starting'
4342
4343    ! First step: we should determine a common set of channels among MPI tasks
4344    call tvs_getCommonChannelSet(channels,countUniqueChannel, listAll)
4345
4346    ! Second step: mpi task 0 will do the job
4347    if ( mmpi_myid == 0 ) then
4348      call rttov_read_coefs (         &
4349          errorStatus,                &! out
4350          coefs,                      &
4351          opts,                       &
4352          instrument=instrument,      &! in
4353          channels=listAll(1:countUniqueChannel)  )     ! in option
4354      if (errorStatus /= errorStatus_success) then
4355        write(*,*) 'tvs_rttov_read_coefs: failure in rttov_read_coefs while reading RTTOV coefficient file', instrument, errorStatus
4356        call utl_abort('tvs_rttov_read_coefs')
4357      end if
4358    else
4359      call rttov_nullify_coef(coefs%coef)
4360    end if
4361
4362    ! Third step: common (i.e. independent from the channel list) parameters are simply broadcasted to other processors
4363    ! Scalar and fixed size arrays and  strings first
4364    coefs%initialised = .true.                                                    ! Logical flag for initialization
4365    call rpn_comm_bcast(coefs%coef%id_platform, 1, 'MPI_INTEGER', 0, 'GRID', ierr)! OK
4366    call rpn_comm_bcast(coefs%coef%id_sat, 1, 'MPI_INTEGER', 0, 'GRID', ierr)     ! OK
4367    call rpn_comm_bcast(coefs%coef%id_inst, 1, 'MPI_INTEGER', 0, 'GRID', ierr)    ! OK
4368    call rpn_comm_bcast(coefs%coef%id_sensor, 1, 'MPI_INTEGER', 0, 'GRID', ierr)  ! OK 
4369    call rpn_comm_bcast(coefs%coef%id_comp_lvl, 1, 'MPI_INTEGER', 0, 'GRID', ierr)! OK
4370    call rpn_comm_bcast(coefs%coef%id_comp_pc, 1, 'MPI_INTEGER', 0, 'GRID', ierr) ! OK
4371
4372    call rpn_comm_bcast(coefs%coef%fmv_model_ver, 1, 'MPI_INTEGER', 0, 'GRID', ierr) !ok
4373    call rpn_comm_bcast(coefs%coef%fmv_chn, 1, 'MPI_INTEGER', 0, 'GRID', ierr) !ok
4374    call rpn_comm_bcast(coefs%coef%fmv_gas, 1, 'MPI_INTEGER', 0, 'GRID', ierr) !ok
4375    call rpn_comm_bcast(coefs%coef%fmv_ori_nchn, 1, 'MPI_INTEGER', 0, 'GRID', ierr) !ok
4376
4377    call rpn_comm_bcast(coefs%coef%nmixed, 1, 'MPI_INTEGER', 0, 'GRID', ierr)          ! number of variables/predictors for Mixed Gases
4378    call rpn_comm_bcast(coefs%coef%nwater, 1, 'MPI_INTEGER', 0, 'GRID', ierr)          ! number of variables/predictors for Water Vapour
4379    call rpn_comm_bcast(coefs%coef%nozone, 1, 'MPI_INTEGER', 0, 'GRID', ierr)          ! number of variables/predictors for Ozone
4380    call rpn_comm_bcast(coefs%coef%nwvcont, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of variables/predictors for WV continuum
4381    call rpn_comm_bcast(coefs%coef%nco2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)            ! number of variables/predictors for CO2
4382    call rpn_comm_bcast(coefs%coef%nn2o , 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of variables/predictors for N2O
4383    call rpn_comm_bcast(coefs%coef%nco, 1, 'MPI_INTEGER', 0, 'GRID', ierr)             ! number of variables/predictors for CO
4384    call rpn_comm_bcast(coefs%coef%nch4, 1, 'MPI_INTEGER', 0, 'GRID', ierr)            ! number of variables/predictors for CH4
4385    call rpn_comm_bcast(coefs%coef%nso2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)            ! number of variables/predictors for SO2
4386
4387    call rpn_comm_bcast(coefs%coef%nlevels, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of levels(pres/absorber) same for all gases
4388    call rpn_comm_bcast(coefs%coef%nlayers, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of layers(pres/absorber) nlevels-1
4389    call rpn_comm_bcast(coefs%coef%pmc_nlay, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4390    call rpn_comm_bcast(coefs%coef%pmc_nvar, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4391    call rpn_comm_bcast(coefs%coef%IncZeeman, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)       ! Flag to include Zeeman effect for this sensor
4392    call rpn_comm_bcast(coefs%coef%solarcoef, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)       ! Flag to include solar reflection
4393    call rpn_comm_bcast(coefs%coef%nltecoef, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)        ! Flag to include nlte corrections
4394    call rpn_comm_bcast(coefs%coef%pmc_shift, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
4395
4396    call rpn_comm_bcast(coefs%coef%ncmixed, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of coefficients for Mixed Gases
4397    call rpn_comm_bcast(coefs%coef%ncwater, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of coefficients for Water Vapour
4398    call rpn_comm_bcast(coefs%coef%ncozone, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of coefficients for Ozone
4399    call rpn_comm_bcast(coefs%coef%ncwvcont, 1, 'MPI_INTEGER', 0, 'GRID', ierr)        ! number of coefficients for WV continuum
4400    call rpn_comm_bcast(coefs%coef%ncco2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for CO2
4401    call rpn_comm_bcast(coefs%coef%ncn2o, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for N2O
4402    call rpn_comm_bcast(coefs%coef%ncco , 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for CO
4403    call rpn_comm_bcast(coefs%coef%ncch4, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for CH4
4404    call rpn_comm_bcast(coefs%coef%ncso2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for SO2
4405
4406    call rpn_comm_bcast(coefs%coef%nccmixed, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of coefficients for Mixed Gases
4407    call rpn_comm_bcast(coefs%coef%nccwater, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of coefficients for Water Vapour
4408    call rpn_comm_bcast(coefs%coef%nccozone, 1, 'MPI_INTEGER', 0, 'GRID', ierr)         ! number of coefficients for Ozone
4409    call rpn_comm_bcast(coefs%coef%nccwvcont, 1, 'MPI_INTEGER', 0, 'GRID', ierr)        ! number of coefficients for WV continuum
4410    call rpn_comm_bcast(coefs%coef%nccco2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for CO2
4411    call rpn_comm_bcast(coefs%coef%nccn2o, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for N2O
4412    call rpn_comm_bcast(coefs%coef%nccco , 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for CO
4413    call rpn_comm_bcast(coefs%coef%nccch4, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for CH4
4414    call rpn_comm_bcast(coefs%coef%nccso2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)           ! number of coefficients for SO2
4415
4416    call rpn_comm_bcast(coefs%coef%ws_nomega, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4417
4418    call rpn_comm_bcast(coefs%coef%id_creation_date, 3, 'MPI_INTEGER', 0, 'GRID', ierr) ! OK 
4419    call rpn_comm_bcastc(coefs%coef%id_creation, 80, 'MPI_CHARACTER', 0, 'GRID', ierr)  ! OK 
4420    call rpn_comm_bcastc(coefs%coef%id_Common_name, 32, 'MPI_CHARACTER', 0, 'GRID', ierr) !OK
4421    do i=1, 100
4422      call rpn_comm_bcastc(coefs%coef%line_by_line(i), 132, 'MPI_CHARACTER', 0, 'GRID', ierr) !ok
4423      call rpn_comm_bcastc(coefs%coef%readme_srf(i), 132, 'MPI_CHARACTER', 0, 'GRID', ierr) !ok
4424    end do
4425    call rpn_comm_bcastc(coefs%coef%fmv_model_def, 32, 'MPI_CHARACTER', 0, 'GRID', ierr)  !OK
4426    call rpn_comm_bcast(coefs%coef%fc_planck_c1, 1, 'MPI_REAL8', 0, 'GRID', ierr) ! first radiation constant (mW/(m2*sr*cm-4)) !ok
4427    call rpn_comm_bcast(coefs%coef%fc_planck_c2, 1, 'MPI_REAL8', 0, 'GRID', ierr) !second radiation constant (mW/(m2*sr*cm-4)) !ok
4428    call rpn_comm_bcast(coefs%coef%fc_sat_height, 1, 'MPI_REAL8', 0, 'GRID', ierr)! satellite nominal altitude (km) !ok
4429
4430    call rpn_comm_bcast(coefs%coef%pmc_lengthcell, 1, 'MPI_REAL8', 0, 'GRID', ierr)
4431    call rpn_comm_bcast(coefs%coef%pmc_tempcell, 1, 'MPI_REAL8', 0, 'GRID', ierr)
4432    call rpn_comm_bcast(coefs%coef%pmc_betaplus1, 1, 'MPI_REAL8', 0, 'GRID', ierr)
4433    ! FASTEM section
4434    call rpn_comm_bcast(coefs%coef%ssirem_ver, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4435    call rpn_comm_bcast(coefs%coef%iremis_version, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4436    call rpn_comm_bcast(coefs%coef%iremis_ncoef, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4437    call rpn_comm_bcast(coefs%coef%iremis_angle0, 1, 'MPI_REAL8', 0, 'GRID', ierr)
4438    call rpn_comm_bcast(coefs%coef%iremis_tskin0, 1, 'MPI_REAL8', 0, 'GRID', ierr)
4439    call rpn_comm_bcast(coefs%coef%ratoe, 1, 'MPI_REAL8', 0, 'GRID', ierr) 
4440    ! then variable size vectors
4441    ! this one must be done first because it is used to dimension other ones ....
4442    if (mmpi_myid > 0) allocate( coefs%coef%fmv_lvl(coefs%coef%fmv_gas))
4443    call rpn_comm_bcast(coefs%coef%fmv_lvl, coefs%coef%fmv_gas, 'MPI_INTEGER', 0, 'GRID', ierr)
4444    if (mmpi_myid > 0) then
4445      if (coefs%coef%nltecoef) allocate( coefs%coef%nlte_coef)
4446      allocate( coefs%coef%fmv_gas_id(coefs%coef%fmv_gas))
4447      allocate( coefs%coef%fmv_gas_pos(ngases_max)) !size is from rttov consts
4448      allocate( coefs%coef%fmv_var(coefs%coef%fmv_gas))
4449      allocate( coefs%coef%fmv_coe(coefs%coef%fmv_gas)) ! number of coefficients by gas (fmv_gas)
4450      allocate( coefs%coef%fmv_ncorr(coefs%coef%fmv_gas)) ! number of coefs by gas for correction term (fmv_gas) (v13 only)
4451      allocate( coefs%coef%ws_npoint(coefs%coef%ws_nomega) )
4452      allocate( coefs%coef%ws_k_omega(coefs%coef%ws_nomega) )
4453      allocate( coefs%coef%ref_prfl_p(coefs%coef%nlevels ) )
4454      allocate( coefs%coef%ref_prfl_t(coefs%coef%nlevels, coefs%coef%fmv_gas ) )
4455      allocate( coefs%coef%ref_prfl_mr(coefs%coef%nlevels, coefs%coef%fmv_gas ) )
4456      allocate( coefs%coef%bkg_prfl_mr(coefs%coef%nlevels, coefs%coef%fmv_gas ) )
4457      allocate( coefs%coef%lim_prfl_p(coefs%coef%nlevels ) )
4458      allocate( coefs%coef%lim_prfl_tmax(coefs%coef%fmv_lvl(gas_id_mixed) ) )
4459      allocate( coefs%coef%lim_prfl_tmin(coefs%coef%fmv_lvl(gas_id_mixed) ) )
4460      allocate( coefs%coef%lim_prfl_gmax(coefs%coef%fmv_lvl(gas_id_mixed), coefs%coef%fmv_gas ) )
4461      allocate( coefs%coef%lim_prfl_gmin(coefs%coef%fmv_lvl(gas_id_mixed), coefs%coef%fmv_gas ) )
4462      allocate( coefs%coef%env_prfl_tmax(coefs%coef%nlevels ) )
4463      allocate( coefs%coef%env_prfl_tmin(coefs%coef%nlevels ) )
4464      allocate( coefs%coef%env_prfl_gmax(coefs%coef%nlevels, coefs%coef%fmv_gas ) )
4465      allocate( coefs%coef%env_prfl_gmin(coefs%coef%nlevels, coefs%coef%fmv_gas ) )
4466      allocate( coefs%coef%dpp(0:coefs%coef%nlayers) )
4467      allocate( coefs%coef%dp(coefs%coef%nlayers) )
4468      allocate( coefs%coef%tstar(coefs%coef%nlayers) )
4469      allocate( coefs%coef%tstar_r(coefs%coef%nlayers) )
4470      allocate( coefs%coef%tstar_wsum_r(0:coefs%coef%nlayers) )
4471      if (coefs%coef%fmv_model_ver == 8) &
4472           allocate( coefs%coef%tstarmod_wsum_r(coefs%coef%nlayers) )
4473      if (coefs%coef%fmv_model_ver <= 9) &
4474           allocate( coefs%coef%tstar_uwsum_r(0:coefs%coef%nlayers) )
4475      allocate( coefs%coef%wstar(coefs%coef%nlayers) )
4476      allocate( coefs%coef%wstar_r(coefs%coef%nlayers) )
4477      allocate( coefs%coef%wstar_wsum_r(0:coefs%coef%nlayers) )
4478      allocate( coefs%coef%wtstar_wsum_r(0:coefs%coef%nlayers) )
4479    end if
4480
4481    call broadcastI41dArray( coefs%coef%fmv_gas_id )
4482    call broadcastI41dArray( coefs%coef%fmv_gas_pos )
4483    call broadcastI41dArray( coefs%coef%fmv_var )
4484    call broadcastI41dArray( coefs%coef%fmv_coe )
4485    call broadcastI41dArray( coefs%coef%fmv_ncorr )
4486    call broadcastR81dArray( coefs%coef%ws_npoint )
4487    call broadcastR81dArray( coefs%coef%ws_k_omega )
4488    call broadcastR81dArray( coefs%coef%ref_prfl_p )
4489    call broadcastR82dArray( coefs%coef%ref_prfl_t )
4490    call broadcastR82dArray( coefs%coef%ref_prfl_mr )
4491    call broadcastR82dArray( coefs%coef%bkg_prfl_mr )
4492    call broadcastR81dArray( coefs%coef%lim_prfl_p )
4493    call broadcastR81dArray( coefs%coef%lim_prfl_tmax )
4494    call broadcastR81dArray( coefs%coef%lim_prfl_tmin )
4495    call broadcastR82dArray( coefs%coef%lim_prfl_gmax )
4496    call broadcastR82dArray( coefs%coef%lim_prfl_gmin )
4497    call broadcastR81dArray( coefs%coef%env_prfl_tmax )
4498    call broadcastR81dArray( coefs%coef%env_prfl_tmin )
4499    call broadcastR82dArray( coefs%coef%env_prfl_gmax )
4500    call broadcastR82dArray( coefs%coef%env_prfl_gmin )
4501    call broadcastR81dArray( coefs%coef%dp )
4502    call broadcastR81dArray( coefs%coef%dpp )
4503    call broadcastR81dArray( coefs%coef%tstar ) 
4504    call broadcastR81dArray( coefs%coef%tstar_r )
4505    call broadcastR81dArray( coefs%coef%tstar_wsum_r )
4506    if (coefs%coef%fmv_model_ver == 8) &
4507         call broadcastR81dArray( coefs%coef%tstarmod_wsum_r )
4508    if (coefs%coef%fmv_model_ver <= 9) &
4509         call broadcastR81dArray( coefs%coef%tstar_uwsum_r )
4510    call broadcastR81dArray( coefs%coef%wstar )
4511    call broadcastR81dArray( coefs%coef%wstar_r )
4512    call broadcastR81dArray( coefs%coef%wstar_wsum_r )
4513    call broadcastR81dArray( coefs%coef%wtstar_wsum_r )
4514    if (coefs%coef%nozone > 0) then
4515      if (mmpi_myid > 0) then
4516        allocate( coefs%coef%to3star(coefs%coef%nlayers) )
4517        allocate( coefs%coef%ostar(coefs%coef%nlayers) )
4518        allocate( coefs%coef%to3star_r(coefs%coef%nlayers) )
4519        allocate( coefs%coef%ostar_r(coefs%coef%nlayers) )
4520        allocate( coefs%coef%ostar_wsum_r(0:coefs%coef%nlayers) )
4521      end if
4522      call rpn_comm_bcast(coefs%coef%to3star, size(coefs%coef%to3star) , 'MPI_REAL8', 0, 'GRID', ierr) 
4523      call rpn_comm_bcast(coefs%coef%ostar, size(coefs%coef%ostar) , 'MPI_REAL8', 0, 'GRID', ierr)
4524      call rpn_comm_bcast(coefs%coef%to3star_r, size(coefs%coef%to3star_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4525      call rpn_comm_bcast(coefs%coef%ostar_r, size(coefs%coef%ostar_r) , 'MPI_REAL8', 0, 'GRID', ierr)
4526      call rpn_comm_bcast(coefs%coef%ostar_wsum_r, size(coefs%coef%ostar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4527    end if
4528    if ( coefs%coef%nco2 > 0) then
4529      if (mmpi_myid>0) then
4530        allocate( coefs%coef%co2star(coefs%coef%nlayers) )
4531        allocate( coefs%coef%co2star_r(coefs%coef%nlayers) )
4532        allocate( coefs%coef%co2star_wsum_r(0:coefs%coef%nlayers) )
4533      end if
4534      call rpn_comm_bcast(coefs%coef%co2star, size(coefs%coef%co2star) , 'MPI_REAL8', 0, 'GRID', ierr) 
4535      call rpn_comm_bcast(coefs%coef%co2star_r, size(coefs%coef%co2star_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4536      call rpn_comm_bcast(coefs%coef%co2star_wsum_r, size(coefs%coef%co2star_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4537    end if
4538    if ( coefs%coef%nn2o > 0) then
4539      if (mmpi_myid>0) then
4540        allocate( coefs%coef%n2ostar(coefs%coef%nlayers) )
4541        allocate( coefs%coef%n2ostar_r(coefs%coef%nlayers) )
4542        allocate( coefs%coef%n2ostar_wsum_r(0:coefs%coef%nlayers) )
4543        allocate( coefs%coef%n2otstar_wsum_r(0:coefs%coef%nlayers) )
4544      end if
4545      call rpn_comm_bcast(coefs%coef%n2ostar, size(coefs%coef%n2ostar) , 'MPI_REAL8', 0, 'GRID', ierr) 
4546      call rpn_comm_bcast(coefs%coef%n2ostar_r, size(coefs%coef%n2ostar_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4547      call rpn_comm_bcast(coefs%coef%n2ostar_wsum_r, size(coefs%coef%n2ostar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4548      call rpn_comm_bcast(coefs%coef%n2otstar_wsum_r, size(coefs%coef%n2otstar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4549    end if
4550    if ( coefs%coef%nco > 0) then
4551      if (mmpi_myid>0) then
4552        allocate( coefs%coef%costar(coefs%coef%nlayers) )
4553        allocate( coefs%coef%costar_r(coefs%coef%nlayers) )
4554        allocate( coefs%coef%costar_wsum_r(0:coefs%coef%nlayers) )
4555        allocate( coefs%coef%cotstar_wsum_r(0:coefs%coef%nlayers) )
4556      end if
4557      call rpn_comm_bcast(coefs%coef%costar, size(coefs%coef%costar) , 'MPI_REAL8', 0, 'GRID', ierr)
4558      call rpn_comm_bcast(coefs%coef%costar_r, size(coefs%coef%costar_r) , 'MPI_REAL8', 0, 'GRID', ierr)
4559      call rpn_comm_bcast(coefs%coef%costar_wsum_r, size(coefs%coef%costar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr)
4560      call rpn_comm_bcast(coefs%coef%cotstar_wsum_r, size(coefs%coef%cotstar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4561    end if
4562    if ( coefs%coef%nch4 > 0) then
4563      if (mmpi_myid>0) then
4564        allocate( coefs%coef%ch4star(coefs%coef%nlayers) )
4565        allocate( coefs%coef%ch4star_r(coefs%coef%nlayers) )
4566        allocate( coefs%coef%ch4star_wsum_r(0:coefs%coef%nlayers) )
4567        allocate( coefs%coef%ch4tstar_wsum_r(coefs%coef%nlayers) )
4568      end if
4569      call rpn_comm_bcast(coefs%coef%ch4star, size(coefs%coef%ch4star) , 'MPI_REAL8', 0, 'GRID', ierr) 
4570      call rpn_comm_bcast(coefs%coef%ch4star_r, size(coefs%coef%ch4star_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4571      call rpn_comm_bcast(coefs%coef%ch4star_wsum_r, size(coefs%coef%ch4star_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4572      call rpn_comm_bcast(coefs%coef%ch4tstar_wsum_r, size(coefs%coef%ch4tstar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr) 
4573    end if
4574    if (coefs%coef%nso2 > 0) then
4575      if (mmpi_myid>0) then
4576        allocate( coefs%coef%so2star(coefs%coef%nlayers) )
4577        allocate( coefs%coef%so2star_r(coefs%coef%nlayers) )
4578        allocate( coefs%coef%so2star_wsum_r(0:coefs%coef%nlayers) )
4579        allocate( coefs%coef%so2tstar_wsum_r(coefs%coef%nlayers) )
4580      end if
4581      call rpn_comm_bcast(coefs%coef%so2star, size(coefs%coef%so2star) , 'MPI_REAL8', 0, 'GRID', ierr)
4582      call rpn_comm_bcast(coefs%coef%so2star_r, size(coefs%coef%so2star_r) , 'MPI_REAL8', 0, 'GRID', ierr)
4583      call rpn_comm_bcast(coefs%coef%so2star_wsum_r, size(coefs%coef%so2star_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr)
4584      call rpn_comm_bcast(coefs%coef%so2tstar_wsum_r, size(coefs%coef%so2tstar_wsum_r) , 'MPI_REAL8', 0, 'GRID', ierr)
4585    end if
4586    ! Fourth step: channel dependent parameters are extracted according to the channel list and sent to each MPI task
4587    coefs%coef%fmv_chn = size( channels )
4588
4589    if (mmpi_myid == 0) deallocate ( coefs%coef%ff_ori_chn)
4590    allocate ( coefs%coef%ff_ori_chn(coefs%coef%fmv_chn) )
4591    coefs%coef%ff_ori_chn =  channels
4592
4593    do i=1,  coefs%coef%fmv_chn
4594      loopj2:do j=1, countUniqueChannel
4595        if (listAll(j) == channels(i)) then
4596          indexchan(i) = j
4597          exit loopj2
4598        end if
4599      end do loopj2
4600    end do
4601    
4602    ! 1D arrays first
4603    call extractI41dArray(coefs%coef%pw_val_chn, countUniqueChannel,indexchan)
4604    call extractI41dArray(coefs%coef%ff_val_chn, countUniqueChannel,indexchan)
4605    call extractR81dArray(coefs%coef%ff_cwn, countUniqueChannel,indexchan)
4606    call extractR81dArray(coefs%coef%ff_bco, countUniqueChannel,indexchan)
4607    call extractR81dArray(coefs%coef%ff_bcs, countUniqueChannel,indexchan) 
4608    call extractR81dArray(coefs%coef%ff_gam, countUniqueChannel,indexchan)
4609    call extractI41dArray(coefs%coef%tt_val_chn, countUniqueChannel,indexchan) 
4610    call extractR81dArray(coefs%coef%tt_a0, countUniqueChannel,indexchan) 
4611    call extractR81dArray(coefs%coef%tt_a1, countUniqueChannel,indexchan) 
4612    call extractI41dArray(coefs%coef%ss_val_chn, countUniqueChannel,indexchan) 
4613    call extractR81dArray(coefs%coef%ss_solar_spectrum, countUniqueChannel,indexchan)
4614    if ( coefs%coef%fmv_model_ver > 9) then
4615      call extractR81dArray(coefs%coef%ss_rayleigh_ext, countUniqueChannel,indexchan)
4616    end if
4617    call extractCmplx81dArray(coefs%coef%woc_waopc_ow, countUniqueChannel, indexchan) 
4618    call extractCmplx81dArray(coefs%coef%woc_waopc_fw, countUniqueChannel, indexchan)
4619  
4620    call extractI41dArray(coefs%coef%fastem_polar, countUniqueChannel,indexchan)
4621    call extractR81dArray(coefs%coef%pol_phi, countUniqueChannel,indexchan)
4622    call extractR81dArray(coefs%coef%ssirem_a0, countUniqueChannel,indexchan)
4623    call extractR81dArray(coefs%coef%ssirem_a1, countUniqueChannel,indexchan)
4624    call extractR81dArray(coefs%coef%ssirem_a2, countUniqueChannel,indexchan)
4625    call extractR81dArray(coefs%coef%ssirem_xzn1, countUniqueChannel,indexchan)
4626    call extractR81dArray(coefs%coef%ssirem_xzn2, countUniqueChannel,indexchan)
4627
4628    call extractR81dArray(coefs%coef%planck1, countUniqueChannel,indexchan)
4629    call extractR81dArray(coefs%coef%planck2, countUniqueChannel,indexchan)
4630    if (coefs%coef%id_sensor == sensor_id_mw .or. coefs%coef%id_sensor == sensor_id_po) &
4631         call extractR81dArray(coefs%coef%frequency_ghz, countUniqueChannel,indexchan)
4632
4633    call extractR81dArray(coefs%coef%pmc_pnominal, countUniqueChannel,indexchan)
4634    call extractR81dArray(coefs%coef%pmc_ppmc, countUniqueChannel,indexchan)
4635    call extractR81dArray(coefs%coef%pol_fac_v, countUniqueChannel,indexchan)
4636    call extractR81dArray(coefs%coef%pol_fac_h, countUniqueChannel,indexchan)
4637
4638    ! 2D arrays
4639    call extractR82dArray(coefs%coef%iremis_coef,coefs%coef%iremis_ncoef,countUniqueChannel,indexchan)
4640    ! 3D arrays
4641    call extractR83dArray(coefs%coef%pmc_coef,coefs%coef%pmc_nlay,countUniqueChannel,coefs%coef%pmc_nvar,indexchan)
4642
4643    ! then coefficients. It is more complicated with RTTOV12
4644    call dispatch_fast_coef(errorStatus, coefs%coef%thermal, coefs%coef%fmv_gas_id, coefs%coef%fmv_coe, coefs%coef%fmv_model_ver, &
4645         coefs%coef%nlayers, coefs%coef%fmv_gas)
4646    if (coefs%coef%fmv_model_ver > 9) THEN
4647      call dispatch_fast_coef(errorStatus, coefs%coef%thermal_corr, coefs%coef%fmv_gas_id, coefs%coef%fmv_ncorr, coefs%coef%fmv_model_ver, &
4648           coefs%coef%nlayers, coefs%coef%fmv_gas)
4649    end if
4650    if (coefs%coef%solarcoef) then
4651      call dispatch_fast_coef(errorStatus, coefs%coef%solar, coefs%coef%fmv_gas_id, coefs%coef%fmv_coe, coefs%coef%fmv_model_ver, &
4652           coefs%coef%nlayers, coefs%coef%fmv_gas)
4653      if (coefs%coef%fmv_model_ver > 9) THEN
4654        call dispatch_fast_coef(errorStatus, coefs%coef%solar_corr, coefs%coef%fmv_gas_id, coefs%coef%fmv_ncorr, coefs%coef%fmv_model_ver, &
4655             coefs%coef%nlayers, coefs%coef%fmv_gas)
4656      end if
4657    end if
4658
4659    if (coefs%coef%nltecoef) then
4660
4661      call rpn_comm_bcast(coefs%coef%nlte_coef%ncoef, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4662      call rpn_comm_bcast(coefs%coef%nlte_coef%nsol, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4663      call rpn_comm_bcast(coefs%coef%nlte_coef%nsat, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4664      call rpn_comm_bcast(coefs%coef%nlte_coef%nchan, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4665      call rpn_comm_bcast(coefs%coef%nlte_coef%start_chan, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4666
4667      allocate(nlte_chans(coefs%coef%fmv_chn)) ! Index of selected channels in nlte_coefs array in the file
4668
4669      nlte_count = 0  ! Number of NLTE channels being read in
4670      nlte_start = 0  ! Index (in input channel list) of first NLTE channel being read in
4671      do i = 1, coefs%coef%fmv_chn
4672        if (channels(i) >= coefs%coef%nlte_coef%start_chan .and. &
4673             channels(i) < coefs%coef%nlte_coef%start_chan + coefs%coef%nlte_coef%nchan) then
4674          nlte_count = nlte_count + 1
4675          nlte_chans(nlte_count) = channels(i) - coefs%coef%nlte_coef%start_chan + 1
4676          if (nlte_count == 1) nlte_start = i
4677        end if
4678      end do
4679
4680      coefs%coef%nltecoef = ( nlte_count > 0)
4681
4682      nlte_file_nchan  = coefs%coef%nlte_coef%nchan
4683
4684      ! Reset NLTE channel variables according to input channel limit
4685      coefs%coef%nlte_coef%start_chan  = nlte_start
4686      coefs%coef%nlte_coef%nchan      = nlte_count
4687
4688      if (mmpi_myid > 0) then
4689         allocate (coefs%coef%nlte_coef%sec_sat(coefs%coef%nlte_coef%nsat) )
4690         allocate (coefs%coef%nlte_coef%sol_zen_angle(coefs%coef%nlte_coef%nsol) )
4691         allocate (coefs%coef%nlte_coef%sat_zen_angle(coefs%coef%nlte_coef%nsat) )
4692         allocate (coefs%coef%nlte_coef%cos_sol(coefs%coef%nlte_coef%nsol) )
4693      end if
4694      call rpn_comm_bcast(coefs%coef%nlte_coef%sec_sat, coefs%coef%nlte_coef%nsat, 'MPI_REAL8', 0, 'GRID', ierr)
4695      call rpn_comm_bcast(coefs%coef%nlte_coef%sol_zen_angle, coefs%coef%nlte_coef%nsol, 'MPI_REAL8', 0, 'GRID', ierr)
4696      call rpn_comm_bcast(coefs%coef%nlte_coef%sat_zen_angle, coefs%coef%nlte_coef%nsat, 'MPI_REAL8', 0, 'GRID', ierr)
4697      call rpn_comm_bcast(coefs%coef%nlte_coef%cos_sol, coefs%coef%nlte_coef%nsol, 'MPI_REAL8', 0, 'GRID', ierr)
4698
4699      allocate(bigArray(coefs%coef%nlte_coef%ncoef, coefs%coef%nlte_coef%nsat, &
4700           coefs%coef%nlte_coef%nsol, nlte_file_nchan) )
4701
4702      if (mmpi_myid == 0) then
4703         do ichan = 1, nlte_file_nchan
4704            do isol = 1, coefs%coef%nlte_coef%nsol
4705               do isat = 1, coefs%coef%nlte_coef%nsat
4706                  do I=1, coefs%coef%nlte_coef%ncoef
4707                     bigArray(i, isat, isol, ichan) = coefs%coef%nlte_coef%coef(i,isat,isol,ichan)
4708                  end do
4709               end do
4710            end do
4711         end do
4712         deallocate(  coefs%coef%nlte_coef%coef )
4713      end if
4714
4715      call rpn_comm_bcast(bigArray, size(bigArray), 'MPI_REAL8', 0, 'GRID', ierr)
4716      allocate(coefs%coef%nlte_coef%coef(coefs%coef%nlte_coef%ncoef, coefs%coef%nlte_coef%nsat, &
4717           coefs%coef%nlte_coef%nsol, nlte_count))
4718      coefs%coef%nlte_coef%coef(:,:,:,:) = bigArray(:,:,:,nlte_chans(1:nlte_count))
4719      deallocate(nlte_chans, bigArray)
4720       
4721    end if
4722
4723    if (mmpi_myid==0 .and. associated(coefs%coef%bounds) )  deallocate(coefs%coef%bounds)
4724  
4725    !allocate bounds array to store opdep calculation layer limits
4726    !1st dim: upper boundary layer [ub](above which coefs all zeros), lower boundary layer [lb]
4727    !4th dim: thermal layer limits, solar layer limits
4728    allocate(coefs%coef%bounds(2, coefs%coef%fmv_gas, coefs%coef%fmv_chn, 2))
4729    call set_fastcoef_level_bounds(coefs%coef, coefs%coef%thermal, thermal = .true._jplm)
4730    ! if the solar_fast_coefficients section is not present then point the solar coefs to the thermal coefs
4731    if (coefs%coef%solarcoef) then
4732      call set_fastcoef_level_bounds(coefs%coef, coefs%coef%solar, thermal = .false._jplm)
4733    else
4734      coefs%coef%solar => coefs%coef%thermal
4735      coefs%coef%solar_corr => coefs%coef%thermal_corr
4736      coefs%coef%bounds(:,:,:,2) = coefs%coef%bounds(:,:,:,1)
4737    end if
4738
4739    coefs%coef%ff_val_bc = any(coefs%coef%ff_bco(:) /= 0.0d0) .or. any(coefs%coef%ff_bcs(:) /= 1.d0)
4740    coefs%coef%ff_val_gam = any(coefs%coef%ff_gam(:) /= 1.d0)
4741
4742    ! surface water reflectance for visible/near-ir channels
4743    if (any(coefs%coef%ss_val_chn == 2)) then
4744      if ( mmpi_myid==0) deallocate(coefs%coef%refl_visnir_ow, &
4745           coefs%coef%refl_visnir_fw, stat = errorStatus)
4746      allocate(coefs%coef%refl_visnir_ow(coefs%coef%fmv_chn), &
4747           coefs%coef%refl_visnir_fw(coefs%coef%fmv_chn), stat = errorStatus)
4748      call rttov_refl_water_interp(coefs%coef%ff_cwn, coefs%coef%refl_visnir_ow, coefs%coef%refl_visnir_fw)
4749    end if
4750
4751    if (coefs%coef%pmc_shift .and. mmpi_myid > 0) then
4752      allocate(coefs%coef%pmc_ppmc(coefs%coef%fmv_chn), stat = errorStatus)
4753    else
4754      nullify(coefs%coef%pmc_pnominal, coefs%coef%pmc_coef, coefs%coef%pmc_ppmc)
4755    end if
4756
4757    contains
4758
4759    subroutine nullify_gas_coef_pointers(fast_coef)
4760      implicit none
4761
4762      ! Arguments:
4763      type(rttov_fast_coef), intent(inout) :: fast_coef
4764
4765      nullify (fast_coef%mixedgas,&
4766           fast_coef%watervapour, &
4767           fast_coef%ozone,       &
4768           fast_coef%wvcont,      &
4769           fast_coef%co2,         &
4770           fast_coef%n2o,         &
4771           fast_coef%co,          &
4772           fast_coef%ch4,         &
4773           fast_coef%so2)
4774    end subroutine nullify_gas_coef_pointers
4775
4776    subroutine dispatch_fast_coef(err, fast_coef, gas_ids, ncoefs, version, nlayers, ngas)
4777      implicit none
4778
4779      ! Arguments:
4780      integer,                        intent(out)   :: err
4781      type(rttov_fast_coef), pointer, intent(inout) :: fast_coef(:)
4782      integer(jpim),                  intent(in)    :: gas_ids(:)
4783      integer(jpim),                  intent(in)    :: ncoefs(:)
4784      integer(jpim),                  intent(in)    :: version
4785      integer(jpim),                  intent(in)    :: nlayers
4786      integer(jpim),                  intent(in)    :: ngas
4787
4788      ! Locals:
4789      integer(jpim) :: channelIndex, gasIndex, layerIndex, coefIndex
4790      real(8), allocatable :: bigArray(:,:,:,:)
4791      logical :: allocated0
4792
4793      allocate(bigArray(countUniqueChannel,maxval(ncoefs),ngas,nlayers), stat=err )
4794      bigArray(:,:,:,:) = 0.0d0
4795
4796      if (mmpi_myid > 0) then
4797        allocate (fast_coef(countUniqueChannel) )
4798        do channelIndex = 1, countUniqueChannel
4799          allocate(fast_coef(channelIndex)%gasarray(ngas) )
4800          do gasIndex = 1, ngas
4801            allocate (fast_coef(channelIndex)%gasarray(gasIndex)%coef( ncoefs(gasIndex), nlayers) )
4802          end do
4803        end do
4804      end if
4805
4806      do channelIndex = 1, countUniqueChannel
4807        do gasIndex = 1, ngas
4808          call broadcastR82dArray( fast_coef(channelIndex)%gasarray(gasIndex)%coef )
4809        end do
4810      end do
4811
4812      do channelIndex = 1, countUniqueChannel  
4813        do gasIndex = 1, ngas
4814          associated0 = associated( fast_coef(channelIndex)%gasarray(gasIndex)%coef )
4815          call rpn_comm_bcast(associated0, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
4816          if (associated0) then
4817            do layerIndex=1, nlayers
4818              do coefIndex=1, ncoefs(gasIndex)
4819                bigArray(channelIndex,coefIndex,gasIndex,layerIndex) = fast_coef(channelIndex)%gasarray(gasIndex)%coef(coefIndex,layerIndex)
4820              end do
4821            end do
4822          end if
4823        end do
4824      end do
4825
4826      do channelIndex = 1, countUniqueChannel
4827        do gasIndex = 1, ngas
4828          associated0 = associated(fast_coef(channelIndex)%gasarray(gasIndex)%coef)
4829          if (associated0) deallocate(fast_coef(channelIndex)%gasarray(gasIndex)%coef)
4830        end do
4831        deallocate(fast_coef(channelIndex)%gasarray)
4832      end do
4833      deallocate(fast_coef)
4834      allocate (fast_coef(coefs%coef%fmv_chn) )
4835      do channelIndex = 1, coefs%coef%fmv_chn
4836        allocate (fast_coef(channelIndex)%gasarray(ngas) )
4837        call nullify_gas_coef_pointers( fast_coef(channelIndex) )
4838        do gasIndex = 1, ngas
4839          if (any( bigArray(indexchan(channelIndex),:,gasIndex,:) /= 0.) ) then
4840            allocate (fast_coef(channelIndex)%gasarray(gasIndex)%coef( ncoefs(gasIndex), nlayers) )
4841            do layerIndex=1, nlayers
4842              do coefIndex=1, ncoefs(gasIndex)
4843                fast_coef(channelIndex)%gasarray(gasIndex)%coef(coefIndex,layerIndex)  = bigArray(indexchan(channelIndex),coefIndex,gasIndex,layerIndex)
4844              end do
4845            end do
4846          end if
4847          call set_pointers(fast_coef(channelIndex), gasIndex, gas_ids(gasIndex))
4848        end do
4849      end do
4850
4851      deallocate(bigArray, stat=err )
4852
4853    end subroutine dispatch_fast_coef
4854
4855  end subroutine tvs_rttov_read_coefs
4856
4857
4858  subroutine extractI41dArray(array,oldSize,index)
4859    implicit none
4860
4861    ! Arguments:
4862    integer, pointer, intent(inout) :: array(:)
4863    integer,          intent(in)    :: oldSize
4864    integer,          intent(in)    :: index(:)
4865
4866    ! Locals:
4867    integer :: newSize, tmpI41d(oldSize), ierr, trueSize
4868
4869    if (mmpi_myid == 0) then
4870      if (associated(array)) then
4871        trueSize = size(array)
4872      else
4873        trueSize = 0
4874      end if
4875    end if
4876    ierr = 0
4877    call rpn_comm_bcast(trueSize, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4878    if (ierr /= 0) then
4879      write(*,*) 'error 1 in rpn_comm_bcast', ierr, trueSize
4880      call utl_abort('extractI41dArray')
4881    end if
4882    if (trueSize < 1) return
4883    
4884    if (trueSize /= oldSize) then
4885      write(*,*) 'extractI41dArray: should not happen ', trueSize, oldSize
4886    end if
4887    
4888    newSize = size( index )
4889
4890    if (mmpi_myid > 0) allocate( array(oldSize))
4891    ierr = 0
4892    call rpn_comm_bcast(array, oldSize, 'MPI_INTEGER', 0, 'GRID', ierr)
4893    if (ierr /= 0) then
4894      write(*,*) 'error 2 in rpn_comm_bcast', ierr, array(:)
4895      call utl_abort('extractI41dArray')
4896    end if
4897    tmpI41d = array
4898    deallocate( array )
4899    allocate( array(newSize))
4900    array( : ) =  tmpI41d( index(:) )
4901  end subroutine extractI41dArray
4902  
4903  subroutine extractR81dArray(array,oldSize,index)
4904    implicit none
4905
4906    ! Arguments:
4907    real(8), pointer, intent(inout) :: array(:)
4908    integer,          intent(in)    :: oldSize
4909    integer,          intent(in)    :: index(:)
4910
4911    ! Locals:
4912    integer :: newSize, ierr, trueSize
4913    real(8) :: tmpR81d(oldSize)
4914    
4915    if (mmpi_myid == 0) then
4916      if (associated(array)) then
4917        trueSize = size(array)
4918      else
4919        trueSize = 0
4920      end if
4921    end if
4922    ierr = 0
4923    call rpn_comm_bcast(trueSize, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4924    if (ierr /= 0) then
4925      write(*,*) 'error 1 in rpn_comm_bcast', ierr, trueSize
4926      call utl_abort('extractR81dArray')
4927    end if
4928    if (trueSize < 1) return
4929    
4930    if (trueSize /= oldSize) then
4931      write(*,*) 'extractR81dArray: should not happen ', trueSize, oldSize
4932    end if
4933    
4934    newSize = size( index )
4935
4936    if (mmpi_myid > 0) allocate( array(oldSize))
4937    ierr = 0
4938    call rpn_comm_bcast(array, oldSize, 'MPI_REAL8', 0, 'GRID', ierr)
4939    if (ierr /= 0) then
4940      write(*,*) 'error 2 in rpn_comm_bcast', ierr, array(:)
4941      call utl_abort('extractR81dArray')
4942    end if
4943    tmpR81d = array
4944    deallocate( array )
4945    allocate( array(newSize))
4946    array( : ) =  tmpR81d( index(:) )
4947  end subroutine extractR81dArray
4948
4949
4950  subroutine extractR82dArray(array,oldSize1,oldSize2,index)
4951    !second dimension is for channels
4952    implicit none
4953
4954    ! Arguments:
4955    real(8), pointer, intent(inout) :: array(:,:)
4956    integer,          intent(in)    :: oldSize1
4957    integer,          intent(in)    :: oldSize2
4958    integer,          intent(in)    :: index(:)
4959
4960    ! Locals:
4961    integer :: newSize, ierr, trueSize,i
4962    real(8) :: tmpR82d(oldSize1,oldsize2)
4963    
4964    if (mmpi_myid == 0) then
4965      if (associated(array)) then
4966        trueSize = size(array)
4967      else
4968        trueSize = 0
4969      end if
4970    end if
4971    ierr = 0
4972    call rpn_comm_bcast(trueSize, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
4973    if (ierr /= 0) then
4974      write(*,*) 'error 1 in rpn_comm_bcast', ierr, trueSize
4975      call utl_abort('extractR82dArray')
4976    end if
4977    if (trueSize < 1) return
4978    
4979    if (trueSize /= oldSize1 * oldSize2) then
4980      write(*,*) 'extractR82dArray: should not happen ', trueSize, oldSize1, oldSize2
4981    end if
4982
4983    newSize = size( index )
4984
4985    if (mmpi_myid > 0) allocate( array(oldSize1,oldSize2) )
4986    ierr = 0
4987    call rpn_comm_bcast(array, oldSize1*oldSize2, 'MPI_REAL8', 0, 'GRID', ierr)
4988    if (ierr /= 0) then
4989      write(*,*) 'error 2 in rpn_comm_bcast', ierr, array(:,:)
4990      call utl_abort('extractR82dArray')
4991    end if
4992    tmpR82d = array
4993    deallocate( array )
4994    allocate( array(oldSize1,newSize))
4995    do i=1, newSize
4996      array( :,i) =  tmpR82d(:, index(i) )
4997    end do
4998  end subroutine extractR82dArray
4999
5000  subroutine extractR83dArray(array,oldSize1,oldSize2,oldSize3,index)
5001    !second dimension is for channels
5002    implicit none
5003
5004    ! Arguments:
5005    real(8), pointer, intent(inout) :: array(:,:,:)
5006    integer,          intent(in) :: oldSize1
5007    integer,          intent(in) :: oldSize2
5008    integer,          intent(in) :: oldSize3
5009    integer,          intent(in) :: index(:)
5010
5011    ! Locals:
5012    integer :: newSize, ierr, trueSize,i
5013    real(8) :: tmpR83d(oldSize1,oldSize2,oldSize3)
5014    
5015    if (mmpi_myid == 0) then
5016      if (associated(array)) then
5017        trueSize = size(array)
5018      else
5019        trueSize = 0
5020      end if
5021    end if
5022    ierr = 0
5023    call rpn_comm_bcast(trueSize, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
5024    if (ierr /= 0) then
5025      write(*,*) 'error 1 in rpn_comm_bcast', ierr, trueSize
5026      call utl_abort('extractR83dArray')
5027    end if
5028    if (trueSize < 1) return
5029
5030    if (trueSize /= oldSize1 * oldSize2 * oldSize3) then
5031      write(*,*) 'extractR83dArray: should not happen ', trueSize, oldSize1, oldSize2, oldSize3
5032    end if
5033  
5034    newSize = size( index )
5035  
5036    if (mmpi_myid > 0) allocate( array(oldSize1,oldSize2, oldSIze3) )
5037    ierr = 0
5038    call rpn_comm_bcast(array, oldSize1*oldSize2*oldSize3, 'MPI_REAL8', 0, 'GRID', ierr)
5039    if (ierr /= 0) then
5040      write(*,*) 'error 2 in rpn_comm_bcast', ierr, array(:,:,:)
5041      call utl_abort('extractR83dArray')
5042    end if
5043    tmpR83d = array
5044    deallocate( array )
5045    allocate( array(oldSize1,newSize,oldSize3))
5046    do i=1, newSize
5047      array( :,i,:) =  tmpR83d(:, index(i),: )
5048    end do
5049  end subroutine extractR83dArray
5050
5051  subroutine extractCmplx81dArray(array,oldSize,index)
5052    implicit none
5053
5054    ! Arguments:
5055    complex(kind=8), pointer, intent(inout) :: array(:)
5056    integer,                  intent(in) :: oldSize
5057    integer,                  intent(in) :: index(:)
5058
5059    ! Locals:
5060    integer :: newSize, ierr, trueSize
5061    complex(kind=8) :: tmpCx81d(oldSize)
5062
5063    if (mmpi_myid == 0) then
5064      if (associated(array)) then
5065        trueSize = size(array)
5066      else
5067        trueSize = 0
5068      end if
5069    end if
5070    ierr = 0
5071    call rpn_comm_bcast(trueSize, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
5072    if (ierr /= 0) then
5073      write(*,*) 'error 1 in rpn_comm_bcast', ierr, trueSize
5074      call utl_abort('extractCmplx81dArray')
5075    end if
5076    if (trueSize < 1) return
5077  
5078    if (trueSize /= oldSize) then
5079      write(*,*) 'extractCmplx81dArray: should not happen ', trueSize, oldSize
5080    end if
5081
5082    newSize = size( index )
5083    
5084    if (mmpi_myid > 0) allocate( array(oldSize))
5085    ierr = 0
5086    call rpn_comm_bcast(array, oldSize, 'MPI_COMPLEX8', 0, 'GRID', ierr)
5087    if (ierr /= 0) then
5088      write(*,*) 'error 2 in rpn_comm_bcast', ierr, array(:)
5089      call utl_abort('extractCmplx81dArray')
5090    end if
5091    tmpCx81d = array
5092    deallocate( array )
5093    allocate( array(newSize))
5094    array( : ) =  tmpCx81d( index(:) )
5095  end subroutine extractCmplx81dArray
5096  
5097
5098  subroutine broadcastR82dArray(array)
5099    implicit none
5100
5101    ! Arguments:
5102    real(kind=8), pointer, intent(inout) :: array(:,:)
5103
5104    ! Locals:
5105    logical :: associated0
5106    integer :: ierr
5107
5108    associated0 = associated(array)
5109    call rpn_comm_bcast(associated0, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
5110    if (ierr /= 0) then
5111      write(*,*) 'error 1 in rpn_comm_bcast', ierr, associated0
5112      call utl_abort('broadcastR82dArray')
5113    end if
5114    ierr = 0
5115    if (associated0) call rpn_comm_bcast(array, size(array) , 'MPI_REAL8', 0, 'GRID', ierr)
5116    if (ierr /= 0) then
5117      write(*,*) 'error 2 in rpn_comm_bcast', ierr, size(array,dim=1), size(array,dim=2)
5118      call utl_abort('broadcastR82dArray')
5119    end if
5120   
5121  end subroutine broadcastR82dArray
5122
5123  subroutine broadcastR81dArray(array)
5124    implicit none
5125
5126    ! Arguments:
5127    real(kind=8), pointer, intent(inout) :: array(:)
5128
5129    ! Locals:
5130    logical :: associated0
5131    integer :: ierr
5132    
5133    associated0 = associated(array)
5134    call rpn_comm_bcast(associated0, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
5135    if (ierr/=0) then
5136      write(*,*) 'error 1 in rpn_comm_bcast', ierr, associated0
5137      call utl_abort('broadcastR81dArray')
5138    end if
5139    ierr = 0
5140    if (associated0) call rpn_comm_bcast(array, size(array) , 'MPI_REAL8', 0, 'GRID', ierr)
5141    if (ierr/=0) then
5142      write(*,*) 'error 2 in rpn_comm_bcast', ierr, size(array)
5143      call utl_abort('broadcastR81dArray')
5144    end if
5145    
5146  end subroutine broadcastR81dArray
5147
5148
5149  subroutine broadcastI41dArray(array)
5150    implicit none
5151
5152    ! Arguments:
5153    integer(kind=4), pointer, intent(inout) :: array(:)
5154
5155    ! Locals:
5156    logical :: associated0
5157    integer :: ierr
5158
5159    associated0 = associated(array)
5160    call rpn_comm_bcast(associated0, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
5161    if (ierr/=0) then
5162      write(*,*) 'error 1 in rpn_comm_bcast', ierr, associated0
5163      call utl_abort('broadcastI41dArray')
5164    end if
5165    ierr = 0
5166    if (associated0) call rpn_comm_bcast(array, size(array) , 'MPI_INTEGER', 0, 'GRID', ierr)
5167    if (ierr/=0) then
5168      write(*,*) 'error 2 in rpn_comm_bcast', ierr, size(array)
5169      call utl_abort('broadcastI41dArray')
5170    end if
5171
5172  end subroutine broadcastI41dArray
5173
5174  !--------------------------------------------------------------------------
5175  !   tvs_printDetailledOmfStatistics
5176  !--------------------------------------------------------------------------
5177  subroutine tvs_printDetailledOmfStatistics(obsSpaceData)
5178    !
5179    !:Purpose: Print channel by channnel O-F statistics fro radiances
5180    !
5181    implicit none
5182
5183    ! Arguments:
5184    type(struct_obs), intent(inout) :: obsSpaceData! obsSpacaData structure
5185
5186    ! Locals:
5187    integer :: sensorIndex, channelIndex, tovsIndex
5188    real(8) zjoch  (0:tvs_maxChannelNumber,tvs_maxNumberOfSensors)
5189    real(8) zavgnrm(0:tvs_maxChannelNumber,tvs_maxNumberOfSensors)
5190    real(pre_obsReal) :: zdtb, obsPRM
5191    integer nchanperline, startChannel, endChannel
5192    integer count, incanjo
5193    integer idatyp
5194    integer rttovChannelNumber, bufrChannelNumber
5195    integer inobsch(0:tvs_maxChannelNumber,tvs_maxNumberOfSensors)
5196    integer lcanjo(tvs_maxChannelNumber)
5197    integer :: headerIndex, bodyIndex
5198    real(8) :: sigmaObs
5199
5200    write(*,*) 'tvs_printDetailledOmfStatistics: Starting'
5201
5202    if ( tvs_nobtov == 0) return    ! exit if there are not tovs data
5203
5204    ! 1.  Computation of (hx - z)/sigma for tovs data only
5205
5206    count  = 0
5207    inobsch(:,:) = 0
5208    zjoch  (:,:) = 0.0d0
5209    zavgnrm(:,:) = 0.0d0
5210
5211    ! loop over all header indices of the 'TO' family
5212    call obs_set_current_header_list(obsSpaceData,'TO')
5213    HEADER: do
5214      headerIndex = obs_getHeaderIndex(obsSpaceData)
5215      if (headerIndex < 0) exit HEADER
5216
5217      ! 1.1  Extract general information for this observation point
5218      !      ------------------------------------------------------
5219
5220      ! process only radiance data to be assimilated?
5221      idatyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
5222      if ( .not. tvs_isIdBurpTovs(idatyp) ) then
5223        write(*,*) 'tvs_printDetailledOmfStatistics: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
5224        cycle HEADER
5225      end if
5226      tovsIndex = tvs_tovsIndex(headerIndex)
5227      if ( tovsIndex == -1 ) cycle HEADER
5228       
5229      sensorIndex = tvs_lsensor(tovsIndex)
5230
5231      ! Set the body list
5232      ! (& start at the beginning of the list)
5233      call obs_set_current_body_list(obsSpaceData, headerIndex)
5234      count = 0
5235      BODY: do 
5236        bodyIndex = obs_getBodyIndex(obsSpaceData)
5237        if (bodyIndex < 0) exit BODY
5238        
5239        ! Only consider if flagged for assimilation
5240        if ( obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) /= obs_assimilated ) cycle BODY                
5241
5242        call tvs_getChannelNumIndexFromPPP( obsSpaceData, headerIndex, bodyIndex, &
5243                                            rttovChannelNumber, channelIndex )
5244        bufrChannelNumber = rttovChannelNumber + tvs_channelOffset(sensorIndex)
5245        if ( channelIndex == 0 ) then
5246          write(*,'(A)') '  tvs_printDetailledOmfStatistics: error with channel number'
5247          call utl_abort(' tvs_printDetailledOmfStatistics')
5248        end if
5249
5250        zdtb = obs_bodyElem_r(obsSpaceData,OBS_PRM,bodyIndex) - &
5251             tvs_radiance (tovsIndex) % bt(channelIndex)
5252        if ( tvs_debug ) then
5253          obsPRM = obs_bodyElem_r(obsSpaceData,OBS_PRM,bodyIndex)
5254          write(*,'(a,i4,2f8.2,f6.2)') ' rttovChannelNumber,sim,obs,diff= ', &
5255               rttovChannelNumber,  tvs_radiance (tovsIndex) % bt(channelIndex), &
5256               obsPRM, -zdtb
5257        end if
5258
5259        sigmaObs = obs_bodyElem_r(obsSpaceData,OBS_OER,bodyIndex)
5260
5261        if ( sigmaObs == MPC_missingValue_R8) cycle body
5262
5263        count = count + 1
5264        inobsch(bufrChannelNumber,sensorIndex) = inobsch(bufrChannelNumber,sensorIndex) + 1
5265        zjoch(bufrChannelNumber,sensorIndex)   = &
5266             zjoch(bufrChannelNumber,sensorIndex) &
5267             + zdtb * zdtb / (sigmaObs * sigmaObs)
5268        zavgnrm(bufrChannelNumber,sensorIndex)   = &
5269             zavgnrm(bufrChannelNumber,sensorIndex) - &
5270             zdtb / sigmaObs
5271      end do BODY
5272
5273    end do HEADER
5274
5275    !   2.  Close up, print summary
5276    !   .   -----------------------
5277
5278
5279    ! printout of mean jo and normalized average for each sensor.
5280
5281    nchanperline = 18
5282    if ( count > 0 ) then
5283      write(*,*)
5284      write(*,*)
5285      write(*,'(10x,A)') '- tvs_printDetailledOmfStatistics: computing jo and residuals to tovs  observations'
5286
5287      do sensorIndex = 1, tvs_nsensors
5288        inobsch(0,sensorIndex) = sum ( inobsch(1:,sensorIndex) )
5289        zjoch(0,sensorIndex) = sum( zjoch(1:,sensorIndex) )
5290        zavgnrm(0,sensorIndex) = sum( zavgnrm(1:,sensorIndex) )
5291      end do
5292
5293      do sensorIndex = 1, tvs_nsensors
5294        incanjo = 0
5295        do channelIndex = 0, tvs_maxChannelNumber
5296          if ( inobsch(channelIndex, sensorIndex) /= 0 ) then
5297            incanjo = incanjo + 1
5298            lcanjo(incanjo) = channelIndex
5299          end if
5300        end do
5301        if ( incanjo /= 0 ) then
5302          write(*,"(/1x,'sensor #',i2,'. platform: ',a, 'instrument: ',a)") &
5303               sensorIndex, tvs_satelliteName(sensorIndex), tvs_instrumentName(sensorIndex)
5304          do startChannel = 1, incanjo, nchanperline
5305            endChannel = min(startChannel + nchanperline - 1 , incanjo)
5306            if ( startChannel == 1 ) then
5307              write(*,"(1x,'channel',t13,'   all',17i6)") (lcanjo(channelIndex), channelIndex=startChannel+1, endChannel)
5308            else
5309              write(*,"(1x,'channel',t13,18i6)") (lcanjo(channelIndex), channelIndex=startChannel, endChannel)
5310            end if
5311            write(*,"(1x,'no. obs.',t13,18i6)") (inobsch(lcanjo(channelIndex),sensorIndex), channelIndex=startChannel, endChannel)
5312            write(*,"(1x,'mean jo',t13,18f6.2)") &
5313                 (zjoch(lcanjo(channelIndex),sensorIndex)/max(1,inobsch(lcanjo(channelIndex),sensorIndex)), channelIndex=startChannel,endChannel)
5314            write(*,"(1x,'norm. bias',t13,18f6.2,/)") &
5315                 (zavgnrm(lcanjo(channelIndex),sensorIndex)/max(1,inobsch(lcanjo(channelIndex), sensorIndex)) , channelIndex=startChannel, endChannel)
5316          end do
5317        end if
5318      end do
5319    end if
5320
5321  end subroutine  tvs_printDetailledOmfStatistics
5322
5323
5324  !--------------------------------------------------------------------------
5325  !  tvs_getLocalChannelIndexFromChannelNumber
5326  !--------------------------------------------------------------------------
5327  subroutine tvs_getLocalChannelIndexFromChannelNumber(idsat,channelIndex_out,channelNumber_in)
5328    !
5329    !:Purpose: to get local channel index from channel number
5330    !
5331    implicit none
5332
5333    ! Arguments:
5334    integer, intent(in)  :: idsat            ! Satellite index
5335    integer, intent(out) :: channelIndex_out ! Channel index
5336    integer, intent(in)  :: channelNumber_in ! Channel number
5337
5338    ! Locals:
5339    logical, save              :: first =.true.
5340    integer                    :: channelNumber, sensorIndex, channelIndex 
5341    integer, allocatable, save :: savedChannelIndexes(:,:)
5342
5343    if (first) then
5344      allocate( savedChannelIndexes(tvs_nsensors, tvs_maxChannelNumber ) )
5345      savedChannelIndexes(:,:) = -1
5346      do sensorIndex = 1, tvs_nsensors
5347        channels:do channelNumber = 1,  tvs_maxChannelNumber
5348          indexes: do channelIndex =1, tvs_nchan(sensorIndex)
5349            if ( channelNumber == tvs_ichan(channelIndex,sensorIndex) ) then
5350              savedChannelIndexes(sensorIndex,channelNumber) = channelIndex
5351              exit indexes
5352            end if
5353          end do indexes
5354        end do channels
5355      end do
5356      first = .false.
5357    end if
5358
5359    channelIndex_out = savedChannelIndexes(idsat,channelNumber_in)
5360
5361    if (channelIndex_out == -1) then
5362      write(*,*) 'channel number requested = ', channelNumber_in
5363      write(*,*) 'idsat = ', idsat
5364      write(*,*) 'tvs_getLocalChannelIndexFromChannelNumber: warning channel not found'  
5365    end if
5366
5367  end subroutine tvs_getLocalChannelIndexFromChannelNumber
5368
5369
5370  subroutine updateCloudInTovsProfile(sensorTovsIndexes, nlv_T, mode, beSilent)
5371    !
5372    !:Purpose: Modify the cloud in tvs_profiles_nl structure of rttov.
5373    !
5374    implicit none
5375    
5376    ! Arguments:
5377    integer,      intent(in) :: sensorTovsIndexes(:)
5378    integer,      intent(in) :: nlv_T
5379    character(*), intent(in) :: mode         ! save or restore
5380    logical,      intent(in) :: beSilent     ! flag to control verbosity
5381
5382    ! Locals:
5383    integer :: profileIndex, profileCount
5384    real(8), allocatable, save :: cloudProfileToStore(:,:)
5385
5386    if ( .not. beSilent ) write(*,*) 'updateCloudInTovsProfile: Starting'
5387    if ( .not. beSilent ) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
5388
5389    profileCount = size(sensorTovsIndexes)
5390
5391    if ( trim(mode) == 'save' ) then 
5392      if (allocated(cloudProfileToStore)) deallocate(cloudProfileToStore)
5393      allocate(cloudProfileToStore(nlv_T,profileCount))
5394
5395      do profileIndex = 1, profileCount
5396        cloudProfileToStore(:,profileIndex) = tvs_profiles_nl(sensorTovsIndexes(profileIndex)) % clw(:)
5397        tvs_profiles_nl(sensorTovsIndexes(profileIndex)) % clw(:) = qlim_getMinValueCloud('LWCR') 
5398      end do
5399
5400    else if ( trim(mode) == 'restore' ) then 
5401      do profileIndex = 1, profileCount
5402        tvs_profiles_nl(sensorTovsIndexes(profileIndex)) % clw(:) = cloudProfileToStore(:,profileIndex)
5403      end do
5404
5405      deallocate(cloudProfileToStore)
5406
5407    else
5408      call utl_abort('updateCloudInTovsProfile: mode should be either "save" or "restore"')
5409
5410    end if
5411
5412  end subroutine updateCloudInTovsProfile
5413
5414
5415  subroutine updateCloudInTovsCloudProfile(sensorTovsIndexes, nlv_T, mode, beSilent)
5416    !
5417    !:Purpose: Modify the cloud in tvs_cld_profiles_nl structure of rttovScatt.
5418    !
5419    implicit none
5420    
5421    ! Arguments:
5422    integer,      intent(in) :: sensorTovsIndexes(:)
5423    integer,      intent(in) :: nlv_T
5424    character(*), intent(in) :: mode         ! save or restore
5425    logical,      intent(in) :: beSilent     ! flag to control verbosity
5426
5427    ! Locals:
5428    integer :: profileIndex, profileCount
5429    real(8), allocatable, save :: rainFluxProfileToStore(:,:)
5430    real(8), allocatable, save :: snowFluxProfileToStore(:,:)
5431    real(8), allocatable, save :: clwProfileToStore(:,:)
5432    real(8), allocatable, save :: ciwProfileToStore(:,:)
5433    real(8), allocatable, save :: cloudFractionProfileToStore(:,:)
5434
5435    if ( .not. beSilent ) write(*,*) 'updateCloudInTovsCloudProfile: Starting'
5436    if ( .not. beSilent ) write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
5437
5438    profileCount = size(sensorTovsIndexes)
5439
5440    if ( trim(mode) == 'save' ) then 
5441      if (allocated(rainFluxProfileToStore)) deallocate(rainFluxProfileToStore)
5442      if (allocated(snowFluxProfileToStore)) deallocate(snowFluxProfileToStore)
5443      if (allocated(clwProfileToStore)) deallocate(clwProfileToStore)
5444      if (allocated(ciwProfileToStore)) deallocate(ciwProfileToStore)
5445      if (allocated(cloudFractionProfileToStore)) deallocate(cloudFractionProfileToStore)
5446      allocate(rainFluxProfileToStore(nlv_T,profileCount))
5447      allocate(snowFluxProfileToStore(nlv_T,profileCount))
5448      allocate(clwProfileToStore(nlv_T,profileCount))
5449      allocate(ciwProfileToStore(nlv_T,profileCount))
5450      allocate(cloudFractionProfileToStore(nlv_T,profileCount))
5451
5452      do profileIndex = 1, profileCount
5453        rainFluxProfileToStore(:,profileIndex) = tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,1)
5454        snowFluxProfileToStore(:,profileIndex) = tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,2)
5455        clwProfileToStore(:,profileIndex) = tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,4)
5456        ciwProfileToStore(:,profileIndex) = tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,5)
5457        cloudFractionProfileToStore(:,profileIndex) = tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro_frac(:,1)
5458        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,1) = qlim_getMinValueCloud('RF')
5459        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,2) = qlim_getMinValueCloud('SF')
5460        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,4) = qlim_getMinValueCloud('LWCR')
5461        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,5) = qlim_getMinValueCloud('IWCR')
5462        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro_frac(:,1) = qlim_getMinValueCloud('CLDR')
5463      end do
5464
5465    else if ( trim(mode) == 'restore' ) then 
5466      do profileIndex = 1, profileCount
5467        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,1) = rainFluxProfileToStore(:,profileIndex)
5468        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,2) = snowFluxProfileToStore(:,profileIndex)
5469        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,4) = clwProfileToStore(:,profileIndex)
5470        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro(:,5) = ciwProfileToStore(:,profileIndex)
5471        tvs_cld_profiles_nl(sensorTovsIndexes(profileIndex)) % hydro_frac(:,1) = cloudFractionProfileToStore(:,profileIndex)
5472      end do
5473
5474      deallocate(rainFluxProfileToStore)
5475      deallocate(snowFluxProfileToStore)
5476      deallocate(clwProfileToStore)
5477      deallocate(ciwProfileToStore)
5478      deallocate(cloudFractionProfileToStore)
5479
5480    else
5481      call utl_abort('updateCloudInTovsCloudProfile: mode should be either "save" or "restore"')
5482
5483    end if
5484
5485  end subroutine updateCloudInTovsCloudProfile
5486
5487  !--------------------------------------------------------------------------
5488  !  tvs_getChannelNumIndexFromPPP
5489  !--------------------------------------------------------------------------
5490  subroutine tvs_getChannelNumIndexFromPPP( obsSpaceData, headerIndex, bodyIndex, &
5491                                            channelNumber, channelIndex )
5492    !
5493    !:Purpose: Get channel number/index from obs_ppp for TO observations.
5494    !
5495    implicit none
5496
5497    ! Arguments:
5498    type(struct_obs), intent(in)  :: obsSpaceData
5499    integer,          intent(in)  :: headerIndex
5500    integer,          intent(in)  :: bodyIndex
5501    integer,          intent(out) :: channelNumber
5502    integer,          intent(out) :: channelIndex
5503
5504    ! Locals:
5505    integer :: tovsIndex, sensorIndex
5506
5507    tovsIndex = tvs_tovsIndex(headerIndex)
5508    sensorIndex = tvs_lsensor(tovsIndex)
5509
5510    channelNumber = nint(obs_bodyElem_r(obsSpaceData,OBS_PPP,bodyIndex))
5511    channelNumber = max( 0 , min( channelNumber , tvs_maxChannelNumber + 1))
5512    channelNumber = channelNumber - tvs_channelOffset(sensorIndex)
5513    channelIndex = utl_findloc(tvs_ichan(:,sensorIndex),channelNumber)
5514
5515  end subroutine tvs_getChannelNumIndexFromPPP
5516
5517end module tovsNL_mod