SUBROUTINE TASKOBTL
!****-------------------------------------------------------------------
!**** *TASKOBTL* - Task treating the first set of non correlated obs
!**** which is available and repeating the action until no set left.
!****
!***  Purpose : Control the execution of one task treating one set of
!***  -------   observations which are not correlated in the horizontal.
!***
!**   Interface : *CALL* * TASKOBTL*
!**   ---------   OR *CALL TSKSTART(.,TASKOBTL)
!**   ---------   DEPENDING ON MULTITASKING IMPLEMENTATION
!**         The common YOMOBSET is an implicit input of TASKOB

!     EXTERNALS. 
!     ----------  SURFACTL - JO FOR SURFACE OBS - T.L.
!                 UPPERATL - JO FOR UPPER AIR OBS - T.L.
!                 SATEMTL  - JO FOR SATEM - T.L
!                 TOVCLRTL - JO FOR TOVS RADIANCES - T.L.

!     Author: Mats Hamrud 
!     Date  : 97-02-21   (from TASKOB, tangent linear option)

!     MODIFICATIONS
!     -------------
!     E. Gerard     :  99-05-05 If NSSMI call tovclrtl instead if satemtl
!****-------------------------------------------------------------------
!        M.Hamrud      01-Oct-2003 CY28 Cleaning
!        P.Burton   :  09/11/04 Thread-safe LVARBC code
!        S. Healy   :  14/03/05 Changes for 2d operators

!        G. Radnoti :  21/02/06 Double scan for correlated obs error model
!     S. Saarinen   :  26-Sep-2007 Obs. group based Dr.Hook'ing in KSET-loop
!     S. Saarinen   :  16-Nov-2007 Added ZTIMER to dynamically load balance the KSET-loop

USE PARKIND1 , ONLY : JPIM     ,JPRB
USE YOMHOOK  , ONLY : LHOOK,   DR_HOOK
USE YOMDIMO  , ONLY : L_TASKOBTL_USE_SORTED_TIMES
USE YOMOBSET , ONLY : MTYPOB   ,MLNSET   ,MMXBDY   ,NSETOT
USE OML_MOD  , ONLY : OML_MAX_THREADS, OML_INIT_LOCK
USE YOMVAR   , ONLY : LCO2ANER
USE YOMECTAB , ONLY : NOBSPROFS

USE YOMCOSJO , ONLY : LOBSCOR, OBSCOR_AUX, NBCORBLK
USE YOMTVRAD , ONLY : SATGRP_TABLE  , CHSENSOR, MXSENSOR, &
                    & SATOBGRP_TABLE,CHMETHOD, MXMETHOD
USE ECSORT_MIX   , ONLY : KEYSORT
USE YOMMP    , ONLY : MYPROC
USE YOMLUN   , ONLY : NULOUT

IMPLICIT NONE

INTEGER(KIND=JPIM) :: ICSET,ITYPOB,ILEN,IDLEN,IMXBDY,JSET,IHORIZ,ISCAN
INTEGER(KIND=JPIM) :: IGRP,ISENSOR,IMETHOD,ICODETYPE,ISATID,ITHRMAX
INTEGER(KIND=JPIM) :: IRET
REAL(KIND=JPRB) :: ZHOOK_HANDLE
REAL(KIND=JPRB) :: ZHOOK_KSET_LOOP
REAL(KIND=JPRB) :: ZHOOK_JSET
REAL(KIND=JPRB) :: TIMEF, ZT
REAL(KIND=JPRB), ALLOCATABLE, SAVE :: ZTIMER(:,:) ! Note : never released, but a small array
CHARACTER(LEN=40) :: CLOBSGRP

#include "hoptl.intfb.h"
#include "obscor_sumup_scalp.intfb.h"
IF (LHOOK) CALL DR_HOOK('TASKOBTL',0,ZHOOK_HANDLE)

ITHRMAX = OML_MAX_THREADS()
IF (allocated(ZTIMER)) THEN
  IF (ITHRMAX > 1 .AND. L_TASKOBTL_USE_SORTED_TIMES) THEN
    CALL KEYSORT(IRET, ZTIMER, NSETOT, KEY=2) ! "2" := smallest time at the top
    IF(MYPROC==1)THEN
      DO JSET=1,NSETOT
        ICSET=ZTIMER(JSET,1)
        WRITE(NULOUT,'("TASKOBTL: SET=",I6," TIME=",F10.3)')ICSET,ZTIMER(JSET,2)
      ENDDO
    ENDIF
  ENDIF
