SUBROUTINE SM_EKF_MAIN(KL,KBLOCK,KSEKFCV,KSTART,KSTOP,&
                    &  KSEKFQ,p_ZINC,p_ZDEBUG, &
                    &  p_ZKGAIN,p_ZBACK,p_ZCANER,p_ZOCGR,p_ZMOD_ANA)

!**** *SM_EKF_MAIN*  - controls simplified extended KF analysis for soil moisture


!     Input parameters.
!     -----------------

!     KL     :   Grid point index within NPROMA chunk
!     KBLOCK :   NPROMA chunk index
!     KSEKFCV:   Number of control variables
!     KSTART :   First model step
!     KSTOP  :   Last model step

!     Output parameters.
!     ------------------

!     KSEKFQ   : Quality flag for the analysis
!     p_ZDEBUG   : Output fields for debugging
!     p_ZINC     : Soil moisture analysis increment
!     p_ZKGAIN   : Kalman Gain
!     p_ZOCGR    : one-side finite difference for H approx.
!     p_ZCANER   : Analysis error A
!     p_ZBACK    : Background error B
!     p_ZMOD_ANA : Analysed soil moisture at NANATIME

!     Purpose.
!     --------
!     (1) Controls simplified extended KF analysis for soil moisture

!**   Interface.
!     ----------
!        *CALL* *SM_EKF_MAIN(...)

!        Explicit arguments :           None
!        --------------------

!        Implicit arguments :      None
!        --------------------

!     Method.
!     -------
!        See documentation

!     Externals.
!     ----------

!     Reference.
!     ----------
!        ECMWF Research Department documentation of the IFS

!     Author.
!     -------
!        M. Drusch  *ECMWF*

!     Modifications.
!     --------------
!       2008-06-17 - K. Scipal - Change threshold in the Jacobian check
!       2008-06-24 - K. Scipal - Simplified and Cleaned code
!       2008-08-03 - K. Scipal - changed calculation of Jacobians (changed step 3.0 and 7.0)
!       2009-02-10 - P. de Rosnay - Code cleaned and coding standard SEKF controle loop (remove GOTO) 
!       2009-12-15 - P. de Rosnay - Exit LoopSEKF 
!     ------------------------------------------------------------------

USE PARKIND1  ,ONLY : JPIM, JPRB
USE YOMHOOK   ,ONLY : LHOOK, DR_HOOK
USE YOMLUN    ,ONLY : NULOUT
USE YOMSEKF   ,ONLY : NOBS_SCREEN, NANAL, NANATIME, &
 & NOBS_SEKF_MAX, T2M_OBS, TD2M_OBS, VOL_SM_FG, NSLAY, &
 & T2M_FG, TD2M_FG, &
 & LUSE_T2M, LUSE_RH2M, LUSE_ASCAT,&
 & NREF_BLOCK, NREF_GP, &
 & YLASCATOBS, NOBS_ASCAT, NOBS_ASCAT_TOT, NOBS_TSTEP, NANA_TSTEP, &
 & MOD_ERR,BACK_ERR,ANA_ERR,T2M_ERR,RH2M_ERR,ASCAT_ERR

IMPLICIT NONE

INTEGER(KIND=JPIM),INTENT(IN)  ::  KBLOCK, KL, KSEKFCV, KSTART, KSTOP
INTEGER(KIND=JPIM),INTENT(OUT) ::  KSEKFQ
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZINC(KSEKFCV)
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZDEBUG(20)
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZKGAIN(KSEKFCV,NOBS_SEKF_MAX)
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZOCGR(NOBS_SEKF_MAX,KSEKFCV)
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZCANER(KSEKFCV,KSEKFCV)
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZBACK(KSEKFCV,KSEKFCV)
REAL(KIND=JPRB),INTENT(OUT)    ::  p_ZMOD_ANA(NANAL,KSEKFCV)


INTEGER(KIND=JPIM)  ::  IOBS      ! Total number of observations
INTEGER(KIND=JPIM)  ::  IOBST     ! Number of 2m temperature observations
INTEGER(KIND=JPIM)  ::  IOBSH     ! Number of 2m relative humidity obs.
INTEGER(KIND=JPIM)  ::  IOBSA     ! Number of ASCAT observations

INTEGER(KIND=JPIM), ALLOCATABLE  ::  IFLAG(:)   ! flagging for H operator calculation

REAL(KIND=JPRB), ALLOCATABLE  ::  ZKGAIN_I(:,:)
REAL(KIND=JPRB), ALLOCATABLE  ::  ZOCGR_I(:,:)

INTEGER(KIND=JPIM), ALLOCATABLE  ::  IOBSA_TSTEP(:)! ASCAT observation times
REAL(KIND=JPRB), ALLOCATABLE  ::  ZOBS(:)       ! observation vector
REAL(KIND=JPRB), ALLOCATABLE  ::  ZMOD(:)       ! model first guess vector
REAL(KIND=JPRB), ALLOCATABLE  ::  ZPARBCVN(:,:) ! soil moisture first guess at obs. time
REAL(KIND=JPRB), ALLOCATABLE  ::  ZMOD_G(:,:)   ! screen level param. from perturbed runs at obs. time
REAL(KIND=JPRB), ALLOCATABLE  ::  ZVARB(:)      ! soil moisture at the first time step
REAL(KIND=JPRB), ALLOCATABLE  ::  ZVARB_END(:)  ! soil moisture at the last time step
REAL(KIND=JPRB), ALLOCATABLE  ::  ZVARG(:)      ! perturbed soil moisture at the first time step
REAL(KIND=JPRB), ALLOCATABLE  ::  ZVARG_END(:,:)! perturbed soil moisture at the last time step
REAL(KIND=JPRB), ALLOCATABLE  ::  ZPARGCVN(:,:) ! perturbed soil moisture at obs. time
REAL(KIND=JPRB), ALLOCATABLE  ::  ZBERR(:)      ! soil moisture model error Q
REAL(KIND=JPRB), ALLOCATABLE  ::  ZOERR(:)      ! observation error

INTEGER(KIND=JPIM) ::  IK, J1, J2, INFO, ICHECK_J, ICHECK_FG, JCOUNT
REAL(KIND=JPRB)    ::  ZGRAD, ZCHECK_J, ZEPS, ZRH
REAL(KIND=JPRB)    ::  ZHOOK_HANDLE
LOGICAL            ::  LLDEBUGPRINT             ! Logical switch of debuging environment

#include "sekf_magn_rh.intfb.h"
!#include "sekf_backgerr.intfb.h"
#include "sekf_gain.intfb.h"
#include "sekf_costf.intfb.h"

!*     ------------------------------------------------------------------

IF (LHOOK) CALL DR_HOOK('SM_EKF_MAIN',0,ZHOOK_HANDLE)

!*    -----------------------------------------------------------------------------------
!*    0.0 Initialize variables
!*    -----------------------------------------------------------------------------------

LLDEBUGPRINT = .False.
!WRITE(NULOUT,*) 'START SM_SEKF_MAIN - LLDEBUGPRINT=',LLDEBUGPRINT


KSEKFQ = 0._JPRB
p_ZDEBUG(:) = 0._JPRB

IOBS=0_JPIM
IOBST=0_JPIM
IOBSH=0_JPIM
IOBSA=0_JPIM

p_ZINC(:) = 0._JPRB


ZEPS=100._JPRB*tiny(1._JPRB)


! Define the Loop that controles the SEKF

LoopSEKF: DO 

!*    0.1 check on availability of observations


  IF (LUSE_T2M) THEN
    IOBST = NOBS_SCREEN
    IOBS=IOBS+IOBST
  ENDIF
  IF (LUSE_RH2M) THEN
    IOBSH = NOBS_SCREEN
    IOBS=IOBS+IOBSH
  ENDIF
  IF (LUSE_ASCAT) THEN
    IOBSA = NOBS_ASCAT(KL,KBLOCK)
    IOBS=IOBS+IOBSA
  ENDIF

  IF (IOBS == 0) THEN
! Quality flag set to no obs value
    KSEKFQ = 1_JPIM
    exit LoopSEKF
  ENDIF

!*    -----------------------------------------------------------------------------------
!*    1.0 Observation vector Y
!*    -----------------------------------------------------------------------------------


  ALLOCATE(ZOBS(IOBS))
  ALLOCATE(IFLAG(IOBS))   ! IFLAG holds observation ID (1-T2M , 2-RH2M or 3-ASCAT)

  ZOBS(:) = 0._JPRB
  IFLAG(:) = 0_JPIM
  IK = 0_JPIM