ELSE
!$ CALL OML_INIT_LOCK()
  ZT = TIMEF() ! Make sure the timer has been initialized outside the OpenMP-region
  ALLOCATE(ZTIMER(NSETOT,2))
  DO JSET=1,NSETOT
    ZTIMER(JSET,1) = JSET
    ZTIMER(JSET,2) = 0.0_JPRB
  ENDDO
ENDIF

CALL GSTATS(1061,0)
ISCAN=1
IF (LOBSCOR) THEN
  ISCAN=2
  ALLOCATE(OBSCOR_AUX(NSETOT,NBCORBLK))
ENDIF

1000 FORMAT(A,A,":",I5.5,".",I2.2,".",I3.3,".",I2.2)

!$OMP PARALLEL DO SCHEDULE(DYNAMIC,1) &
!$OMP&PRIVATE(JSET,ICSET,ITYPOB,ILEN,IDLEN,IMXBDY,IHORIZ,ZT, &
!$OMP&        ZHOOK_KSET_LOOP,ZHOOK_JSET,CLOBSGRP,IGRP,ISENSOR,IMETHOD,ICODETYPE,ISATID)
DO JSET=NSETOT,1,-1
  ZT = TIMEF()
  IF (LHOOK) CALL DR_HOOK('TASKOBTL>KSET_LOOP',0,ZHOOK_KSET_LOOP)
  ICSET = ZTIMER(JSET,1)

!*       1.1  OBSERVATION TYPE

  ITYPOB = MOD(MTYPOB(ICSET),100)
  IF (ITYPOB == 7) THEN ! ATOVS
    IGRP = MTYPOB(ICSET)/100
    ISENSOR = SATGRP_TABLE(IGRP)%SENSOR
    ICODETYPE = SATGRP_TABLE(IGRP)%CODETYPE
    ISATID = SATGRP_TABLE(IGRP)%BUFRID
    IF (ISENSOR >= 0 .AND. ISENSOR <= MXSENSOR) THEN
      WRITE(CLOBSGRP,1000) &
           & 'TASKOBTL>OBSGRP=',TRIM(CHSENSOR(ISENSOR)),ISATID,ISENSOR,ICODETYPE,ITYPOB
    ELSE
      WRITE(CLOBSGRP,1000) &
           & 'TASKOBTL>OBSGRP=','<UNDEF>',ISATID,ISENSOR,ICODETYPE,ITYPOB
    ENDIF
  ELSEIF (ITYPOB == 3) THEN ! SATOB
    IGRP = MTYPOB(ICSET)/100
    IMETHOD = SATOBGRP_TABLE(IGRP)%METHOD
    ICODETYPE = SATOBGRP_TABLE(IGRP)%CODETYPE
    ISATID = SATOBGRP_TABLE(IGRP)%BUFRID
    IF (IMETHOD >= 0 .AND. IMETHOD <= MXMETHOD) THEN
      WRITE(CLOBSGRP,1000) &
           & 'TASKOBTL>OBSGRP=',TRIM(CHMETHOD(IMETHOD)),ISATID,IMETHOD,ICODETYPE,ITYPOB
    ELSE
      WRITE(CLOBSGRP,1000) &
           & 'TASKOBTL>OBSGRP=','<UNDEF>',ISATID,IMETHOD,ICODETYPE,ITYPOB
    ENDIF
  ELSE ! ANY OTHER OBS.TYPE
    WRITE(CLOBSGRP,'(A,I2.2)') 'TASKOBTL>OBSGRP=',ITYPOB
  ENDIF
  IF (LHOOK) CALL DR_HOOK(CLOBSGRP,0,ZHOOK_JSET)

  ILEN   = MLNSET(ICSET)
  IF(MOD(ILEN,2) == 0) THEN
    IDLEN  =ILEN+1
  ELSE
    IDLEN  =ILEN
  ENDIF
!            SECOND DIMENSION, COULD BE ZERO.
  IMXBDY = MAX(MMXBDY(ICSET),1)

! How many vertical profiles are required per observation

  IHORIZ = NOBSPROFS(ITYPOB) 

!*       1.3      CALL THE APPROPRIATE OBS OPERATOR

  CALL HOPTL(IDLEN,IMXBDY,ICSET,IHORIZ,1)

!*       1.5      NEXT AVAILABLE SET

  IF (LHOOK) CALL DR_HOOK(CLOBSGRP,1,ZHOOK_JSET)
  IF (LHOOK) CALL DR_HOOK('TASKOBTL>KSET_LOOP',1,ZHOOK_KSET_LOOP)
  IF (ITHRMAX > 1 .AND. L_TASKOBTL_USE_SORTED_TIMES) THEN
    ZTIMER(JSET,2) = TIMEF() - ZT
  ENDIF