!*    1.1 T2M "observations"

  IF (LUSE_T2M .AND. IOBST>0) THEN
   DO J1 = 1, IOBST
     IK = IK + 1
     ZOBS(IK) = T2M_OBS(KL,KBLOCK,J1)
     IFLAG(IK) = 1_JPIM
   ENDDO
  ENDIF
  
!*    1.2 RH2M "observations"

  IF (LUSE_RH2M .AND. IOBSH>0) THEN
    DO J1 = 1, IOBSH
      IK = IK + 1
      ZRH=TD2M_OBS(KL,KBLOCK,J1)
      CALL SEKF_MAGN_RH(ZRH,T2M_OBS(KL,KBLOCK,J1))
      ZOBS(IK) = ZRH
      IFLAG(IK) = 2_JPIM
    ENDDO
  ENDIF

!*    1.3 ASCAT SM observations

  IF (LUSE_ASCAT .AND. IOBSA>0) THEN
    JCOUNT = 0
    ALLOCATE(IOBSA_TSTEP(IOBSA))
    DO J1 = 1, NOBS_ASCAT_TOT
      IF ((YLASCATOBS(J1)%IPROMA==KL) .AND. (YLASCATOBS(J1)%IGPBLCK==KBLOCK)) THEN
        IK = IK + 1
        JCOUNT=JCOUNT+1
        ZOBS(IK) = YLASCATOBS(J1)%ZOBS
        IOBSA_TSTEP(JCOUNT) = YLASCATOBS(J1)%ISTEP
        IFLAG(IK) = 3
      ENDIF
    ENDDO
    IF (IOBSA/=JCOUNT) THEN
       WRITE(NULOUT,*) 'ERROR: JCOUNT not equal IOBSA ',IOBSA, JCOUNT
    ENDIF
  ENDIF

!*    1.5 Write debug information to log file
  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN
      WRITE(NULOUT,*) 'SM_EKF_MAIN:'
      WRITE(NULOUT,*) 'Number of observations:', IOBS
      DO J1 = 1, IOBS
        WRITE(NULOUT,'(1x,f12.7)') ZOBS(J1)
      ENDDO
    ENDIF
  ENDIF
  
! we have either 2 (12h analysis cycles) or 1 (6h analysis cuycles) T2M and RH2M observation
! for ASCAT we can have >2 observation depending on latitude and analysis cycle length
!   impracticable to save so for debuging only save one but also store the number
  
  IF (LUSE_T2M .AND. IOBST>0 .AND. IOBST<=2) p_ZDEBUG(1:IOBST) = ZOBS(1:IOBST)
  IF (LUSE_RH2M .AND. IOBSH>0 .AND. IOBSH<=2) p_ZDEBUG(3:3+IOBSH-1) = ZOBS(1+IOBST:IOBST+IOBSH)
  IF (LUSE_ASCAT .AND. IOBSA>0) THEN
    p_ZDEBUG(19) = ZOBS(IOBST+IOBSH+1)
    p_ZDEBUG(20) = IOBSA_TSTEP(1)
  ENDIF



!*    -----------------------------------------------------------------------------------
!*    2.0 Model first guess vector Xb
!         and do a quality check on first guess departures
!*    -----------------------------------------------------------------------------------

  ALLOCATE(ZMOD(IOBS))
  ZMOD(:) = 0._JPRB
  IK = 0
  ICHECK_FG = 0_JPIM

!*    2.1 T2M first guess

  IF (LUSE_T2M .AND. IOBST>0) THEN
    DO J1 = 1, IOBST
      IK = IK + 1
      ZMOD(IK) = T2M_FG(KL,KBLOCK,NOBS_TSTEP(J1),1)
      IF (ABS(ZMOD(IK) - ZOBS(IK)) > 5.) THEN
        ICHECK_FG = 1_JPIM
        KSEKFQ = 2_JPIM
      ENDIF
    ENDDO
  ENDIF

!*    2.2 RH2M first guess

  IF (LUSE_RH2M .AND. IOBSH>0) THEN
    DO J1 = 1, IOBSH
      IK = IK + 1
      ZRH = TD2M_FG(KL,KBLOCK,NOBS_TSTEP(J1),1)
      CALL SEKF_MAGN_RH(ZRH,T2M_FG(KL,KBLOCK,NOBS_TSTEP(J1),1))
      ZMOD(IK) = ZRH
      IF (ABS(ZMOD(IK) - ZOBS(IK)) > 20.) THEN
        ICHECK_FG = 1_JPIM
        KSEKFQ = 3_JPIM
      ENDIF
    ENDDO
  ENDIF

!*    2.3 soil moisture first guess

  IF (LUSE_ASCAT .AND. IOBSA>0) THEN
    DO J1 = 1, IOBSA
      IK = IK + 1
      ZMOD(IK) = VOL_SM_FG(KL,1,KBLOCK,IOBSA_TSTEP(J1),1)
      p_ZDEBUG(18) = ABS(ZMOD(IK) - ZOBS(IK))
      IF (ABS(ZMOD(IK) - ZOBS(IK)) > 0.1) THEN
        ICHECK_FG = 1_JPIM
        KSEKFQ = 4_JPIM
      ENDIF
    ENDDO
  ENDIF

!*    2.4 Write debug information to log file

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN
      WRITE(NULOUT,*) 'SM_EKF_MAIN:'
      WRITE(NULOUT,*) 'model first guess:', IOBS
      DO J1 = 1, IOBS
        WRITE(NULOUT,'(1x,f12.7)') ZMOD(J1)
      ENDDO
    ENDIF
  ENDIF

  IF (LUSE_T2M .AND. IOBST>0 .AND. IOBST<=2) p_ZDEBUG(5:5+IOBST-1) = ZMOD(1:IOBST)
  IF (LUSE_RH2M .AND. IOBSH>0 .AND. IOBSH<=2) p_ZDEBUG(7:7+IOBSH-1) = ZMOD(1+IOBST:IOBST+IOBSH)

!*    2.5 if one of the fg dep. quality checks is negative goto end

  IF (ICHECK_FG==1) exit LoopSEKF 


! -----------------------------------------------------------------------------------
! 3.0 Process first guess soil moisture at initial time step 
! -----------------------------------------------------------------------------------


  ALLOCATE(ZPARBCVN(IOBS,KSEKFCV))
  ZPARBCVN(:,:) = 0._JPRB
  IK = 0

!*    3.1 Process T2M

  IF (LUSE_T2M .AND. IOBST>0) THEN
    DO J1 = 1, IOBST
      IK = IK + 1
      DO J2 = 1, KSEKFCV
        ZPARBCVN(IK,J2) = VOL_SM_FG(KL,J2,KBLOCK,1,1)
      ENDDO
    ENDDO
  ENDIF
    
!*    3.2 Process RH2M

  IF (LUSE_RH2M .AND. IOBSH>0) THEN
    DO J1 = 1, IOBSH
      IK = IK + 1
      DO J2 = 1, KSEKFCV
         ZPARBCVN(IK,J2) = VOL_SM_FG(KL,J2,KBLOCK,1,1)
      ENDDO
    ENDDO
  ENDIF
  
!*    3.3 Process ASCAT SM

  IF (LUSE_ASCAT .AND. IOBSA>0) THEN
    DO J1 = 1, IOBSA
      IK = IK + 1
      DO J2 = 1, KSEKFCV
        ZPARBCVN(IK,J2) = VOL_SM_FG(KL,J2,KBLOCK,1,1)
      ENDDO
    ENDDO
  ENDIF