ENDDO
!$OMP END PARALLEL DO
CALL GSTATS(1061,1)
!CALL GSTATS(1791,0)
IF (LOBSCOR)THEN
!   OBSCOR_AUX  ------->  OBSCOR_SCALPR (DM-LOCAL, POINT-WISE PRODUCTS--> INNER PRODUCT)
    CALL OBSCOR_SUMUP_SCALP
    DEALLOCATE(OBSCOR_AUX)
ENDIF
!CALL GSTATS(1791,1)
IF (ISCAN == 2) THEN
! second scan...
  CALL GSTATS(1067,0)
!$OMP PARALLEL DO SCHEDULE(DYNAMIC,1) &
!$OMP&PRIVATE(JSET,ICSET,ITYPOB,ILEN,IDLEN,IMXBDY,IHORIZ, &
!$OMP&        ZHOOK_KSET_LOOP,ZHOOK_JSET,CLOBSGRP,IGRP,ISENSOR,IMETHOD,ICODETYPE,ISATID)
  DO JSET=NSETOT,1,-1
    IF (LHOOK) CALL DR_HOOK('TASKOBTL>KSET_LOOP_2',0,ZHOOK_KSET_LOOP)
    ICSET = JSET

!*       1.1/2  OBSERVATION TYPE

    ITYPOB = MOD(MTYPOB(ICSET),100)
    IF (ITYPOB == 7) THEN ! ATOVS
      IGRP = MTYPOB(ICSET)/100
      ISENSOR = SATGRP_TABLE(IGRP)%SENSOR
      ICODETYPE = SATGRP_TABLE(IGRP)%CODETYPE
      ISATID = SATGRP_TABLE(IGRP)%BUFRID
      IF (ISENSOR >= 0 .AND. ISENSOR <= MXSENSOR) THEN
        WRITE(CLOBSGRP,1000) &
             & 'TASKOBTL>OBSG_2=',TRIM(CHSENSOR(ISENSOR)),ISATID,ISENSOR,ICODETYPE,ITYPOB
      ELSE
        WRITE(CLOBSGRP,1000) &
             & 'TASKOBTL>OBSG_2=','<UNDEF>',ISATID,ISENSOR,ICODETYPE,ITYPOB
      ENDIF
    ELSEIF (ITYPOB == 3) THEN ! SATOB
      IGRP = MTYPOB(ICSET)/100
      IMETHOD = SATOBGRP_TABLE(IGRP)%METHOD
      ICODETYPE = SATOBGRP_TABLE(IGRP)%CODETYPE
      ISATID = SATOBGRP_TABLE(IGRP)%BUFRID
      IF (IMETHOD >= 0 .AND. IMETHOD <= MXMETHOD) THEN
        WRITE(CLOBSGRP,1000) &
           & 'TASKOBTL>OBSG_2=',TRIM(CHMETHOD(IMETHOD)),ISATID,IMETHOD,ICODETYPE,ITYPOB
      ELSE
        WRITE(CLOBSGRP,1000) &
           & 'TASKOBTL>OBSG_2=','<UNDEF>',ISATID,IMETHOD,ICODETYPE,ITYPOB
      ENDIF
    ELSE ! ANY OTHER OBS.TYPE
      WRITE(CLOBSGRP,'(A,I2.2)') 'TASKOBTL>OBSG_2=',ITYPOB
    ENDIF
    IF (LHOOK) CALL DR_HOOK(CLOBSGRP,0,ZHOOK_JSET)

    ILEN   = MLNSET(ICSET)
    IF(MOD(ILEN,2) == 0) THEN
      IDLEN  =ILEN+1
    ELSE
      IDLEN  =ILEN
    ENDIF
!              SECOND DIMENSION, COULD BE ZERO.
    IMXBDY = MAX(MMXBDY(ICSET),1)

! How many vertical profiles are required per observation

    IHORIZ = NOBSPROFS(ITYPOB)

!*       1.3      CALL THE APPROPRIATE OBS OPERATOR

    CALL HOPTL(IDLEN,IMXBDY,ICSET,IHORIZ,2)

!*       1.5      NEXT AVAILABLE SET

    IF (LHOOK) CALL DR_HOOK(CLOBSGRP,1,ZHOOK_JSET)
    IF (LHOOK) CALL DR_HOOK('TASKOBTL>KSET_LOOP_2',1,ZHOOK_KSET_LOOP)
  ENDDO
!$OMP END PARALLEL DO
  CALL GSTATS(1067,1)
ENDIF
CALL GSTATS_BARRIER(755)
LCO2ANER=.FALSE.

!-----------------------------------------------------------------------

IF (LHOOK) CALL DR_HOOK('TASKOBTL',1,ZHOOK_HANDLE)
END SUBROUTINE TASKOBTL