!*    3.4 Write debug information to log file

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'Soil moisture first guess at observation time.'
      WRITE(NULOUT,*) 'Dimension: IOBS * KVAR'
      DO J1 = 1, IOBS
       WRITE(NULOUT,'(3(1x,f12.7))') (ZPARBCVN(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF

  IF (LUSE_T2M .AND. IOBST>0 .AND. IOBST<=2) p_ZDEBUG(11:11+IOBST-1) = ZPARBCVN(1:IOBST,1)


!*    -----------------------------------------------------------------------------------
!*    4.0 Process model output (screen level param.) from the perturbed runs at obs. time
!*    -----------------------------------------------------------------------------------


! In the initialisation step we perturbed soil moisture for the first three layers and ran a forecast for each.
! The result of each pertubed run is stored in the FG fields, i.e. for T2M and RH2M it is in the last dimension
! (the first value is the unperturbed field, value 2 is the fg after layer1 was perturbed etc)
! for soil moisture 3 layers have to be stored for each pertubation. 
! So the last dimensions determines the perturbation
! layer, the second dimesion the fg for the three soil layers based on the perturbed initial cond.

  ALLOCATE(ZMOD_G(IOBS,KSEKFCV))
  ZMOD_G(:,:) = 0._JPRB
  IK=0

!*    4.1 Process T2M perturbed

  IF (LUSE_T2M .AND. IOBST>0) THEN
    DO J1 = 1, IOBST
      IK=IK+1
      DO J2 = 1, KSEKFCV
        ZMOD_G(IK,J2)= T2M_FG(KL,KBLOCK,NOBS_TSTEP(J1),J2+1)
      ENDDO
    ENDDO
  ENDIF

!*    4.2 Process RH2M perturbed

  IF (LUSE_RH2M .AND. IOBSH>0) THEN
    DO J1 = 1, IOBSH
      IK=IK+1
      DO J2 = 1, KSEKFCV
        ZRH = TD2M_FG(KL,KBLOCK,NOBS_TSTEP(J1),J2+1)
        CALL SEKF_MAGN_RH(ZRH,T2M_FG(KL,KBLOCK,NOBS_TSTEP(J1),J2+1))
        ZMOD_G(IK,J2) = ZRH
      ENDDO
    ENDDO
  ENDIF
  
!*    4.3 Process soil moisture perturbed
!         we need soil moisture from layer 1

  IF (LUSE_ASCAT .AND. IOBSA>0) THEN
    DO J1 = 1, IOBSA
      IK=IK+1
      DO J2 = 1, KSEKFCV
        ZMOD_G(IK,J2) = VOL_SM_FG(KL,1,KBLOCK,IOBSA_TSTEP(J1),J2+1)
      ENDDO
    ENDDO
  ENDIF
  
!*    4.4 Write debug information to log file

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN
      WRITE(NULOUT,*) 'Perturbed screen level parameters at obs. time ...'
      WRITE(NULOUT,*) 'Dimension: IOBS * KVAR'
      DO J1 = 1, IOBS
       WRITE(NULOUT,'(3(1x,f12.7))') (ZMOD_G(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF
  
!*    -----------------------------------------------------------------------------------
!*    5.0 Store first guess soil moisture at first and last time steps
!*    -----------------------------------------------------------------------------------

  ALLOCATE(ZVARB(KSEKFCV))
  ALLOCATE(ZVARB_END(KSEKFCV))

  DO J1 = 1, KSEKFCV
    ZVARB(J1) = VOL_SM_FG(KL,J1,KBLOCK,KSTART,1)
    ZVARB_END(J1) = VOL_SM_FG(KL,J1,KBLOCK,KSTOP-1,1)
  ENDDO
  
!*    5.1 Write debug information to log file

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN
      WRITE(NULOUT,*) 'SM at first time step '
      WRITE(NULOUT,*) (ZVARB(J2),J2=1,NSLAY)
      WRITE(NULOUT,*) 'SM at last time step '
      WRITE(NULOUT,*) (ZVARB_END(J2),J2=1,NSLAY)
    ENDIF
  ENDIF

  p_ZDEBUG(9) = ZVARB(1)
  p_ZDEBUG(10)= ZVARB_END(1)




!*    -----------------------------------------------------------------------------------
!*    6.0 Store perturbed soil moisture at first and last time steps
!*    -----------------------------------------------------------------------------------

  ALLOCATE(ZVARG(KSEKFCV))
  ALLOCATE(ZVARG_END(KSEKFCV,KSEKFCV))
  
  ZVARG(:) = 0._JPRB
  ZVARG_END(:,:) = 0._JPRB
  
  DO J1 = 1, KSEKFCV
! Save the soil moisture of the perturbed variable
    ZVARG(J1) = VOL_SM_FG(KL,J1,KBLOCK,KSTART,J1+1)
    DO J2 = 1, KSEKFCV
      ZVARG_END(J2,J1) = VOL_SM_FG(KL,J1,KBLOCK,KSTOP-1,J2+1)
    ENDDO
  ENDDO

!*    6.1 Write debug information to log file

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN
      WRITE(NULOUT,*) 'Perturbed SM at first time step:'
      WRITE(NULOUT,*) 'Dimension KVAR'
      WRITE(NULOUT,*) (ZVARG(J1),J1=1,NSLAY)
      WRITE(NULOUT,*) 'Perturbed SM at last time step:', KSTOP
      WRITE(NULOUT,*) 'Dimension KVAR*KVAR'
      DO J1 = 1, NSLAY
        WRITE(NULOUT,*) (ZVARG_END(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF

  p_ZDEBUG(13) = ZVARG(1)
  p_ZDEBUG(14) = ZVARG_END(1,1)




!*    -----------------------------------------------------------------------------------
!*    7.0 Process perturbed soil moisture at initial time step 
!*    -----------------------------------------------------------------------------------


  ALLOCATE(ZPARGCVN(IOBS,KSEKFCV))
  ZPARGCVN(:,:) = 0._JPRB
  IK = 0
  
  IF (LUSE_T2M .AND. IOBST>0) THEN
    DO J1 = 1, IOBST
     IK = IK + 1
     DO J2 = 1, KSEKFCV
       ZPARGCVN(IK,J2) = VOL_SM_FG(KL,J2,KBLOCK,1,J2+1)
     ENDDO
    ENDDO
  ENDIF

  IF (LUSE_RH2M .AND. IOBSH>0) THEN
    DO J1 = 1, IOBSH
      IK = IK + 1
      DO J2 = 1, KSEKFCV
        ZPARGCVN(IK,J2) = VOL_SM_FG(KL,J2,KBLOCK,1,J2+1)
      ENDDO
    ENDDO
  ENDIF

  IF (LUSE_ASCAT .AND. IOBSA>0) THEN
    DO J1 = 1, IOBSA
      IK = IK + 1
      DO J2 = 1, KSEKFCV
        ZPARGCVN(IK,J2) = VOL_SM_FG(KL,J2,KBLOCK,1,J2+1)
      ENDDO
    ENDDO
  ENDIF
  
  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'Perturbed soil moisture first guess at observation time.'
      WRITE(NULOUT,*) 'Dimension: IOBS * KVAR'
      DO J1 = 1, IOBS
        WRITE(NULOUT,'(3(1x,f12.7))') (ZPARGCVN(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF




!*    -----------------------------------------------------------------------------------
!*    8.0 Compute one side finite difference (H approximation)
!*    -----------------------------------------------------------------------------------


  ALLOCATE(ZOCGR_I(IOBS,KSEKFCV))
  ZOCGR_I(:,:) = 0._JPRB
  p_ZOCGR(:,:) = 0._JPRB
  
  ZGRAD = 0._JPRB

  DO J1 = 1, IOBS
    DO J2 = 1, KSEKFCV
      ZGRAD = ZPARGCVN(J1,J2)-ZPARBCVN(J1,J2)
      IF (ABS(ZGRAD) >= ZEPS) THEN
        ZOCGR_I(J1,J2) = (ZMOD_G(J1,J2)-ZMOD(J1))/ZGRAD
      ELSE
        ZOCGR_I(J1,J2) = 0.0_JPRB
        IF (IFLAG(J1)==1) WRITE(NULOUT,*) 'Temperature gradient in H computation is zero!'
        IF (IFLAG(J1)==2) WRITE(NULOUT,*) 'Humidity gradient in H computation is zero!'
        IF (IFLAG(J1)==3) WRITE(NULOUT,*) 'Soil moisture gradient in H computation is zero!'
      ENDIF
    ENDDO
  ENDDO
  
!*    8.1 Check the Jacobians ....

  ICHECK_J = 0_JPIM
  
  DO J1 = 1, IOBS
    DO J2 = 1, KSEKFCV
        IF (IFLAG(J1)==1) ZCHECK_J = 50._JPRB  ! Temperature
        IF (IFLAG(J1)==2) ZCHECK_J = 500._JPRB ! Relative Humidity
        IF (IFLAG(J1)==3) ZCHECK_J = 2._JPRB   ! soil moisture
        IF (ABS(ZOCGR_I(J1,J2)) > ZCHECK_J) THEN
          ZOCGR_I(J1,J2) = SIGN(1000._JPRB, ZOCGR_I(J1,J2)) ! set p_ZOCGR to either 1000 or -1000
          ICHECK_J = 1_JPIM
          KSEKFQ = 4_JPIM + IFLAG(J1) ! results in debug message 5, 6 or 7 depending on obstype
        ENDIF
    ENDDO
  ENDDO

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'One-side finite differences ... H'
      WRITE(NULOUT,*) 'Dimension: IOBS * KVAR'
      DO J1 = 1, IOBS
        WRITE(NULOUT,'(3(1x,f15.8))') (ZOCGR_I(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF

! Fill up output array
  DO J1 = 1, IOBS
    DO J2 = 1, KSEKFCV
      p_ZOCGR(J1,J2)= ZOCGR_I(J1,J2) ! only write to output if larger than tiny to avoid problems with IOSTREAM
      IF ((ABS(ZOCGR_I(J1,J2))>1000.)) WRITE(NULOUT,*) 'Problem p_ZOCGR: ', ZOCGR_I(J1,J2)
   ENDDO
  ENDDO

  IF (ICHECK_J==1) exit LoopSEKF 



!*    -----------------------------------------------------------------------------------
!*    9.0 Compute the linearized state transition matrix M and
!*        propagate background error B from t=0 to t=end
!*    -----------------------------------------------------------------------------------

  ALLOCATE(ZBERR(KSEKFCV))

  ZBERR(:) = 0._JPRB
  p_ZCANER(:,:) = 0._JPRB
  p_ZBACK(:,:) = 0._JPRB

! Initializing model error and analysis error
! Changes needed for operational application !
! preset model error Q

  ZBERR(1) = MOD_ERR
  ZBERR(2) = MOD_ERR
  ZBERR(3) = MOD_ERR

! define background error at t = 0 on the diagonal

!DO J1 = 1, KSEKFCV
!  p_ZBACK(J1,J1) = 0.05
!ENDDO

! define the entire matrix ...

  DO J1 = 1, KSEKFCV
    DO J2 = 1, KSEKFCV
      IF (J1 == J2) p_ZBACK(J1,J2) = BACK_ERR
      IF (J1 /= J2) p_ZBACK(J1,J2) = 0.
    ENDDO
  ENDDO

! define the analysis error
  DO J1 = 1, KSEKFCV
    DO J2 = 1, KSEKFCV
      p_ZCANER(J1,J1) = ANA_ERR
    ENDDO
  ENDDO

!------
! Do not propagate errors (test during the debugging)
!CALL SEKF_BACKGERR(KL,KBLOCK,KSEKFCV,ZVARB,ZVARG,ZVARB_END,ZVARG_END,ZBERR,p_ZCANER)

!p_ZBACK(:,:) = p_ZCANER(:,:)
!-----

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'Background error at the end of the assimilation window:'
      WRITE(NULOUT,*) 'Dimension: KVAR * KVAR'
      DO J1 = 1, KSEKFCV
        WRITE(NULOUT,*) (p_ZBACK(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF




!*    -----------------------------------------------------------------------------------
!*   10.0 Set the observation error and compute Kalman Gain K
!*        and soil moisture increments
!*    -----------------------------------------------------------------------------------

  ALLOCATE(ZOERR(IOBS))
  ALLOCATE(ZKGAIN_I(KSEKFCV,IOBS))

  ZKGAIN_I(:,:) = 0._JPRB
  p_ZKGAIN(:,:) = 0._JPRB

  IF (LUSE_T2M) ZOERR(1:IOBST) = T2M_ERR
  IF (LUSE_RH2M) ZOERR(1+IOBST:IOBST+IOBSH) = RH2M_ERR
  IF (LUSE_ASCAT) ZOERR(1+IOBST+IOBSH:IOBS) = ASCAT_ERR

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'Observation errors:'
      WRITE(NULOUT,'(6(1x,f12.7))') (ZOERR(J1),J1=1,IOBS)
    ENDIF
  ENDIF

  CALL SEKF_GAIN(KL,KBLOCK,IOBS,KSEKFCV,ZOERR,p_ZBACK,ZOBS,ZMOD,ZOCGR_I,p_ZINC,p_ZCANER,ZKGAIN_I,INFO)

  IF (INFO > 0) THEN
    p_ZINC(:) = 0._JPRB
    KSEKFQ = 7_JPIM + INFO ! results in debug message 8, 9 or 10 depending on gain failure
    exit LoopSEKF
  ENDIF


! Fill up output array
  DO J1 = 1, KSEKFCV
    DO J2 = 1, IOBS
      p_ZKGAIN(J1,J2)= ZKGAIN_I(J1,J2)
      IF ((ABS(ZKGAIN_I(J1,J2))>1)) WRITE(NULOUT,*) 'Problem ZGAIN: ', p_ZKGAIN(J1,J2)
   ENDDO
  ENDDO

  DO J1 = 1, KSEKFCV
    IF (ABS(p_ZINC(J1)) > 0.1) THEN
      p_ZINC(:) = 0._JPRB
      KSEKFQ = 11_JPIM
      exit LoopSEKF
    ENDIF
  ENDDO

!*    -----------------------------------------------------------------------------------
!*    11.0 Quality check on cost function
!*    -----------------------------------------------------------------------------------

  CALL SEKF_COSTF(KL,KBLOCK,IOBS,KSEKFCV,ZOERR,ZOBS,ZMOD)

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'Soil moisture increments:'
      WRITE(NULOUT,*) (p_ZINC(J1),J1=1,KSEKFCV)
      WRITE(NULOUT,*) 'KSEKFQ is:', KSEKFQ
    ENDIF
  ENDIF

  IF (LLDEBUGPRINT) THEN
    IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
      WRITE(NULOUT,*) 'Background error at the end of SEKF:'
      WRITE(NULOUT,*) 'Dimension: KVAR * KVAR'
      DO J1 = 1, KSEKFCV
        WRITE(NULOUT,*) (p_ZBACK(J1,J2),J2=1,KSEKFCV)
      ENDDO
    ENDIF
  ENDIF


! END OF THE SEKF CONTROL LOOP
    exit LoopSEKF
  ENDDO LoopSEKF

!*    -----------------------------------------------------------------------------------
!*    12.0 Compute soil moisture at analyses times
!*    -----------------------------------------------------------------------------------

p_ZMOD_ANA(:,:) = 0._JPRB

DO J1 = 1, NANAL
  DO J2 = 1, KSEKFCV
    p_ZMOD_ANA(J1,J2) = VOL_SM_FG(KL,J2,KBLOCK,NANA_TSTEP(J1),1) + p_ZINC(J2)
  ENDDO
ENDDO

IF (LLDEBUGPRINT) THEN
  IF (KL==NREF_GP .AND. KBLOCK==NREF_BLOCK) THEN   ! write to log file
    DO J1 = 1, NANAL
      WRITE(NULOUT,*) 'Analysed soil moisture at analysis time', NANATIME(J1), ':'
      WRITE(NULOUT,*) (p_ZMOD_ANA(J1,J2),J2=1,KSEKFCV)
    ENDDO
  ENDIF
ENDIF



!*    -----------------------------------------------------------------------------------
!*    13.0 Deallocate SEKF arrays used locally
!*    -----------------------------------------------------------------------------------

IF(ALLOCATED(ZOBS)) DEALLOCATE(ZOBS)
IF(ALLOCATED(ZMOD)) DEALLOCATE(ZMOD)
IF(ALLOCATED(ZPARBCVN)) DEALLOCATE(ZPARBCVN)
IF(ALLOCATED(ZMOD_G)) DEALLOCATE(ZMOD_G)
IF(ALLOCATED(ZVARB)) DEALLOCATE(ZVARB)
IF(ALLOCATED(ZVARB_END)) DEALLOCATE(ZVARB_END)
IF(ALLOCATED(ZVARG)) DEALLOCATE(ZVARG)
IF(ALLOCATED(ZVARG_END)) DEALLOCATE(ZVARG_END)
IF(ALLOCATED(ZPARGCVN)) DEALLOCATE(ZPARGCVN)
IF(ALLOCATED(IFLAG)) DEALLOCATE(IFLAG)
IF(ALLOCATED(ZBERR)) DEALLOCATE(ZBERR)
IF(ALLOCATED(ZOERR)) DEALLOCATE(ZOERR)
IF(ALLOCATED(ZOERR)) DEALLOCATE(ZOCGR_I)
IF(ALLOCATED(ZOERR)) DEALLOCATE(ZKGAIN_I)
IF(ALLOCATED(IOBSA_TSTEP)) DEALLOCATE(IOBSA_TSTEP)

IF (LHOOK) CALL DR_HOOK('SM_EKF_MAIN',1,ZHOOK_HANDLE)

END SUBROUTINE SM_EKF_MAIN
